Первый увиденный способ добавления ключа в RSA был ужасен: PEM_read_RSA_PUBKEY(FILE*, ...); Я давно и обычного open() не касался, не то, что нелюбимого мной fopen();
Второй способ был лучше, но все же не без глюков: PEM_read_bio_RSA_PUBKEY(BIO*); Которая создавалась через BIO_new_mem_buf(char* buf, int size); Наркомания заключалась в том, что в этом случае устанавливался флаг запрета на запись в память. Ок, я снимал этот флаг вручную и сразу же натыкался на удаление моего буффера и создания нового, при записи ключа. Ребята банально не рассчитывали, что кто-то рискнет снять флаг защиты от записи и не продумали этот момент. Короче программа так и пыталась упасть там где можно и нельзя.
В итоге пришлось решать хаком, через создание переменной BUF_MEM mp; заполнением ее, созданием пустого BIO *bp=BIO_new(BIO_s_mem()); и втыканием буффера в bp->ptr=& mp . Перед удалением BIO, буффер тем же способом тихо убирается bp->ptr=0; Править код openssl желания не было, он и так нестабилен.
В итоге у меня получилось три замечательных функции: RSACreateKeys(&pub_key, &secret_key), RSAEncode(pub_key, text), RSADecode(secret_key, text); Примерно в таком виде я надеялся получить их из библиотеки openssl, но видно не судьба.
Код функций:
void RSACreateKeys(MString &pub, MString &sec){ // generate keys RSA *rsa = RSA_generate_key(2*1024, 64*1024+1, NULL, NULL); // bufs pub.Reserv(451); sec.Reserv(1679); BUF_MEM mp; mp.data=pub; mp.length=0; mp.max=pub; BUF_MEM ms; ms.data=sec; ms.length=0; ms.max=sec; BIO *bp=BIO_new(BIO_s_mem()); bp->ptr=∓ BIO *bs=BIO_new(BIO_s_mem()); bs->ptr=&ms; PEM_write_bio_RSA_PUBKEY(bp, rsa); PEM_write_bio_RSAPrivateKey(bs, rsa, 0, 0, 0, 0, 0); bp->ptr=0; bs->ptr=0; BIO_free(bp); BIO_free(bs); RSA_free(rsa); } MString RSAEncode(VString key, VString text){ MString ret; RSA *rsa = RSA_new(); BIO *b=BIO_new_mem_buf(key, key); PEM_read_bio_RSA_PUBKEY(b, &rsa, 0, 0); ret.Reserv(RSA_size(rsa)); int sz=RSA_public_encrypt(text, text, ret, rsa, RSA_PKCS1_PADDING); BIO_free(b); RSA_free(rsa); ret.Reserv(sz); return ret; } MString RSADecode(VString key, VString text){ MString ret; RSA *rsa = RSA_new(); BIO *b=BIO_new_mem_buf(key, key); PEM_read_bio_RSAPrivateKey(b, &rsa, 0, 0); ret.Reserv(RSA_size(rsa)); int sz=RSA_private_decrypt(text, text, ret, rsa, RSA_PKCS1_PADDING); BIO_free(b); RSA_free(rsa); ret.Reserv(sz); return ret; } void test(){ MString pub, sec, e, d; RSACreateKeys(pub, sec); e=RSAEncode(pub, "The test string for encrypt/decrypt"); d=RSADecode(sec, e); }
MString и VString это классы с unsigned char *data - указателем на данные и unsigned int sz - их размер. Reserv(int sz) - выделяет блок памяти.
В функции стоит добавить еще проверок, ибо, например, код может упасть если дать ему строку не соответствующую формату ключа.
Вот так, наркоманы рядом. И вы каждый день пользуетесь результатами их труда.