/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2012 Amaury Pouly * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "mg.h" /* on Windows, we use Cryptography API, on other platforms we rely on crypto++ */ #if defined(_WIN32) || defined(__WIN32__) #include #include #include static HCRYPTPROV g_hCryptProv; typedef struct { BLOBHEADER hdr; DWORD dwKeySize; BYTE rgbKeyData[]; } PLAINTEXTKEY; static bool check_context() { if(g_hCryptProv) return true; return CryptAcquireContext(&g_hCryptProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT); } static HCRYPTKEY import_key(ALG_ID algid, DWORD mode, const uint8_t *key, int key_size, const uint8_t *iv) { if(!check_context()) return 0; DWORD blob_size = sizeof(PLAINTEXTKEY) + key_size; PLAINTEXTKEY *key_blob = (PLAINTEXTKEY *)malloc(blob_size); key_blob->hdr.bType = PLAINTEXTKEYBLOB; key_blob->hdr.bVersion = CUR_BLOB_VERSION; key_blob->hdr.reserved = 0; key_blob->hdr.aiKeyAlg = algid; key_blob->dwKeySize = key_size; memcpy(key_blob->rgbKeyData, key, key_size); HCRYPTKEY hKey; if(!CryptImportKey(g_hCryptProv, (const BYTE *)key_blob, blob_size, 0, 0, &hKey)) return 0; CryptSetKeyParam(hKey, KP_MODE, (const BYTE *)&mode, 0); if(iv) CryptSetKeyParam(hKey, KP_IV, (const BYTE *)iv, 0); return hKey; } void MD5_CalculateDigest(void *digest, const void *input, size_t length) { if(!check_context()) return; HCRYPTHASH hHash; if(!CryptCreateHash(g_hCryptProv, CALG_MD5, 0, 0, &hHash)) return; if(!CryptHashData(hHash, (const BYTE *)input, length, 0)) return; DWORD dwSize = 16; if(!CryptGetHashParam(hHash, HP_HASHVAL, (BYTE *)digest, &dwSize, 0)) return; CryptDestroyHash(hHash); } void *md5_start() { if(!check_context()) return NULL; HCRYPTHASH hHash; if(!CryptCreateHash(g_hCryptProv, CALG_MD5, 0, 0, &hHash)) return NULL; return reinterpret_cast(hHash); } void md5_update(void *md5_obj, const void *input, size_t length) { HCRYPTHASH hHash = reinterpret_cast(md5_obj); CryptHashData(hHash, (const BYTE *)input, length, 0); } void md5_final(void *md5_obj, void *digest) { HCRYPTHASH hHash = reinterpret_cast(md5_obj); DWORD dwSize = 16; if(!CryptGetHashParam(hHash, HP_HASHVAL, (BYTE *)digest, &dwSize, 0)) return; CryptDestroyHash(hHash); } void mg_decrypt_fw(void *in, int size, void *out, uint8_t *key) { if(!check_context() || (size % 8) != 0) abort(); /* size must be a multiple of 8 */ HCRYPTKEY hKey = import_key(CALG_DES, CRYPT_MODE_ECB, key, 8, NULL); memcpy(out, in, size); DWORD dwSize = size; CryptDecrypt(hKey, 0, FALSE, 0, (BYTE *)out, &dwSize); CryptDestroyKey(hKey); } static HCRYPTKEY g_des_ecb_dec_key; void des_ecb_dec_set_key(const uint8_t key[8]) { if(g_des_ecb_dec_key) CryptDestroyKey(g_des_ecb_dec_key); g_des_ecb_dec_key = import_key(CALG_DES, CRYPT_MODE_ECB, key, 8, NULL); } void des_ecb_dec(void *in, int size, void *out) { if(size % 8) abort(); /* size must be a multiple of 8 */ memcpy(out, in, size); DWORD dwSize = size; CryptDecrypt(g_des_ecb_dec_key, 0, FALSE, 0, (BYTE *)out, &dwSize); } static HCRYPTKEY g_des_ecb_enc_key; void des_ecb_enc_set_key(const uint8_t key[8]) { if(g_des_ecb_enc_key) CryptDestroyKey(g_des_ecb_enc_key); g_des_ecb_enc_key = import_key(CALG_DES, CRYPT_MODE_ECB, key, 8, NULL); } void des_ecb_enc(void *in, int size, void *out) { if(size % 8) abort(); /* size must be a multiple of 8 */ memcpy(out, in, size); DWORD dwSize = size; CryptEncrypt(g_des_ecb_enc_key, 0, FALSE, 0, (BYTE *)out, &dwSize, dwSize); } static HCRYPTKEY g_aes_ecb_dec_key; void aes_ecb_dec_set_key(const uint8_t key[16]) { if(g_aes_ecb_dec_key) CryptDestroyKey(g_aes_ecb_dec_key); g_aes_ecb_dec_key = import_key(CALG_AES_128, CRYPT_MODE_ECB, key, 16, NULL); } void aes_ecb_dec(void *in, int size, void *out) { if(size % 16) abort(); /* size must be a multiple of 16 */ memcpy(out, in, size); DWORD dwSize = size; CryptDecrypt(g_aes_ecb_dec_key, 0, FALSE, 0, (BYTE *)out, &dwSize); } static HCRYPTKEY g_aes_ecb_enc_key; void aes_ecb_enc_set_key(const uint8_t key[16]) { if(g_aes_ecb_enc_key) CryptDestroyKey(g_aes_ecb_enc_key); g_aes_ecb_enc_key = import_key(CALG_AES_128, CRYPT_MODE_ECB, key, 16, NULL); } void aes_ecb_enc(void *in, int size, void *out) { if(size % 16) abort(); /* size must be a multiple of 16 */ memcpy(out, in, size); DWORD dwSize = size; CryptEncrypt(g_aes_ecb_enc_key, 0, FALSE, 0, (BYTE *)out, &dwSize, dwSize); } static HCRYPTKEY g_aes_cbc_dec_key; void aes_cbc_dec_set_key_iv(const uint8_t key[16], const uint8_t iv[16]) { if(g_aes_cbc_dec_key) CryptDestroyKey(g_aes_cbc_dec_key); g_aes_cbc_dec_key = import_key(CALG_AES_128, CRYPT_MODE_CBC, key, 16, iv); } void aes_cbc_dec(void *in, int size, void *out) { if(size % 16) abort(); /* size must be a multiple of 16 */ memcpy(out, in, size); DWORD dwSize = size; CryptDecrypt(g_aes_cbc_dec_key, 0, FALSE, 0, (BYTE *)out, &dwSize); } static HCRYPTKEY g_aes_cbc_enc_key; void aes_cbc_enc_set_key_iv(const uint8_t key[16], const uint8_t iv[16]) { if(g_aes_cbc_enc_key) CryptDestroyKey(g_aes_cbc_enc_key); g_aes_cbc_enc_key = import_key(CALG_AES_128, CRYPT_MODE_CBC, key, 16, iv); } void aes_cbc_enc(void *in, int size, void *out) { if(size % 16) abort(); /* size must be a multiple of 16 */ memcpy(out, in, size); DWORD dwSize = size; CryptEncrypt(g_aes_cbc_enc_key, 0, FALSE, 0, (BYTE *)out, &dwSize, dwSize); } #else /* Not on Windows */ /* MD5 is considered insecure by crypto++ */ #define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 #include #include #include #include #include using namespace CryptoPP; using namespace CryptoPP::Weak; void MD5_CalculateDigest(void *digest, const void *input, size_t length) { MD5().CalculateDigest((byte *)digest, (const byte *)input, length); } void *md5_start() { return new MD5; } void md5_update(void *md5_obj, const void *input, size_t length) { MD5 *md5 = reinterpret_cast(md5_obj); md5->Update(reinterpret_cast(input), length); } void md5_final(void *md5_obj, void *digest) { MD5 *md5 = reinterpret_cast(md5_obj); md5->Final(reinterpret_cast(digest)); delete md5; } void mg_decrypt_fw(void *in, int size, void *out, uint8_t *key) { ECB_Mode< DES >::Decryption dec; if(size % 8) abort(); /* size must be a multiple of 8 */ dec.SetKey(key, 8); dec.ProcessData((byte*)out, (byte*)in, size); } static ECB_Mode< DES >::Decryption g_des_ecb_dec; void des_ecb_dec_set_key(const uint8_t key[8]) { g_des_ecb_dec.SetKey(key, 8); } void des_ecb_dec(void *in, int size, void *out) { if(size % 8) abort(); /* size must be a multiple of 8 */ g_des_ecb_dec.ProcessData((byte*)out, (byte*)in, size); } static ECB_Mode< DES >::Encryption g_des_ecb_enc; void des_ecb_enc_set_key(const uint8_t key[8]) { g_des_ecb_enc.SetKey(key, 8); } void des_ecb_enc(void *in, int size, void *out) { if(size % 8) abort(); /* size must be a multiple of 8 */ g_des_ecb_enc.ProcessData((byte*)out, (byte*)in, size); } static ECB_Mode< AES >::Decryption g_aes_ecb_dec; void aes_ecb_dec_set_key(const uint8_t key[16]) { g_aes_ecb_dec.SetKey(key, 16); } void aes_ecb_dec(void *in, int size, void *out) { if(size % 16) abort(); /* size must be a multiple of 16 */ g_aes_ecb_dec.ProcessData((byte*)out, (byte*)in, size); } static ECB_Mode< AES >::Encryption g_aes_ecb_enc; void aes_ecb_enc_set_key(const uint8_t key[16]) { g_aes_ecb_enc.SetKey(key, 16); } void aes_ecb_enc(void *in, int size, void *out) { if(size % 16) abort(); /* size must be a multiple of 16 */ g_aes_ecb_enc.ProcessData((byte*)out, (byte*)in, size); } static CBC_Mode< AES >::Decryption g_aes_cbc_dec; void aes_cbc_dec_set_key_iv(const uint8_t key[16], const uint8_t iv[16]) { g_aes_cbc_dec.SetKeyWithIV(key, 16, iv); } void aes_cbc_dec(void *in, int size, void *out) { if(size % 16) abort(); /* size must be a multiple of 16 */ g_aes_cbc_dec.ProcessData((byte*)out, (byte*)in, size); } static CBC_Mode< AES >::Encryption g_aes_cbc_enc; void aes_cbc_enc_set_key_iv(const uint8_t key[16], const uint8_t iv[16]) { g_aes_cbc_enc.SetKeyWithIV(key, 16, iv); } void aes_cbc_enc(void *in, int size, void *out) { if(size % 16) abort(); /* size must be a multiple of 16 */ g_aes_cbc_enc.ProcessData((byte*)out, (byte*)in, size); } #endif