为什么我的密钥标识符不匹配?

Mar*_*ark 7 java bouncycastle certificate smime

我正在尝试解密S/MIME电子邮件(最初通过Outlook发送),为此,我正在使用bouncycastle API.不过,我遇到了麻烦.

我在Windows证书存储区中拥有收件人的证书.我之前用它将签名和加密的电子邮件发送给另一方,然后他们用它向我发送加密回复.然后我将证书(带私钥)导出为.pfx文件,然后将此pfx文件加载到Java KeyStore中.但是,它不起作用,我怀疑这是因为主题密钥标识符不匹配.

这是我用来从KeyStore获取主题密钥id的代码:

KeyStore ks = KeyStore.getInstance("PKCS12");
char[]   pw = "password".toCharArray();

ks.load(new FileInputStream("d:\\cert_priv_key.pfx"), pw);

Enumeration en = ks.aliases();

while( en.hasMoreElements() )
{
    String alias = (String)en.nextElement();
    System.out.println(alias);

    if( ks.isKeyEntry(alias) )
    {
        Certificate[]   chain = ks.getCertificateChain(alias);
        X509Certificate cert  = (X509Certificate)chain[0];

        byte[] id = cert.getExtensionValue("2.5.29.14");

        System.out.println("  " + toHex(id));
    }
}
Run Code Online (Sandbox Code Playgroud)

这将打印出以下密钥标识符:

04 16 04 14 88 ed bb 7c 64 7b 41 63 48 0a 24 40 2b 3c d0 78 72 3c 30 b3
Run Code Online (Sandbox Code Playgroud)

但是,当我检查Windows证书存储区时,密钥标识符是不同的:

88 ed bb 7c 64 7b 41 63 48 0a 24 40 2b 3c d0 78 72 3c 30 b3
Run Code Online (Sandbox Code Playgroud)

KeyStore在前面返回额外的4个字节(主题密钥标识符应该是密钥的160位SHA1散列,因此20个字节长,正确吗?).

更令人困惑的是,当我使用bouncycastle API解析S/MIME电子邮件并通过收件人(SMIMEEnveloped.getRecipientInfos().getRecipients())时,返回的唯一收件人(应该只有一个)具有此主题密钥标识符:

04 14 88 ed bb 7c 64 7b 41 63 48 0a 24 40 2b 3c d0 78 72 3c 30 b3
Run Code Online (Sandbox Code Playgroud)

...它只有两个额外的字节,而不是四个,我想这就是为什么我无法用证书解密电子邮件.

为什么这些主题密钥标识符都不匹配?我究竟做错了什么?

Jam*_*olk 16

如果您了解所有规格,所有这些答案都是一致的,但当然这意味着如果您不理解它们会让您感到困惑.首先要看的是RFC 5280,第4.2.1.2节.在这种情况下,使用方法(1).接下来,查看KeyIdentifier定义中的A.2节.它被定义为OCTET STRING.现在看看ASN.1 OCTET STRING 应该如何编码.它应该以十六进制04开始,后跟长度(以字节为单位)(20字节或14十六进制),后跟实际的八位字节字符串(SHA1哈希).所以扩展的内容应该是

04 14 88 ed bb 7c 64 7b 41 63 48 0a 24 40 2b 3c d0 78 72 3c 30 b3
Run Code Online (Sandbox Code Playgroud)

最后,看一下Extension的ASN.1定义.它表示扩展值必须编码为OCTET STRING.在这种特定扩展的情况下,净效果是连续两次编码为OCTET STRING.在此级别,OCTET STRING是前一个OCTET STRING,它包含两个头字节04 14,因此长度为十六进制16,编码为

04 16 04 14 88 ed bb 7c 64 7b 41 63 48 0a 24 40 2b 3c d0 78 72 3c 30 b3
Run Code Online (Sandbox Code Playgroud)

这是X509Extension.getExtensionValue()方法返回的值.现在,key id的有趣部分只是SHA1哈希的开头88,所以这就是Windows实用程序显示的内容.显然,您使用的bouncycastle方法显示扩展而不进行额外的解码.