nstool/lib/libfnd/source/aes_wrapper.cpp

159 lines
4.5 KiB
C++

#include <fnd/aes.h>
#include <polarssl/aes.h>
using namespace fnd::aes;
inline void XorBlock(const uint8_t a[kAesBlockSize], const uint8_t b[kAesBlockSize], uint8_t out[kAesBlockSize])
{
for (uint8_t i = 0; i < 16; i++)
{
out[i] = a[i] ^ b[i];
}
}
inline uint32_t getbe32(const uint8_t* data) { return data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; }
inline void putbe32(uint8_t* data, uint32_t val) { data[0] = val >> 24; data[1] = val >> 16; data[2] = val >> 8; data[3] = val; }
void fnd::aes::AesEcbDecrypt(const uint8_t * in, uint64_t size, const uint8_t key[kAes128KeySize], uint8_t * out)
{
aes_context ctx;
aes_setkey_dec(&ctx, key, 128);
for (size_t i = 0; i < size / kAesBlockSize; i++)
{
aes_crypt_ecb(&ctx, AES_DECRYPT, in + kAesBlockSize * i, out + kAesBlockSize * i);
}
}
void fnd::aes::AesEcbEncrypt(const uint8_t * in, uint64_t size, const uint8_t key[kAes128KeySize], uint8_t * out)
{
aes_context ctx;
aes_setkey_enc(&ctx, key, 128);
for (size_t i = 0; i < size / kAesBlockSize; i++)
{
aes_crypt_ecb(&ctx, AES_ENCRYPT, in + kAesBlockSize * i, out + kAesBlockSize * i);
}
}
void fnd::aes::AesCtr(const uint8_t* in, uint64_t size, const uint8_t key[kAes128KeySize], uint8_t ctr[kAesBlockSize], uint8_t* out)
{
aes_context ctx;
uint8_t block[kAesBlockSize] = { 0 };
size_t counterOffset = 0;
aes_setkey_enc(&ctx, key, 128);
aes_crypt_ctr(&ctx, size, &counterOffset, ctr, block, in, out);
}
void fnd::aes::AesIncrementCounter(const uint8_t in[kAesBlockSize], size_t block_num, uint8_t out[kAesBlockSize])
{
memcpy(out, in, kAesBlockSize);
uint32_t ctr[4];
ctr[3] = getbe32(&in[0]);
ctr[2] = getbe32(&in[4]);
ctr[1] = getbe32(&in[8]);
ctr[0] = getbe32(&in[12]);
for (uint32_t i = 0; i < 4; i++) {
uint64_t total = ctr[i] + block_num;
// if there wasn't a wrap around, add the two together and exit
if (total <= 0xffffffff) {
ctr[i] += (uint32_t)block_num;
break;
}
// add the difference
ctr[i] = (uint32_t)(total - 0x100000000);
// carry to next word
block_num = (uint32_t)(total >> 32);
}
putbe32(&out[0], ctr[3]);
putbe32(&out[4], ctr[2]);
putbe32(&out[8], ctr[1]);
putbe32(&out[12], ctr[0]);
}
void fnd::aes::AesCbcDecrypt(const uint8_t* in, uint64_t size, const uint8_t key[kAes128KeySize], uint8_t iv[kAesBlockSize], uint8_t* out)
{
aes_context ctx;
aes_setkey_dec(&ctx, key, 128);
aes_crypt_cbc(&ctx, AES_DECRYPT, size, iv, in, out);
}
void fnd::aes::AesCbcEncrypt(const uint8_t* in, uint64_t size, const uint8_t key[kAes128KeySize], uint8_t iv[kAesBlockSize], uint8_t* out)
{
aes_context ctx;
aes_setkey_enc(&ctx, key, 128);
aes_crypt_cbc(&ctx, AES_ENCRYPT, size, iv, in, out);
}
void fnd::aes::AesXtsDecryptSector(const uint8_t * in, uint64_t sector_size, const uint8_t key1[kAes128KeySize], const uint8_t key2[kAes128KeySize], uint8_t tweak[kAesBlockSize], uint8_t * out)
{
aes_context data_ctx;
aes_setkey_dec(&data_ctx, key1, 128);
uint8_t enc_tweak[kAesBlockSize];
AesEcbEncrypt(tweak, kAesBlockSize, key2, enc_tweak);
size_t block_num = sector_size / kAesBlockSize;
uint8_t block[kAesBlockSize];
for (size_t i = 0; i < block_num; i++)
{
XorBlock(in + (i * kAesBlockSize), enc_tweak, block);
aes_crypt_ecb(&data_ctx, AES_DECRYPT, block, block);
XorBlock(block, enc_tweak, out + i * kAesBlockSize);
GaloisFunc(enc_tweak);
}
if (sector_size % kAesBlockSize)
{
// TODO: implement ciphertext stealing
}
}
void fnd::aes::AesXtsEncryptSector(const uint8_t * in, uint64_t sector_size, const uint8_t key1[kAes128KeySize], const uint8_t key2[kAes128KeySize], uint8_t tweak[kAesBlockSize], uint8_t * out)
{
aes_context data_ctx;
aes_setkey_enc(&data_ctx, key1, 128);
uint8_t enc_tweak[kAesBlockSize];
AesEcbEncrypt(tweak, kAesBlockSize, key2, enc_tweak);
size_t block_num = sector_size / kAesBlockSize;
uint8_t block[kAesBlockSize];
for (size_t i = 0; i < block_num; i++)
{
XorBlock(in + (i * kAesBlockSize), enc_tweak, block);
aes_crypt_ecb(&data_ctx, AES_ENCRYPT, block, block);
XorBlock(block, enc_tweak, out + (i * kAesBlockSize));
GaloisFunc(enc_tweak);
}
if (sector_size % kAesBlockSize)
{
// TODO: implement ciphertext stealing
}
}
void fnd::aes::AesXtsMakeTweak(uint8_t tweak[kAesBlockSize], size_t block_index)
{
memset(tweak, 0, kAesBlockSize);
AesIncrementCounter(tweak, block_index, tweak);
}
void fnd::aes::GaloisFunc(uint8_t x[kAesBlockSize])
{
uint8_t t = x[15];
for (uint8_t i = 15; i > 0; i--)
{
x[i] = (x[i] << 1) | (x[i - 1] & 0x80 ? 1 : 0);
}
x[0] = (x[0] << 1) ^ (t & 0x80 ? 0x87 : 0x00);
}