【问题标题】:Separating public and private keys from RSA keypair variable从 RSA 密钥对变量中分离公钥和私钥
【发布时间】:2014-04-26 14:39:20
【问题描述】:

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

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

这是生成密钥的代码:

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

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

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

// 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] = '\0';
pub_key[pub_len] = '\0';

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

此代码有效,因为我已在 Visual Studio 2012 中对其进行了测试。 关于如何分离密钥的任何想法,然后将它们重新组合成一个“密钥对”,或者如何分别使用它们来加密/解密一些字符串变量?

谢谢

(完整代码)

#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] = '\0';
    pub_key[pub_len] = '\0';

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

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

// 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\n", 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\n", err);
    goto free_stuff;
}
printf("Decrypted message: %s\n", 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/

【问题讨论】:

  • 我通过搜索发现有些人尝试过问同样的问题,但到目前为止没有正确的答案 -> (stackoverflow.com/questions/20002029/…)
  • 使用命令行工具'rsa'和'rsautl'怎么样?
  • RSA_public_encrypt 似乎需要一个公钥(根据 API)。您是否尝试过使用公钥而不是密钥对?为什么要重新创建密钥对?你试过什么失败了?
  • @ChiaraHsieh 在网站上推荐有关编程的命令行实用程序有点奇怪。
  • 是的,这将超出加密的目的。您正在尝试做的事情非常基本,我想知道是否没有示例。否则,您可以查看 CLI 应用程序的源代码。如果您需要一个字符串而不是字节,那么您可以简单地对 PKCS#1 公钥进行 base 64 编码。或者添加一个 ASCII 装甲 (PEM)。

标签: c++ openssl rsa


【解决方案1】:

您可以使用 d2i_RSAPublicKeyi2d_RSAPublicKey (link) 从 RSA 密钥对中提取 RSA 公钥。使用i2d_RSAPublicKey 将您的密钥对编码为PKCS#1 RSAPublicKey 结构,将其存储在一个字节串中,然后使用d2i_RSAPublicKey 将其解码回RSA 密钥结构。

【讨论】:

  • 感谢您的建议,过去几个小时我一直在努力完成这项工作,尽管我不知道该怎么做。这是我尝试过的://Trying to encode keypair to PKCS#1 Public Key struct unsigned char **mypub=NULL;i2d_RSAPublicKey(keypair,mypub);printf("\n%s\n",mypub);
  • 打印出来时,mypub 似乎为空。我也尝试使用malloc 分配mupub 一定数量的内存,但这似乎没有帮助。有什么建议吗?
  • 那是因为i2d_RSAPublicKey修改了mypub,让它指向了另一个地方。您可以尝试使用临时变量来保存原始 mypub,然后在 i2d_RSAPublicKey 之后使用 mypub = temp;
【解决方案2】:

我在其他 Stack-Overflow 帖子中找到了我的问题的解决方案,即 Reading Public/Private Key from Memory with OpenSSL

@SquareRootOfTwentyThree 回答了我正在寻找的答案是他的最后一行代码,

将公钥提取到名为 pub 的 BIO 变量中后:

PEM_write_bio_RSAPublicKey(pub, keypair);

我可以通过网络发送变量 pub,在它到达另一端后创建一个 RSA 变量并将 pub 放入其中:

解决方案:

RSA *keypair2 = NULL; 
PEM_read_bio_RSAPublicKey( pub, &keypair2, NULL, NULL);

完成此操作后,我可以像往常一样使用 keypair2 成功加密消息:

加密:

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, keypair2 ,RSA_PKCS1_OAEP_PADDING)) == -1) {
    ERR_load_crypto_strings();
    ERR_error_string(ERR_get_error(), err);
    fprintf(stderr, "Error encrypting message: %s\n", err);
}

然后我可以将此加密变量发送回第一台机器,并像往常一样使用我原来的 keypair 对其进行解密,而无需通过网络发送。

解密:

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\n", err);
}

感谢大家为这篇文章做出贡献!!!

【讨论】:

  • 干得好!为你 +1。
  • 谢谢! ^^ 为像我这样没有经验的人做了一些研究,找到了这个非常简单的解决方案,
【解决方案3】:

查看您的代码,您似乎成功地将 publicprivate 键分离为字符串 pub_key 和 pri_key,但随后使用 printf 输出它们,将它们粘贴在一起。要仅打印 public 键,请将 printf 语句更改为:

printf("\n%s\n", pub_key); 

【讨论】:

    【解决方案4】:

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

    ...关于如何分离密钥,然后将它们重新组合成一个“密钥对”或者如何分别使用它们来加密/解密一些字符串变量的任何想法?

    您可以使用RSAPublicKey_dupRSAPrivateKey_dup,而无需通过 ASN.1/DER 或 PEM 编码来往返它们。在这里,往返包括使用像 PEM_write_bio_RSAPublicKeyPEM_read_bio_RSAPublicKey 这样的函数。

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

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


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


    // 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, "\n");
        RSA_print_fp(stdout, rsa_pub.get(), 0);
    
        fprintf(stdout, "\n");
        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 密钥进行加密或解密,但您声称加密和解密问题的答案显示在您的答案中的代码中。

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

    【讨论】:

      猜你喜欢
      • 2018-07-19
      • 2013-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-07
      • 1970-01-01
      • 2017-05-11
      相关资源
      最近更新 更多