Android数字签名解析(二)
在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数字签名解析(二)的更多相关文章
- Android数字签名解析(三)
在刚才開始学习android数字签名的相关知识点的时候,被资料中出现的keystore.x509.密钥对.debug.keystore弄的晕头 转向.经过一段时间的了解,总算明确一些. 一.make_ ...
- Android zxing 解析二维码,生成二维码极简demo
zxing 官方的代码很多,看起来很费劲,此demo只抽取了有用的部分,实现了相机预览解码,解析本地二维码,生成二维码三个功能. 简化后的结构如下: 废话少说直接上代码: BaseDecodeHand ...
- Android数字签名解析(一)
一.数字签名概述 所谓"数字签名"就是通过某种password运算生成一系列符号及代码组成电子password进行签名,来取代书写签名或印章. 数字签名有两种功效:一是能确定消息 ...
- android XMl 解析神奇xstream 二: 把对象转换成xml
前言:对xstream不理解的请看:android XMl 解析神奇xstream 一: 解析android项目中 asset 文件夹 下的 aa.xml 文件 1.Javabeen 代码 packa ...
- android XMl 解析神奇xstream 六: 把集合list 转化为 XML文档
前言:对xstream不理解的请看: android XMl 解析神奇xstream 一: 解析android项目中 asset 文件夹 下的 aa.xml 文件 android XMl 解析神奇xs ...
- android XMl 解析神奇xstream 五: 把复杂对象转换成 xml ,并写入SD卡中的xml文件
前言:对xstream不理解的请看: android XMl 解析神奇xstream 一: 解析android项目中 asset 文件夹 下的 aa.xml 文件 android XMl 解析神奇xs ...
- android XMl 解析神奇xstream 四: 将复杂的xml文件解析为对象
前言:对xstream不理解的请看: android XMl 解析神奇xstream 一: 解析android项目中 asset 文件夹 下的 aa.xml 文件 android XMl 解析神奇xs ...
- android XMl 解析神奇xstream 三: 把复杂对象转换成 xml
前言:对xstream不理解的请看: android XMl 解析神奇xstream 一: 解析android项目中 asset 文件夹 下的 aa.xml 文件 android XMl 解析神奇xs ...
- android 中解析XML的方法(转)
在XML解析和使用原始XML资源中都涉及过对XML的解析,之前使用的是 DOM4J和 XmlResourceParser 来解析的.本文中将使用XmlPullParser来解析,分别解析不同复杂度的t ...
随机推荐
- mysql基础: mysql列类型--字符串
mysql列类型:整型 http://blog.csdn.net/jk110333/article/details/9342283 mysql列类型--时间和日期 http://blog.csd ...
- Android学习笔记(十三)——碎片(一)
碎片 碎片可看作第二种形式的活动,能够创建碎片来包括视图. 碎片总是嵌入在活动中,一般有两种常见形式: 1.碎片A和碎片B分别处于不同的活动中,当选择碎片A中的某一项时,触发碎片B启动: 2.碎片A和 ...
- 【数据库摘要】12_Sql_存储过程
SQL 存储过程 存储过程创建语法: create or replace procedure 存储过程名(param1 in type,param2 out type) as 变量1 类型(值范围); ...
- javascript学习笔记--迭代函数
概要 这里的迭代函数指的是对数组对象的操作方法,js数组共有五个迭代函数:every.fifter.forEach.map.some. 1.every every方法,返回值为Boolean类型,tr ...
- Lucene.Net 2.3.1开发介绍 —— 三、索引(一)
原文:Lucene.Net 2.3.1开发介绍 -- 三.索引(一) 在说索引之前,先说说索引是什么?为什么要索引?怎么索引? 先想想看,假如现在有一个文本,我们会怎么去搜索.比如,有一个string ...
- hdu 5183(hash)
传送门:Negative and Positive (NP) 题意:给定一个数组(a0,a1,a2,⋯an−1)和一个整数K, 请来判断一下是否存在二元组(i,j)(0≤i≤j<n)使得 NP− ...
- Ubuntu12.04创建 Eclipse launcher
Ubuntu 12.04 默认无法launcher Eclipse快捷图标到左侧Dash,需要手工配置,步骤如下: 1) 首先,创建并打开 ~/.local/share/applications/op ...
- Matlab图像处理系列1———线性变换和直方图均衡
注:本系列来自于图像处理课程实验,用Matlab实现最主要的图像处理算法 图像点处理是图像处理系列的基础,主要用于让我们熟悉Matlab图像处理的编程环境.灰度线性变换和灰度拉伸是对像素灰度值的变换操 ...
- python基础教程_学习笔记1:序列-1
序列 数据结构:通过某种方式组织在一起的数据元素的集合,这些数据元素能够是数字或者字符,甚至能够是其它数据结构. python中,最主要的数据结构是序列. 序列中的每一个元素被分配一个序号--即元素的 ...
- hash应用以及vector的使用简介:POJ 3349 Snowflake Snow Snowflakes
今天学的hash.说实话还没怎么搞懂,明天有时间把知识点总结写了,今天就小小的写个结题报告吧! 题意: 在n (n<100000)个雪花中判断是否存在两片完全相同的雪花,每片雪花有6个角,每个角 ...