Previous Entry Share Next Entry
RSA. Все могло быть проще.
mikelsv
Решив воспользоваться библиотекой openssl, а точнее алгоритмом RSA я был буквально удивлен той наркоманией, что творится в коде. Привыкнув к тому, что обычно код пишется легко и просто я малость охренел от этой кучи непонятных функций и количества параметров.

Первый увиденный способ добавления ключа в 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) - выделяет блок памяти.

В функции стоит добавить еще проверок, ибо, например, код может упасть если дать ему строку не соответствующую формату ключа.

Вот так, наркоманы рядом. И вы каждый день пользуетесь результатами их труда.
Tags:

?

Log in

No account? Create an account