I'm trying to send an RSA public key of 2048 bits (256byte) to a server. I need to read the data as a byte stream. I don't seem to find a way.
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);
It prints in memory the key in a DER format, with hex bytes formatted as strings, and ":" between each byte, and a header. I could parse it but i think there must be a better way. In the docs it's written that by using a ASN1_PCTX I can fine tune the output, but I can't find any documentation of it.
Any idea of a simple way to get the key as raw bytes? Thanks
Ok.. I couldn't wait so I devised a dirty hack:
THe ASN.1 parse is dirty, to say the least. Suggestions welcome
I've used also the excellent http://lapo.it/asn1js/ to explore the ASN.1 structure. And https://shanetully.com/2012/04/simple-public-key-encryption-with-rsa-and-openssl/ to get a go at printing keys to string in base64 form.
//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;
}
Create RSA public key from der encoded byte stream using, d2i_RSA_PUBKEY()
then use BN_bn2bin()
function to convert RSA public keys modulus to a big-endian byte stream.
eg.
RSA * pubKey = d2i_RSA_PUBKEY(NULL, <der encoded byte stream pointer>, <num bytes>);
BN_bn2bin(pubKey->n, <where to put the result>);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.