`
sswh
  • 浏览: 161732 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

JAR数字签名格式解析示例

    博客分类:
  • java
阅读更多

JAR文件数字签名后在META-INF下产生两个文件,以JCE Unlimited 6为例,两个文件为JCE_RSA.SF文件和JCE_RSA.RSA文件。

jce_policy-6文件下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html

 

JCE_RSA.SF文件是对MANIFEST.MF文件的消息摘要;

JCE_RSA.RSA文件是对JCE_RSA.SF文件进行数字签名后的结果,签名文件内容遵循加密消息语法标准PKCS#7,按DER进行编码。

 

DER格式编码我们借助 bouncycastle来分析。比较有用的方法ASN1Dump.dumpAsString();

PKCS#7数据对应于org.bouncycastle.asn1.pkcs.SignedData类。

<dependency>
	<groupId>org.bouncycastle</groupId>
	<artifactId>bcprov-jdk16</artifactId>
	<version>1.46</version>
</dependency>

 

 

X509证书可以用Windows的证书管理器(certmgr.msc)来查看证书细节,对照分析结果;

另外,也可以导出对应的证书进行分析。

 

import java.io.FileInputStream;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.Security;

import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEREncodable;
import org.bouncycastle.asn1.util.ASN1Dump;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

public class DerDemo {

	public static void main(String[] args) throws Exception {
		Security.addProvider(new BouncyCastleProvider());

		InputStream in = new FileInputStream("test.cer");
		byte[] content = new byte[in.available()];
		in.read(content);
		in.close();

		ASN1InputStream asnin = new ASN1InputStream(content);
		ASN1Sequence cert = (ASN1Sequence) asnin.readObject();
		asnin.close();

		//第一段:证书内容
		ASN1Sequence tbsCertificate = (ASN1Sequence) cert.getObjectAt(0);
		System.out.println(new String(Hex.encode(tbsCertificate.getDEREncoded())));
		for (int i = 0; i < tbsCertificate.size(); i++) {
			DEREncodable info = tbsCertificate.getObjectAt(i);
			System.out.println(new String(Hex.encode(info.getDERObject().getDEREncoded())));
			System.out.println(ASN1Dump.dumpAsString(info, true));
		}

		//第二段签名算法
		ASN1Sequence signatureAlgorithm = (ASN1Sequence) cert.getObjectAt(1);
		System.out.println(new String(Hex.encode(signatureAlgorithm.getDEREncoded())));
		System.out.println(ASN1Dump.dumpAsString(signatureAlgorithm, true));

		//第三段证书签名
		DEREncodable signatureValue = cert.getObjectAt(2);
		System.out.println(new String(Hex.encode(signatureValue.getDERObject().getDEREncoded())));
		System.out.println(ASN1Dump.dumpAsString(signatureValue, true));

		//证书指纹计算
		MessageDigest md = MessageDigest.getInstance("SHA1");
		md.update(/*tbsCertificate.getDEREncoded()*/content);
		byte[] digest = md.digest();
		System.out.println(new String(Hex.encode(digest)));
	}
}

 

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.RSAPublicKeySpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

public class X509Demo {

	public static void main(String[] args) throws Exception {
		Security.addProvider(new BouncyCastleProvider());

		InputStream in = new FileInputStream("test.cer");
		byte[] content = new byte[in.available()];
		in.read(content);
		in.close();

		CertificateFactory factory = CertificateFactory.getInstance("X.509");
		System.out.println(factory.getProvider());
		X509Certificate cert = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(content));
		// 证书
		System.out.println(cert);

		// 证书内容:也是被发行者签名的部分
		System.out.println("证书内容:" + new String(Hex.encode(cert.getTBSCertificate())));

		PublicKey publickey = cert.getPublicKey();
		// 公钥DER编码(包含公钥算法、RSA模数和RSA公钥指数,windows证书查看器显示的公钥编码不含算法部分)
		System.out.println("公钥DER编码:" + new String(Hex.encode(publickey.getEncoded())));
		RSAPublicKeySpec rsapublic = KeyFactory.getInstance("RSA").getKeySpec(publickey, RSAPublicKeySpec.class);
		System.out.println("RSA模数:" + rsapublic.getModulus());
		System.out.println("RSA公钥指数:" + rsapublic.getPublicExponent());
	}
}

 

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;
import javax.security.auth.x500.X500Principal;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.pkcs.ContentInfo;
import org.bouncycastle.asn1.pkcs.SignedData;
import org.bouncycastle.asn1.pkcs.SignerInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

public class PKCS7Demo {

	static Map<String, String> OIDS = new HashMap<String, String>();
	static {
		OIDS.put("1.3.14.3.2.26", "SHA1");
		OIDS.put("1.2.840.113549.1.1.1", "RSA");
	}

	public static void main(String[] args) throws Exception {
		Security.addProvider(new BouncyCastleProvider());

		InputStream in = new FileInputStream("JCE_RSA.RSA");
		byte[] content = new byte[in.available()];
		in.read(content);
		in.close();

		ASN1InputStream asnin = new ASN1InputStream(content);
		ASN1Sequence asndata = (ASN1Sequence) asnin.readObject();
		asnin.close();

		DERTaggedObject tag0 = (DERTaggedObject) asndata.getObjectAt(1);
		SignedData pkcs7 = SignedData.getInstance(tag0.getObject());
		System.out.println("版本:" + pkcs7.getVersion());
		System.out.println("消息摘要算法:" + pkcs7.getDigestAlgorithms());
		ContentInfo contentInfo = pkcs7.getContentInfo();
		System.out.println("数据类型:" + contentInfo.getContentType());
		System.out.println("数据正文:" + contentInfo.getContent());

		for (ASN1Encodable certNode : pkcs7.getCertificates().toArray()) {
			System.out.println("证书:" + new String(Hex.encode(certNode.getDEREncoded())));
		}

		System.out.println("作废证书:" + pkcs7.getCRLs());
		for (ASN1Encodable signerNode : pkcs7.getSignerInfos().toArray()) {
			SignerInfo signer = SignerInfo.getInstance(signerNode);
			System.out.println("签名者信息:" + new String(Hex.encode(signerNode.getDEREncoded())));
			System.out.println("版本:" + signer.getVersion());
			System.out.println("证书发行者:" + signer.getIssuerAndSerialNumber().getName());
			System.out.println("证书序列号:" + signer.getIssuerAndSerialNumber().getCertificateSerialNumber());
			System.out.println("消息摘要算法:" + signer.getDigestAlgorithm().getAlgorithm());
			System.out.println("签名时间:" + signer.getAuthenticatedAttributes());
			System.out.println("签名算法:" + signer.getDigestEncryptionAlgorithm().getAlgorithm());
			System.out.println("签名:" + signer.getEncryptedDigest());
		}

		System.out.println("-----验证签名-----");
		SignerInfo signer = SignerInfo.getInstance(pkcs7.getSignerInfos().getObjectAt(0));
		X500Principal issuer = new X500Principal(signer.getIssuerAndSerialNumber().getName().getDEREncoded());
		BigInteger sn = signer.getIssuerAndSerialNumber().getCertificateSerialNumber().getValue();
		CertificateFactory factory = CertificateFactory.getInstance("X.509");
		X509Certificate cert = null;
		for (ASN1Encodable certNode : pkcs7.getCertificates().toArray()) {
			X509Certificate acert = (X509Certificate) factory.generateCertificate(//
				new ByteArrayInputStream(certNode.getDEREncoded()));
			if (issuer.equals(acert.getIssuerX500Principal()) && sn.equals(acert.getSerialNumber())) {
				cert = acert;
				break;
			}
		}
		System.out.println("签名证书:" + cert.getIssuerX500Principal());
		System.out.println("证书序号:" + cert.getSerialNumber());

		String signerAlgorithm = OIDS.get(signer.getDigestEncryptionAlgorithm().getAlgorithm().getId());
		System.out.println("签名算法:" + signerAlgorithm);

		Cipher cipher = Cipher.getInstance(signerAlgorithm);
		cipher.init(Cipher.DECRYPT_MODE, cert.getPublicKey());
		cipher.update(signer.getEncryptedDigest().getOctets());
		byte[] derDecrypt = cipher.doFinal();
		System.out.println("DER格式的解密签名:" + new String(Hex.encode(derDecrypt)));

		asnin = new ASN1InputStream(derDecrypt);
		ASN1Sequence derDecryptSeq = (ASN1Sequence) asnin.readObject();
		asnin.close();
		System.out.println("解密签名中的消息摘要算法:" + ((ASN1Sequence) derDecryptSeq.getObjectAt(0)).getObjectAt(0));
		String digestAlgorithm = OIDS.get(//
			((ASN1ObjectIdentifier) // 
			((ASN1Sequence) derDecryptSeq.getObjectAt(0)).getObjectAt(0)//
			).getId()//
			);
		System.out.println("解密签名中的消息摘要算法::" + digestAlgorithm);
		byte[] decryptDigest = ((ASN1OctetString) derDecryptSeq.getObjectAt(1)).getOctets();
		System.out.println("解密的消息摘要:" + new String(Hex.encode(decryptDigest)));

		in = new FileInputStream("JCE_RSA.SF");
		byte[] raw = new byte[in.available()];
		in.read(raw);
		in.close();
		MessageDigest md = MessageDigest.getInstance(digestAlgorithm);
		md.update(raw);
		byte[] rawDigest = md.digest();
		System.out.println("明文消息摘要:" + new String(Hex.encode(rawDigest)));
		System.out.println("验证通过:" + Arrays.equals(decryptDigest, rawDigest));
	}
}

 

0
1
分享到:
评论

相关推荐

    JavaPDF操作类库API_Free Spire.PDF for Java_5.1.0

    数字签名、文档加密、骑缝章;表格;字体应用;附件;打印;超链接;注释;书签等。 2.应用场景:PDF文档创建、编辑、转换、预览及保存等需求的程序设计、系统等。 3.适用人群:所有(包括初学者及任何用途的程序...

    Java核心技术II(第8版)

    5.2 数字格式 5.2.1 货币 5.3 日期和时间 5.4 排序 5.4.1 排序强度 5.4.2 分解 10.5 消息格式化 10.5.1 选择格式 10.6 文本文件和字符集 10.6.1 源文件的字符编码 10.7 资源包 10.7.1 定位资源包 10.7.2 属性文件 ...

    JAVA上百实例源码以及开源项目

     关于数字签名:产生RSA密钥对(myKeyPair),得到RSA密钥对,产生Signature对象,对用私钥对信息(info)签名,用指定算法产生签名对象,用私钥初始化签名对象,将待签名的数据传送给签名对象(须在初始化之后),用公钥...

    java源码包---java 源码 大量 实例

     关于数字签名:产生RSA密钥对(myKeyPair),得到RSA密钥对,产生Signature对象,对用私钥对信息(info)签名,用指定算法产生签名对象,用私钥初始化签名对象,将待签名的数据传送给签名对象(须在初始化之后),用公钥...

    JAVA上百实例源码以及开源项目源代码

     关于数字签名:产生RSA密钥对(myKeyPair),得到RSA密钥对,产生Signature对象,对用私钥对信息(info)签名,用指定算法产生签名对象,用私钥初始化签名对象,将待签名的数据传送给签名对象(须在初始化之后),用公钥...

    java源码包2

     关于数字签名:产生RSA密钥对(myKeyPair),得到RSA密钥对,产生Signature对象,对用私钥对信息(info)签名,用指定算法产生签名对象,用私钥初始化签名对象,将待签名的数据传送给签名对象(须在初始化之后),用公钥...

    java源码包3

     关于数字签名:产生RSA密钥对(myKeyPair),得到RSA密钥对,产生Signature对象,对用私钥对信息(info)签名,用指定算法产生签名对象,用私钥初始化签名对象,将待签名的数据传送给签名对象(须在初始化之后),用公钥...

    java源码包4

     关于数字签名:产生RSA密钥对(myKeyPair),得到RSA密钥对,产生Signature对象,对用私钥对信息(info)签名,用指定算法产生签名对象,用私钥初始化签名对象,将待签名的数据传送给签名对象(须在初始化之后),用公钥...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    Java 数字签名、数字证书生成源码 2个目标文件 摘要:JAVA源码,系统相关,数字签名,数字证书 Java 数字签名、数字证书的相关实例。 关于数字签名:产生RSA密钥对(myKeyPair),得到RSA密钥对,产生Signature对象,对用...

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    Java 数字签名、数字证书生成源码 2个目标文件 摘要:JAVA源码,系统相关,数字签名,数字证书 Java 数字签名、数字证书的相关实例。 关于数字签名:产生RSA密钥对(myKeyPair),得到RSA密钥对,产生Signature对象,对用...

    Android开发艺术探索.任玉刚(带详细书签).pdf

    3.4.2 事件分发的源码解析 144 3.5 View的滑动冲突 154 3.5.1 常见的滑动冲突场景 155 3.5.2 滑动冲突的处理规则 156 3.5.3 滑动冲突的解决方式 157 第4章 View的工作原理 174 4.1 初识ViewRoot和DecorView ...

    Android开发艺术探索

     3.4.2 事件分发的源码解析 / 144  3.5 View的滑动冲突 / 154  3.5.1 常见的滑动冲突场景 / 155  3.5.2 滑动冲突的处理规则 / 156  3.5.3 滑动冲突的解决方式 / 157  第4章 View的工作原理 / 174  4.1 初识...

    android开发艺术探索高清完整版PDF

    469 13.4.1 使用dex2jar和jd—gui反编译apk / 470 13.4.2 使用apktool对apk进行二次打包 / 470 第14章 JNI和NDK编程 / 473 14.1 JNI的开发流程 / 474 14.2 NDK的开发流程 / 478 14.3 JNI的数据类型和类型签名 ...

Global site tag (gtag.js) - Google Analytics