JAR数字签名格式解析示例 博客分类: java
程序员文章站
2024-02-22 09:16:10
...
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)); } }