diff --git a/include/arm9/crypto.h b/include/arm9/crypto.h index 151f866..10e4aea 100644 --- a/include/arm9/crypto.h +++ b/include/arm9/crypto.h @@ -1,7 +1,5 @@ /* - * AES code based on code from Normmatt - * - * 2016 - 2017 + * 2017 * profi200 */ @@ -10,13 +8,14 @@ #include "types.h" + ////////////////////////////////// // AES // ////////////////////////////////// -#define AES_MAX_BUF_SIZE (0xFFFC0) +#define AES_MAX_BLOCKS (0xFFFC) -#define AES_WRITE_FIFO_COUNT (REG_AESCNT>>0 & 0x1F) +#define AES_WRITE_FIFO_COUNT (REG_AESCNT & 0x1F) #define AES_READ_FIFO_COUNT (REG_AESCNT>>5 & 0x1F) #define AES_FLUSH_READ_FIFO (1u<<10) @@ -24,14 +23,16 @@ #define AES_MAC_SIZE(n) (((n - 2) / 2)<<16) #define AES_MAC_SRC_REG (1u<<20) #define AES_MAC_VALID ((bool)(REG_AESCNT>>21 & 1)) -#define AES_OUTPUT_BIG (1u<<22) + +#define AES_OUTPUT_BIG (1u) #define AES_OUTPUT_LITTLE (0u) -#define AES_INPUT_BIG (1u<<23) +#define AES_INPUT_BIG (1u) #define AES_INPUT_LITTLE (0u) -#define AES_OUTPUT_NORMAL (1u<<24) +#define AES_OUTPUT_NORMAL (4u) #define AES_OUTPUT_REVERSED (0u) -#define AES_INPUT_NORMAL (1u<<25) +#define AES_INPUT_NORMAL (4u) #define AES_INPUT_REVERSED (0u) + #define AES_UPDATE_KEYSLOT (1u<<26) #define AES_IRQ_ENABLE (1u<<30) #define AES_ENABLE (1u<<31) @@ -45,96 +46,118 @@ #define AES_MODE_ECB_ENCRYPT (7u<<27) -typedef enum -{ - AES_KEY_TYPE_NORMAL = 0, - AES_KEY_TYPE_X = 1, - AES_KEY_TYPE_Y = 2, -} AesKeyType; - typedef struct { - u32 ctrIvNonce[4]; u32 ctrIvNonceParams; + u32 ctrIvNonce[4]; u32 aesParams; } AES_ctx; +/** + * @brief Initializes the AES hardware and the NDMA channels used by it. + */ void AES_init(void); + /** - * @brief Selects keyslot and sets the key for the specified key type. + * @brief Sets a normal key. * - * @param[in] params Word order and endianess bitmask. - * @param[in] keyslot The keyslot this key will be set for. - * @param[in] keyType The key type. Can be AES_KEY_TYPE_NORMAL/X/Y. - * @param[in] key Pointer to 128-bit AES key data. - * @param[in] useTwlScrambler bool true if TWL keyscrambler is used instead of CTR keyscrambler (only with CTR keyslots). - * @param[in] updateKeyslot bool true if the final AES key should immediately be calculated and set. + * @param[in] keyslot The keyslot this key will be set for. + * @param[in] orderEndianess Word order and endianess bitmask. + * @param[in] key Pointer to 128-bit AES key data. */ -void AES_setKey(u32 params, u8 keyslot, AesKeyType type, const u32 *restrict key, bool useTwlScrambler, bool updateKeyslot); +void AES_setNormalKey(u8 keyslot, u8 orderEndianess, const u32 key[4]); + + +/** + * @brief Sets a keyX. + * + * @param[in] keyslot The keyslot this key will be set for. + * @param[in] orderEndianess Word order and endianess bitmask. + * @param[in] useTwlScrambler Set to true to use the TWL keyscrambler for keyslots > 0x03. + * @param[in] keyX Pointer to 128-bit AES keyX data. + */ +void AES_setKeyX(u8 keyslot, u8 orderEndianess, bool useTwlScrambler, const u32 keyX[4]); + + +/** + * @brief Sets a keyY. + * + * @param[in] keyslot The keyslot this key will be set for. + * @param[in] orderEndianess Word order and endianess bitmask. + * @param[in] useTwlScrambler Set to true to use the TWL keyscrambler for keyslots > 0x03. + * @param[in] keyY Pointer to 128-bit AES keyY data. + */ +void AES_setKeyY(u8 keyslot, u8 orderEndianess, bool useTwlScrambler, const u32 keyY[4]); + /** * @brief Selects the given keyslot for all following crypto operations. * - * @param[in] keyslot The keyslot to select. - * @param[in] updateKeyslot bool true if the final AES key should immediately be calculated and set. + * @param[in] keyslot The keyslot to select. */ -void AES_selectKeyslot(u8 keyslot, bool updateKeyslot); +void AES_selectKeyslot(u8 keyslot); + /** - * @brief Copies the given CTR/IV/nonce into internal state. + * @brief Copies the given nonce into internal state. * - * @param ctx Pointer to AES_ctx (AES context). - * @param[in] ctrIvNonce Pointer to CTR/IV/nonce data. Size is determined by params. - * @param[in] params Word order, endianess and AES cipher mode bitmask. - * @param[in] initialCtr Value to update the counter in CTR mode with. Can be 0. + * @param ctx Pointer to AES_ctx (AES context). + * @param[in] orderEndianess Word order and endianess bitmask. + * @param[in] nonce Pointer to the nonce data. */ -void AES_setCtrIvNonce(AES_ctx *restrict ctx, const u32 *restrict ctrIvNonce, u32 params, u32 initialCtr); +void AES_setNonce(AES_ctx *const ctx, u8 orderEndianess, const u32 nonce[3]); + /** - * @brief Returns a pointer to the CTR/IV/nonce stored in internal state. + * @brief Copies the given counter/initialization vector into internal state. * - * @param ctx Pointer to AES_ctx (AES context). - * - * @return A pointer to the internal CTR/IV/nonce data. + * @param ctx Pointer to AES_ctx (AES context). + * @param[in] orderEndianess Word order and endianess bitmask. + * @param[in] ctrIv Pointer to the counter/initialization vector data. */ -u32* AES_getCtrIvNoncePtr(AES_ctx *restrict ctx); +void AES_setCtrIv(AES_ctx *const ctx, u8 orderEndianess, const u32 ctrIv[4]); -/** - * @brief Sets params in internal state for all following crypto operations. - * - * @param ctx Pointer to AES_ctx (AES context). - * @param[in] params Params bitmask to set. - */ -void AES_setCryptParams(AES_ctx *restrict ctx, u32 params); - -/** - * @brief En-/decrypts data with the previosly set params. - * @brief In CTR mode the internal counter is updated after each call. - * - * @param ctx Pointer to AES_ctx (AES context). - * @param[in] in In data pointer. Can be the same as out. - * @param out Out data pointer. Can be the same as in. - * @param[in] size Data size. If not 16 bytes aligned it is rounded up. - */ -void AES_crypt(AES_ctx *restrict ctx, const u32 *restrict in, u32 *restrict out, u32 size); /** * @brief Increments the internal counter with the given value (CTR mode). * - * @param ctx Pointer to AES_ctx (AES context). - * @param[in] val Value to add to the counter. + * @param ctr Pointer to the counter data. + * @param[in] val Value to increment the counter with. */ -void AES_addCounter(AES_ctx *restrict ctx, u32 val); // TODO: Handle endianess! +void AES_addCounter(u32 ctr[4], u32 val); + /** * @brief Decrements the internal counter with the given value (CTR mode). * - * @param ctx Pointer to AES_ctx (AES context). - * @param[in] val Value to substract from the counter. + * @param ctr Pointer to the counter data. + * @param[in] val Value to decrement the counter with. */ -void AES_subCounter(AES_ctx *restrict ctx, u32 val); +void AES_subCounter(u32 ctr[4], u32 val); + + +/** + * @brief Sets params in the AES context for all following crypto operations. + * + * @param ctx Pointer to AES_ctx (AES context). + * @param[in] inEndianessOrder Input endianess and word order bitmask. + * @param[in] outEndianessOrder Output endianess and word order bitmask. + */ +void AES_setCryptParams(AES_ctx *const ctx, u8 inEndianessOrder, u8 outEndianessOrder); + + +/** + * @brief En-/decrypts data with AES CTR. + * + * @param ctx Pointer to AES_ctx (AES context). + * @param[in] in In data pointer. Can be the same as out. + * @param out Out data pointer. Can be the same as in. + * @param[in] blocks Number of blocks to process. 1 block is 16 bytes. + * @param[in] dma Set to true to enable DMA. + */ +void AES_ctr(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool dma); @@ -148,10 +171,9 @@ #define SHA_INPUT_LITTLE (0u) #define SHA_OUTPUT_BIG (SHA_INPUT_BIG) #define SHA_OUTPUT_LITTLE (SHA_INPUT_LITTLE) - #define SHA_MODE_256 (0u) #define SHA_MODE_224 (1u<<4) -#define SHA_MODE_1 (1u<<5) +#define SHA_MODE_1 (2u<<4) /** @@ -159,7 +181,7 @@ * * @param[in] params Mode and input endianess bitmask. */ -void SHA_start(u32 params); +void SHA_start(u8 params); /** * @brief Hashes the data pointed to. @@ -167,7 +189,7 @@ * @param[in] data Pointer to data to hash. * @param[in] size Size of the data to hash. */ -void SHA_update(const u32 *restrict data, u32 size); +void SHA_update(const u32 *data, u32 size); /** * @brief Generates the final hash. @@ -175,7 +197,7 @@ * @param hash Pointer to memory to copy the hash to. * @param[in] endianess Endianess bitmask for the hash. */ -void SHA_finish(u32 *restrict hash, u32 endianess); +void SHA_finish(u32 *const hash, u8 endianess); /** * @brief Hashes a single block of data and outputs the hash. @@ -186,4 +208,4 @@ * @param[in] params Mode and input endianess bitmask. * @param[in] hashEndianess Endianess bitmask for the hash. */ -void sha(const u32 *restrict data, u32 size, u32 *restrict hash, u32 params, u32 hashEndianess); +void sha(const u32 *data, u32 size, u32 *const hash, u8 params, u8 hashEndianess); diff --git a/include/arm9/ndma.h b/include/arm9/ndma.h index 28553d9..2d4ee72 100644 --- a/include/arm9/ndma.h +++ b/include/arm9/ndma.h @@ -87,7 +87,7 @@ // REG_NDMA_GLOBAL_CNT -#define NDMA_ROUND_ROBIN(n) ((u32)log2(n) | (1u<<31) | 1u) // n = number of CPU cycles +#define NDMA_ROUND_ROBIN(n) ((u32)log2(n)<<16 | 1u<<31 | 1u) // n = number of CPU cycles #define NDMA_HIGHEST_PRIO (1u) // REG_NDMA_INT_CNT diff --git a/include/cache.h b/include/cache.h index c755158..518c8e7 100644 --- a/include/cache.h +++ b/include/cache.h @@ -5,8 +5,8 @@ void invalidateICache(void); -void invalidateICacheRange(void *base, u32 size); +void invalidateICacheRange(const void *const base, u32 size); void flushDCache(void); -void flushDCacheRange(void *base, u32 size); +void flushDCacheRange(const void *const base, u32 size); void invalidateDCache(void); -void invalidateDCacheRange(void *base, u32 size); +void invalidateDCacheRange(const void *const base, u32 size); diff --git a/source/arm9/crypto.c b/source/arm9/crypto.c index 0abf2b2..199c694 100644 --- a/source/arm9/crypto.c +++ b/source/arm9/crypto.c @@ -1,7 +1,5 @@ /* - * AES code based on code from Normmatt - * - * 2016 + * 2017 * profi200 */ @@ -20,34 +18,35 @@ // AES // ////////////////////////////////// -#define AES_REGS_BASE (IO_MEM_ARM9_ONLY + 0x9000) -#define REG_AESCNT *((vu32*)(AES_REGS_BASE + 0x000)) -#define REG_AESBLKCNT *((vu32*)(AES_REGS_BASE + 0x004)) -#define REG_AESBLKCNTH1 *((vu16*)(AES_REGS_BASE + 0x004)) -#define REG_AESBLKCNTH2 *((vu16*)(AES_REGS_BASE + 0x006)) -#define REG_AESWRFIFO ((vu32*)(AES_REGS_BASE + 0x008)) -#define REG_AESRDFIFO ((vu32*)(AES_REGS_BASE + 0x00C)) -#define REG_AESKEYSEL *((vu8* )(AES_REGS_BASE + 0x010)) -#define REG_AESKEYCNT *((vu8* )(AES_REGS_BASE + 0x011)) -#define REG_AESCTR ((vu32*)(AES_REGS_BASE + 0x020)) -#define REG_AESMAC ((vu32*)(AES_REGS_BASE + 0x030)) +#define AES_REGS_BASE (IO_MEM_ARM9_ONLY + 0x9000) +#define REG_AESCNT *((vu32*)(AES_REGS_BASE + 0x000)) -#define REG_AESKEY0 ((vu32*)(AES_REGS_BASE + 0x040)) -#define REG_AESKEYX0 ((vu32*)(AES_REGS_BASE + 0x050)) -#define REG_AESKEYY0 ((vu32*)(AES_REGS_BASE + 0x060)) -#define REG_AESKEY1 ((vu32*)(AES_REGS_BASE + 0x070)) -#define REG_AESKEYX1 ((vu32*)(AES_REGS_BASE + 0x080)) -#define REG_AESKEYY1 ((vu32*)(AES_REGS_BASE + 0x090)) -#define REG_AESKEY2 ((vu32*)(AES_REGS_BASE + 0x0A0)) -#define REG_AESKEYX2 ((vu32*)(AES_REGS_BASE + 0x0B0)) -#define REG_AESKEYY2 ((vu32*)(AES_REGS_BASE + 0x0C0)) -#define REG_AESKEY3 ((vu32*)(AES_REGS_BASE + 0x0D0)) -#define REG_AESKEYX3 ((vu32*)(AES_REGS_BASE + 0x0E0)) -#define REG_AESKEYY3 ((vu32*)(AES_REGS_BASE + 0x0F0)) +#define REG_AESBLKCNT *((vu32*)(AES_REGS_BASE + 0x004)) +#define REG_AES_BLKCNT_LOW *((vu16*)(AES_REGS_BASE + 0x004)) +#define REG_AES_BLKCNT_HIGH *((vu16*)(AES_REGS_BASE + 0x006)) +#define REG_AESWRFIFO ( AES_REGS_BASE + 0x008) +#define REG_AESRDFIFO ( AES_REGS_BASE + 0x00C) +#define REG_AESKEYSEL *((vu8* )(AES_REGS_BASE + 0x010)) +#define REG_AESKEYCNT *((vu8* )(AES_REGS_BASE + 0x011)) +#define REG_AESCTR ((vu32*)(AES_REGS_BASE + 0x020)) +#define REG_AESMAC ((vu32*)(AES_REGS_BASE + 0x030)) -#define REG_AESKEYFIFO ((vu32*)(AES_REGS_BASE + 0x100)) -#define REG_AESKEYXFIFO ((vu32*)(AES_REGS_BASE + 0x104)) -#define REG_AESKEYYFIFO ((vu32*)(AES_REGS_BASE + 0x108)) +#define REG_AESKEY0 ((vu32*)(AES_REGS_BASE + 0x040)) +#define REG_AESKEYX0 ((vu32*)(AES_REGS_BASE + 0x050)) +#define REG_AESKEYY0 ((vu32*)(AES_REGS_BASE + 0x060)) +#define REG_AESKEY1 ((vu32*)(AES_REGS_BASE + 0x070)) +#define REG_AESKEYX1 ((vu32*)(AES_REGS_BASE + 0x080)) +#define REG_AESKEYY1 ((vu32*)(AES_REGS_BASE + 0x090)) +#define REG_AESKEY2 ((vu32*)(AES_REGS_BASE + 0x0A0)) +#define REG_AESKEYX2 ((vu32*)(AES_REGS_BASE + 0x0B0)) +#define REG_AESKEYY2 ((vu32*)(AES_REGS_BASE + 0x0C0)) +#define REG_AESKEY3 ((vu32*)(AES_REGS_BASE + 0x0D0)) +#define REG_AESKEYX3 ((vu32*)(AES_REGS_BASE + 0x0E0)) +#define REG_AESKEYY3 ((vu32*)(AES_REGS_BASE + 0x0F0)) + +#define REG_AESKEYFIFO *((vu32*)(AES_REGS_BASE + 0x100)) +#define REG_AESKEYXFIFO *((vu32*)(AES_REGS_BASE + 0x104)) +#define REG_AESKEYYFIFO *((vu32*)(AES_REGS_BASE + 0x108)) void AES_init(void) @@ -55,12 +54,12 @@ REG_AESCNT = AES_MAC_SIZE(4) | AES_FLUSH_WRITE_FIFO | AES_FLUSH_READ_FIFO; *((vu8*)0x10000008) |= 0xCu; // ?? - REG_NDMA0_DST_ADDR = (u32)REG_AESWRFIFO; + REG_NDMA0_DST_ADDR = REG_AESWRFIFO; REG_NDMA0_INT_CNT = NDMA_INT_SYS_FREQ; REG_NDMA0_CNT = NDMA_REPEATING_MODE | NDMA_STARTUP_AES_IN | NDMA_SRC_UPDATE_INC | NDMA_DST_UPDATE_FIXED; - REG_NDMA1_SRC_ADDR = (u32)REG_AESRDFIFO; + REG_NDMA1_SRC_ADDR = REG_AESRDFIFO; REG_NDMA1_INT_CNT = NDMA_INT_SYS_FREQ; REG_NDMA1_CNT = NDMA_REPEATING_MODE | NDMA_STARTUP_AES_OUT | NDMA_SRC_UPDATE_FIXED | NDMA_DST_UPDATE_INC; @@ -68,36 +67,201 @@ REG_IRQ_IE |= 1u< 3) + { + REG_AESKEYCNT = keyslot | 0x80u; + REG_AESKEYFIFO = key[0]; + REG_AESKEYFIFO = key[1]; + REG_AESKEYFIFO = key[2]; + REG_AESKEYFIFO = key[3]; + } + else + { + u32 lastu32; + vu32 *twlKeyNReg = ®_AESKEY0[12 * keyslot]; + if(orderEndianess & 4) + { + twlKeyNReg[0] = key[3]; + twlKeyNReg[1] = key[2]; + twlKeyNReg[2] = key[1]; + lastu32 = key[0]; + } + else + { + twlKeyNReg[0] = key[0]; + twlKeyNReg[1] = key[1]; + twlKeyNReg[2] = key[2]; + lastu32 = key[3]; + } + twlKeyNReg[3] = lastu32; + } +} + +void AES_setKeyX(u8 keyslot, u8 orderEndianess, bool useTwlScrambler, const u32 keyX[4]) +{ + assert(keyslot < 0x40); + assert(keyX != NULL); + + + REG_AESCNT = (u32)orderEndianess<<23; + if(keyslot > 3) + { + REG_AESKEYCNT = keyslot | (u8)useTwlScrambler<<6 | 0x80u; + REG_AESKEYXFIFO = keyX[0]; + REG_AESKEYXFIFO = keyX[1]; + REG_AESKEYXFIFO = keyX[2]; + REG_AESKEYXFIFO = keyX[3]; + } + else + { + u32 lastu32; + vu32 *twlKeyNReg = ®_AESKEY0[12 * keyslot]; + if(orderEndianess & 4) + { + twlKeyNReg[4] = keyX[3]; + twlKeyNReg[5] = keyX[2]; + twlKeyNReg[6] = keyX[1]; + lastu32 = keyX[0]; + } + else + { + twlKeyNReg[4] = keyX[0]; + twlKeyNReg[5] = keyX[1]; + twlKeyNReg[6] = keyX[2]; + lastu32 = keyX[3]; + } + twlKeyNReg[7] = lastu32; + } +} + +void AES_setKeyY(u8 keyslot, u8 orderEndianess, bool useTwlScrambler, const u32 keyY[4]) +{ + assert(keyslot < 0x40); + assert(keyY != NULL); + + + REG_AESCNT = (u32)orderEndianess<<23; + if(keyslot > 3) + { + REG_AESKEYCNT = keyslot | (u8)useTwlScrambler<<6 | 0x80u; + REG_AESKEYYFIFO = keyY[0]; + REG_AESKEYYFIFO = keyY[1]; + REG_AESKEYYFIFO = keyY[2]; + REG_AESKEYYFIFO = keyY[3]; + } + else + { + u32 lastu32; + vu32 *twlKeyNReg = ®_AESKEY0[12 * keyslot]; + if(orderEndianess & 4) + { + twlKeyNReg[8] = keyY[3]; + twlKeyNReg[9] = keyY[2]; + twlKeyNReg[10] = keyY[1]; + lastu32 = keyY[0]; + } + else + { + twlKeyNReg[8] = keyY[0]; + twlKeyNReg[9] = keyY[1]; + twlKeyNReg[10] = keyY[2]; + lastu32 = keyY[3]; + } + twlKeyNReg[11] = lastu32; + } +} + +void AES_selectKeyslot(u8 keyslot) +{ + assert(keyslot < 0x40); + + + REG_AESKEYSEL = keyslot; + REG_AESCNT |= AES_UPDATE_KEYSLOT; +} + +void AES_setNonce(AES_ctx *const ctx, u8 orderEndianess, const u32 nonce[3]) +{ + assert(ctx != NULL); + assert(nonce != NULL); + + + ctx->ctrIvNonceParams = (u32)orderEndianess<<23; + u32 lastu32; + if(orderEndianess & 4) + { + ctx->ctrIvNonce[0] = nonce[2]; + ctx->ctrIvNonce[1] = nonce[1]; + lastu32 = nonce[0]; + } + else + { + ctx->ctrIvNonce[0] = nonce[0]; + ctx->ctrIvNonce[1] = nonce[1]; + lastu32 = nonce[2]; + } + ctx->ctrIvNonce[2] = lastu32; +} + +void AES_setCtrIv(AES_ctx *const ctx, u8 orderEndianess, const u32 ctrIv[4]) +{ + assert(ctx != NULL); + assert(ctrIv != NULL); + + + ctx->ctrIvNonceParams = (u32)orderEndianess<<23; + u32 lastu32; + if(orderEndianess & 4) + { + ctx->ctrIvNonce[0] = ctrIv[3]; + ctx->ctrIvNonce[1] = ctrIv[2]; + ctx->ctrIvNonce[2] = ctrIv[1]; + lastu32 = ctrIv[0]; + } + else + { + ctx->ctrIvNonce[0] = ctrIv[0]; + ctx->ctrIvNonce[1] = ctrIv[1]; + ctx->ctrIvNonce[2] = ctrIv[2]; + lastu32 = ctrIv[3]; + } + ctx->ctrIvNonce[3] = lastu32; +} + // TODO: Handle endianess! -static void addCounter(u32 *restrict ctr, u32 val) +void AES_addCounter(u32 ctr[4], u32 val) { u32 carry, i = 1; u64 sum; - sum = ctr[0]; - sum += (val>>4); - carry = sum>>32; - ctr[0] = sum & 0xFFFFFFFF; + sum += (val >> 4); + carry = sum >> 32; + ctr[0] = sum & 0xFFFFFFFFu; while(carry) { sum = ctr[i]; sum += carry; - carry = sum>>32; - ctr[i] = sum & 0xFFFFFFFF; + carry = sum >> 32; + ctr[i] = sum & 0xFFFFFFFFu; i++; } } -// TODO: Handle endianess! -static void subCounter(u32 *restrict ctr, u32 val) +void AES_subCounter(u32 ctr[4], u32 val) { u32 carry, i = 1; u32 sum; - - sum = ctr[0] - (val>>4); + sum = ctr[0] - (val >> 4); carry = (sum > ctr[0]); ctr[0] = sum; @@ -110,172 +274,116 @@ } } -void AES_setKey(u32 params, u8 keyslot, AesKeyType type, const u32 *restrict key, bool useTwlScrambler, bool updateKeyslot) +void AES_setCryptParams(AES_ctx *const ctx, u8 inEndianessOrder, u8 outEndianessOrder) { - REG_AESCNT = params; + assert(ctx != NULL); - if(keyslot > 3) // CTR keyslot + ctx->aesParams = (u32)inEndianessOrder<<23 | (u32)outEndianessOrder<<22; +} + +static void processBlocksCpu(const u32 *in, u32 *out, u32 blocks) +{ + REG_AES_BLKCNT_HIGH = blocks; + REG_AESCNT |= AES_ENABLE | 3<<12 | AES_FLUSH_READ_FIFO | AES_FLUSH_WRITE_FIFO; + + for(u32 i = 0; i < blocks * 4; i += 4) { - REG_AESKEYCNT = keyslot | (useTwlScrambler<<6) | 0x80; - for(u32 i = 0; i < 4; i++) REG_AESKEYFIFO[(u32)type] = key[i]; + *((vu32*)REG_AESWRFIFO) = in[0 + i]; + *((vu32*)REG_AESWRFIFO) = in[1 + i]; + *((vu32*)REG_AESWRFIFO) = in[2 + i]; + *((vu32*)REG_AESWRFIFO) = in[3 + i]; + + while(AES_READ_FIFO_COUNT == 0); + + out[0 + i] = *((vu32*)REG_AESRDFIFO); + out[1 + i] = *((vu32*)REG_AESRDFIFO); + out[2 + i] = *((vu32*)REG_AESRDFIFO); + out[3 + i] = *((vu32*)REG_AESRDFIFO); } - else // TWL keyslot - { - REG_AESKEYCNT = keyslot | 0x80; - for(u32 i = 0; i < 4; i++) REG_AESKEY0[(u32)12 * keyslot + ((u32)type * 4) + i] = key[i]; - } - - REG_AESKEYSEL = keyslot; - if(updateKeyslot) REG_AESCNT = AES_UPDATE_KEYSLOT; } -void AES_selectKeyslot(u8 keyslot, bool updateKeyslot) -{ - REG_AESKEYSEL = keyslot; - if(updateKeyslot) REG_AESCNT = AES_UPDATE_KEYSLOT; -} - -void AES_setCtrIvNonce(AES_ctx *restrict ctx, const u32 *restrict ctrIvNonce, u32 params, u32 initialCtr) -{ - u32 ctrIvNonceSize, mode; - if((mode = (params>>27 & 7)) > 1) ctrIvNonceSize = 4; - else ctrIvNonceSize = 3; - - if(params & AES_INPUT_NORMAL) - { - for(u32 i = 0; i < ctrIvNonceSize; i++) ctx->ctrIvNonce[i] = ctrIvNonce[ctrIvNonceSize - 1 - i]; - } - else for(u32 i = 0; i < ctrIvNonceSize; i++) ctx->ctrIvNonce[i] = ctrIvNonce[i]; - ctx->ctrIvNonceParams = params; - - // If cipher mode is CTR add the initial value to it. Can be 0. - if(mode == 2) addCounter(ctx->ctrIvNonce, initialCtr); -} - -u32* AES_getCtrIvNoncePtr(AES_ctx *restrict ctx) -{ - return ctx->ctrIvNonce; -} - -void AES_setCryptParams(AES_ctx *restrict ctx, u32 params) -{ - ctx->aesParams = params; -} - -static void setupNdma(const u32 *restrict in, u32 *restrict out, u32 wordCount, u32 burstSize) -{ - REG_NDMA0_SRC_ADDR = (u32)in; - REG_NDMA0_LOG_BLK_CNT = wordCount; - REG_NDMA0_CNT = (REG_NDMA0_CNT & 0xFFF0FFFFu) | NDMA_ENABLE | burstSize; - - REG_NDMA1_DST_ADDR = (u32)out; - REG_NDMA1_LOG_BLK_CNT = wordCount; - REG_NDMA1_CNT = (REG_NDMA1_CNT & 0xFFF0FFFFu) | NDMA_ENABLE | burstSize; -} - -void AES_crypt(AES_ctx *restrict ctx, const u32 *restrict in, u32 *restrict out, u32 size) +// AES_init() must be called before this works +static void processBlocksDma(const u32 *in, u32 *out, u32 blocks) { // DMA can't reach TCMs assert(((u32)in >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)in < DTCM_BASE) || ((u32)in >= DTCM_BASE + DTCM_SIZE))); assert(((u32)out >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)out < DTCM_BASE) || ((u32)out >= DTCM_BASE + DTCM_SIZE))); - // Align to 16 bytes. - size = (size + 0xFu) & ~0xFu; - // Size is 4 words except for CCM mode. - u32 mode, ctrIvNonceSize; - if((mode = (ctx->aesParams>>27 & 7)) > 1) ctrIvNonceSize = 4; - else ctrIvNonceSize = 3; - - // All writes must finish before using DMA - flushDCacheRange(in, size); - if(in != out) flushDCacheRange(out, size); - // Save the original out pointer for later invalidation - const u32 *savedOut = out; - - u32 offset = 0; - const u32 aesParams = AES_ENABLE | AES_IRQ_ENABLE | ctx->aesParams | AES_FLUSH_READ_FIFO | AES_FLUSH_WRITE_FIFO; - while(offset < size) + // Check block alignment + u32 aesFifoSize, dmaBurstSize; + if(!(blocks & 3)) { - u32 blockSize = ((size - offset > AES_MAX_BUF_SIZE) ? AES_MAX_BUF_SIZE : size - offset); + aesFifoSize = 3; + dmaBurstSize = NDMA_BURST_SIZE(16); + } + else if(!(blocks & 1)) + { + aesFifoSize = 1; + dmaBurstSize = NDMA_BURST_SIZE(8); + } + else + { + aesFifoSize = 0; + dmaBurstSize = NDMA_BURST_SIZE(4); + } - // Check block alignment - u32 aesDmaFifoSize, ndmaBurstSize; - /*if(!(blockSize & 63)) // This burst size seems to be buggy and causes mem corruption - { - aesDmaFifoSize = 3; - ndmaBurstSize = NDMA_BURST_SIZE(16); - } - else*/ if(!(blockSize & 31)) - { - aesDmaFifoSize = 1; - ndmaBurstSize = NDMA_BURST_SIZE(8); - } - else - { - aesDmaFifoSize = 0; - ndmaBurstSize = NDMA_BURST_SIZE(4); - } - setupNdma(in, out, aesDmaFifoSize * 4 + 4, ndmaBurstSize); + REG_NDMA0_SRC_ADDR = (u32)in; + REG_NDMA0_LOG_BLK_CNT = aesFifoSize * 4 + 4; + REG_NDMA0_CNT = (REG_NDMA0_CNT & 0xFFF0FFFFu) | NDMA_ENABLE | dmaBurstSize; - // Set CTR/IV/nonce - REG_AESCNT = ctx->ctrIvNonceParams; - for(u32 i = 0; i < ctrIvNonceSize; i++) REG_AESCTR[i] = ctx->ctrIvNonce[i]; - if(mode == 4) // AES_MODE_CBC_DECRYPT - { - // Save last 16 bytes of current input block as next IV for CBC decrypt - if(ctx->ctrIvNonceParams & AES_INPUT_NORMAL) - { - for(u32 i = 0; i < 4; i++) ctx->ctrIvNonce[i] = in[(blockSize>>2) - 4 + 3 - i]; - } - else for(u32 i = 0; i < 4; i++) ctx->ctrIvNonce[i] = in[(blockSize>>2) - 4 + i]; - } + REG_NDMA1_DST_ADDR = (u32)out; + REG_NDMA1_LOG_BLK_CNT = aesFifoSize * 4 + 4; + REG_NDMA1_CNT = (REG_NDMA1_CNT & 0xFFF0FFFFu) | NDMA_ENABLE | dmaBurstSize; - // Setup the AES engine and wait for it to finish - REG_AESBLKCNT = (blockSize>>4)<<16; - REG_AESCNT = aesParams | (aesDmaFifoSize<<14) | ((3 - aesDmaFifoSize)<<12); - while(REG_AESCNT & AES_ENABLE) - { - waitForIrq(); - } - - - if(mode == 2) // AES_MODE_CTR - { - // Increase counter. - addCounter(ctx->ctrIvNonce, blockSize); - } - else if(mode == 5) // AES_MODE_CBC_ENCRYPT - { - // Save last 16 bytes of current output block as next IV for CBC encrypt - if(ctx->ctrIvNonceParams & AES_INPUT_NORMAL) - { - for(u32 i = 0; i < 4; i++) ctx->ctrIvNonce[i] = out[(blockSize>>2) - 4 + 3 - i]; - } - else for(u32 i = 0; i < 4; i++) ctx->ctrIvNonce[i] = out[(blockSize>>2) - 4 + i]; - } - - in += blockSize>>2; - out += blockSize>>2; - offset += blockSize; + REG_AES_BLKCNT_HIGH = blocks; + REG_AESCNT |= AES_ENABLE | AES_IRQ_ENABLE | aesFifoSize<<14 | (3 - aesFifoSize)<<12 | + AES_FLUSH_READ_FIFO | AES_FLUSH_WRITE_FIFO; + while(REG_AESCNT & AES_ENABLE) + { + waitForIrq(); } // Disable the NDMA channels REG_NDMA0_CNT = (REG_NDMA0_CNT<<1)>>1; REG_NDMA1_CNT = (REG_NDMA1_CNT<<1)>>1; - - // Throw possibly cached lines out of the window - invalidateDCacheRange(savedOut, size); } -void AES_addCounter(AES_ctx *restrict ctx, u32 val) +void AES_ctr(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool dma) { - addCounter(ctx->ctrIvNonce, val); -} + assert(ctx != NULL); + assert(in != NULL); + assert(out != NULL); -void AES_subCounter(AES_ctx *restrict ctx, u32 val) -{ - subCounter(ctx->ctrIvNonce, val); + const u32 ctrParams = ctx->ctrIvNonceParams; + u32 *const ctr = ctx->ctrIvNonce; + const u32 aesParams = AES_MODE_CTR | ctx->aesParams; + + + if(dma) + { + flushDCacheRange(in, blocks<<4); + invalidateDCacheRange(out, blocks<<4); + } + + while(blocks) + { + REG_AESCNT = ctrParams; + REG_AESCTR[0] = ctr[0]; + REG_AESCTR[1] = ctr[1]; + REG_AESCTR[2] = ctr[2]; + REG_AESCTR[3] = ctr[3]; + + REG_AESCNT = aesParams; + u32 blockNum = ((blocks > AES_MAX_BLOCKS) ? AES_MAX_BLOCKS : blocks); + if(dma) processBlocksDma(in, out, blockNum); + else processBlocksCpu(in, out, blockNum); + + AES_addCounter(ctr, blockNum<<4); + in += blockNum<<2; + out += blockNum<<2; + blocks -= blockNum; + } } @@ -291,15 +399,13 @@ #define REG_SHA_INFIFO ( (SHA_REGS_BASE + 0x80)) -void SHA_start(u32 params) +void SHA_start(u8 params) { - REG_SHA_CNT = SHA_ENABLE | params; + REG_SHA_CNT = SHA_ENABLE | (u32)params; } -void SHA_update(const u32 *restrict data, u32 size) +void SHA_update(const u32 *data, u32 size) { - //const u32 *restrict dataPtr = data; - while(size >= 0x40) { for(u32 i = 0; i < 4; i++) @@ -317,32 +423,31 @@ if(size) memcpy((void*)REG_SHA_INFIFO, data, size); } -void SHA_finish(u32 *restrict hash, u32 endianess) +void SHA_finish(u32 *const hash, u8 endianess) { - REG_SHA_CNT = SHA_PAD_INPUT | endianess | (REG_SHA_CNT & (SHA_MODE_1 | SHA_MODE_224 | SHA_MODE_256)); + REG_SHA_CNT = (REG_SHA_CNT & (SHA_MODE_1 | SHA_MODE_224 | SHA_MODE_256)) | (u32)endianess | SHA_PAD_INPUT; while(REG_SHA_CNT & SHA_ENABLE); u32 hashSize; - switch(REG_SHA_CNT & (SHA_MODE_256 | SHA_MODE_224 | SHA_MODE_1)) + switch(REG_SHA_CNT & (SHA_MODE_1 | SHA_MODE_224 | SHA_MODE_256)) { case SHA_MODE_256: - hashSize = 8;//32; + hashSize = 8; // 32; break; case SHA_MODE_224: - hashSize = 7;//28; + hashSize = 7; // 28; break; case SHA_MODE_1: - hashSize = 5;//20; + hashSize = 5; // 20; break; default: return; } - //memcpy(hash, REG_SHA_HASH, hashSize); for(u32 i = 0; i < hashSize; i++) hash[i] = REG_SHA_HASH[i]; } -void sha(const u32 *restrict data, u32 size, u32 *restrict hash, u32 params, u32 hashEndianess) +void sha(const u32 *data, u32 size, u32 *const hash, u8 params, u8 hashEndianess) { SHA_start(params); SHA_update(data, size); diff --git a/source/arm9/dev.c b/source/arm9/dev.c index f34dab1..3d29448 100644 --- a/source/arm9/dev.c +++ b/source/arm9/dev.c @@ -234,7 +234,8 @@ pad[2] ^= ((u32*)BOOT9_BASE)[2]; pad[3] ^= ((u32*)BOOT9_BASE)[3]; - AES_setKey(AES_INPUT_BIG | AES_INPUT_NORMAL, 0x05, AES_KEY_TYPE_Y, pad, false, true); + AES_setKeyY(0x05, AES_INPUT_BIG | AES_INPUT_NORMAL, false, pad); + AES_selectKeyslot(0x05); } @@ -310,11 +311,8 @@ } // Hash NAND CID to create the CTRs for crypto - u32 hash[8]; - sha((u32*)0x01FFCD84, 16, hash, SHA_INPUT_BIG | SHA_MODE_1, SHA_OUTPUT_BIG); - memcpy(dev_dnand.twlCounter, hash, 16); - sha((u32*)0x01FFCD84, 16, hash, SHA_INPUT_BIG | SHA_MODE_256, SHA_OUTPUT_LITTLE); - memcpy(dev_dnand.ctrCounter, hash, 16); + sha((u32*)0x01FFCD84, 16, dev_dnand.twlCounter, SHA_INPUT_BIG | SHA_MODE_1, SHA_OUTPUT_BIG); + sha((u32*)0x01FFCD84, 16, dev_dnand.ctrCounter, SHA_INPUT_BIG | SHA_MODE_256, SHA_OUTPUT_LITTLE); // TWL keyslot 0x03 keyX u32 twlKeyX[4]; @@ -322,19 +320,19 @@ twlKeyX[1] = 0x544E494E; // "NINT" twlKeyX[2] = 0x4F444E45; // "ENDO" twlKeyX[3] = *((u32*)0x01FFB80C) ^ 0x08C267B7; - AES_setKey(AES_INPUT_LITTLE | AES_INPUT_REVERSED, 3, AES_KEY_TYPE_X, twlKeyX, false, false); + AES_setKeyX(0x03, AES_INPUT_LITTLE | AES_INPUT_REVERSED, false, twlKeyX); // TWL keyslot 0x03 keyY u32 twlKeyY[4]; for(int i = 0; i < 3; i++) twlKeyY[i] = ((u32*)0x01FFD3C8)[i]; twlKeyY[3] = 0xE1A00005; - AES_setKey(AES_INPUT_LITTLE | AES_INPUT_REVERSED, 3, AES_KEY_TYPE_Y, twlKeyY, false, true); + AES_setKeyY(0x03, AES_INPUT_LITTLE | AES_INPUT_REVERSED, false, twlKeyY); // Crypt settings - AES_setCryptParams(&dev_dnand.twlAesCtx, AES_OUTPUT_LITTLE | AES_INPUT_LITTLE | AES_OUTPUT_REVERSED | - AES_INPUT_REVERSED | AES_MODE_CTR); - AES_setCryptParams(&dev_dnand.ctrAesCtx, AES_OUTPUT_BIG | AES_INPUT_BIG | AES_OUTPUT_NORMAL | - AES_INPUT_NORMAL | AES_MODE_CTR); + AES_setCryptParams(&dev_dnand.twlAesCtx, AES_INPUT_LITTLE | AES_INPUT_REVERSED, + AES_OUTPUT_LITTLE | AES_OUTPUT_REVERSED); + AES_setCryptParams(&dev_dnand.ctrAesCtx, AES_INPUT_BIG | AES_INPUT_NORMAL, + AES_OUTPUT_BIG | AES_OUTPUT_NORMAL); dev_dnand.dev.initialized = true; } @@ -359,20 +357,22 @@ return false; // unknown partition type AES_ctx *ctx; - AES_selectKeyslot(keyslot, true); + AES_selectKeyslot(keyslot); if(keyslot == 0x03) { ctx = &dev_dnand.twlAesCtx; - AES_setCtrIvNonce(ctx, dev_dnand.twlCounter, AES_INPUT_LITTLE | AES_INPUT_REVERSED | AES_MODE_CTR, sector<<9); + AES_setCtrIv(ctx, AES_INPUT_LITTLE | AES_INPUT_REVERSED, dev_dnand.twlCounter); + AES_addCounter(ctx->ctrIvNonce, sector<<9); } else { ctx = &dev_dnand.ctrAesCtx; - AES_setCtrIvNonce(ctx, dev_dnand.ctrCounter, AES_INPUT_LITTLE | AES_INPUT_NORMAL | AES_MODE_CTR, sector<<9); + AES_setCtrIv(ctx, AES_INPUT_LITTLE | AES_INPUT_NORMAL, dev_dnand.ctrCounter); + AES_addCounter(ctx->ctrIvNonce, sector<<9); } if(sdmmc_nand_readsectors(sector, count, buf)) return false; - AES_crypt(ctx, buf, buf, count<<9); + AES_ctr(ctx, buf, buf, count<<5, true); return true; } @@ -392,33 +392,42 @@ if(keyslot == 0xFF) return false; // unknown partition type - - AES_ctx *ctx; - ctx = &dev_dnand.ctrAesCtx; if(!count) return false; - const size_t crypto_buf_size = min(count<<9, 0x1000); - void *crypto_buf = malloc(crypto_buf_size); + const size_t crypto_sec_size = min(count, 0x1000>>9); + void *crypto_buf = malloc(crypto_sec_size<<9); if(!crypto_buf) return false; - AES_selectKeyslot(keyslot, true); - AES_setCtrIvNonce(ctx, dev_dnand.ctrCounter, AES_INPUT_LITTLE | AES_INPUT_NORMAL | AES_MODE_CTR, sector<<9); + AES_selectKeyslot(keyslot); + AES_ctx *ctx; + if(keyslot == 0x03) + { + ctx = &dev_dnand.twlAesCtx; + AES_setCtrIv(ctx, AES_INPUT_LITTLE | AES_INPUT_REVERSED, dev_dnand.twlCounter); + AES_addCounter(ctx->ctrIvNonce, sector<<9); + } + else + { + ctx = &dev_dnand.ctrAesCtx; + AES_setCtrIv(ctx, AES_INPUT_LITTLE | AES_INPUT_NORMAL, dev_dnand.ctrCounter); + AES_addCounter(ctx->ctrIvNonce, sector<<9); + } do { - size_t crypt_size = min(count<<9, crypto_buf_size); - - AES_crypt(ctx, buf, crypto_buf, crypt_size); - if(sdmmc_nand_writesectors(sector, crypt_size >> 9, crypto_buf)) + size_t crypt_size = min(count, crypto_sec_size); + + AES_ctr(ctx, buf, crypto_buf, crypt_size<<5, true); + if(sdmmc_nand_writesectors(sector, crypt_size, crypto_buf)) { free(crypto_buf); return false; } - sector += crypt_size >> 9; - count -= crypt_size >> 9; + sector += crypt_size; + count -= crypt_size; buf += crypt_size; } while(count);