用Java生成X509Certificate的主题哈希

我目前正在尝试使用Java Security API和BouncyCastle生成主题哈希。

当我使用Openssl库时,这就是我的工作:

openssl x509 -in /Users/Sn0wfreezeDev/Downloads/Test.pem -hash 

这会生成一个短的8位数哈希值1817886a

这是我的Java代码

 X509Certificate cert = CertManager.getCertificate(number, c); MessageDigest sha1 = MessageDigest.getInstance("SHA1"); System.out.println(" Subject " + cert.getSubjectDN()); System.out.println(" Issuer " + cert.getIssuerDN()); sha1.update(cert.getSubjectDN().getName().getBytes()); String hexString = bytesToHex(sha1.digest()); System.out.println(" sha1 " + hexString); System.out.println(); 

这会生成一个短的8位数哈希值1817886a

OpenSSL有两种forms:

 $ cd openssl-1.0.2-src $ grep -R X509_subject_name_hash * ... crypto/x509/x509.h:unsigned long X509_subject_name_hash(X509 *x); crypto/x509/x509.h:unsigned long X509_subject_name_hash_old(X509 *x); crypto/x509/x509_cmp.c:unsigned long X509_subject_name_hash(X509 *x) crypto/x509/x509_cmp.c:unsigned long X509_subject_name_hash_old(X509 *x) ... 

在Java中生成X509Certificate的主题哈希…

以下是来自crypto/x509/x509_cmp.c的源代码:

 unsigned long X509_subject_name_hash(X509 *x) { return (X509_NAME_hash(x->cert_info->subject)); } #ifndef OPENSSL_NO_MD5 unsigned long X509_subject_name_hash_old(X509 *x) { return (X509_NAME_hash_old(x->cert_info->subject)); } #endif 

最后:

 unsigned long X509_NAME_hash(X509_NAME *x) { unsigned long ret = 0; unsigned char md[SHA_DIGEST_LENGTH]; /* Make sure X509_NAME structure contains valid cached encoding */ i2d_X509_NAME(x, NULL); if (!EVP_Digest(x->canon_enc, x->canon_enclen, md, NULL, EVP_sha1(), NULL)) return 0; ret = (((unsigned long)md[0]) | ((unsigned long)md[1] << 8L) | ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L) ) & 0xffffffffL; return (ret); } #ifndef OPENSSL_NO_MD5 unsigned long X509_NAME_hash_old(X509_NAME *x) { EVP_MD_CTX md_ctx; unsigned long ret = 0; unsigned char md[16]; /* Make sure X509_NAME structure contains valid cached encoding */ i2d_X509_NAME(x, NULL); EVP_MD_CTX_init(&md_ctx); EVP_MD_CTX_set_flags(&md_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); if (EVP_DigestInit_ex(&md_ctx, EVP_md5(), NULL) && EVP_DigestUpdate(&md_ctx, x->bytes->data, x->bytes->length) && EVP_DigestFinal_ex(&md_ctx, md, NULL)) ret = (((unsigned long)md[0]) | ((unsigned long)md[1] << 8L) | ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L) ) & 0xffffffffL; EVP_MD_CTX_cleanup(&md_ctx); return (ret); } #endif 

i2d_X509_NAME使用RFC 2459 (以及其他地方)将X509_NAME编码为标准表示forms。 例如,它用于证书主题和发行者名称。

您可以使用openssl x509 -in -text -noout等命令查看OpenSSL用于名称字符串的内容。 它看起来类似于C=US, ST=California, L=Mountain View, O=Google Inc, CN=www.google.com (取自Google证书)。


在Java中生成X509Certificate的主题哈希...

在大图中,您将生成Subject的Distinguished Name字符串的哈希并返回unsigned long。 unsigned long实际上是一个截断的哈希。

X509_subject_name_hash使用SHA-1, X509_subject_name_hash_old使用MD5。


(评论)...他们如何使用sha1哈希生成该短哈希

OpenSSL提供截断哈希的hex编码。 整个哈希值是mdmd将是16字节(MD5)或20字节(SHA-1)。

通过选择字节[0,3]和对md[0]md[1]md[2]md[3]的位操作进行截断。

8位数字来自16位字节的hex编码。