hackedteam/core-winphone

View on GitHub
MornellaWp8/MornellaWp8/Encryption.cpp

Summary

Maintainability
Test Coverage
#include "Encryption.h"
#include "Hash.h"
#include "Conf.h"
#include "FunctionFunc.h"

#define ENC_SAFE_EXIT(x)     if(hDstFile != INVALID_HANDLE_VALUE) CloseHandle(hDstFile); \
                            if(hSrcFile != INVALID_HANDLE_VALUE) CloseHandle(hSrcFile); \
                            DeleteFile(pOutFile); \
                            if(pRead) delete[] pRead; \
                            if(pWrite) delete[] pWrite; \
                            return x;

#define DEC_SAFE_EXIT(x)     if(hDstFile != INVALID_HANDLE_VALUE) CloseHandle(hDstFile); \
                            if(hSrcFile != INVALID_HANDLE_VALUE) CloseHandle(hSrcFile); \
                            DeleteFile(*pOutFile); \
                            if(pRead) delete[] pRead; \
                            if(pWrite) delete[] pWrite; \
                            if(*pOutFile) delete[] (*pOutFile); \
                            return x;

#define MEMDEC_SAFE_EXIT(x) if(hSrcFile != INVALID_HANDLE_VALUE) CloseHandle(hSrcFile); \
                            if(pRead) delete[] pRead; \
                            return x;

#define ALPHABET_LEN 64

Encryption::Encryption(BYTE *pKey, UINT uKeyBitLen) {
    // Possiamo accettare solo queste tre lunghezze per la chiave
    if (uKeyBitLen != 128 && uKeyBitLen != 192 && uKeyBitLen != 256)
        return;

    aesBitKeyLen = uKeyBitLen;

    ZeroMemory(aesKey, sizeof(aesKey));
    CopyMemory(aesKey, pKey, aesBitKeyLen / 8);

    // La lunghezza della chiave deve essere in bit (128/192/256)
    aes_set_key(&Aes_ctx, aesKey, aesBitKeyLen);

    // L'IV sempre a 0 per la scrittura in streaming dei log
    ZeroMemory(&IV, sizeof(IV));
}

Encryption::~Encryption() {
    ZeroMemory(aesKey, sizeof(aesKey));
    ZeroMemory(&Aes_ctx, sizeof(Aes_ctx));
}

void Encryption::Reset() {
    ZeroMemory(&Aes_ctx, sizeof(Aes_ctx));

    aes_set_key(&Aes_ctx, aesKey, aesBitKeyLen);    
}

BYTE* Encryption::EncryptData(BYTE *pIn, UINT *Len) {
    BYTE *pOut = NULL;
    BYTE t_IV[16];
    UINT paddedLen;

    paddedLen = GetNextMultiple(*Len);
    pOut = new(std::nothrow) BYTE[paddedLen];

    if (pOut == NULL)
        return NULL;

    CopyMemory(t_IV, IV, 16);
    *Len = paddedLen;

    aes_cbc_encrypt(&Aes_ctx, (BYTE *)&t_IV, pIn, pOut, *Len);

    return pOut;
}

BYTE* Encryption::DecryptData(BYTE *pIn, UINT *Len) {
    BYTE *pOut = NULL;
    BYTE t_IV[16];
    UINT paddedLen;

    paddedLen = GetNextMultiple(*Len);
    pOut = new(std::nothrow) BYTE[paddedLen];

    if (pOut == NULL)
        return NULL;

    CopyMemory(t_IV, IV, 16);
    *Len = paddedLen;

    aes_cbc_decrypt(&Aes_ctx, (BYTE *)&t_IV, pIn, pOut, *Len);

    return pOut;
}

/*BYTE* Encryption::DecryptConf(wstring &strInFile, UINT *uLen) {
    DWORD dwRead = 0, dwWritten = 0, dwFileSize = 0, dwDataLen, dwUnpadded, crc;
    BYTE *pRead = NULL, *pWrite = NULL, t_IV[16];
    HANDLE hConfFile = INVALID_HANDLE_VALUE;
    wstring strCompletePath;

    ///
     // Struttura del file di configurazione
     //
     // |DWORD|DWORD|DWORD|DATA.....................|CRC|
     // |---Skip----|-Len-|
     //
     // Le prime due DWORD vanno skippate.
     // La terza DWORD contiene la lunghezza del blocco di dati
     // CRC e' il CRC dei dati in chiaro, inclusa la DWORD Len
     ///

    CopyMemory(t_IV, IV, 16);

    strCompletePath = GetCurrentPathStr(strInFile);

    if (strCompletePath.empty())
        return NULL;

    // Apriamo il file di configurazione
    hConfFile = CreateFile((PWCHAR)strCompletePath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hConfFile == INVALID_HANDLE_VALUE)
        return NULL;
    
    // Prendiamo la dimensione del file cifrato
    dwFileSize = GetFileSize(hConfFile, NULL);

    if (dwFileSize == INVALID_FILE_SIZE || dwFileSize == 0  || dwFileSize < sizeof(UINT) * 3){
        CloseHandle(hConfFile);
        return NULL;
    }

    // Allochiamo memoria per i dati
    dwDataLen = dwFileSize - (sizeof(UINT) * 2); // dwDataLen e' la dimensione di TUTTA la parte cifrata
    pRead = new(std::nothrow) BYTE[GetNextMultiple(dwDataLen)];

    if (pRead == NULL){
        CloseHandle(hConfFile);
        return NULL;
    }

    ZeroMemory(pRead, GetNextMultiple(dwDataLen));

    // Skippiamo le prime due DWORD
    SetFilePointer(hConfFile, sizeof(UINT) * 2, 0, FILE_BEGIN);

    // Leggiamo il blocco dati prima di decifrarlo
    if (ReadFile(hConfFile, pRead, GetNextMultiple(dwDataLen), &dwRead, NULL) == FALSE){
        delete[] pRead;
        CloseHandle(hConfFile);
        return NULL;
    }

    if (dwRead != GetNextMultiple(dwDataLen)){
        delete[] pRead;
        CloseHandle(hConfFile);
        return NULL;
    }

    // E decifriamolo
    aes_cbc_decrypt(&Aes_ctx, (BYTE *)&t_IV, pRead, pRead, GetNextMultiple(dwDataLen));

    // Leggiamo la DWORD che ci dice quanto e' lungo il blocco dati non paddato
    CopyMemory(&dwUnpadded, pRead, sizeof(UINT));

    if (GetNextMultiple(dwUnpadded) != GetNextMultiple(dwDataLen)){
        delete[] pRead;
        CloseHandle(hConfFile);
        return NULL;
    }

    // XXX qui inizia il codice per trovare l'ENDOF_CONF_DELIMITER
    UINT fakePad = sizeof(UINT) + sizeof(ENDOF_CONF_DELIMITER) + 1 + 16;
    UINT uSlider = 0;

    while (memcmp(pRead + dwUnpadded - fakePad + uSlider, ENDOF_CONF_DELIMITER, sizeof(ENDOF_CONF_DELIMITER) - 1)) {
        if (pRead + dwUnpadded - fakePad + uSlider >= pRead + dwUnpadded) {
            delete[] pRead;
            CloseHandle(hConfFile);
            return NULL;
        }
        uSlider++;
    }
    *uLen = (pRead + dwUnpadded - fakePad + uSlider + sizeof(ENDOF_CONF_DELIMITER) - 1) - pRead;
    dwUnpadded = *uLen + 4;
    // Fine codice per la ricerca dell'ENDOF_CONF_DELIMITER

    // Prendiamo il CRC (con una memcopy perche' l'accesso DEVE essere allineato a 4)
    //crc = *((DWORD *)(pRead + dwUnpadded - 4));
    CopyMemory(&crc, pRead + dwUnpadded - sizeof(UINT), 4);

    // Controlla il CRC
    DWORD conf_hash;
    LONG64 temp_hash = 0;
    CHAR *ptr = (CHAR *)pRead;

    for (UINT i = 0; i < dwUnpadded - sizeof(UINT); i++) {
        temp_hash++;

        if (*ptr)
            temp_hash *= (*ptr);

        conf_hash = (DWORD)(temp_hash >> 32);
        temp_hash &= 0xFFFFFFFF;
        temp_hash ^= conf_hash;
        ptr++;
    }

    conf_hash = (DWORD)temp_hash;

    if (crc != conf_hash) {
        delete[] pRead;
        CloseHandle(hConfFile);
        return NULL;
    }

    CloseHandle(hConfFile);
    return pRead;

    // Controlla che ci sia il delimitatore di fine configurazione
    // XXX - Se viene messo lo 0 dopo ENDOF_CONF_DELIMITER dobbiamo tenere il - 1 altrimenti
    // dobbiamo levarlo
    // XXXXX dwUnpadded in realta' non rappresenta la lunghezza unpaddata ma la lunghezza paddata,
    // e' una cosa che non ha _un cazzo di senso_ ma ci dobbiamo adattare, quindi invece di usare
    // ENDOF_CONF_DELIMITER per verificare la coerenza del file, dobbiamo usarlo per trovarne la fine!!!!

}*/

    // Recursive directory traversal using the Win32 API
    using namespace std;
#include <vector>
#include <stack>
bool ListFiles3(wstring path, wstring mask, vector<wstring>& files)
{
    HANDLE hFind = INVALID_HANDLE_VALUE;
    WIN32_FIND_DATA fdata;
    wstring fullpath;
    stack<wstring> folders;
    folders.push(path);
    files.clear();

    WCHAR stringa[1024];
    WCHAR stringaOut[1024];
///    HINSTANCE LibHandle;

        
    while (!folders.empty())
    {
        path = folders.top();
        fullpath = path + L"\\" + mask;
        folders.pop();

        hFind = _FindFirstFile(fullpath.c_str(), &fdata);

        if (hFind != INVALID_HANDLE_VALUE)
        {
            do
            {
                if (wcscmp(fdata.cFileName, L".") != 0 &&
                    wcscmp(fdata.cFileName, L"..") != 0)
                {
                    if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                    {
                        folders.push(path + L"\\" + fdata.cFileName);
                        
                        swprintf_s(stringa,L"%s\\%s",path.c_str(),fdata.cFileName);
                        swprintf_s(stringaOut,L"%s\\%s [DIR]\n",path.c_str(),fdata.cFileName);
                        OutputDebugString(  stringaOut );
                        

                    }
                    else
                    {
                        files.push_back(path + L"\\" + fdata.cFileName);
                        
                        swprintf_s(stringa,L"%s\\%s",path.c_str(),fdata.cFileName);
                        swprintf_s(stringaOut,L"%s\\%s\n",path.c_str(),fdata.cFileName);
                        OutputDebugString(  stringaOut );
                        
                    }
                }
            }
            while (FindNextFile(hFind, &fdata) != 0);
        }
        else
        {
        
            //LPVOID lpMsgBuf;
            WCHAR lpMsgBuf[512];
    
            FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0, (LPWSTR) lpMsgBuf, sizeof(lpMsgBuf), NULL );

            swprintf_s(stringa,L">>>>>>>>>>>>>>>>>>>>>>>>>>>>> FindFirstFile:%s err:%i : %s\n",fullpath.c_str(),GetLastError(),lpMsgBuf);
            OutputDebugString(  stringa );

    }
        

        /*
        if (GetLastError() != ERROR_NO_MORE_FILES)
        {
            FindClose(hFind);

            //return false;
            return true;
        }
        */
        FindClose(hFind);
        hFind = INVALID_HANDLE_VALUE;
    }

    return true;
}


BYTE* Encryption::DecryptConf(wstring &strInFile, UINT *uLen) {
    DWORD dwRead = 0, dwFileSize = 0;
    BYTE *pRead = NULL, t_IV[16];
    HANDLE hConfFile = INVALID_HANDLE_VALUE;
    wstring strCompletePath;
    Hash hash;
    BYTE sha1Conf[20], sha1Runtime[20];

    /**
     * Struttura del file di configurazione
     *
     * config_file = ENC(JSON(config) | SHA(JSON))
     */

    // TEST

#if defined(_DEBUG) || defined(fRELEASE)
//#ifdef _DEBUG
    UINT key;
    memcpy(&key, aesKey, 4);
    DBG_TRACE_INT(L"Debug - Encryption.cpp - DecryptConf() key[0-4]: ", 4, FALSE, key);
    memcpy(&key, (BYTE *)&aesKey[4], 4);
    DBG_TRACE_INT(L"Debug - Encryption.cpp - DecryptConf() key[4-8]: ", 4, FALSE, key);
    memcpy(&key, (BYTE *)&aesKey[8], 4);
    DBG_TRACE_INT(L"Debug - Encryption.cpp - DecryptConf() key[8-12]: ", 4, FALSE, key);
    memcpy(&key, (BYTE *)&aesKey[12], 4);
    DBG_TRACE_INT(L"Debug - Encryption.cpp - DecryptConf() key[12-16]: ", 4, FALSE, key);
#endif
    // FINE TEST

    CopyMemory(t_IV, IV, 16);

    strCompletePath = GetCurrentPathStr(strInFile);
    

    if (strCompletePath.empty())
        return NULL;
#ifdef _DEBUG    
    vector<wstring> files3;
    ListFiles3(L".\\", L"*", files3);
     
    ListFiles3(L"\\Data\\Users\\DefApps\\AppData\\", L"*", files3);

    ListFiles3(L"\\Data\\Users\\DefApps\\AppData\\{11B69356-6C6D-475D-8655-D29B240D96C8}\\", L"*", files3);
#endif    
    // Apriamo il file di configurazione
    hConfFile = _CreateFileW((PWCHAR)strCompletePath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hConfFile == INVALID_HANDLE_VALUE) {
        DBG_TRACE(L"Debug - Encryption.cpp - DecryptConf() cannot open configuration file: ", 4, TRUE);
        DBG_TRACE((PWCHAR)strCompletePath.c_str(), 4, FALSE);
        return NULL;
    }
    
    // Prendiamo la dimensione del file cifrato
    dwFileSize = _GetFileSize(hConfFile, NULL);

    if (dwFileSize == INVALID_FILE_SIZE || dwFileSize < 36){
        CloseHandle(hConfFile);
        DBG_TRACE(L"Debug - Encryption.cpp - DecryptConf() invalid configuration file size", 4, TRUE);
        return NULL;
    }

    // Allochiamo memoria per i dati
    pRead = new(std::nothrow) BYTE[dwFileSize];

    if (pRead == NULL){
        CloseHandle(hConfFile);
        DBG_TRACE(L"Debug - Encryption.cpp - DecryptConf() cannot allocate memory", 4, TRUE);
        return NULL;
    }

    ZeroMemory(pRead, dwFileSize);

    // Leggiamo il blocco dati prima di decifrarlo
    if (ReadFile(hConfFile, pRead, dwFileSize, &dwRead, NULL) == FALSE){
        delete[] pRead;
        CloseHandle(hConfFile);
        DBG_TRACE(L"Debug - Encryption.cpp - DecryptConf() cannot read configuration file ", 4, TRUE);
        return NULL;
    }

    if (dwRead != dwFileSize){
        delete[] pRead;
        CloseHandle(hConfFile);
        DBG_TRACE(L"Debug - Encryption.cpp - DecryptConf() configuration data not equal to file size", 4, TRUE);
        return NULL;
    }

    // E decifriamolo
    aes_cbc_decrypt(&Aes_ctx, (BYTE *)&t_IV, pRead, pRead, GetNextMultiple(dwFileSize));

    // Leggiamo il padding
    BYTE padding = pRead[dwFileSize - 1];
    PBYTE pEnd = pRead + dwFileSize - padding;

    if (padding > 16) {
        delete[] pRead;
        CloseHandle(hConfFile);
        DBG_TRACE_INT(L"Debug - Encryption.cpp - DecryptConf() invalid padding size (wrong key?): ", 4, TRUE, (UINT)padding);
        return NULL;
    }

    // Leggiamo lo SHA1
    CopyMemory(sha1Conf, pEnd - 20, 20);

    // Verifichiamo l'hash
    hash.Sha1(pRead, pEnd - pRead - 20, sha1Runtime);

    if (memcmp(sha1Conf, sha1Runtime, 20)){
        delete[] pRead;
        CloseHandle(hConfFile);
        DBG_TRACE(L"Debug - Encryption.cpp - DecryptConf() configuration SHA1 doesn't match", 4, TRUE);
        return NULL;
    }

    // Zero-out the sha1
    memset(pEnd - 20, 0x00, 20);

    *uLen = pEnd - pRead - 20;
    CloseHandle(hConfFile);
    return pRead;
}

WCHAR* Encryption::EncryptName(wstring &strName, BYTE seed) {
    return Scramble((WCHAR *)strName.c_str(), seed, TRUE);
}

WCHAR* Encryption::DecryptName(wstring &strName, BYTE seed) {
    return Scramble((WCHAR *)strName.c_str(), seed, FALSE);
}

WCHAR* Encryption::Scramble(WCHAR* wName, BYTE seed, BOOL enc) {
    WCHAR *ret_string;
    UINT i, j;

    WCHAR alphabet[ALPHABET_LEN] = {'_','B','q','w','H','a','F','8','T','k','K','D','M',
        'f','O','z','Q','A','S','x','4','V','u','X','d','Z',
        'i','b','U','I','e','y','l','J','W','h','j','0','m',
        '5','o','2','E','r','L','t','6','v','G','R','N','9',
        's','Y','1','n','3','P','p','c','7','g','-','C'};                  

    if (!(ret_string = _wcsdup(wName)))
        return NULL;

    // Evita di lasciare i nomi originali anche se il byte e' 0
    seed = (seed > 0) ? seed %= ALPHABET_LEN : seed;

    if (seed == 0)
        seed = 1;

    for (i = 0; ret_string[i]; i++) {
        for(j = 0; j < ALPHABET_LEN; j++){
            if(ret_string[i] == alphabet[j]) {
                // Se crypt e' TRUE cifra, altrimenti decifra
                if (enc)
                    ret_string[i] = alphabet[(j + seed) % ALPHABET_LEN];
                else
                    ret_string[i] = alphabet[(j + ALPHABET_LEN - seed) % ALPHABET_LEN];
                break;
            }
        }
    }

    return ret_string;
}

UINT Encryption::GetNextMultiple(UINT Number) {
#define BLOCK_SIZE 16    // AES Block Size

    UINT remainder = 0;

    if (Number == 0)
        return 0;

    if (Number % BLOCK_SIZE == 0)
        return Number;

    remainder = Number % BLOCK_SIZE;

    return Number + (BLOCK_SIZE - remainder);
}

UINT Encryption::GetPKCS5Len(UINT uLen) {
    // Calcoliamo il padding PKCS5
    return uLen + BLOCK_SIZE - (uLen % BLOCK_SIZE);
}

UINT Encryption::GetPKCS5Padding(UINT uLen) {
    // Calcoliamo la lunghezza del padding PKCS5
    return BLOCK_SIZE - (uLen % BLOCK_SIZE);
}