From f424a18112032cf61d2871a6b91a5af607c171ae Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Fri, 20 Jul 2012 16:21:49 +0000 Subject: CryptoPP: changed folder structure git-svn-id: http://svn.miranda-ng.org/main/trunk@1083 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/CryptoPP/src/cpp_rsam.cpp | 1074 +++++++++++++++++++++++++++++++++++++ 1 file changed, 1074 insertions(+) create mode 100644 plugins/CryptoPP/src/cpp_rsam.cpp (limited to 'plugins/CryptoPP/src/cpp_rsam.cpp') diff --git a/plugins/CryptoPP/src/cpp_rsam.cpp b/plugins/CryptoPP/src/cpp_rsam.cpp new file mode 100644 index 0000000000..3cdb391660 --- /dev/null +++ b/plugins/CryptoPP/src/cpp_rsam.cpp @@ -0,0 +1,1074 @@ +#include "commonheaders.h" + +/////////////////////////////////////////////////////////////////////////// + +#define RAND_SIZE (256/8) + +RSA_EXPORT exports = { + rsa_gen_keypair, + rsa_get_keypair, + rsa_get_keyhash, + rsa_set_keypair, + rsa_get_pubkey, + rsa_set_pubkey, + rsa_set_timeout, + rsa_get_state, + rsa_get_hash, + rsa_connect, + rsa_disconnect, + rsa_disabled, + rsa_recv, + rsa_send, + rsa_encrypt_file, + rsa_decrypt_file, + utf8encode, + utf8decode, + is_7bit_string, + is_utf8_string, + rsa_export_keypair, + rsa_import_keypair, + rsa_export_pubkey, + rsa_import_pubkey +}; + +pRSA_IMPORT imp; + +string null; +int timeout = 10; + +const string priv_beg = "-----BEGIN SECUREIM PRIVATE KEY BLOCK-----"; +const string priv_end = "-----END SECUREIM PRIVATE KEY BLOCK-----"; + +const string pub_beg = "-----BEGIN SECUREIM PUBLIC KEY BLOCK-----"; +const string pub_end = "-----END SECUREIM PUBLIC KEY BLOCK-----"; + +const string crlf = "\x0D\x0A"; + +/////////////////////////////////////////////////////////////////////////// + + +int __cdecl rsa_init(pRSA_EXPORT* e, pRSA_IMPORT i) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_init"); +#endif + *e = &exports; + imp = i; + if ( !hRSA4096 ) { + // create context for private rsa keys + hRSA4096 = (HANDLE) cpp_create_context(MODE_RSA_4096|MODE_PRIV_KEY); + pCNTX tmp = (pCNTX) hRSA4096; + pRSAPRIV p = new RSAPRIV; + tmp->pdata = (PBYTE) p; + } + return 1; +} + + +int __cdecl rsa_done(void) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_done"); +#endif + return 1; +} + + +/////////////////////////////////////////////////////////////////////////// + + +pRSAPRIV rsa_gen_keys(HANDLE context) { + + if ( context!=hRSA4096 ) return 0; + +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_gen_keys: %d", context); +#endif + pCNTX ptr = get_context_on_id(context); + pRSAPRIV r = (pRSAPRIV) ptr->pdata; + + string priv, pub; + GenerateRSAKey(4096, priv, pub); + + StringSource privsrc(priv, true, NULL); + RSAES_PKCS1v15_Decryptor Decryptor(privsrc); + + priv = tlv(1, IntegerToBinary(Decryptor.GetTrapdoorFunction().GetModulus() )) + + tlv(2, IntegerToBinary(Decryptor.GetTrapdoorFunction().GetPublicExponent() )) + + tlv(3, IntegerToBinary(Decryptor.GetTrapdoorFunction().GetPrivateExponent() )) + + tlv(4, IntegerToBinary(Decryptor.GetTrapdoorFunction().GetPrime1() )) + + tlv(5, IntegerToBinary(Decryptor.GetTrapdoorFunction().GetPrime2() )) + + tlv(6, IntegerToBinary(Decryptor.GetTrapdoorFunction().GetModPrime1PrivateExponent() )) + + tlv(7, IntegerToBinary(Decryptor.GetTrapdoorFunction().GetModPrime2PrivateExponent() )) + + tlv(8, IntegerToBinary(Decryptor.GetTrapdoorFunction().GetMultiplicativeInverseOfPrime2ModPrime1() )); + + init_priv(r,priv); + + return r; +} + + +pRSAPRIV rsa_get_priv(pCNTX ptr) { + pCNTX p = get_context_on_id(hRSA4096); + pRSAPRIV r = (pRSAPRIV) p->pdata; + return r; +} + + +int __cdecl rsa_gen_keypair(short mode) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_gen_keypair: %d", mode); +#endif + if ( mode&MODE_RSA_4096 ) rsa_gen_keys(hRSA4096); // 4096 + + return 1; +} + + +int __cdecl rsa_get_keypair(short mode, PBYTE privKey, int* privKeyLen, PBYTE pubKey, int* pubKeyLen) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_get_keypair: %d", mode); +#endif + pCNTX ptr = get_context_on_id(hRSA4096); + pRSAPRIV r = (pRSAPRIV) ptr->pdata; + + *privKeyLen = r->priv_k.length(); if ( privKey ) r->priv_k.copy((char*)privKey, *privKeyLen); + *pubKeyLen = r->pub_k.length(); if ( pubKey ) r->pub_k.copy((char*)pubKey, *pubKeyLen); + + return 1; +} + + +int __cdecl rsa_get_keyhash(short mode, PBYTE privKey, int* privKeyLen, PBYTE pubKey, int* pubKeyLen) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_get_keyhash: %d", mode); +#endif + pCNTX ptr = get_context_on_id(hRSA4096); + pRSAPRIV r = (pRSAPRIV) ptr->pdata; + + if ( privKey ) { *privKeyLen = r->priv_s.length(); r->priv_s.copy((char*)privKey, *privKeyLen); } + if ( pubKey ) { *pubKeyLen = r->pub_s.length(); r->pub_s.copy((char*)pubKey, *pubKeyLen); } + + return 1; +} + + +int __cdecl rsa_set_keypair(short mode, PBYTE privKey, int privKeyLen) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_set_keypair: %s", privKey); +#endif + pCNTX ptr = get_context_on_id(hRSA4096); + pRSAPRIV r = (pRSAPRIV) ptr->pdata; + + if ( privKey && privKeyLen ) { + string priv; + priv.assign((char*)privKey, privKeyLen); + + if ( mode & MODE_RSA_BER ) { + // old BER format + StringStore s(priv); + r->priv.BERDecode(s); + + RSAES_PKCS1v15_Decryptor Decryptor(r->priv); + + priv = tlv(1, IntegerToBinary(Decryptor.GetTrapdoorFunction().GetModulus() )) + + tlv(2, IntegerToBinary(Decryptor.GetTrapdoorFunction().GetPublicExponent() )) + + tlv(3, IntegerToBinary(Decryptor.GetTrapdoorFunction().GetPrivateExponent() )) + + tlv(4, IntegerToBinary(Decryptor.GetTrapdoorFunction().GetPrime1() )) + + tlv(5, IntegerToBinary(Decryptor.GetTrapdoorFunction().GetPrime2() )) + + tlv(6, IntegerToBinary(Decryptor.GetTrapdoorFunction().GetModPrime1PrivateExponent() )) + + tlv(7, IntegerToBinary(Decryptor.GetTrapdoorFunction().GetModPrime2PrivateExponent() )) + + tlv(8, IntegerToBinary(Decryptor.GetTrapdoorFunction().GetMultiplicativeInverseOfPrime2ModPrime1() )); + + } + init_priv(r,priv); + } + + return 1; +} + + +int __cdecl rsa_get_pubkey(HANDLE context, PBYTE pubKey, int* pubKeyLen) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_get_pubkey: %s", pubKey); +#endif + pCNTX ptr = get_context_on_id(context); if (!ptr) return 0; + pRSADATA p = (pRSADATA) cpp_alloc_pdata(ptr); + + *pubKeyLen = p->pub_k.length(); if ( pubKey ) p->pub_k.copy((char*)pubKey, *pubKeyLen); + + return 1; +} + + +int __cdecl rsa_set_pubkey(HANDLE context, PBYTE pubKey, int pubKeyLen) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_set_pubkey: %s", pubKey); +#endif + pCNTX ptr = get_context_on_id(context); if (!ptr) return 0; + pRSADATA p = (pRSADATA) cpp_alloc_pdata(ptr); + + if ( pubKey && pubKeyLen ) { + string pub; + pub.assign((char*)pubKey, pubKeyLen); + init_pub(p,pub); + } + + return 1; +} + + +void __cdecl rsa_set_timeout(int t) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_set_timeout: %d", t); +#endif + timeout = t; +} + + +int __cdecl rsa_get_state(HANDLE context) { + + pCNTX ptr = get_context_on_id(context); if (!ptr) return 0; + pRSADATA p = (pRSADATA) cpp_alloc_pdata(ptr); + + return p->state; +} + + +int __cdecl rsa_get_hash(PBYTE pubKey, int pubKeyLen, PBYTE pubHash, int* pubHashLen) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_get_hash: %d", pubKeyLen); +#endif + string sig; + sig = ::hash(pubKey, pubKeyLen); + + *pubHashLen = sig.length(); + if ( pubHash ) sig.copy((char*)pubHash, *pubHashLen); + + return 1; +} + + +int __cdecl rsa_connect(HANDLE context) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_connect: %08x", context); +#endif + pCNTX ptr = get_context_on_id(context); if (!ptr) return 0; + pRSADATA p = (pRSADATA) cpp_alloc_pdata(ptr); if (p->state) return p->state; + pRSAPRIV r = rsa_get_priv(ptr); + + if (ptr->mode&MODE_RSA_ONLY) { + inject_msg(context,0x0D,tlv(0,0)+tlv(1,r->pub_k)+tlv(2,p->pub_s)); + p->state = 0x0D; + } + else { + inject_msg(context,0x10,tlv(0,0)+tlv(1,r->pub_s)+tlv(2,p->pub_s)); + p->state = 2; + } + p->time = gettime()+timeout; + + return p->state; +} + + +int __cdecl rsa_disconnect(HANDLE context) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_disconnect: %08x", context); +#endif + pCNTX ptr = get_context_on_id(context); if (!ptr) return 0; + rsa_free( ptr ); // удалим трэд и очередь сообщений + + pRSADATA p = (pRSADATA) cpp_alloc_pdata(ptr); + if ( !p->state ) return 1; + + PBYTE buffer=(PBYTE) alloca(RAND_SIZE); + GlobalRNG().GenerateBlock(buffer,RAND_SIZE); + inject_msg(context,0xF0,encode_msg(0,p,::hash(buffer,RAND_SIZE))); + + p->state = 0; + imp->rsa_notify(context,-3); // соединение разорвано вручную + + return 1; +} + + +int __cdecl rsa_disabled(HANDLE context) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_disabled: %08x", context); +#endif + pCNTX ptr = get_context_on_id(context); if (!ptr) return 0; + rsa_free( ptr ); // удалим трэд и очередь сообщений + + pRSADATA p = (pRSADATA) cpp_alloc_pdata(ptr); + p->state = 0; + inject_msg(context,0xFF,null); +// imp->rsa_notify(-context,-8); // соединение разорвано по причине "disabled" + return 1; +} + + +LPSTR __cdecl rsa_recv(HANDLE context, LPCSTR msg) { + +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_recv: %s", msg); +#endif + pCNTX ptr = get_context_on_id(context); if (!ptr) return 0; + pRSADATA p = (pRSADATA) cpp_alloc_pdata(ptr); + pRSAPRIV r = rsa_get_priv(ptr); + + rtrim(msg); + + string buf = base64decode(msg); + if ( !buf.length() ) return 0; + + string data; int type; + un_tlv(buf,type,data); + if ( type==-1 ) return 0; + +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_recv: %02x %d", type, p->state); +#endif + if ( type>0x10 && type<0xE0 ) // проверим тип сообщения (когда соединение еще не установлено) + if ( p->state==0 || p->state!=(type>>4) ) { // неверное состояние + // шлем перерывание сессии + p->state=0; p->time=0; + rsa_free( ptr ); // удалим трэд и очередь сообщений + null_msg(context,0x00,-1); // сессия разорвана по ошибке, неверный тип сообщения + return 0; + } + + switch( type ) { + + case 0x00: // прерывание сессии по ошибке другой стороной + { + // если соединение установлено - ничего не делаем + if ( p->state == 0 || p->state == 7 ) return 0; + // иначе сбрасываем текущее состояние + p->state=0; p->time=0; + imp->rsa_notify(context,-2); // сессия разорвана по ошибке другой стороной + } break; + + // это все будем обрабатывать в отдельном потоке, чтобы избежать таймаутов + case 0x10: // запрос на установку соединения + case 0x22: // получили удаленный паблик, отправляем уже криптоключ + case 0x23: // отправляем локальный паблик + case 0x24: // получили удаленный паблик, отправим локальный паблик + case 0x33: // получили удаленный паблик, отправляем криптоключ + case 0x34: + case 0x21: // получили криптоключ, отправляем криптотест + case 0x32: + case 0x40: + case 0x0D: // запрос паблика + case 0xD0: // ответ пабликом + { + if ( !p->event ) { + p->event = CreateEvent(NULL,FALSE,FALSE,NULL); + unsigned int tID; + p->thread = (HANDLE) _beginthreadex(NULL, 0, sttConnectThread, (PVOID)context, 0, &tID); +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_recv: _beginthreadex(sttConnectThread)"); +#endif + } + EnterCriticalSection(&localQueueMutex); + p->queue->push(tlv(type,data)); + LeaveCriticalSection(&localQueueMutex); + SetEvent(p->event); // сказали обрабатывать :) + } break; + + case 0x50: // получили криптотест, отправляем свой криптотест + { + string msg = decode_msg(p,data); + if ( !msg.length() ) { + p->state=0; p->time=0; + null_msg(context,0x00,-type); // сессия разорвана по ошибке + return 0; + } + PBYTE buffer=(PBYTE) alloca(RAND_SIZE); + GlobalRNG().GenerateBlock(buffer,RAND_SIZE); + inject_msg(context,0x60,encode_msg(0,p,::hash(buffer,RAND_SIZE))); + p->state=7; p->time=0; + rsa_free_thread( p ); // удалим трэд и очередь сообщений + imp->rsa_notify(context,1); // заебися, криптосессия установлена + } break; + + case 0x60: // получили криптотест, сессия установлена + { + string msg = decode_msg(p,data); + if ( !msg.length() ) { + p->state=0; p->time=0; + null_msg(context,0x00,-type); // сессия разорвана по ошибке + return 0; + } + p->state=7; p->time=0; + rsa_free_thread( p ); // удалим трэд и очередь сообщений + imp->rsa_notify(context,1); // заебися, криптосессия установлена + } break; + + case 0x70: // получили AES сообщение, декодируем + { + SAFE_FREE(ptr->tmp); + string msg = decode_msg(p,data); + if ( msg.length() ) { + ptr->tmp = (LPSTR) _strdup(msg.c_str()); + } + else { + imp->rsa_notify(context,-5); // ошибка декодирования AES сообщения + } + return ptr->tmp; + } break; + + case 0xE0: // получили RSA сообщение, декодируем + { + SAFE_FREE(ptr->tmp); + string msg = decode_rsa(p,r,data); + if ( msg.length() ) { + ptr->tmp = (LPSTR) _strdup(msg.c_str()); + } + else { + imp->rsa_notify(context,-6); // ошибка декодирования RSA сообщения + } + return ptr->tmp; + } break; + + case 0xF0: // разрыв соединения вручную + { + if ( p->state != 7 ) return 0; + string msg = decode_msg(p,data); + if ( !msg.length() ) return 0; + p->state=0; + rsa_free( ptr ); // удалим трэд и очередь сообщений + imp->rsa_notify(context,-4); // соединение разорвано вручную другой стороной + } break; + + case 0xFF: // разрыв соединения по причине "disabled" + { + p->state=0; + rsa_free( ptr ); // удалим трэд и очередь сообщений + imp->rsa_notify(context,-8); // соединение разорвано по причине "disabled" + } break; + + } + + if ( p->state != 0 && p->state != 7 ) + p->time = gettime() + timeout; + + return 0; +} + +int __cdecl rsa_send(HANDLE context, LPCSTR msg) { + + pCNTX ptr = get_context_on_id(context); if (!ptr) return 0; + pRSADATA p = (pRSADATA) cpp_alloc_pdata(ptr); if (p->state!=0 && p->state!=7) return 0; + + if ( p->state == 7 ) // сессия установлена, шифруем AES и отправляем + inject_msg(context,0x70,encode_msg(1,p,string(msg))); + else + if ( p->state == 0 ) { // сессия установлена, отправляем RSA сообщение + if ( !p->pub_k.length() ) return 0; + // есть паблик ключ - отправим сообщение + pRSAPRIV r = rsa_get_priv(ptr); + inject_msg(context,0xE0,encode_rsa(1,p,r,string(msg))); + } + + return 1; +} + + +void inject_msg(HANDLE context, int type, const string& msg) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("inject_msg(%02x): %s", type, msg.c_str()); +#endif + string txt=base64encode(tlv(type,msg)); + imp->rsa_inject(context,(LPCSTR)txt.c_str()); +} + + +string encode_msg(short z, pRSADATA p, string& msg) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("encode_msg: %s", msg.c_str()); +#endif + string zlib = (z) ? cpp_zlibc(msg) : msg; + string sig = ::hash(zlib); + + string ciphered; + try { + CBC_Mode::Encryption enc((PBYTE)p->aes_k.data(),p->aes_k.length(),(PBYTE)p->aes_v.data()); + StreamTransformationFilter cbcEncryptor(enc,new StringSink(ciphered)); + cbcEncryptor.Put((PBYTE)zlib.data(),zlib.length()); + cbcEncryptor.MessageEnd(); + } + catch (...) { + ; + } + return tlv(z,ciphered)+tlv(2,sig); +} + + +string decode_msg(pRSADATA p, string& msg) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("decode_msg: %s", msg.c_str()); +#endif + string ciphered,sig; int t1,t2; + un_tlv(msg,t1,ciphered); + un_tlv(msg,t2,sig); + + string unciphered,zlib; + try { + CBC_Mode::Decryption dec((PBYTE)p->aes_k.data(),p->aes_k.length(),(PBYTE)p->aes_v.data()); + StreamTransformationFilter cbcDecryptor(dec,new StringSink(zlib)); + cbcDecryptor.Put((PBYTE)ciphered.data(),ciphered.length()); + cbcDecryptor.MessageEnd(); + + if ( sig == ::hash(zlib) ) { + unciphered = (t1==1) ? cpp_zlibd(zlib) : zlib; + } + } + catch (...) { + ; + } + return unciphered; +} + + +string encode_rsa(short z, pRSADATA p, pRSAPRIV r, string& msg) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("encode_rsa: %s", msg.c_str()); +#endif + string zlib = (z) ? cpp_zlibc(msg) : msg; + + string enc = RSAEncryptString(p->pub,zlib); + string sig = RSASignString(r->priv,zlib); + + return tlv(z,enc)+tlv(2,sig); +} + + +string decode_rsa(pRSADATA p, pRSAPRIV r, string& msg) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("decode_rsa: %s", msg.c_str()); +#endif + string ciphered,sig; int t1,t2; + un_tlv(msg,t1,ciphered); + un_tlv(msg,t2,sig); + + string unciphered,zlib; + zlib = RSADecryptString(r->priv,ciphered); + if ( zlib.length() && RSAVerifyString(p->pub,zlib,sig) ) { + unciphered = (t1==1) ? cpp_zlibd(zlib) : zlib; + } + return unciphered; +} + + +string gen_aes_key_iv(short m, pRSADATA p, pRSAPRIV r) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("gen_aes_key_iv: %04x", m); +#endif + PBYTE buffer=(PBYTE) alloca(RAND_SIZE); + + GlobalRNG().GenerateBlock(buffer, RAND_SIZE); + p->aes_k = hash256(buffer,RAND_SIZE); + + GlobalRNG().GenerateBlock(buffer, RAND_SIZE); + p->aes_v = hash256(buffer,RAND_SIZE); + + string buf = tlv(10,p->aes_k)+tlv(11,p->aes_v); + + return encode_rsa(0,p,r,buf); +} + + +void init_priv(pRSAPRIV r, string& priv) { + + r->priv_k = priv; + r->priv_s = ::hash(priv); + + int t; + string tmp, n, e, d, p, q, dp, dq, u; + + while( priv.length() ) { + un_tlv(priv,t,tmp); + switch(t) { + case 1: n = tmp; break; + case 2: e = tmp; break; + case 3: d = tmp; break; + case 4: p = tmp; break; + case 5: q = tmp; break; + case 6: dp = tmp; break; + case 7: dq = tmp; break; + case 8: u = tmp; break; + } + } + + // if ( !empty ); + + r->pub_k = tlv(1,n)+tlv(2,e); + r->pub_s = ::hash(r->pub_k); + + r->priv.Initialize(BinaryToInteger(n),BinaryToInteger(e), + BinaryToInteger(d),BinaryToInteger(p),BinaryToInteger(q), + BinaryToInteger(dp),BinaryToInteger(dq),BinaryToInteger(u)); +} + + +void init_pub(pRSADATA p, string& pub) { + + p->pub_k = pub; + p->pub_s = ::hash(pub); + + int t; + string tmp, n, e; + + while( pub.length() ) { + un_tlv(pub,t,tmp); + switch(t) { + case 1: n = tmp; break; + case 2: e = tmp; break; + } + } + + // if ( !empty ); + + p->pub.Initialize(BinaryToInteger(n),BinaryToInteger(e)); +} + + +void null_msg(HANDLE context, int type, int status) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("null_msg: %02x", status); +#endif + inject_msg(context,type,null); + imp->rsa_notify(context,status); +} + + +void rsa_timeout(HANDLE context, pRSADATA p) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_timeout"); +#endif + p->state=0; p->time=0; +// null_msg(context,0x00,-7); + imp->rsa_notify(context,-7); // сессия разорвана по таймауту +} + + +int __cdecl rsa_encrypt_file(HANDLE context,LPCSTR file_in,LPCSTR file_out) { + + pCNTX ptr = get_context_on_id(context); if (!ptr) return 0; + pRSADATA p = (pRSADATA) cpp_alloc_pdata(ptr); if (p->state!=7) return 0; + + try { + CBC_Mode::Encryption enc((PBYTE)p->aes_k.data(),p->aes_k.length(),(PBYTE)p->aes_v.data()); + FileSource *f = new FileSource(file_in,true,new StreamTransformationFilter (enc,new FileSink(file_out))); + delete f; + } + catch (...) { + return 0; + } + return 1; +} + + +int __cdecl rsa_decrypt_file(HANDLE context,LPCSTR file_in,LPCSTR file_out) { + + pCNTX ptr = get_context_on_id(context); if (!ptr) return 0; + pRSADATA p = (pRSADATA) cpp_alloc_pdata(ptr); if (p->state!=7) return 0; + + try { + CBC_Mode::Decryption dec((PBYTE)p->aes_k.data(),p->aes_k.length(),(PBYTE)p->aes_v.data()); + FileSource *f = new FileSource(file_in,true,new StreamTransformationFilter (dec,new FileSink(file_out))); + delete f; + } + catch (...) { + return 0; + } + return 1; +} + + +int __cdecl rsa_recv_thread(HANDLE context, string& msg) { + +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_recv_thread: %s", msg.c_str()); +#endif + pCNTX ptr = get_context_on_id(context); if (!ptr) return 0; + pRSADATA p = (pRSADATA) cpp_alloc_pdata(ptr); + pRSAPRIV r = rsa_get_priv(ptr); + + string data; int type; + un_tlv(msg,type,data); + if ( type==-1 ) return 0; + +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_recv_thread: %02x %d", type, p->state); +#endif + int t[4]; + + switch( type ) { + + case 0x10: + { + int features; string sha1,sha2; + un_tlv(un_tlv(un_tlv(data,t[0],features),t[1],sha1),t[2],sha2); + BOOL lr = (p->pub_s==sha1); BOOL ll = (r->pub_s==sha2); + switch( (lr<<4)|ll ) { + case 0x11: { // оба паблика совпали + inject_msg(context,0x21,gen_aes_key_iv(ptr->mode,p,r)); + p->state=5; + } break; + case 0x10: { // совпал удаленный паблик, нужен локальный + inject_msg(context,0x22,tlv(0,features)+tlv(1,r->pub_k)+tlv(2,r->pub_s)); + p->state=3; + } break; + case 0x01: { // совпал локальный паблик, нужен удаленный + inject_msg(context,0x23,tlv(0,features)); + p->state=3; + } break; + case 0x00: { // не совпали оба паблика + inject_msg(context,0x24,tlv(0,features)+tlv(1,r->pub_k)+tlv(2,r->pub_s)); + p->state=3; + } break; + } + } break; + + case 0x22: // получили удаленный паблик, отправляем уже криптоключ + { + int features; string pub; + un_tlv(un_tlv(data,t[0],features),t[1],pub); + string sig = ::hash(pub); + if ( !imp->rsa_check_pub(context,(PBYTE)pub.data(),pub.length(),(PBYTE)sig.data(),sig.length()) ) { + p->state=0; p->time=0; + null_msg(context,0x00,-type); // сессия разорвана по ошибке + return 0; + } + init_pub(p,pub); + if ( p->state==0 ) { // timeout +// rsa_connect(context); + return -1; + } + inject_msg(context,0x32,gen_aes_key_iv(ptr->mode,p,r)); + p->state=5; + } break; + + case 0x23: // отправляем локальный паблик + { + int features; + un_tlv(data,t[0],features); + inject_msg(context,0x33,tlv(1,r->pub_k)+tlv(2,r->pub_s)); + p->state=4; + } break; + + case 0x24: // получили удаленный паблик, отправим локальный паблик + { + int features; string pub; + un_tlv(un_tlv(data,t[0],features),t[1],pub); + string sig = ::hash(pub); + if ( !imp->rsa_check_pub(context,(PBYTE)pub.data(),pub.length(),(PBYTE)sig.data(),sig.length()) ) { + p->state=0; p->time=0; + null_msg(context,0x00,-type); // сессия разорвана по ошибке + return 0; + } + init_pub(p,pub); + if ( p->state==0 ) { // timeout +// rsa_connect(context); + return -1; + } + inject_msg(context,0x34,tlv(1,r->pub_k)+tlv(2,r->pub_s)); + p->state=4; + } break; + + case 0x33: // получили удаленный паблик, отправляем криптоключ + case 0x34: + { + string pub; + un_tlv(data,t[0],pub); + string sig = ::hash(pub); + if ( !imp->rsa_check_pub(context,(PBYTE)pub.data(),pub.length(),(PBYTE)sig.data(),sig.length()) ) { + p->state=0; p->time=0; + null_msg(context,0x00,-type); // сессия разорвана по ошибке + return 0; + } + init_pub(p,pub); + if ( p->state==0 ) { // timeout +// rsa_connect(context); + return -1; + } + inject_msg(context,0x40,gen_aes_key_iv(ptr->mode,p,r)); + p->state=5; + } break; + + case 0x21: // получили криптоключ, отправляем криптотест + case 0x32: + case 0x40: + { + string key = decode_rsa(p,r,data); + if ( !key.length() ) { + p->state=0; p->time=0; + null_msg(context,0x00,-type); // сессия разорвана по ошибке + return 0; + } + un_tlv(key,t[0],p->aes_k); + un_tlv(key,t[1],p->aes_v); + PBYTE buffer=(PBYTE) alloca(RAND_SIZE); + GlobalRNG().GenerateBlock(buffer,RAND_SIZE); + inject_msg(context,0x50,encode_msg(0, p, ::hash(buffer,RAND_SIZE))); + p->state=6; + } break; + + case 0x0D: // запрос паблика + case 0xD0: // ответ пабликом + { + int features; string pub,sha; + un_tlv(un_tlv(un_tlv(data,t[0],features),t[1],pub),t[2],sha); + if ( p->pub_k!=pub ) { // пришел новый паблик + string sig = ::hash(pub); + if ( !imp->rsa_check_pub(context,(PBYTE)pub.data(),pub.length(),(PBYTE)sig.data(),sig.length()) ) { + p->state=0; p->time=0; + null_msg(context,0x00,-type); // сессия разорвана по ошибке + return 0; + } + init_pub(p,pub); + } + if ( type == 0x0D ) { // нужно отправить мой паблик + inject_msg(context,0xD0,tlv(0,features)+tlv(1,r->pub_k)+tlv(2,p->pub_s)); + } + p->state=0; p->time=0; + } break; + + } + + if ( p->state != 0 && p->state != 7 ) + p->time = gettime() + timeout; + + return 1; +} + + +void rsa_alloc( pCNTX ptr ) { + pRSADATA p = new RSADATA; + p->state = 0; + p->time = 0; + p->thread = p->event = NULL; + p->thread_exit = 0; + p->queue = new STRINGQUEUE; + ptr->pdata = (PBYTE) p; +} + + +void rsa_free( pCNTX ptr ) { + pRSADATA p = (pRSADATA) ptr->pdata; + if ( p && p->event ) { + p->thread_exit = 2; // отпускаем поток в свободное плавание + SetEvent( p->event ); + rsa_alloc(ptr); + } +} + + +void rsa_free_thread( pRSADATA p ) { + if ( p->event ) { + p->thread_exit = 1; + SetEvent( p->event ); + // ждем завершения потока + WaitForSingleObject(p->thread, INFINITE); + CloseHandle( p->thread ); + CloseHandle( p->event ); + p->thread = p->event = NULL; + p->thread_exit = 0; + } + p->time = 0; + clear_queue( p ); +} + + +void clear_queue( pRSADATA p ) { + EnterCriticalSection(&localQueueMutex); + while( p->queue && !p->queue->empty() ) { + p->queue->pop(); + } + LeaveCriticalSection(&localQueueMutex); +} + + +// establish RSA/AES thread +unsigned __stdcall sttConnectThread( LPVOID arg ) { + + HANDLE context = (HANDLE) arg; + + pCNTX ptr = get_context_on_id(context); if (!ptr) return 0; + pRSADATA p = (pRSADATA) cpp_alloc_pdata(ptr); + + while(1) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("sttConnectThread: WaitForSingleObject"); +#endif + WaitForSingleObject(p->event, INFINITE); // dwMsec rc==WAIT_TIMEOUT + if ( p->thread_exit == 1 ) return 0; + if ( p->thread_exit == 2 ) { + // мы в свободном плавании - освободим память и завершим трэд + CloseHandle( p->thread ); + CloseHandle( p->event ); + SAFE_DELETE(p->queue); + SAFE_DELETE(p); + return 0; + } + // дождались сообщения в очереди + while( !p->thread_exit && p->queue && !p->queue->empty() ) { + // обработаем сообщения из очереди + if ( rsa_recv_thread(context, p->queue->front()) == -1 ) { + // очистить очередь + clear_queue(p); + break; + } + EnterCriticalSection(&localQueueMutex); + p->queue->pop(); + LeaveCriticalSection(&localQueueMutex); + } + } +} + + +int __cdecl rsa_export_keypair(short mode, LPSTR privKey, LPSTR pubKey, LPSTR passPhrase) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_export_keypair: %d", mode); +#endif + pCNTX ptr = get_context_on_id(hRSA4096); + pRSAPRIV r = (pRSAPRIV) ptr->pdata; + + if ( pubKey ) { + string pub; + pub = tlv(3,r->pub_k) + tlv(4,r->pub_s); + pub = pub_beg + crlf + add_delim(base64encode(pub),crlf,65) + pub_end + crlf; + strcpy(pubKey, pub.c_str()); + } + + if ( privKey && passPhrase ) { + string key = hash256(passPhrase); + string iv = hash256(key); + string priv = pad256(r->priv_k); + + string ciphered; + try { + CBC_Mode::Encryption enc((PBYTE)key.data(),key.length(),(PBYTE)iv.data()); + StreamTransformationFilter cbcEncryptor(enc,new StringSink(ciphered)); + cbcEncryptor.Put((PBYTE)priv.data(),priv.length()); + cbcEncryptor.MessageEnd(); + } + catch (...) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_export_keypair: error bad_passphrase"); +#endif + return 0; + } + + priv = tlv(1,ciphered) + tlv(2,::hash(ciphered)); + priv = priv_beg + crlf + add_delim(base64encode(priv),crlf,65) + priv_end + crlf; + + strcpy(privKey, priv.c_str()); + } + + return 1; +} + + +int __cdecl rsa_import_keypair(short mode, LPSTR privKey, LPSTR passPhrase) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_import_keypair: %d", mode); +#endif + pCNTX ptr = get_context_on_id(hRSA4096); + pRSAPRIV r = (pRSAPRIV) ptr->pdata; + + if ( !passPhrase ) return 0; + + string priv; + u_int found; + + priv.assign(privKey); + del_delim(priv,crlf); + + found = priv.find(priv_beg); + if ( found != string::npos ) { + priv = priv.substr(found+priv_beg.length()); + found = priv.find(priv_end); + if ( found != string::npos ) { + priv = base64decode(priv.substr(0,found)); + TLV k(priv); + if ( k.exist(1) && k.exist(2) && ::hash(k.get(1)) == k.get(2) ) { + priv = k.get(1); + + string key = hash256(passPhrase); + string iv = hash256(key); + + string unciphered; + try { + CBC_Mode::Decryption dec((PBYTE)key.data(),key.length(),(PBYTE)iv.data()); + StreamTransformationFilter cbcDecryptor(dec,new StringSink(unciphered)); + cbcDecryptor.Put((PBYTE)priv.data(),priv.length()); + cbcDecryptor.MessageEnd(); + } + catch (...) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_import_keypair: error bad_passphrase"); +#endif + return 0; + } + + init_priv(r,unciphered); + return 1; + } + } + } + + return 0; +} + + +int __cdecl rsa_export_pubkey(HANDLE context, LPSTR pubKey) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_export_pubkey: %08x", context); +#endif + pCNTX ptr = get_context_on_id(context); if (!ptr) return 0; + pRSADATA p = (pRSADATA) cpp_alloc_pdata(ptr); + + if ( !p->pub_k.length() || !pubKey ) return 0; + + string pub; + pub = tlv(3,p->pub_k) + tlv(4,p->pub_s); + pub = pub_beg + crlf + add_delim(base64encode(pub),crlf,65) + pub_end + crlf; + strcpy(pubKey, pub.c_str()); + + return 1; +} + + +int __cdecl rsa_import_pubkey(HANDLE context, LPSTR pubKey) { +#if defined(_DEBUG) || defined(NETLIB_LOG) + Sent_NetLog("rsa_import_pubkey: %08x", context); +#endif + pCNTX ptr = get_context_on_id(context); if (!ptr) return 0; + pRSADATA p = (pRSADATA) cpp_alloc_pdata(ptr); + + if ( !pubKey ) return 0; + + string pub; + u_int found; + + pub.assign(pubKey); + del_delim(pub,crlf); + + found = pub.find(pub_beg); + if ( found != string::npos ) { + pub = pub.substr(found+pub_beg.length()); + found = pub.find(pub_end); + if ( found != string::npos ) { + pub = base64decode(pub.substr(0,found)); + TLV k(pub); + if ( k.exist(3) && k.exist(4) && ::hash(k.get(3)) == k.get(4) ) { + init_pub(p,k.get(3)); + return 1; + } + } + } + return 0; +} + + +// EOF -- cgit v1.2.3