Here是一个在线工具,可将JWK转换为PEM,反之亦然。
我想要相同的C ++代码。
对于JWK:
{
"kty":"RSA",
"e":"AQAB",
"kid":"18b4f6a6-f9ec-456b-a3e8-04af5e97790e",
"n":"tVKUtcx_n9rt5afY_2WFNvU6PlFMggCatsZ3l4RjKxH0jgdLq6CScb0P3ZGXYbPzXvmmLiWZizpb-h0qup5jznOvOr-Dhw9908584BSgC83YacjWNqEK3urxhyE2jWjwRm2N95WGgb5mzE5XmZIvkvyXnn7X8dvgFPF5QwIngGsDG8LyHuJWlaDhr_EPLMW4wHvH0zZCuRMARIJmmqiMy3VD4ftq4nS5s8vJL0pVSrkuNojtokp84AtkADCDU_BUhrc2sIgfnvZ03koCQRoZmWiHu86SuJZYkDFstVTVSR0hiXudFlfQ2rOhPlpObmku68lXw-7V-P7jwrQRFfQVXw"
}
在线工具提供PEM:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtVKUtcx/n9rt5afY/2WF
NvU6PlFMggCatsZ3l4RjKxH0jgdLq6CScb0P3ZGXYbPzXvmmLiWZizpb+h0qup5j
znOvOr+Dhw9908584BSgC83YacjWNqEK3urxhyE2jWjwRm2N95WGgb5mzE5XmZIv
kvyXnn7X8dvgFPF5QwIngGsDG8LyHuJWlaDhr/EPLMW4wHvH0zZCuRMARIJmmqiM
y3VD4ftq4nS5s8vJL0pVSrkuNojtokp84AtkADCDU/BUhrc2sIgfnvZ03koCQRoZ
mWiHu86SuJZYkDFstVTVSR0hiXudFlfQ2rOhPlpObmku68lXw+7V+P7jwrQRFfQV
XwIDAQAB
-----END PUBLIC KEY-----
反之亦然。因此kty
和kid
字段也以某种方式包含在PEM中。
我已经尝试过像这样的OpenSSL:
std::string_view nnInBase64Url = "tVKUtcx_n9rt5afY_2WFNvU6PlFMggCatsZ3l4RjKxH0jgdLq6CScb0P3ZGXYbPzXvmmLiWZizpb-h0qup5jznOvOr-Dhw9908584BSgC83YacjWNqEK3urxhyE2jWjwRm2N95WGgb5mzE5XmZIvkvyXnn7X8dvgFPF5QwIngGsDG8LyHuJWlaDhr_EPLMW4wHvH0zZCuRMARIJmmqiMy3VD4ftq4nS5s8vJL0pVSrkuNojtokp84AtkADCDU_BUhrc2sIgfnvZ03koCQRoZmWiHu86SuJZYkDFstVTVSR0hiXudFlfQ2rOhPlpObmku68lXw-7V-P7jwrQRFfQVXw";
std::string_view eeInBase64Url = "AQAB";
auto nnBin = cppcodec::base64_url_unpadded::decode(nnInBase64Url);
auto eeBin = cppcodec::base64_url_unpadded::decode(eeInBase64Url);
BIGNUM* modul = BN_bin2bn(nnBin.data(),nnBin.size(),NULL);
BIGNUM* expon = BN_bin2bn(eeBin.data(),eeBin.size(),NULL);
RSA* rr = RSA_new();
RSA_set0_key(rr, modul, expon, NULL);
BIO* ff = BIO_new_file("public.pem","w+");
PEM_write_bio_RSAPublicKey(ff, rr);
但这给了我不同的PEM,这很明显,至少我没有指定kid
。
最后,问题是:如何使用OpenSSL或其他C ++库实现正确的转换,因此它还将考虑kid
和kty
字段,并得出与PEM相同的PEM在线工具提供了什么?
答案 0 :(得分:1)
您已经非常接近第一个实现中的解决方案,只是在最后一步,您应该使用PEM_write_bio_RSAPublicKey
来代替PEM_write_bio_RSA_PUBKEY
。
std::string_view nnInBase64Url = "tVKUtcx_n9rt5afY_2WFNvU6PlFMggCatsZ3l4RjKxH0jgdLq6CScb0P3ZGXYbPzXvmmLiWZizpb-h0qup5jznOvOr-Dhw9908584BSgC83YacjWNqEK3urxhyE2jWjwRm2N95WGgb5mzE5XmZIvkvyXnn7X8dvgFPF5QwIngGsDG8LyHuJWlaDhr_EPLMW4wHvH0zZCuRMARIJmmqiMy3VD4ftq4nS5s8vJL0pVSrkuNojtokp84AtkADCDU_BUhrc2sIgfnvZ03koCQRoZmWiHu86SuJZYkDFstVTVSR0hiXudFlfQ2rOhPlpObmku68lXw-7V-P7jwrQRFfQVXw";
std::string_view eeInBase64Url = "AQAB";
auto nnBin = cppcodec::base64_url_unpadded::decode(nnInBase64Url);
auto eeBin = cppcodec::base64_url_unpadded::decode(eeInBase64Url);
BIGNUM* modul = BN_bin2bn(nnBin.data(),nnBin.size(),NULL);
BIGNUM* expon = BN_bin2bn(eeBin.data(),eeBin.size(),NULL);
RSA* rr = RSA_new();
RSA_set0_key(rr, modul, expon, NULL);
BIO* ff = BIO_new_file("public.pem","w+");
PEM_write_bio_RSA_PUBKEY(ff, rr);
有关更多信息,请参阅this discussion的引号
RSAPublicKey函数使用RSA结构处理RSA公钥。公钥使用PKCS#1 RSAPublicKey结构进行编码。
RSA_PUBKEY函数还使用RSA结构处理RSA公钥。但是,公共密钥使用SubjectPublicKeyInfo结构进行编码,如果公共密钥不是RSA,则会发生错误。
并且来自RFC 3280,
4.1.2.7主题公钥信息
此字段用于携带公钥并标识算法 与之配合使用的密钥(例如RSA,DSA或Diffie-Hellman)。的 使用AlgorithmIdentifier结构识别算法 在第4.1.1.2节中指定。的对象标识符 支持的算法和对公钥进行编码的方法 资料(公钥和参数)在[PKIXALGS]中指定。
答案 1 :(得分:0)
这是我使用CryptoPP和CryptoPP-PEM找到的解决方案:
std::string getRSAPublicKeyInPEMFormat(std::string_view nnInBase64UrlUnpadded, std::string_view eeInBase64UrlUnpadded)
{
auto nnBin = cppcodec::base64_url_unpadded::decode(nnInBase64UrlUnpadded);
auto eeBin = cppcodec::base64_url_unpadded::decode(eeInBase64UrlUnpadded);
CryptoPP::Integer nn(nnBin.data(), nnBin.size(), CryptoPP::Integer::UNSIGNED, CryptoPP::BIG_ENDIAN_ORDER);
CryptoPP::Integer ee(eeBin.data(), eeBin.size(), CryptoPP::Integer::UNSIGNED, CryptoPP::BIG_ENDIAN_ORDER);
CryptoPP::RSA::PublicKey pubKey;
pubKey.Initialize(nn, ee);
std::ostringstream pem;
CryptoPP::FileSink sink(pem);
CryptoPP::PEM_Save(sink, pubKey);
return pem.str();
}