【问题标题】:How to convert JWK public key to PEM format in C++如何在 C++ 中将 JWK 公钥转换为 PEM 格式
【发布时间】:2019-12-04 15:36:46
【问题描述】:

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-----

反之亦然。因此,ktykid 字段也以某种方式包含在 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++ 库实现正确的转换,因此它还将考虑 kidkty 字段并使用与在线工具提供的相同 PEM 的结果?

【问题讨论】:

标签: c++ openssl public-key pem jwk


【解决方案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] 中指定。

【讨论】:

    【解决方案2】:

    这是我使用CryptoPPCryptoPP-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();
    }
    

    【讨论】:

      猜你喜欢
      • 2017-05-06
      • 2013-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-23
      • 2018-01-04
      • 2017-10-14
      • 1970-01-01
      相关资源
      最近更新 更多