C++ 通过openssl/c/c+将RSA公钥作为字节读取+;

C++ 通过openssl/c/c+将RSA公钥作为字节读取+;,c++,c,openssl,rsa,C++,C,Openssl,Rsa,我正在尝试向服务器发送2048位(256字节)的RSA公钥。我需要以字节流的形式读取数据。 我似乎找不到办法 BIO *memBio = BIO_new(BIO_s_mem()); ASN1_PCTX *asn1=ASN1_PCTX_new();//useless unless I know how to use it BIO_set_flags(memBio, BIO_FLAGS_WRITE); int ret=EVP_PKEY_print_private(memBio,rsaAppKey

我正在尝试向服务器发送2048位(256字节)的RSA公钥。我需要以字节流的形式读取数据。 我似乎找不到办法

BIO *memBio = BIO_new(BIO_s_mem());

ASN1_PCTX *asn1=ASN1_PCTX_new();//useless unless I know how to use it

BIO_set_flags(memBio, BIO_FLAGS_WRITE);
int ret=EVP_PKEY_print_private(memBio,rsaAppKeys,0, asn1 );

BUF_MEM *bptr;
BIO_get_mem_ptr(memBio, &bptr);
BIO_set_close(memBio, BIO_NOCLOSE); /* So BIO_free() leaves BUF_MEM alone */
BIO_free(memBio);
它以DER格式在内存中打印密钥,十六进制字节格式为字符串,每个字节和头之间为“:”。我可以解析它,但我认为一定有更好的方法。 在文档中写到,通过使用ASN1_PCTX,我可以微调输出,但我找不到任何关于它的文档

有没有一个简单的方法来获取原始字节的密钥?
谢谢,好的。。我等不及了,所以我设计了一个肮脏的黑客:

  • 首先,我生成一个PEM格式的密钥
  • 然后解析它以提取ASN.1结构
  • 然后从ASN.1结构中提取2048位密钥
至少可以说,ASN.1解析是肮脏的。欢迎提出建议

我还使用了优秀的工具来探索ASN.1结构。 并尝试将键打印到base64格式的字符串

//generic method to extract data from an EVP_PKEY
//it's very UGLY. I'm ashamed especially of the ASN.1 parsing (!!)
-(NSData *)getPublicKeyBytes:(EVP_PKEY *)rsaKey{
    ///try to write bytes
    BIO *pub = BIO_new(BIO_s_mem());

    //write pub key as this format:
    //-----BEGIN RSA PUBLIC KEY-----
    //MIIBCgKCAQEA3J7MfnosapxZH9ibxm9Gz88X+ryEEk616BtXGFx3SH1T7ssjdTvv
    //pL8FRAvnmHegtNm0JsCFbEWdGzFr1F7BFYu1lj6h7JFPIhlalMMSlGsRP5dzzj8q
    //....
    //-----END RSA PUBLIC KEY-----
    //
    PEM_write_bio_RSAPublicKey(pub, rsaKey->pkey.rsa);

    size_t pub_len = BIO_pending(pub);

    char *pub_key = malloc(pub_len + 1);

    BIO_read(pub, pub_key, pub_len);
    //zero terminated string
    pub_key[pub_len] = '\0';

    //transform to nsstring
    NSString *plainKey=[[NSString alloc]initWithCString:pub_key encoding:NSASCIIStringEncoding];
    //search for header
    NSRange range=[plainKey rangeOfString:@"-----BEGIN RSA PUBLIC KEY-----"];
    if(range.location==NSNotFound){
        DLog(@"Error, RSA pub key in wrong format: %@",plainKey);
        return nil;
    }
    //strip header
    plainKey=[plainKey substringFromIndex:range.location+range.length];

    //search footer
    range=[plainKey rangeOfString:@"-----END RSA PUBLIC KEY-----"];
    if(range.location==NSNotFound){
        DLog(@"Error, RSA pub key in wrong format: %@",plainKey);
        return nil;
    }

    //strip footer
    plainKey=[plainKey substringToIndex:range.location];

    //now remove \n
    plainKey=[plainKey stringByReplacingOccurrencesOfString:@"\n" withString:@""];
    plainKey=[plainKey stringByReplacingOccurrencesOfString:@"\r" withString:@""];
    //DLog(@"Plain key stripped %@",plainKey);

    //now read as byte
    NSData *rsaBytes=[NSData dataWithBase64EncodedString:plainKey];
    //DLog(@"Data is %d len %@",rsaBytes.length,rsaBytes);
    //unfortunately data is in a ASN1 rame;;
    //it's a sequence of 2 element, integer and exponent (65537).
    //the key starts from byte 9, or 10.. (byte 9 is a zero).
    NSData *pubKeyBytes=[rsaBytes subdataWithRange:NSMakeRange(9, 256)];
    DLog(@"pubKeyBytes is %d len %@",pubKeyBytes.length,pubKeyBytes);

    return pubKeyBytes;
}

好的。。我等不及了,所以我设计了一个肮脏的黑客:

  • 首先,我生成一个PEM格式的密钥
  • 然后解析它以提取ASN.1结构
  • 然后从ASN.1结构中提取2048位密钥
至少可以说,ASN.1解析是肮脏的。欢迎提出建议

我还使用了优秀的工具来探索ASN.1结构。 并尝试将键打印到base64格式的字符串

//generic method to extract data from an EVP_PKEY
//it's very UGLY. I'm ashamed especially of the ASN.1 parsing (!!)
-(NSData *)getPublicKeyBytes:(EVP_PKEY *)rsaKey{
    ///try to write bytes
    BIO *pub = BIO_new(BIO_s_mem());

    //write pub key as this format:
    //-----BEGIN RSA PUBLIC KEY-----
    //MIIBCgKCAQEA3J7MfnosapxZH9ibxm9Gz88X+ryEEk616BtXGFx3SH1T7ssjdTvv
    //pL8FRAvnmHegtNm0JsCFbEWdGzFr1F7BFYu1lj6h7JFPIhlalMMSlGsRP5dzzj8q
    //....
    //-----END RSA PUBLIC KEY-----
    //
    PEM_write_bio_RSAPublicKey(pub, rsaKey->pkey.rsa);

    size_t pub_len = BIO_pending(pub);

    char *pub_key = malloc(pub_len + 1);

    BIO_read(pub, pub_key, pub_len);
    //zero terminated string
    pub_key[pub_len] = '\0';

    //transform to nsstring
    NSString *plainKey=[[NSString alloc]initWithCString:pub_key encoding:NSASCIIStringEncoding];
    //search for header
    NSRange range=[plainKey rangeOfString:@"-----BEGIN RSA PUBLIC KEY-----"];
    if(range.location==NSNotFound){
        DLog(@"Error, RSA pub key in wrong format: %@",plainKey);
        return nil;
    }
    //strip header
    plainKey=[plainKey substringFromIndex:range.location+range.length];

    //search footer
    range=[plainKey rangeOfString:@"-----END RSA PUBLIC KEY-----"];
    if(range.location==NSNotFound){
        DLog(@"Error, RSA pub key in wrong format: %@",plainKey);
        return nil;
    }

    //strip footer
    plainKey=[plainKey substringToIndex:range.location];

    //now remove \n
    plainKey=[plainKey stringByReplacingOccurrencesOfString:@"\n" withString:@""];
    plainKey=[plainKey stringByReplacingOccurrencesOfString:@"\r" withString:@""];
    //DLog(@"Plain key stripped %@",plainKey);

    //now read as byte
    NSData *rsaBytes=[NSData dataWithBase64EncodedString:plainKey];
    //DLog(@"Data is %d len %@",rsaBytes.length,rsaBytes);
    //unfortunately data is in a ASN1 rame;;
    //it's a sequence of 2 element, integer and exponent (65537).
    //the key starts from byte 9, or 10.. (byte 9 is a zero).
    NSData *pubKeyBytes=[rsaBytes subdataWithRange:NSMakeRange(9, 256)];
    DLog(@"pubKeyBytes is %d len %@",pubKeyBytes.length,pubKeyBytes);

    return pubKeyBytes;
}

使用,
d2i\u RSA\u PUBKEY()

然后使用
BN_bn2bin()
函数将RSA公钥模数转换为大端字节流

例如

RSA*pubKey=d2i_RSA_pubKey(NULL,);
BN_bn2bin(publikey->n,);

使用,
d2i\u RSA\u PUBKEY()从der编码的字节流创建RSA公钥。

然后使用
BN_bn2bin()
函数将RSA公钥模数转换为大端字节流

例如

RSA*pubKey=d2i_RSA_pubKey(NULL,);
BN_bn2bin(publikey->n,);