如何在 C 语言的 OpenSSL 3.0 中从原始数据正确创建 RSA 密钥?
How to properly create an RSA key from raw data in OpenSSL 3.0 in C language?
我对 OpenSSL 还很陌生,我目前的工作是将项目代码从 OpenSSL 1.1.1 更新到 OpenSSL 3.0,我遇到了一个非常奇怪的问题。
我正在尝试根据给定的原始数据创建一个 RSA 密钥,准确地说是转换为 BIGNUM 的二进制模数和指数。我已经尝试按照手册中的描述进行制作并且密钥创建有效,但问题是我尝试使用该密钥(或基于它的 CTX)所做的任何事情都失败了,无论是签名解密还是验证。
这是我创建密钥的代码:
/* function set up above */
ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
if ( ctx == NULL) {
ERROR("Error: failed to initialize CTX from name.\n");
goto OPENSSL_ERROR;
}
modulus = BN_bin2bn(pubkey->data, pubkey->size, NULL);
exponent = BN_bin2bn(exp_arr, 3, NULL);
if ( modulus == NULL || exponent == NULL ) {
goto OPENSSL_ERROR;
}
OSSL_PARAM params[] = {
OSSL_PARAM_BN("n", &modulus, BN_num_bytes(modulus)*8),
OSSL_PARAM_BN("e", &exponent, BN_num_bytes(exponent)*8),
OSSL_PARAM_BN("d", NULL, 0),
OSSL_PARAM_END
};
status = EVP_PKEY_fromdata_init(ctx);
if ( status <= 0 ) {
ERROR("Error: failed to initialize key creation.\n");
goto OPENSSL_ERROR;
}
status = EVP_PKEY_fromdata(ctx, &evp_key, EVP_PKEY_PUBLIC_KEY, params);
if ( status <= 0 || evp_key == NULL ) {
ERROR("Error: failed to create key.\n");
goto OPENSSL_ERROR;
}
/* goes on to decrypt signature and later verify it against data - both fail */
它很快就通过了,但是试图用那个密钥或基于那个密钥的 CTX 做任何事情都失败了。
我尝试使用 EVP_PKEY_CTX_new_id() 创建 CTX,但它没有任何改变。
我尝试省略参数“d”,但它没有任何改变。
如果有人知道我做错了什么以及应该更改什么 - 将不胜感激所有帮助。
P.S.
- pubkey作为参数传递给函数,data是二进制数组,size显然是它的大小(size_t)
- 赋予键的参数与使用
RSA_set0_key()
函数的先前版本代码相同
unsigned char exp_arr[] = {0x01, 0x00, 0x01};
在手册中并不明显(OpenSSL 没有新内容)。
问题是 OSSL_PARAM params 数组无法按照上面代码中的方式进行初始化。它需要使用 OSSL_PARAM_BLD 构建,如下所示:
OSSL_PARAM_BLD *params_build = OSSL_PARAM_BLD_new();
if ( params_build == NULL ) {
goto OPENSSL_ERROR;
}
if ( !OSSL_PARAM_BLD_push_BN(params_build, "n", modulus) ) {
ERROR("Error: failed to push modulus into param build.\n");
goto OPENSSL_ERROR;
}
if ( !OSSL_PARAM_BLD_push_BN(params_build, "e", exponent) ) {
ERROR("Error: failed to push exponent into param build.\n");
goto OPENSSL_ERROR;
}
if ( !OSSL_PARAM_BLD_push_BN(params_build, "d", NULL) ) {
ERROR("Error: failed to push NULL into param build.\n");
goto OPENSSL_ERROR;
}
OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(params_build);
if ( params == NULL ) {
ERROR("Error: failed to construct params from build.\n");
goto OPENSSL_ERROR;
}
它可能与使用 EVP_PKEY_fromdata()
函数创建的所有其他类型的密钥一样工作。
[重要!]
请记住检查您要创建的密钥的可设置参数,否则您可能会在该部分停留很长时间而不知道您的代码有什么问题;)
我对 OpenSSL 还很陌生,我目前的工作是将项目代码从 OpenSSL 1.1.1 更新到 OpenSSL 3.0,我遇到了一个非常奇怪的问题。
我正在尝试根据给定的原始数据创建一个 RSA 密钥,准确地说是转换为 BIGNUM 的二进制模数和指数。我已经尝试按照手册中的描述进行制作并且密钥创建有效,但问题是我尝试使用该密钥(或基于它的 CTX)所做的任何事情都失败了,无论是签名解密还是验证。
这是我创建密钥的代码:
/* function set up above */
ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
if ( ctx == NULL) {
ERROR("Error: failed to initialize CTX from name.\n");
goto OPENSSL_ERROR;
}
modulus = BN_bin2bn(pubkey->data, pubkey->size, NULL);
exponent = BN_bin2bn(exp_arr, 3, NULL);
if ( modulus == NULL || exponent == NULL ) {
goto OPENSSL_ERROR;
}
OSSL_PARAM params[] = {
OSSL_PARAM_BN("n", &modulus, BN_num_bytes(modulus)*8),
OSSL_PARAM_BN("e", &exponent, BN_num_bytes(exponent)*8),
OSSL_PARAM_BN("d", NULL, 0),
OSSL_PARAM_END
};
status = EVP_PKEY_fromdata_init(ctx);
if ( status <= 0 ) {
ERROR("Error: failed to initialize key creation.\n");
goto OPENSSL_ERROR;
}
status = EVP_PKEY_fromdata(ctx, &evp_key, EVP_PKEY_PUBLIC_KEY, params);
if ( status <= 0 || evp_key == NULL ) {
ERROR("Error: failed to create key.\n");
goto OPENSSL_ERROR;
}
/* goes on to decrypt signature and later verify it against data - both fail */
它很快就通过了,但是试图用那个密钥或基于那个密钥的 CTX 做任何事情都失败了。 我尝试使用 EVP_PKEY_CTX_new_id() 创建 CTX,但它没有任何改变。 我尝试省略参数“d”,但它没有任何改变。
如果有人知道我做错了什么以及应该更改什么 - 将不胜感激所有帮助。
P.S.
- pubkey作为参数传递给函数,data是二进制数组,size显然是它的大小(size_t)
- 赋予键的参数与使用
RSA_set0_key()
函数的先前版本代码相同 unsigned char exp_arr[] = {0x01, 0x00, 0x01};
在手册中并不明显(OpenSSL 没有新内容)。
问题是 OSSL_PARAM params 数组无法按照上面代码中的方式进行初始化。它需要使用 OSSL_PARAM_BLD 构建,如下所示:
OSSL_PARAM_BLD *params_build = OSSL_PARAM_BLD_new();
if ( params_build == NULL ) {
goto OPENSSL_ERROR;
}
if ( !OSSL_PARAM_BLD_push_BN(params_build, "n", modulus) ) {
ERROR("Error: failed to push modulus into param build.\n");
goto OPENSSL_ERROR;
}
if ( !OSSL_PARAM_BLD_push_BN(params_build, "e", exponent) ) {
ERROR("Error: failed to push exponent into param build.\n");
goto OPENSSL_ERROR;
}
if ( !OSSL_PARAM_BLD_push_BN(params_build, "d", NULL) ) {
ERROR("Error: failed to push NULL into param build.\n");
goto OPENSSL_ERROR;
}
OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(params_build);
if ( params == NULL ) {
ERROR("Error: failed to construct params from build.\n");
goto OPENSSL_ERROR;
}
它可能与使用 EVP_PKEY_fromdata()
函数创建的所有其他类型的密钥一样工作。
[重要!] 请记住检查您要创建的密钥的可设置参数,否则您可能会在该部分停留很长时间而不知道您的代码有什么问题;)