extern "C" { #include "7zAES/Aes.c" #include "7zAES/CpuArch.c" #include "C_Encryption.h" #define LTC_NO_CIPHERS #define LTC_BLOWFISH #define LTC_RIJNDAEL #define ENCRYPT_ONLY #define LTC_TWOFISH #define LTC_SERPENT #define LTC_NO_MODES #define LTC_CFB_MODE #define LTC_CTR_MODE #define LTC_NO_HASHES #define LTC_SHA512 #define LTC_NO_MACS #define LTC_HMAC #define LTC_NO_MATH #define LTC_NO_PK #define LTC_MECC #define LTC_NO_TEST #include "ciphers/aes/aes.c" #include "ciphers/blowfish.c" #include "ciphers/twofish/twofish.c" #include "ciphers/serpent.c" #include "crypt/crypt_argchk.c" #include "crypt/crypt_cipher_descriptor.c" #include "crypt/crypt_cipher_is_valid.c" #include "crypt/crypt_find_cipher.c" #include "crypt/crypt_find_hash.c" #include "crypt/crypt_find_prng.c" #include "crypt/crypt_hash_descriptor.c" #include "crypt/crypt_hash_is_valid.c" #include "crypt/crypt_prng_descriptor.c" #include "crypt/crypt_prng_is_valid.c" #include "crypt/crypt_register_cipher.c" #include "crypt/crypt_register_hash.c" #include "crypt/crypt_register_prng.c" #include "hashes/helper/hash_memory.c" #include "hashes/sha2/sha512.c" #include "mac/hmac/hmac_done.c" #include "mac/hmac/hmac_init.c" #include "mac/hmac/hmac_memory.c" #include "mac/hmac/hmac_process.c" #include "misc/error_to_string.c" #include "misc/pkcs5/pkcs_5_2.c" #include "misc/zeromem.c" #include "modes/ctr/ctr_decrypt.c" #include "modes/ctr/ctr_done.c" #include "modes/ctr/ctr_encrypt.c" #include "modes/ctr/ctr_start.c" #include "modes/cfb/cfb_decrypt.c" #include "modes/cfb/cfb_done.c" #include "modes/cfb/cfb_encrypt.c" #include "modes/cfb/cfb_start.c" #include "prngs/fortuna.c" } #include "../MultiThreading.h" /*-------------------------------------------------*/ /* Инициализация библиотеки шифрования LibTomCrypt */ /*-------------------------------------------------*/ // Зарегистировать все включённые в программу алгоритмы int register_all() { register_cipher (&aes_enc_desc); register_cipher (&blowfish_desc); register_cipher (&serpent_desc); register_cipher (&twofish_desc); // register_hash (&sha1_desc); register_hash (&sha512_desc); #ifndef LTC_NO_TEST CHECK (FREEARC_ERRCODE_INTERNAL, blowfish_test()==CRYPT_OK, (s,"blowfish_test failed!")); // CHECK (FREEARC_ERRCODE_INTERNAL, rijndael_test()==CRYPT_OK, (s,"rijndael_test failed!")); CHECK (FREEARC_ERRCODE_INTERNAL, serpent_test ()==CRYPT_OK, (s,"serpent_test failed!")); CHECK (FREEARC_ERRCODE_INTERNAL, twofish_test ()==CRYPT_OK, (s,"twofish_test failed!")); // CHECK (FREEARC_ERRCODE_INTERNAL, sha1_test ()==CRYPT_OK, (s,"sha1_test failed!")); CHECK (FREEARC_ERRCODE_INTERNAL, sha512_test ()==CRYPT_OK, (s,"sha512_test failed!")); // CHECK (FREEARC_ERRCODE_INTERNAL, hmac_test ()==CRYPT_OK, (s,"hmac_test failed!")); // CHECK (FREEARC_ERRCODE_INTERNAL, ctr_test ()==CRYPT_OK, (s,"ctr_test failed!")); // CHECK (FREEARC_ERRCODE_INTERNAL, cfb_test ()==CRYPT_OK, (s,"cfb_test failed!")); #endif return 0; } int call_register_all = register_all(); // Размер буфера Fortuna PRNG int fortuna_size (void) { return sizeof(prng_state); } /*------------------------------------------------------*/ /* Обобщённый интерфейс к режимам шифрования (CFB,CTR) */ /*------------------------------------------------------*/ #define roundup_ptr(p,n) ((p)+(n)-ptrdiff_t(p)%(n)) struct EncryptionMode { enum {CTR,CFB} mode; union { symmetric_CTR ctr; symmetric_CFB cfb; char aesbuf [AES_NUM_IVMRK_WORDS*sizeof(UInt32) + AES_BLOCK_SIZE]; // buffer for g_AesCtr_Code }; char *aesctr; EncryptionMode (int _mode) {mode = (_mode==0? CTR:CFB);} char *name() { switch (mode) { case CTR: return "ctr"; case CFB: return "cfb"; default: abort(); } } int start (int cipher, BYTE *iv, BYTE *key, int keysize, int rounds) { // 7-zip code implements only AES-CTR with default number of rounds if (strequ(cipher_descriptor[cipher].name,"aes") && mode==CTR && rounds==0) { // Init the AES-CTR library static Mutex exclusive_access; { Lock _(exclusive_access); static volatile bool initialized = false; if (!initialized) { initialized = true; AesGenTables(); if (CPU_Is_Aes_Supported()) { FARPROC Fast_AesCtr_Code = LoadFromDLL("Fast_AesCtr_Code"); if (Fast_AesCtr_Code) g_AesCtr_Code = (AES_CODE_FUNC) Fast_AesCtr_Code; } } } // aesctr[] should be aligned to 16-byte boundary aesctr = roundup_ptr (aesbuf, AES_BLOCK_SIZE); // Store in aesctr[] InitVector-1 (since 7-zip code does *pre*increment of counter) memcpy (aesctr, iv, AES_BLOCK_SIZE); for (int i=0; i= 0 ) // выход при ошибке чтения { bool LastBlock = (InSize==0); // True for the last block that should be processed in the special way if ((InSize+=RemainderSize)==0) break; // break if there's no more data int OutSize = encryptor.aesctr==NULL? InSize // process all input data unless optimized AES-CTR code used : LastBlock? roundUp (InSize, AES_BLOCK_SIZE) // process more data if these are the last bytes in input stream : roundDown (InSize, AES_BLOCK_SIZE), x; // process less data and move the rest to the next processing cycle DoEncryption==ENCRYPT ? encryptor.encrypt(Buf, OutSize) : encryptor.decrypt(Buf, OutSize); if (OutSize>InSize) OutSize=InSize; if( (x=callback("write",Buf,OutSize,auxdata))<0 ) {InSize=x; break;} // break on write rror if( LastBlock ) {InSize=0; break;} // break if the last block RemainderSize = InSize-OutSize; // Перенесём необработанный остаток данных в начало буфера if (RemainderSize>0) memmove (Buf, Buf+OutSize, RemainderSize); }} Exit: encryptor.done(); free (Buf0); return InSize; // возвратим код ошибки или 0 если всё в порядке } /*-------------------------------------------------*/ /* Реализация класса ENCRYPTION_METHOD */ /*-------------------------------------------------*/ // Конструктор, присваивающий параметрам метода сжатия значения по умолчанию ENCRYPTION_METHOD::ENCRYPTION_METHOD() { cipher = -1; mode = -1; numIterations = 1000; rounds = 0; keySize = -1; fixed = FALSE; strcpy(key, ""); strcpy(iv, ""); strcpy(salt, ""); strcpy(code, ""); } // Универсальный метод, отвечает на запросы "encryption?", "KeySize" и "IVSize" int ENCRYPTION_METHOD::doit (char *what, int param, void *data, CALLBACK_FUNC *callback) { if (strequ (what, "encryption?")) return 1; // Да, это алгоритм шифрования else if (strequ (what, "keySize")) return keySize; // Возвращает размер ключа, используемого в данном методе сжатия else if (strequ (what, "ivSize")) return ivSize; // Возвращает размер InitVector, используемого в данном методе сжатия else if (strequ (what, "numIterations")) return numIterations; // Возвращает количество итераций, используемых при генерации ключа по password+salt else return COMPRESSION_METHOD::doit (what, param, data, callback); // Передать остальные вызовы родительской процедуре } // Функция распаковки int ENCRYPTION_METHOD::decompress (CALLBACK_FUNC *callback, void *auxdata) { BYTE key_bytes[MAXKEYSIZE]; fixed? decode16 (key, key_bytes) : buggy_decode16 (key, key_bytes); BYTE iv_bytes [MAXKEYSIZE]; fixed? decode16 (iv, iv_bytes) : buggy_decode16 (iv, iv_bytes); return docrypt (DECRYPT, cipher, mode, key_bytes, strlen(key)/2, rounds, iv_bytes, callback, auxdata); } #ifndef FREEARC_DECOMPRESS_ONLY // Функция упаковки int ENCRYPTION_METHOD::compress (CALLBACK_FUNC *callback, void *auxdata) { BYTE key_bytes[MAXKEYSIZE]; fixed? decode16 (key, key_bytes) : buggy_decode16 (key, key_bytes); BYTE iv_bytes [MAXKEYSIZE]; fixed? decode16 (iv, iv_bytes) : buggy_decode16 (iv, iv_bytes); return docrypt (ENCRYPT, cipher, mode, key_bytes, strlen(key)/2, rounds, iv_bytes, callback, auxdata); } #endif // !defined (FREEARC_DECOMPRESS_ONLY) // Записать в buf[MAX_METHOD_STRLEN] строку, описывающую метод сжатия и его параметры (функция, обратная к parse_ENCRYPTION) void ENCRYPTION_METHOD::ShowCompressionMethod (char *buf, bool purify) { sprintf (buf, "%s-%d/%s%s:n%d:r%d%s%s%s%s%s%s%s%s" , cipher_descriptor[cipher].name, keySize*8 , EncryptionMode(mode).name() , fixed? ":f" : "" , numIterations , rounds , *key ?":k":"", key , *iv ?":i":"", iv , *salt?":s":"", salt , *code?":c":"", code ); } // Конструирует объект типа ENCRYPTION_METHOD с заданными параметрами упаковки // или возвращает NULL, если это другой метод сжатия или допущена ошибка в параметрах COMPRESSION_METHOD* parse_ENCRYPTION (char** parameters) { int error = 0; // Признак того, что при разборе параметров произошла ошибка // Делаем локальную копию, поскольку split портит строку char local_method[MAX_METHOD_STRLEN]; strncopy (local_method, parameters[0], MAX_METHOD_STRLEN); // Разбиваем строку метода на максимум 2 части, разделённые знаком '/' // Это метод и режим шифрования (например, "aes/cfb") char *parts[3]; split (local_method, '/', parts, 3); int mode = parts[1]? find_mode(parts[1]) : 0; // Разбиваем строку метода на максимум 2 части, разделённые знаком '-' // После '-' может быть указан размер ключа в битах (например, "aes-128") split (local_method, '-', parts, 3); int cipher = find_cipher(parts[0]); int keySize = parts[1]? parseInt (parts[1], &error)/8 : 0; if (mode<0 || cipher<0 || error) return NULL; // Это не метод ENCRYPTION ENCRYPTION_METHOD *p = new ENCRYPTION_METHOD; p->cipher = cipher; p->mode = mode; p->keySize = keySize? keySize : cipher_descriptor[cipher].max_key_length; p->ivSize = cipher_descriptor[cipher].block_length; // Переберём все параметры метода (или выйдем раньше при возникновении ошибки при разборе очередного параметра) while (*++parameters && !error) { char* param = *parameters; if (strequ (param, "f")) { p->fixed = TRUE; continue; } switch (*param) { // Параметры, содержащие значения case 'k': strncopy (p->key, param+1, sizeof (p->key)); continue; case 'i': strncopy (p->iv, param+1, sizeof (p->iv)); continue; case 's': strncopy (p->salt, param+1, sizeof (p->salt)); continue; case 'c': strncopy (p->code, param+1, sizeof (p->code)); continue; case 'n': p->numIterations = parseInt (param+1, &error); continue; case 'r': p->rounds = parseInt (param+1, &error); continue; default : error=1; continue; } } if (error) {delete p; return NULL;} // Ошибка при парсинге параметров метода return p; } static int ENCRYPTION_x = AddCompressionMethod (parse_ENCRYPTION); // Зарегистрируем парсер метода ENCRYPTION