【问题标题】:Trouble loading RSA public key from file从文件加载 RSA 公钥时遇到问题
【发布时间】:2020-07-13 18:39:04
【问题描述】:

我最近一直在我的 C++ 项目中使用 openssl 库,但我遇到了一个我自己无法解决的问题。

我实际上是在尝试加载存储在文件中的 RSA 公钥并加密 64 个字节。 我的代码在使用使用函数 RSA_generate_key 生成的公钥时可以工作,但是当我使用自己的公钥时,由于某种原因它将不再工作。

我怀疑来自 pkcs1 pkcs8 的密钥格式,尝试了 PEM_read_RSAPublicKey 和 PEM_read_RSA_PUBKEY,但由于某种原因仍然无法正常工作...

这是我的公钥:

-----BEGIN RSA PUBLIC KEY-----
MEYCQQDE91cW7INdIyVon5H/he2b/DIR25wWT0GFLiZOVp0oAgCAVKDvRZ5+Pqu4
f65XbnNUNNHRJLMLEb1t4JgUhgFVAgER
-----END RSA PUBLIC KEY-----

来自 Openssl 库的 RSA_generate_key 函数的密钥,它正在工作:

-----BEGIN RSA PUBLIC KEY-----
MEYCQQDsg/4Qm153/Pr8JRruC0SnVvTrWg/lIPheezIpkwVeWjNz9lMDXNUjdK8v
QgfNUCRJYbnxYIeruAdwTzS/bDXbAgER
-----END RSA PUBLIC KEY-----

这是我的代码:

RSA.h:

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

#ifndef RSA_ALGORITHM_H
#define RSA_ALGORITHM_H

#define KEY_LENGTH       512
#define PUBLIC_EXPONENT  17
#define PUBLIC_KEY_PEM   1
#define PRIVATE_KEY_PEM  0

#define LOG(x)               \
        std::cout << x << std::endl;   \

 /*
  * @brief   create_RSA function creates public key and private key file
  *
  */
RSA* create_RSA(RSA* keypair, int pem_type, char* file_name);

/*
 * @brief   public_ecrypt function encrypts data.
 * @return  If It is fail, return -1
 */
int public_encrypt(int flen, unsigned char* from, unsigned char* to, RSA* key, int padding);

/*
 * @brief   private_decrypt function decrypt data.
 * @return  If It is fail, return -1
 */
int private_decrypt(int flen, unsigned char* from, unsigned char* to, RSA* key, int padding);

/*
 * @brief   create_ecrypted_file function creates .bin file. It contains encrypted data.
 */
void create_encrypted_file(char* encrypted, RSA* key_pair);

#endif //RSA_ALGORITHM_H

RSA.cpp:

#include "RSA.h"

#include <iostream>
#include <string.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <sstream>
#include <iomanip>

int public_encrypt(int flen, unsigned char* from, unsigned char* to, RSA* key, int padding) {
    int result = RSA_public_encrypt(flen, from, to, key, padding);
    return result;
}

void create_encrypted_file(char* encrypted, RSA* key_pair) {

    FILE* encrypted_file = fopen("encrypted_file.bin", "w");
    fwrite(encrypted, sizeof(*encrypted), RSA_size(key_pair), encrypted_file);
    fclose(encrypted_file);
}

RSA* createRSA(int pem_type, char* file_name) {

    RSA* rsa = NULL;
    FILE* fp = NULL;

    if (pem_type == PUBLIC_KEY_PEM) {

        fp = fopen(file_name, "rb");
        PEM_read_RSAPublicKey(fp, &rsa, NULL, NULL);
        fclose(fp);

    }
    else if (pem_type == PRIVATE_KEY_PEM) {

        fp = fopen(file_name, "rb");
        PEM_read_RSAPrivateKey(fp, &rsa, NULL, NULL);
        fclose(fp);

    }

    return rsa;
}

int main() {

    LOG("RSA has been started.");

    char public_key_pem[11] = "public_key";

    RSA* public_key = createRSA(PUBLIC_KEY_PEM, public_key_pem);
    LOG("Public key pem file has been created.");;

    char message[KEY_LENGTH] = "\xc8\xcd\x21\x74\xb9\x84\x33\xb9\x30\x94\xb3\x60\x26\xde\x12\x5a\x7f\x5e\xd8\x5e\xc2\x7e\xe6\xbb\x9e\x99\x6c\xb3\xb9\x38\xe9\xc6\x23\x8c\xc6\x5d\x36\x15\xfb\x63\x5f\x6f\x08\x0f\x6d\xda\x06\x31\x59\x28\xbc\xae\x4c\xcf\x80\x2f\x96\x80\x54\x7d\xb5\x7b\x82\x83";
    char* encrypt = NULL;


    LOG(KEY_LENGTH);
    LOG(PUBLIC_EXPONENT);

    encrypt = (char*)malloc(RSA_size(public_key));
    int encrypt_length = public_encrypt(RSA_size(public_key), (unsigned char*)message, (unsigned char*)encrypt, public_key, RSA_NO_PADDING);
    if (encrypt_length == -1) {
        LOG("An error occurred in public_encrypt() method");
    }
    LOG("Data has been encrypted.");

    create_encrypted_file(encrypt, public_key);
    LOG("Encrypted file has been created.");

    free(public_key);
    free(encrypt);
    LOG("RSA has been finished.");

    return 0;
}

我看过很多帖子,但没有找到任何解决方法,尽管这与我的问题非常相似

Load public key to create rsa object for public encryption

【问题讨论】:

  • 无论如何,我也无法使用openssl 二进制文件加载该密钥。你确定这是一个有效的密钥吗?你是怎么生成的?
  • @tadman 密钥已从证书中删除。

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


【解决方案1】:

该错误实际上与数学有关。密钥和代码都不是导致问题的原因。如果您更改要加密的密钥或数据,出于某种原因它会正常工作。所以我猜想在 RSA 计算过程中发生了一些事情,但还不够聪明,无法弄清楚是什么。

【讨论】:

    【解决方案2】:

    这两个密钥都是公共 RSA 密钥,大小为 512 位,指数为 17,以 PKCS1-PEM 格式指定。

    消息m,不工作密钥的模数n_fail和工作密钥的模数n_ok是:

    m =      0xc8cd2174b98433b93094b36026de125a7f5ed85ec27ee6bb9e996cb3b938e9c6238cc65d3615fb635f6f080f6dda06315928bcae4ccf802f9680547db57b8283
    n_fail = 0xc4f75716ec835d2325689f91ff85ed9bfc3211db9c164f41852e264e569d2802008054a0ef459e7e3eabb87fae576e735434d1d124b30b11bd6de09814860155
    n_ok =   0xec83fe109b5e77fcfafc251aee0b44a756f4eb5a0fe520f85e7b322993055e5a3373f653035cd52374af2f4207cd50244961b9f16087abb807704f34bf6c35db
    

    比较表明

    n_fail < m < n_ok
    

    对于 RSA,条件 m &lt; n 必须适用。 n_fail 违反了此条件,这是问题的原因。这也意味着对应的密钥本身并没有失效。它可用于加密不违反m &lt; n 的消息。但是对于已发布的消息,它的模数太小了。

    关于安全性:现在密钥的大小应该是2048 bits,并且应该使用RFC8017RSAES-PKCS1-v1_5RSAES-OAEP)中指定的填充之一。

    【讨论】:

    • 按照您的回答,我制作了一个具有相同值的 python 脚本,并且加密工作即使它是 n stackoverflow.com/questions/60997745/…
    • 如果一条消息被加密然后再次解密并且违反了m &lt; n的条件,那么原始消息和解密消息通常会不同。您可以使用小数字轻松检查这一点,例如使用维基百科文章RSA 中的数字。另请注意,您正在使用不同的实现。显然,对于m &gt;= n 的情况,C 实现会返回错误,而您的 Python 实现(可能)不会。在后一种情况下,通常在解密过程中会发现错误(这将失败)。
    • 解密工作并给了我与加密前完全相同的值。但是,您能描述一下是什么让这两个实现彼此不同吗?
    • 我怀疑在某处检查了 C 代码以查看是否有 m &lt; n。您还应该发布私钥(如果可能),否则其他人无法重现解密。
    • 如您自己的示例所示,解密不会返回原始消息。您必须先添加n 才能获得原始消息(参见m = m + n # Had to put this in the way to recover correct data 行)。此外,要添加的术语并不总是n,而是取决于m。这意味着失去了唯一性。收件人应该如何知道是否应该添加 n2n...? m &lt; n 不存在此问题。此处无需添加任何内容。
    猜你喜欢
    • 2012-07-09
    • 2013-05-05
    • 1970-01-01
    • 2020-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-17
    • 2012-07-15
    相关资源
    最近更新 更多