欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JAR数字签名格式解析示例 博客分类: java

程序员文章站 2024-02-22 09:11:35
...

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));
	}
}