From c2a4d5c0d155a22406b89b27d5b2168d445370c2 Mon Sep 17 00:00:00 2001 From: d0k3 Date: Wed, 7 Dec 2016 00:00:05 +0100 Subject: [PATCH] Improved and extended aes.c / aes.h Thanks @Gemarcano --- source/crypto/aes.c | 91 +++++++++++++++++++++++++++++++++-------- source/crypto/aes.h | 8 ++-- source/game/ncch.c | 2 +- source/virtual/sddata.c | 4 +- 4 files changed, 82 insertions(+), 23 deletions(-) diff --git a/source/crypto/aes.c b/source/crypto/aes.c index b0eb7a6..7c2a8bd 100644 --- a/source/crypto/aes.c +++ b/source/crypto/aes.c @@ -3,9 +3,9 @@ //FIXME some things make assumptions about alignemnts! -void setup_aeskeyX(uint8_t keyslot, void* keyx) +void setup_aeskeyX(uint8_t keyslot, const void* keyx) { - uint32_t * _keyx = (uint32_t*)keyx; + const uint32_t * _keyx = (const uint32_t*)keyx; *REG_AESCNT = (*REG_AESCNT) | AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER; *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | 0x80; if (keyslot > 3) { @@ -23,9 +23,9 @@ void setup_aeskeyX(uint8_t keyslot, void* keyx) } } -void setup_aeskeyY(uint8_t keyslot, void* keyy) +void setup_aeskeyY(uint8_t keyslot, const void* keyy) { - uint32_t * _keyy = (uint32_t*)keyy; + const uint32_t * _keyy = (const uint32_t*)keyy; *REG_AESCNT = (*REG_AESCNT) | AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER; *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | 0x80; if (keyslot > 3) { @@ -43,9 +43,9 @@ void setup_aeskeyY(uint8_t keyslot, void* keyy) } } -void setup_aeskey(uint8_t keyslot, void* key) +void setup_aeskey(uint8_t keyslot, const void* key) { - uint32_t * _key = (uint32_t*)key; + const uint32_t * _key = (const uint32_t*)key; *REG_AESCNT = (*REG_AESCNT) | AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER; *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | 0x80; if (keyslot > 3) { @@ -88,7 +88,8 @@ void add_ctr(void* ctr, uint32_t carry) uint32_t sum; int32_t i; - for(i=0; i < 4; i++) { + for(i = 0; i < 4; i++) { + //FIXME this assumes alignment... counter[i] = ((uint32_t)outctr[i*4+0]<<24) | ((uint32_t)outctr[i*4+1]<<16) | ((uint32_t)outctr[i*4+2]<<8) | ((uint32_t)outctr[i*4+3]<<0); } @@ -113,23 +114,80 @@ void add_ctr(void* ctr, uint32_t carry) } } -void ctr_decrypt_boffset(void *inbuf, void *outbuf, size_t size, size_t off, uint32_t mode, uint8_t *ctr) +void subtract_ctr(void* ctr, uint32_t carry) +{ + //ctr is in big endian format, 16 bytes + uint32_t counter[4]; + uint8_t *outctr = (uint8_t *) ctr; + + //Convert each 4 byte part of ctr to uint32_t equivalents + for(size_t i = 0; i < 4; i++) { + //FIXME this assumes alignment... + counter[i] = ((uint32_t)outctr[i*4+0]<<24) | ((uint32_t)outctr[i*4+1]<<16) | ((uint32_t)outctr[i*4+2]<<8) | ((uint32_t)outctr[i*4+3]<<0); + } + + for(size_t i = 0; i < 4; ++i) + { + uint32_t sub; + //using modular arithmetic to handle carry + sub = counter[3-i] - carry; + carry = counter[3-i] < carry; + + counter[3-i] = sub; + } + + for(size_t i = 0; i < 4; i++) + { + outctr[i*4+0] = counter[i]>>24; + outctr[i*4+1] = counter[i]>>16; + outctr[i*4+2] = counter[i]>>8; + outctr[i*4+3] = counter[i]>>0; + } +} + +void ecb_decrypt(void *inbuf, void *outbuf, size_t size, uint32_t mode) +{ + aes_decrypt(inbuf, outbuf, size, mode); +} + +void cbc_decrypt(void *inbuf, void *outbuf, size_t size, uint32_t mode, uint8_t *ctr) +{ + size_t blocks_left = size; + size_t blocks; + uint8_t *in = inbuf; + uint8_t *out = outbuf; + uint32_t i; + + while (blocks_left) + { + set_ctr(ctr); + blocks = (blocks_left >= 0xFFFF) ? 0xFFFF : blocks_left; + for (i=0; i= AES_BLOCK_SIZE) ? + size_t last_byte = ((off_fix + bytes_left) >= AES_BLOCK_SIZE) ? AES_BLOCK_SIZE : off_fix + bytes_left; for (i=off_fix; i= AES_BLOCK_SIZE) { - ctr_decrypt(in, out, bytes_left / AES_BLOCK_SIZE, mode, ctr_local); - in += AES_BLOCK_SIZE * (uint32_t) (bytes_left / AES_BLOCK_SIZE); - out += AES_BLOCK_SIZE * (uint32_t) (bytes_left / AES_BLOCK_SIZE); - bytes_left -= AES_BLOCK_SIZE * (uint32_t) (bytes_left / AES_BLOCK_SIZE); + size_t blocks = bytes_left / AES_BLOCK_SIZE; + ctr_decrypt(in, out, blocks, mode, ctr_local); + in += AES_BLOCK_SIZE * blocks; + out += AES_BLOCK_SIZE * blocks; + bytes_left -= AES_BLOCK_SIZE * blocks; } if (bytes_left) // handle misaligned offset (at end) diff --git a/source/crypto/aes.h b/source/crypto/aes.h index ff46726..23e27a1 100644 --- a/source/crypto/aes.h +++ b/source/crypto/aes.h @@ -46,15 +46,15 @@ extern "C" { #define AES_CNT_ECB_DECRYPT_MODE (AES_ECB_DECRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) #define AES_CNT_ECB_ENCRYPT_MODE (AES_ECB_ENCRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) -void setup_aeskeyX(uint8_t keyslot, void* keyx); -void setup_aeskeyY(uint8_t keyslot, void* keyy); -void setup_aeskey(uint8_t keyslot, void* keyy); +void setup_aeskeyX(uint8_t keyslot, const void* keyx); +void setup_aeskeyY(uint8_t keyslot, const void* keyy); +void setup_aeskey(uint8_t keyslot, const void* keyy); void use_aeskey(uint32_t keyno); void set_ctr(void* iv); void add_ctr(void* ctr, uint32_t carry); void aes_decrypt(void* inbuf, void* outbuf, size_t size, uint32_t mode); void ctr_decrypt(void* inbuf, void* outbuf, size_t size, uint32_t mode, uint8_t *ctr); -void ctr_decrypt_boffset(void *inbuf, void *outbuf, size_t size, size_t off, uint32_t mode, uint8_t *ctr); +void ctr_decrypt_byte(void *inbuf, void *outbuf, size_t size, size_t off, uint32_t mode, uint8_t *ctr); void aes_cmac(void* inbuf, void* outbuf, size_t size); void aes_fifos(void* inbuf, void* outbuf, size_t blocks); void set_aeswrfifo(uint32_t value); diff --git a/source/game/ncch.c b/source/game/ncch.c index 3462921..ba739e3 100644 --- a/source/game/ncch.c +++ b/source/game/ncch.c @@ -217,7 +217,7 @@ u32 DecryptNcchSection(u8* data, u32 offset_data, u32 size_data, u8 ctr[16]; GetNcchCtr(ctr, ncch, snum); if (SetNcchKey(ncch, keyid) != 0) return 1; - ctr_decrypt_boffset(data_i, data_i, size_i, offset_i + offset_ctr, mode, ctr); + ctr_decrypt_byte(data_i, data_i, size_i, offset_i + offset_ctr, mode, ctr); return 0; } diff --git a/source/virtual/sddata.c b/source/virtual/sddata.c index 48d853d..3124570 100644 --- a/source/virtual/sddata.c +++ b/source/virtual/sddata.c @@ -87,7 +87,7 @@ FRESULT fx_read (FIL* fp, void* buff, UINT btr, UINT* br) { if (info && info->fptr) { setup_aeskeyY(0x34, info->keyy); use_aeskey(0x34); - ctr_decrypt_boffset(buff, buff, btr, off, AES_CNT_CTRNAND_MODE, info->ctr); + ctr_decrypt_byte(buff, buff, btr, off, AES_CNT_CTRNAND_MODE, info->ctr); } return res; } @@ -104,7 +104,7 @@ FRESULT fx_write (FIL* fp, const void* buff, UINT btw, UINT* bw) { UINT pcount = min(SDCRYPT_BUFFER_SIZE, (btw - p)); UINT bwl = 0; memcpy(SDCRYPT_BUFFER, (u8*) buff + p, pcount); - ctr_decrypt_boffset(SDCRYPT_BUFFER, SDCRYPT_BUFFER, pcount, off + p, AES_CNT_CTRNAND_MODE, info->ctr); + ctr_decrypt_byte(SDCRYPT_BUFFER, SDCRYPT_BUFFER, pcount, off + p, AES_CNT_CTRNAND_MODE, info->ctr); res = f_write(fp, (const void*) SDCRYPT_BUFFER, pcount, &bwl); *bw += bwl; }