rockbox/utils/nwztools/upgtools/mg.cpp
Amaury Pouly 8ce60c54f7 nwztools/upgtool: add support for MD5
When compressing, it is possible to tell the tool to add an entry to the MD5
file (index 1), it is still necessary to give an empty file for that index.
To do so, pass the option "-z idx,name" insteas of "-z idx". This will create
an entry of the form "size md5 name". For instance "-z 6,system.img".
When decompressing, if one passes "-z idx,name" instead of "-z idx", the tool
will decompress and check against the value in the MD5 file.

Change-Id: Ifb945f6121644ae9105265d2d83ce6067301c5b2
2020-10-11 13:08:03 +02:00

328 lines
9 KiB
C++

/***************************************************************************
* __________ __ ___.
* 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 <windows.h>
#include <wincrypt.h>
#include <stdio.h>
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 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 <cryptopp/cryptlib.h>
#include <cryptopp/modes.h>
#include <cryptopp/des.h>
#include <cryptopp/aes.h>
#include <cryptopp/md5.h>
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 *>(md5_obj);
md5->Update(reinterpret_cast<const uint8_t *>(input), length);
}
void md5_final(void *md5_obj, void *digest)
{
MD5 *md5 = reinterpret_cast<MD5 *>(md5_obj);
md5->Final(reinterpret_cast<uint8_t *>(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