JAR数字签名格式解析示例

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

 

猜你喜欢

转载自sswh.iteye.com/blog/2309425