Android数字签名解析(二)
Android 解析 数字签名
2023-09-14 09:08:00 时间
在Android数字签名解析(一)中,介绍了android进行签名的两种方式,当中用密钥对进行签名用到了signapk.jar这个java库。
以下我们就看看signapk签名实现过程,signapk的源代码在build/tools/signapk/下。
一、生成MANIFEST.MF文件
//对apk包中的每一个文件(非目录和非签名文件),生成SHA1的摘要信息。再对这个信息进行Base64编码。 Manifest manifest = addDigestsToManifest(inputJar);
//将上面得到的信息。写入MANIFEST.MF je = new JarEntry(JarFile.MANIFEST_NAME); je.setTime(timestamp); outputJar.putNextEntry(je); manifest.write(outputJar);
二、 生成CERT.SF文件
je = new JarEntry(CERT_SF_NAME); je.setTime(timestamp); outputJar.putNextEntry(je); ByteArrayOutputStream baos = new ByteArrayOutputStream(); writeSignatureFile(manifest, baos); byte[] signedData = baos.toByteArray(); outputJar.write(signedData);
对 整个 MANIFEST.MF 进行 SHA1 计算。并将摘要信息存入 CERT.SF 中 。然后对之前计算的全部摘要信息使用SHA1再次计
算,将结果也写入 CERT.SF 中, 关键代码在 writeSignatureFile(manifest, baos)中,
/** Write a .SF file with a digest of the specified manifest. */ private static void writeSignatureFile(Manifest manifest, OutputStream out) throws IOException, GeneralSecurityException { Manifest sf = new Manifest(); Attributes main = sf.getMainAttributes(); main.putValue("Signature-Version", "1.0"); main.putValue("Created-By", "1.0 (Android SignApk)"); MessageDigest md = MessageDigest.getInstance("SHA1"); PrintStream print = new PrintStream( new DigestOutputStream(new ByteArrayOutputStream(), md), true, "UTF-8"); // Digest of the entire manifest manifest.write(print); print.flush(); main.putValue("SHA1-Digest-Manifest", new String(Base64.encode(md.digest()), "ASCII")); Map<String, Attributes> entries = manifest.getEntries(); for (Map.Entry<String, Attributes> entry : entries.entrySet()) { // Digest of the manifest stanza for this entry. print.print("Name: " + entry.getKey() + "\r\n"); for (Map.Entry<Object, Object> att : entry.getValue().entrySet()) { print.print(att.getKey() + ": " + att.getValue() + "\r\n"); } print.print("\r\n"); print.flush(); Attributes sfAttr = new Attributes(); sfAttr.putValue("SHA1-Digest", new String(Base64.encode(md.digest()), "ASCII")); sf.getEntries().put(entry.getKey(), sfAttr); } CountOutputStream cout = new CountOutputStream(out); sf.write(cout); // A bug in the java.util.jar implementation of Android platforms // up to version 1.6 will cause a spurious IOException to be thrown // if the length of the signature file is a multiple of 1024 bytes. // As a workaround, add an extra CRLF in this case. if ((cout.size() % 1024) == 0) { cout.write('\r'); cout.write('\n'); } }
三、生成CERT.RSA文件
<span style="white-space:pre"> </span>je = new JarEntry(CERT_RSA_NAME); je.setTime(timestamp); outputJar.putNextEntry(je); writeSignatureBlock(new CMSProcessableByteArray(signedData), publicKey, privateKey, outputJar);
关键代码在writeSignatureBlock(new CMSProcessableByteArray(signedData)中
/** Sign data and write the digital signature to 'out'. */ private static void writeSignatureBlock( CMSTypedData data, X509Certificate publicKey, PrivateKey privateKey, OutputStream out) throws IOException, CertificateEncodingException, OperatorCreationException, CMSException { ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>(1); certList.add(publicKey); JcaCertStore certs = new JcaCertStore(certList); CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA") .setProvider(sBouncyCastleProvider) .build(privateKey); gen.addSignerInfoGenerator( new JcaSignerInfoGeneratorBuilder( new JcaDigestCalculatorProviderBuilder() .setProvider(sBouncyCastleProvider) .build()) .setDirectSignature(true) .build(sha1Signer, publicKey)); gen.addCertificates(certs); CMSSignedData sigData = gen.generate(data, false); ASN1InputStream asn1 = new ASN1InputStream(sigData.getEncoded()); DEROutputStream dos = new DEROutputStream(out); dos.writeObject(asn1.readObject()); }
把之前生成的CERT.SF文件,用私有密钥计算出签名, 然后将签名以及公钥信息写入 CERT.RSA 中保存。
相关文章
- android studio不能输入中文_Android模拟器
- android 获取收到短信验证码,Android自动获取短信验证码
- android toast显示时间,Android Toast自定义显示时间「建议收藏」
- android 触摸屏事件_android studio按钮点击事件
- android toast 自定义时间,Android 自定义 Toast 显示时间「建议收藏」
- android开发艺术探索学习 之 Activity的生命周期
- 【Android 系统开发】Android JNI 之 JNIEnv 解析
- 【Android 启动过程】Activity 启动源码分析 ( ActivityThread 流程分析 一 )
- 【Android 逆向】使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 创建反汇编解析器实例对象 | 设置汇编解析器显示细节 )
- 【Android 逆向】启动 DEX 字节码中的 Activity 组件 ( 在 PathClassLoader 和 BootClassLoader 之间插入 DexClassLoader )
- 【Android UI】贝塞尔曲线 ④ ( 使用 android.graphics.Path 提供的 cubicTo 方法绘制三阶贝塞尔曲线示例 )
- 我也有微信朋友圈了 Android实现
- android之service详解手机开发
- android-async-http详解手机开发
- Android中ListView上拉加载更多及下拉刷新详解编程语言
- Eclipse to android详解编程语言
- 开源新闻速递:RaspAnd 发行版可以将树莓派 3 变成一台完备的 Android 计算机
- 硬核观察 | Android 12 发布,小米等设备可以提前测试
- Android实现PHP连接MySQL进行数据交互(android通过php连接mysql)
- android+json+php+mysql实现用户反馈功能方法解析
- 解析Android开发优化之:对界面UI的优化详解(三)
- 解析后台进程对Android性能影响的详解
- Android简单的利用MediaRecorder进行录音的实例代码
- android读取assets文件示例