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