Генерировать предметный хэш сертификата X509 в Java
В настоящее время я пытаюсь сгенерировать хеш объекта с помощью API безопасности Java и 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();
1 ответ
Это генерирует короткий 8-значный хэш 1817886a
Есть две формы этого от OpenSSL:
$ 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)
...
Сгенерировать предметный хеш X509Сертификат в Java...
Вот источник для них из 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
кодирует X509_NAME
в стандартное представление с использованием RFC 2459 (и в других местах). Используется, например, в имени субъекта сертификата и эмитента.
Вы можете увидеть, что OpenSSL использует для строки имени с такими командами, как openssl x509 -in <cert> -text -noout
, Это будет похоже на C=US, ST=California, L=Mountain View, O=Google Inc, CN=www.google.com
(взято из сертификата Google).
Сгенерировать предметный хеш X509Сертификат в Java...
В общем, вы генерируете хеш строки отличительного имени субъекта и возвращаете длинную без знака. Длинный без знака является усеченным хешем.
X509_subject_name_hash
использует SHA-1, и X509_subject_name_hash_old
использует MD5.
(комментарий) ... как они могут использовать хеш sha1 для генерации этого короткого хеша
OpenSSL предоставляет шестнадцатеричное кодирование усеченного хэша. Весь хеш в md
, md
будет 16 байтов (MD5) или 20 байтов (SHA-1).
Усечение происходит с выделением байтов [0,3]
и битовые операции на md[0]
, md[1]
, md[2]
а также md[3]
,
8 цифр взяты из шестнадцатеричного кодирования 4 байтов.