在OpenSSL中验证RSA公钥
Verify a RSA public key in OpenSSL?
我有一个EVP_PKEY,其中只有RSA密钥的公共部分。我从DER编码的SubjectPublicKeyInfo结构中提取了公共部分。这是我现在的代码:
unsigned char publicKey[] = {0x30, 0x5a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, ...}
size_t publicKeyLength = 92;
unsigned char* publicKeyCopy = new unsigned char[publicKeyLength];
memcpy(publicKeyCopy, publicKey, publicKeyLength);
RSA *rsa;
rsa = d2i_RSA_PUBKEY(NULL, (unsigned char const **) &pubKey, pubKeyLen);
EVP_PKEY *pkey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pkey, rsa);
我知道你可以使用RSA_check_key来验证RSA私钥,但是文档说"它不适用于只有模数和公共指数元素填充的RSA公钥"。
那么,有没有可能在没有私钥部分的情况下验证密钥呢?因为您可以看到,我只有 EVP_PKEY的公共部分。我想知道,这可能吗?你会在EVP_PKEY的公开部分验证什么?
您可以看到这个问题的答案,通过编程验证X509证书和私钥匹配,但在那里验证了完整的密钥(私有和公共部分)。
小心在这个问题中发布的原始代码有一个BUG。这是因为内部d2i_RSA_PUBKEY
使用d2i_PUBKEY
, d2i_PUBKEY
使用d2i_X509_PUBKEY
(在x_pubkey.c中)。如果您阅读了d2i_X509的文档,您将看到下一个"警告:使用临时变量是强制性的。一个常见的错误是试图直接使用缓冲区…"。因此,更正后的代码将不得不使用publicKeyCopy
的临时副本,在使用之后,您可以安全地删除publicKeyCopy
:
小心 在这个问题中发布的原始代码有一个BUG…
我将对此进行评论,并向您展示如何处理它。
unsigned char publicKey[] = {0x30, 0x5a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, ...}
size_t publicKeyLength = sizeof(publicKey);
unsigned char* t = publicKey;
rsa = d2i_RSA_PUBKEY(NULL, &t, pubKeyLen);
在内部,临时指针t
是递增的,所以它被浪费了。如果一切正常,它将指向缓冲区之后的某个位置。在函数执行后,您应该找到的是(size_t)t - (size_t)publicKey == publicKeyLength
。
因为你使用了一个临时指针,原来的指针publicKey
仍然是好的。如果内存中有连续的键,可以使用t
来解析下一个键。
没有必要复制数据。
我认为第二个选择是使用内存BIO
和d2i_RSA_PUBKEY_bio
。比如:
BIO* bio = BIO_new_mem_buf(publicKey, (int)publicKeyLength);
ASSERT(bio != NULL);
RSA* rsa = d2i_RSA_PUBKEY_bio(bio, NULL);
ASSERT(rsa != NULL);
/* ... */
RSA_free(rsa);
BIO_free(bio);
get1
增加了引用计数,因此您需要在EVP_PKEY*
和RSA*
上同时调用free
。
在@jww的帮助下回答https://stackoverflow.com/a/29885771/2692914。我想出了这个解决方案,我希望它是ok的:
bool isValidPublicKeyOnly(EVP_PKEY *pkey) {
//EVP_PKEY_get_type from https://stackoverflow.com/a/29885771/2692914
int type = EVP_PKEY_get_type(pkey); //checks nullptr
if (type != EVP_PKEY_RSA && type != EVP_PKEY_RSA2) {
//not RSA
return false;
}
RSA *rsa = EVP_PKEY_get1_RSA(pkey);
if (!rsa) {
return false;
}
bool isValid = isValidRSAPublicKeyOnly(rsa);
RSA_free(rsa);
return isValid;
}
bool isValidRSAPublicKeyOnly(RSA *rsa) {
//from rsa_ameth.c do_rsa_print : has a private key
//from rsa_chk.c RSA_check_key : doesn't have n (modulus) and e (public exponent)
if (!rsa || rsa->d || !rsa->n || !rsa->e) {
return false;
}
//from http://rt.openssl.org/Ticket/Display.html?user=guest&pass=guest&id=1454
//doesnt have a valid public exponent
return BN_is_odd(rsa->e) && !BN_is_one(rsa->e);
}
我有一个类似的问题,我认为它可能是谨慎的显示我的解决方案,这个问题。与lmiguelmh的解决方案不同,这个解决方案在c中有效。
int checkRsaPublic(RSA *rsa, int debug) {
if (!rsa) {
printf("ERROR: RSA key not defined!n");
return 0;
}
//key
const BIGNUM *n;
const BIGNUM *e;
const BIGNUM *d;
//factors
const BIGNUM *p;
const BIGNUM *q;
//crt_params
const BIGNUM *dmp1;
const BIGNUM *dmq1;
const BIGNUM *iqmp;
RSA_get0_key(rsa, &n, &e, &d);
RSA_get0_factors(rsa, &p, &q);
RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
if (debug) {
if (n) {
printf("n is %sn", BN_bn2hex(n));
}
if (e) {
printf("e is %sn", BN_bn2hex(e));
}
if (d) {
printf("d is %sn", BN_bn2hex(d));
}
if (p) {
printf("p is %sn", BN_bn2hex(p));
}
if (q) {
printf("q is %sn", BN_bn2hex(q));
}
if (dmp1) {
printf("dmp1 is %sn", BN_bn2hex(dmp1));
}
if (dmq1) {
printf("dmq1 is %sn", BN_bn2hex(dmq1));
}
if (iqmp) {
printf("iqmp is %sn", BN_bn2hex(iqmp));
}
}
//RSA_check_key : doesn't have n (modulus) and e (public exponent)
if (d || !n || !e) {
printf("ERROR: RSA public key not well defined!n");
return 0;
}
if (BN_is_odd(e) && !BN_is_one(e)) {
return 1;
}
printf("ERROR: Invalid public exponent.");
return 0;
}
- 使用 char 数组公钥的 OpenSSL 进行 RSA 加密
- 从字符串 Crypto++ 导入 RSA 公钥/私钥
- 一代 RSA-2048 密钥(公钥和私钥)
- RSA公共加密使用X509证书C 的公钥
- 如何使用OpenSSL API从其PEM格式字符串中读取RSA公钥
- 加载在JSBN中创建的RSA公钥,然后加密消息
- RSA函数生成的公钥(e)始终为17
- 通过openssl/c/c++以字节形式读取RSA公钥
- 如何从包含 OpenSSL 中的公钥的字符数组中获取 RSA* 对象
- 通过OpenSSL(c++)以XML(w3c)格式保存RSA公钥和私钥
- 提取存储在无符号字符数组中的RSA公钥模数和指数
- 加密API RSA公钥可以解密数据,并不像预期的那样不对称
- 使用公钥的RSA加密.基于密钥的数据大小
- 在Java中使用RSA公钥加密数据,在Crypto++中解密
- 从WinHTTP中的CRYPT_BIT_BLOB中获取RSA公钥
- 使用RSA公钥解密/加密大数据
- 在OpenSSL中验证RSA公钥
- 如何读取RSA公钥和私钥到单个RSA结构
- 从RSA密钥对变量中分离公钥和私钥
- RSA公钥加密