从 RSA 密钥对变量中分离公钥和私钥

2022-01-07 00:00:00 openssl rsa c++

正如标题所说,我有一些代码可以生成一对 RSA 密钥.我想将它们分开并单独使用它们来加密/解密,而不是使用变量密钥对"来加密和解密.

As the title says, I have some code that generates a pair of RSA keys. I want to split them apart and use them individually to encrypt/decrypt, rather than use the variable "keypair" to encrypt, and decrypt.

我正在通过网络传输数据,并希望使用简单的 RSA 加密对其进行加密.因此,我想将公钥发送给不同的用户,以便他可以使用它来加密一些数据,然后将其发回给我.

I am working to transfer data across a network, and want to encrypt it using simple RSA encryption. Therefore i want to send the public key over to a different user, so he can use it to encrypt some data, and then send it back to me.

这是生成密钥的代码:

//Generate key pair
    RSA *keypair = RSA_generate_key(KEY_LENGTH, PUB_EXP, NULL, NULL);

我现在想将公钥和私钥分开,这样我就可以独立使用它们来加密和解密数据.我该怎么做?

I now want to separate the public from the private key, so i can use them independently to encrypt and decrypt data. How can i do that?

我有一些代码可以使用密钥对"并将一些信息提取到一些BIO"变量中,尽管我不确定这对我有什么帮助:

I've got some code that takes the "keypair" and extracts some information into some "BIO" variables, although i am not sure how that would help me:

// To get the C-string PEM form:
BIO *pri = BIO_new(BIO_s_mem());
BIO *pub = BIO_new(BIO_s_mem());

PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
PEM_write_bio_RSAPublicKey(pub, keypair);

pri_len = BIO_pending(pri);
pub_len = BIO_pending(pub);

pri_key = (char*)malloc(pri_len + 1);
pub_key = (char*)malloc(pub_len + 1);

BIO_read(pri, pri_key, pri_len);
BIO_read(pub, pub_key, pub_len);

pri_key[pri_len] = '';
pub_key[pub_len] = '';

#ifdef PRINT_KEYS
    printf("
%s
%s
", pri_key, pub_key);
#endif
printf("done.
");

此代码有效,因为我已在 Visual Studio 2012 中对其进行了测试.关于如何分离密钥的任何想法,然后可能将它们重新放在密钥对"中,或者如何单独使用它们来加密/解密某些字符串变量?

This code works, since i've tested it in visual studio 2012. Any ideas on how to separate the keys, then maybe put them back together in a "keypair" or maybe how to use them separately to encrypt/decrypt some string variables?

谢谢

(完整代码)

#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <stdio.h>
#include <string.h>

#define KEY_LENGTH  2048
#define PUB_EXP     3
#define PRINT_KEYS
#define WRITE_TO_FILE

int main() {
    size_t pri_len;            // Length of private key
    size_t pub_len;            // Length of public key
    char   *pri_key;           // Private key
    char   *pub_key;           // Public key
    char   msg[KEY_LENGTH/8];  // Message to encrypt
    char   *encrypt = NULL;    // Encrypted message
    char   *decrypt = NULL;    // Decrypted message
    char   *err;               // Buffer for any error messages
//Generate key pair
    RSA *keypair = RSA_generate_key(KEY_LENGTH, PUB_EXP, NULL, NULL);

// To get the C-string PEM form:
    BIO *pri = BIO_new(BIO_s_mem());
    BIO *pub = BIO_new(BIO_s_mem());

    PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
    PEM_write_bio_RSAPublicKey(pub, keypair);

    pri_len = BIO_pending(pri);
    pub_len = BIO_pending(pub);

    pri_key = (char*)malloc(pri_len + 1);
    pub_key = (char*)malloc(pub_len + 1);

    BIO_read(pri, pri_key, pri_len);
    BIO_read(pub, pub_key, pub_len);

    pri_key[pri_len] = '';
    pub_key[pub_len] = '';

    #ifdef PRINT_KEYS
        printf("
%s
%s
", pri_key, pub_key);
    #endif
    printf("done.
");

// Get the message to encrypt
    printf("Message to encrypt: ");
    fgets(msg, KEY_LENGTH-1, stdin);
    msg[strlen(msg)-1] = '';

// Encrypt the message
    encrypt = (char*)malloc(RSA_size(keypair));
    int encrypt_len;
    err = (char*)malloc(130);
    if((encrypt_len = RSA_public_encrypt(strlen(msg)+1, (unsigned char*)msg, (unsigned char*)encrypt, keypair, RSA_PKCS1_OAEP_PADDING)) == -1) {
        ERR_load_crypto_strings();
        ERR_error_string(ERR_get_error(), err);
        fprintf(stderr, "Error encrypting message: %s
", err);
        goto free_stuff;
    }

// Decrypt it
decrypt = (char*)malloc(encrypt_len);
if(RSA_private_decrypt(encrypt_len, (unsigned char*)encrypt, (unsigned char*)decrypt, keypair, RSA_PKCS1_OAEP_PADDING) == -1) {
    ERR_load_crypto_strings();
    ERR_error_string(ERR_get_error(), err);
    fprintf(stderr, "Error decrypting message: %s
", err);
    goto free_stuff;
}
printf("Decrypted message: %s
", decrypt);

getchar();

//printf("%s", pub_key);

free_stuff:
RSA_free(keypair);
BIO_free_all(pub);
BIO_free_all(pri);
free(pri_key);
free(pub_key);
free(encrypt);
free(decrypt);
free(err);
}

在此处找到此代码:https://shanetully.com/2012/04/simple-public-key-encryption-with-rsa-and-openssl/

推荐答案

我想将 [密钥对] 分开并单独使用它们来加密/解密

I want to split [the keypair] apart and use them individually to encrypt/decrypt

...关于如何分离密钥的任何想法,然后可能将它们重新放在密钥对"中,或者如何单独使用它们来加密/解密某些字符串变量?

... Any ideas on how to separate the keys, then maybe put them back together in a "keypair" or maybe how to use them separately to encrypt/decrypt some string variables?

您可以使用 RSAPublicKey_dupRSAPrivateKey_dup,而无需通过 ASN.1/DER 或 PEM 编码对它们进行往返.在这里,往返包括使用PEM_write_bio_RSAPublicKeyPEM_read_bio_RSAPublicKey 之类的函数.

You can use RSAPublicKey_dup and RSAPrivateKey_dup, without the need to round trip them by ASN.1/DER or PEM encoding them. Here, round tripping consist of using a functions like PEM_write_bio_RSAPublicKey and PEM_read_bio_RSAPublicKey.

下面是使用它们的示例程序.它是用 C++ 编写的(感谢您添加该标签).

Below is a sample program that uses them. Its written in C++ (thanks for adding that tag).

虽然您可以将它们分开,但它们都使用 RSA 结构.公钥有一些成员设置为 NULL,比如私有指数.

While you can separate them, they both use the RSA structure. The public key has some members set to NULL, like the private exponent.

您还可以使用 RSA_printRSA_print_fp 和朋友打印密钥.请参阅下面的 RSA_print (3) 或其用法.

You can also print the keys with RSA_print, RSA_print_fp and friends. See RSA_print (3) or its use below.

// g++ -Wall -Wextra -std=c++11 -stdlib=libc++ -I/usr/local/ssl/macosx-x64/include 
//     t.cpp -o t.exe /usr/local/ssl/macosx-x64/lib/libcrypto.a

#include <memory>
using std::unique_ptr;

#include <openssl/bn.h>
#include <openssl/rsa.h>

#include <cassert>
#define ASSERT assert

using BN_ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
using RSA_ptr = std::unique_ptr<RSA, decltype(&::RSA_free)>;

int main(int argc, char* argv[])
{
    int rc;

    RSA_ptr rsa(RSA_new(), ::RSA_free);
    BN_ptr bn(BN_new(), ::BN_free);

    rc = BN_set_word(bn.get(), RSA_F4);
    ASSERT(rc == 1);

    rc = RSA_generate_key_ex(rsa.get(), 2048, bn.get(), NULL);
    ASSERT(rc == 1);

    RSA_ptr rsa_pub(RSAPublicKey_dup(rsa.get()), ::RSA_free);
    RSA_ptr rsa_priv(RSAPrivateKey_dup(rsa.get()), ::RSA_free);

    fprintf(stdout, "
");
    RSA_print_fp(stdout, rsa_pub.get(), 0);

    fprintf(stdout, "
");
    RSA_print_fp(stdout, rsa_priv.get(), 0);

    return 0;
}

这是输出:

$ ./t.exe 

Public-Key: (2048 bit)
Modulus:
    00:aa:5a:cc:30:52:f1:e9:49:3d:a6:25:00:33:29:
    a6:fa:f7:53:e0:3c:73:4c:91:41:66:20:ec:62:1f:
    27:2a:2a:6c:0f:90:f8:d9:7e:d5:ec:72:7b:38:8c:
    ca:12:60:f8:d1:fb:f2:65:7c:b1:3a:b6:4e:26:ba:
    5b:86:cc:30:f2:fc:be:c3:a2:00:b9:ea:81:fa:1c:
    22:4e:f7:be:a1:1a:66:90:13:b6:12:66:26:23:6d:
    22:15:7d:3b:a4:99:44:38:fa:1c:70:63:4e:50:6f:
    66:38:6c:f6:1a:13:e1:c7:dc:a6:a1:eb:6f:f9:c9:
    59:c8:30:dc:c2:1b:dc:6c:9d:ea:0c:3d:52:5a:00:
    ea:c9:c9:85:51:21:9f:ec:95:b3:dc:c2:50:21:29:
    c2:64:6c:1e:34:36:d8:61:59:ab:3c:a2:cc:e8:ef:
    57:c3:7f:49:86:be:e3:42:88:1b:39:10:b8:2f:fa:
    81:ef:a0:94:99:0c:71:ae:1e:82:7f:e3:6e:00:6e:
    02:13:66:bb:a9:31:58:ec:90:39:9c:bc:9c:8c:90:
    e9:20:f7:20:8e:d6:a3:a3:df:a2:4a:0f:0f:39:b5:
    57:b9:ef:6a:27:e0:1a:ed:f6:ce:0d:87:cd:43:03:
    bf:67:ef:ff:fd:da:98:cc:22:ab:5e:8d:7b:43:d3:
    90:4d
Exponent: 65537 (0x10001)

Private-Key: (2048 bit)
modulus:
    00:aa:5a:cc:30:52:f1:e9:49:3d:a6:25:00:33:29:
    a6:fa:f7:53:e0:3c:73:4c:91:41:66:20:ec:62:1f:
    27:2a:2a:6c:0f:90:f8:d9:7e:d5:ec:72:7b:38:8c:
    ca:12:60:f8:d1:fb:f2:65:7c:b1:3a:b6:4e:26:ba:
    5b:86:cc:30:f2:fc:be:c3:a2:00:b9:ea:81:fa:1c:
    22:4e:f7:be:a1:1a:66:90:13:b6:12:66:26:23:6d:
    22:15:7d:3b:a4:99:44:38:fa:1c:70:63:4e:50:6f:
    66:38:6c:f6:1a:13:e1:c7:dc:a6:a1:eb:6f:f9:c9:
    59:c8:30:dc:c2:1b:dc:6c:9d:ea:0c:3d:52:5a:00:
    ea:c9:c9:85:51:21:9f:ec:95:b3:dc:c2:50:21:29:
    c2:64:6c:1e:34:36:d8:61:59:ab:3c:a2:cc:e8:ef:
    57:c3:7f:49:86:be:e3:42:88:1b:39:10:b8:2f:fa:
    81:ef:a0:94:99:0c:71:ae:1e:82:7f:e3:6e:00:6e:
    02:13:66:bb:a9:31:58:ec:90:39:9c:bc:9c:8c:90:
    e9:20:f7:20:8e:d6:a3:a3:df:a2:4a:0f:0f:39:b5:
    57:b9:ef:6a:27:e0:1a:ed:f6:ce:0d:87:cd:43:03:
    bf:67:ef:ff:fd:da:98:cc:22:ab:5e:8d:7b:43:d3:
    90:4d
publicExponent: 65537 (0x10001)
privateExponent:
    66:a4:ce:e3:4f:16:f3:b9:6d:ab:ee:1f:70:b4:68:
    28:4f:5d:fa:7e:71:fa:70:8b:37:3e:1f:30:00:15:
    59:12:b6:89:aa:90:46:7c:65:e9:52:11:6c:c1:68:
    00:2a:ed:c1:98:4d:35:59:2c:70:73:e8:22:ed:a6:
    b8:51:d0:2c:98:9d:58:c3:04:2d:01:5f:cf:93:a4:
    18:70:ae:2b:e3:fc:68:53:78:21:1d:eb:5c:ed:24:
    dc:4d:d8:e2:14:77:46:dd:6c:c5:4b:10:a4:e6:7a:
    71:05:36:44:00:36:ca:75:e8:f1:27:2b:11:16:81:
    42:5e:2e:a5:c6:a3:c9:cd:60:59:ce:72:71:76:c8:
    ca:ba:f0:45:c3:86:07:7b:22:20:c4:74:c6:a8:ab:
    7c:2c:f8:de:ea:25:95:81:79:33:54:67:7b:61:91:
    80:a8:1f:4c:38:32:d4:4d:2e:a8:7d:9b:d4:1a:3e:
    6b:ca:50:3c:a0:61:0e:00:ad:f4:5c:0f:26:1a:59:
    00:3c:bd:ee:c3:e8:d0:b8:9b:0e:44:89:49:d1:24:
    a4:39:15:dc:0e:c5:d5:41:a2:4a:f4:e5:e3:23:c7:
    98:8a:87:f7:18:a6:e2:7b:27:83:f6:fb:62:42:46:
    ae:de:ba:48:ad:07:39:40:da:65:17:d1:d2:ed:df:
    01
prime1:
    00:dd:dc:70:b5:70:ea:10:20:28:40:a0:c3:b8:70:
    6d:3d:84:c0:57:2d:69:fc:e9:d4:55:ed:4f:ac:3d:
    c2:e9:19:49:f0:ab:c6:bd:99:9e:0f:e5:a4:61:d4:
    b3:c5:c2:b1:e4:3a:10:ff:e6:cd:ce:6e:2d:93:bc:
    87:12:92:87:7c:d3:dd:bc:32:54:9e:fa:67:b1:9d:
    e2:27:53:e6:03:a7:22:17:45:63:0d:42:f3:96:5d:
    a3:e0:9c:93:f0:42:8b:bb:95:34:e6:f6:0b:f7:b6:
    c5:59:a0:b5:2a:71:59:c0:f2:7e:bf:95:2d:dd:6d:
    94:23:2a:95:4a:4f:f1:d0:93
prime2:
    00:c4:91:6a:33:1b:db:24:eb:fd:d3:69:e9:3c:e2:
    a2:2d:23:7a:92:65:a8:a0:50:1d:0a:2b:b4:f0:64:
    e4:40:57:f3:dc:f7:65:18:7d:51:75:73:b9:d6:67:
    9b:0e:94:5f:37:02:6c:7f:eb:b9:13:4b:bf:8e:65:
    22:0b:2c:c6:8d:2a:a2:88:ec:21:e3:f9:0b:78:b4:
    1d:d0:44:e6:36:0d:ec:3c:8f:0a:c7:3b:0d:91:65:
    b7:de:a3:c9:a3:2a:8c:7f:1f:a1:d2:6e:9b:ee:23:
    78:c1:30:76:87:af:a8:11:a4:15:b4:54:16:d8:94:
    71:5c:64:30:43:58:b5:07:9f
exponent1:
    2f:91:e8:88:be:e1:30:fb:f4:25:87:52:ef:e5:0b:
    47:39:83:94:2d:a4:a0:19:f2:f1:49:a4:df:a5:8e:
    79:34:76:ea:27:aa:c1:54:82:d3:9d:c5:95:44:6a:
    17:69:1b:83:77:ff:d5:1e:c3:da:13:3d:aa:83:ad:
    e2:89:90:8b:6f:52:07:dc:32:d0:b3:98:30:39:4e:
    18:68:a0:d4:ff:ad:0b:98:51:18:b2:d6:4f:d3:5c:
    23:f8:ee:af:81:55:3c:af:4d:5c:88:3d:20:ac:0b:
    bc:9f:fc:b8:50:fd:91:a5:6d:0f:df:08:aa:85:a8:
    51:b1:fb:b8:a7:53:8e:09
exponent2:
    7d:46:0b:7f:ad:06:19:de:c8:b2:7e:f2:25:5a:6e:
    6f:04:08:6e:da:99:00:2a:6e:87:77:d9:65:c7:76:
    ec:46:e1:64:f6:ca:18:34:6d:c0:c3:d3:31:00:70:
    82:77:2e:c3:59:29:1a:d1:78:ef:02:3c:7f:9c:96:
    78:b6:bd:87:64:1f:97:d1:9d:bb:b3:91:8b:08:87:
    63:9f:35:74:47:a5:41:e7:0b:c0:73:33:2f:71:bb:
    20:0a:14:4c:87:a6:68:b2:19:28:8a:53:98:0e:45:
    3c:22:0d:b8:65:cb:60:0a:c9:c6:56:3d:05:24:7d:
    a6:9b:37:63:04:5a:c3:13
coefficient:
    00:cc:d7:5c:e6:0e:7b:79:d4:cb:4f:6d:82:a7:45:
    90:67:90:dc:d3:83:62:f1:4b:17:43:5c:4a:ea:bf:
    38:25:c3:6f:34:e2:05:91:5e:60:d6:de:6d:07:1a:
    73:71:b3:1d:73:f2:3c:60:ed:ec:42:d4:39:f8:a4:
    ae:d5:aa:40:1e:90:b1:eb:b1:05:a3:2f:03:5f:c6:
    b7:07:4c:df:0f:c4:a9:80:8c:31:f5:e2:01:00:73:
    8a:25:03:84:4e:48:7a:31:8e:e6:b8:04:4c:44:61:
    7d:e4:87:1c:57:4f:45:44:33:bb:f3:ae:1c:d2:e1:
    99:ed:78:29:76:4d:8c:6d:91

<小时>

与此相关,您从不询问如何使用 RSA 密钥进行加密或解密,但您声称加密和解密问题的答案已显示在您答案中的代码中.


Related, you never ask how to encrypt or decrypt with a RSA key, yet you claim the answer to the encryption and decryption problems is shown in the code in your answer.

你似乎已经把这个问题变成了一个移动目标:) 你应该在 Stack Overflow 上避免这种情况(我认为在那些用户线程论坛中这样做是可以的).在 Stack Overflow 上,你应该问一个单独的问题.

You seem to have made the question a moving target :) You should probably avoid that on Stack Overflow (I think its OK to do in those user thread forums). On Stack Overflow, you should ask a separate question.

相关文章