生成RSA并保存在ASN.1 / DER中的分段错误?

时间:2015-06-22 05:05:53

标签: c openssl cryptography rsa

#include <string.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <openssl/bio.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/pem.h>

#define RSA_LEN 2048
#define RSA_FACTOR 65537

int genRSA2048(unsigned char **pub,unsigned int *pub_l,unsigned char **priv,unsigned int *priv_l){

    RSA *pRSA = NULL;
    pRSA = RSA_generate_key(RSA_LEN,RSA_FACTOR,NULL,NULL);

    if (pRSA){
        pub_l = malloc(sizeof(pub_l));
        *pub_l = i2d_RSAPublicKey(pRSA,pub);
        priv_l = malloc(sizeof(priv_l));
        *priv_l = i2d_RSAPrivateKey(pRSA,priv);
        return 0;
    } else {
        return 1;
    }
}

int main(){
    unsigned char *pub = NULL;
    unsigned int publ;
    unsigned char *priv = NULL;
    unsigned int privl;
    genRSA2048(&pub,&publ,&priv,&privl);


    RSA *privrsa = NULL;
    d2i_RSAPrivateKey(&privrsa,(const unsigned char **)&priv,privl);

    RSA *pubrsa = NULL;
    d2i_RSAPublicKey(&pubrsa,(const unsigned char **)&pub,publ);

    unsigned char * data ="01234567890123456789012345678912";
    unsigned char encrypted[256];
    unsigned char decrypted[32];

    int len = RSA_private_encrypt(32,data,encrypted,privrsa,RSA_PKCS1_PADDING);
    RSA_public_decrypt(len,encrypted,decrypted,pubrsa,RSA_PKCS1_PADDING);
}

我已经尝试通过检查gdb来查找错误,但是对于CI来说相当新,我找不到任何线索告诉我发生了什么,但我认为这是一个分配问题,但是根据d2i_RSAPrivateKey和类似情况,他们应该自己分配空间。

非常感谢任何帮助。

编译为cc foo.c -lcrypto

这是对这个问题的跟进:

Generate RSA public/private key with OpenSSL?

正如我所引用的那样,我在评论中使用了@WhozCraig示例,这可以在这里找到,即使它完全不同,也有很多帮助。

http://coliru.stacked-crooked.com/a/ae64a70076436165

2 个答案:

答案 0 :(得分:2)

根本不需要

pub_l = malloc(sizeof(pub_l));。也不是priv_l = malloc(sizeof(priv_l));。从功能中删除它们。

你应该填写你的外部参数;相反,你扔掉了调用者提供的地址来填充和(a)填充你自己的地址,然后(b)泄漏你刚刚分配的内存。

结果是来电者privlpubl未受影响,因此解码回RSA功能失调,因为两个值都是不确定的。

答案 1 :(得分:2)

pRSA = RSA_generate_key(RSA_LEN,RSA_FACTOR,NULL,NULL);

我认为这是错误的。我知道你应该使用RSA_generate_key_ex,我认为它需要BIGNUM,而不是整数。你应该得到一个警告。有关详细信息,请参阅RSA_generate_key(3)

您的代码应该类似于:

BIGNUM* exp = BN_new();
ASSERT(exp != NULL);

int rc = BN_set_word(exp, RSA_F4);
ASSERT(rc == 1);

RSA* rsa = RSA_new();
ASSERT(rsa != NULL);

rc = RSA_generate_key_ex(rsa, 2048, exp, NULL);
ASSERT(rc == 1);

请务必致电BN_free上的BIGNUMRSA_free指针上的RSA

RSA *privrsa = NULL;
d2i_RSAPrivateKey(&privrsa,(const unsigned char **)&priv,privl);

RSA *pubrsa = NULL;
d2i_RSAPublicKey(&pubrsa,(const unsigned char **)&pub,publ);

为此,看起来您正在尝试分离公钥和私钥。为此,请使用RSAPublicKey_dupRSAPrivateKey_dup。请参阅Separating public and private keys from RSA keypair variable

我不清楚你要对以下内容做些什么。你应该陈述你要做的事情......

pub_l = malloc(sizeof(pub_l));
*pub_l = i2d_RSAPublicKey(pRSA,pub);
priv_l = malloc(sizeof(priv_l));
*priv_l = i2d_RSAPrivateKey(pRSA,priv);

我只是猜测,但我会说这一切都错了。 sizeof(priv_l)是指针的大小,因此它的4或8个字节。你还要覆盖调用者传入的指针......

另见OpenSSL's rsautl cannot load public key created with PEM_write_RSAPublicKey。它讨论了使用ASN.1 / DER和PEM格式的 SubjectPublicKeyInfo PrivateKeyInfo 保存密钥。

通过编写 {Public | Private} KeyInfo ,OID将被写入密钥。这对于互操作很重要。您还可以使用RSA*(甚至是EVP_PKEY*),而不是字节数组。