相当于 java KeyPairGenerator 的 Openssl 库
Openssl library equivalent of java KeyPairGenerator
我正在尝试从 C++ 服务器向 Java 客户端发送一个 RSA public 密钥。由于客户端是 运行 Java 我相信密钥需要在 X509 中格式化。我需要将密钥作为编码的字符数组获取,但找不到正确的方法。
我需要找到等效于以下内容的 c++ openssl 库:
public byte[] getEncodedPubKey() {
try {
KeyPairGenerator keypairgenerator = KeyPairGenerator.getInstance("RSA");
keypairgenerator.initialize(1024);
return keypairgenerator.generateKeyPair().getPublic().getEncoded();
} catch (Exception exception) {
//Insert error handling
}
}
到目前为止,这是我在 C++ 中对解决方案的最佳尝试:
EVP_PKEY *evpKey = EVP_PKEY_new();
RSA *rsa = RSA_generate_key(1024, RSA_F4, nullptr, nullptr);
EVP_PKEY_assign_RSA(evpKey, rsa);
X509 *x = X509_new();
X509_set_pubkey(x, evpKey);
auto *data = (unsigned char*)malloc(165);
X509_PUBKEY *pubkey = X509_get_X509_PUBKEY(x);
int size = i2d_X509_PUBKEY(pubkey, &data);
std::vector<unsigned char> encodedKey(data, data+size);
为了提供更多信息,这是 java 客户端在收到编码的 public 密钥后所做的:
public PublicKey decodePubKey(byte[] encodedKeyIn) {
try {
KeyFactory keyfactory = KeyFactory.getInstance("RSA");
EncodedKeySpec encodedkeyspec = new X509EncodedKeySpec(encodedKeyIn);
return keyfactory.generatePublic(encodedkeyspec);
} catch (Exception exception) {
//Insert error handling
}
}
我的c++代码生成的编码字节数组的大小与java示例相同。然而,客户端仍然抛出这个错误:
error: java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: DerInputStream.getLength(): lengthTag=77, too big.
对我做错了什么有什么想法吗?提前致谢
这个小代码生成一个RSA
密钥对并将public 密钥存储到一个PEM
格式的字符串中。检查它是否解决了您的问题:
#include <iostream>
#include <string>
#include <memory>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
struct BioDeleter {
void operator()(BIO* bio) { BIO_free(bio); }
};
struct KeyCtxDeleter {
void operator()(EVP_PKEY_CTX* ctx) { EVP_PKEY_CTX_free(ctx); }
};
using BIO_ptr = std::unique_ptr<BIO, BioDeleter>;
using PKEY_CTX_ptr = std::unique_ptr<EVP_PKEY_CTX, KeyCtxDeleter>;
int main() {
EVP_PKEY *pkey = nullptr;
PKEY_CTX_ptr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr));
if (!ctx)
return -1;
if (EVP_PKEY_keygen_init(ctx.get()) <= 0)
return -1;
if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), 2048) <= 0)
return -1;
if (EVP_PKEY_keygen(ctx.get(), &pkey) <= 0)
return -1;
BIO_ptr bio(BIO_new(BIO_s_mem()));
auto res = PEM_write_bio_PUBKEY(bio.get(), pkey);
EVP_PKEY_free(pkey);
if (res <= 0)
return -1;
BUF_MEM* mem = nullptr;
BIO_get_mem_ptr(bio.get(), &mem);
auto str = std::string{mem->data, mem->data + mem->length};
std::cout << str << "\n";
}
另外,你可以这样读PEM
是java的一面:
public static RSAPublicKey readPublicKey(File file) throws Exception {
String key = new String(Files.readAllBytes(file.toPath()), Charset.defaultCharset());
String publicKeyPEM = key
.replace("-----BEGIN PUBLIC KEY-----", "")
.replaceAll(System.lineSeparator(), "")
.replace("-----END PUBLIC KEY-----", "");
byte[] encoded = Base64.decodeBase64(publicKeyPEM);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}
此代码来自here.
此代码根据@Afshin 的 post 编辑,生成 RSA
密钥对并使用 public 密钥的 PEM
数据库填充 std::vector<unsigned char>
64解码。向量中的数据等同于java 函数getEncodedPubKey()
post 生成的byte[]
中的数据。解决我问题的 openssl 函数是 PEM_read_bio()
它的文档在这里 PEM_read_bio。此函数解码 PEM
格式的 BIO
.
中的关键数据
代码如下:
#include <iostream>
#include <vector>
#include <memory>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
struct BioDeleter {
void operator()(BIO* bio) { BIO_free(bio); }
};
struct KeyCtxDeleter {
void operator()(EVP_PKEY_CTX* ctx) { EVP_PKEY_CTX_free(ctx); }
};
using BIO_ptr = std::unique_ptr<BIO, BioDeleter>;
using PKEY_CTX_ptr = std::unique_ptr<EVP_PKEY_CTX, KeyCtxDeleter>;
int main() {
EVP_PKEY *pkey = nullptr;
PKEY_CTX_ptr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr));
EVP_PKEY_keygen_init(ctx.get());
EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), 1024);
EVP_PKEY_keygen(ctx.get(), &pkey);
BIO_ptr bio(BIO_new(BIO_s_mem()));
PEM_write_bio_PUBKEY(bio.get(), pkey);
EVP_PKEY_free(pkey);
long size = 0;
char* dummy1 = NULL;
char* dummy2 = NULL;
unsigned char* data = NULL;
PEM_read_bio(bio.get(), &dummy1, &dummy2, &data, &size);
OPENSSL_free(dummy1);
OPENSSL_free(dummy2);
std::vector<unsigned char> decodedKey(data, data+size);
OPENSSL_free(data);
}
注意:没有错误处理,因为这只是一个示例
我正在尝试从 C++ 服务器向 Java 客户端发送一个 RSA public 密钥。由于客户端是 运行 Java 我相信密钥需要在 X509 中格式化。我需要将密钥作为编码的字符数组获取,但找不到正确的方法。
我需要找到等效于以下内容的 c++ openssl 库:
public byte[] getEncodedPubKey() {
try {
KeyPairGenerator keypairgenerator = KeyPairGenerator.getInstance("RSA");
keypairgenerator.initialize(1024);
return keypairgenerator.generateKeyPair().getPublic().getEncoded();
} catch (Exception exception) {
//Insert error handling
}
}
到目前为止,这是我在 C++ 中对解决方案的最佳尝试:
EVP_PKEY *evpKey = EVP_PKEY_new();
RSA *rsa = RSA_generate_key(1024, RSA_F4, nullptr, nullptr);
EVP_PKEY_assign_RSA(evpKey, rsa);
X509 *x = X509_new();
X509_set_pubkey(x, evpKey);
auto *data = (unsigned char*)malloc(165);
X509_PUBKEY *pubkey = X509_get_X509_PUBKEY(x);
int size = i2d_X509_PUBKEY(pubkey, &data);
std::vector<unsigned char> encodedKey(data, data+size);
为了提供更多信息,这是 java 客户端在收到编码的 public 密钥后所做的:
public PublicKey decodePubKey(byte[] encodedKeyIn) {
try {
KeyFactory keyfactory = KeyFactory.getInstance("RSA");
EncodedKeySpec encodedkeyspec = new X509EncodedKeySpec(encodedKeyIn);
return keyfactory.generatePublic(encodedkeyspec);
} catch (Exception exception) {
//Insert error handling
}
}
我的c++代码生成的编码字节数组的大小与java示例相同。然而,客户端仍然抛出这个错误:
error: java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: DerInputStream.getLength(): lengthTag=77, too big.
对我做错了什么有什么想法吗?提前致谢
这个小代码生成一个RSA
密钥对并将public 密钥存储到一个PEM
格式的字符串中。检查它是否解决了您的问题:
#include <iostream>
#include <string>
#include <memory>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
struct BioDeleter {
void operator()(BIO* bio) { BIO_free(bio); }
};
struct KeyCtxDeleter {
void operator()(EVP_PKEY_CTX* ctx) { EVP_PKEY_CTX_free(ctx); }
};
using BIO_ptr = std::unique_ptr<BIO, BioDeleter>;
using PKEY_CTX_ptr = std::unique_ptr<EVP_PKEY_CTX, KeyCtxDeleter>;
int main() {
EVP_PKEY *pkey = nullptr;
PKEY_CTX_ptr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr));
if (!ctx)
return -1;
if (EVP_PKEY_keygen_init(ctx.get()) <= 0)
return -1;
if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), 2048) <= 0)
return -1;
if (EVP_PKEY_keygen(ctx.get(), &pkey) <= 0)
return -1;
BIO_ptr bio(BIO_new(BIO_s_mem()));
auto res = PEM_write_bio_PUBKEY(bio.get(), pkey);
EVP_PKEY_free(pkey);
if (res <= 0)
return -1;
BUF_MEM* mem = nullptr;
BIO_get_mem_ptr(bio.get(), &mem);
auto str = std::string{mem->data, mem->data + mem->length};
std::cout << str << "\n";
}
另外,你可以这样读PEM
是java的一面:
public static RSAPublicKey readPublicKey(File file) throws Exception {
String key = new String(Files.readAllBytes(file.toPath()), Charset.defaultCharset());
String publicKeyPEM = key
.replace("-----BEGIN PUBLIC KEY-----", "")
.replaceAll(System.lineSeparator(), "")
.replace("-----END PUBLIC KEY-----", "");
byte[] encoded = Base64.decodeBase64(publicKeyPEM);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}
此代码来自here.
此代码根据@Afshin 的 post 编辑,生成 RSA
密钥对并使用 public 密钥的 PEM
数据库填充 std::vector<unsigned char>
64解码。向量中的数据等同于java 函数getEncodedPubKey()
post 生成的byte[]
中的数据。解决我问题的 openssl 函数是 PEM_read_bio()
它的文档在这里 PEM_read_bio。此函数解码 PEM
格式的 BIO
.
代码如下:
#include <iostream>
#include <vector>
#include <memory>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
struct BioDeleter {
void operator()(BIO* bio) { BIO_free(bio); }
};
struct KeyCtxDeleter {
void operator()(EVP_PKEY_CTX* ctx) { EVP_PKEY_CTX_free(ctx); }
};
using BIO_ptr = std::unique_ptr<BIO, BioDeleter>;
using PKEY_CTX_ptr = std::unique_ptr<EVP_PKEY_CTX, KeyCtxDeleter>;
int main() {
EVP_PKEY *pkey = nullptr;
PKEY_CTX_ptr ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr));
EVP_PKEY_keygen_init(ctx.get());
EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), 1024);
EVP_PKEY_keygen(ctx.get(), &pkey);
BIO_ptr bio(BIO_new(BIO_s_mem()));
PEM_write_bio_PUBKEY(bio.get(), pkey);
EVP_PKEY_free(pkey);
long size = 0;
char* dummy1 = NULL;
char* dummy2 = NULL;
unsigned char* data = NULL;
PEM_read_bio(bio.get(), &dummy1, &dummy2, &data, &size);
OPENSSL_free(dummy1);
OPENSSL_free(dummy2);
std::vector<unsigned char> decodedKey(data, data+size);
OPENSSL_free(data);
}
注意:没有错误处理,因为这只是一个示例