diff --git a/Makefile.main b/Makefile.main index a3a5b0b2..54e816a0 100644 --- a/Makefile.main +++ b/Makefile.main @@ -28,6 +28,7 @@ SOURCES := source \ source/gc \ source/gecko \ source/gui \ + source/hw \ source/homebrew \ source/libwbfs \ source/list \ diff --git a/source/hw/aes.c b/source/hw/aes.c new file mode 100644 index 00000000..3850241f --- /dev/null +++ b/source/hw/aes.c @@ -0,0 +1,90 @@ +/**************************************************************************** + * Copyright (C) 2013 FIX94 + * + * 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include "loader/utils.h" +#include "memory/memory.h" +#include "aes.h" + +#define AES_CMD_FLAG_EXEC (1<<31) +#define AES_CMD_FLAG_ENA (1<<28) +#define AES_CMD_FLAG_DEC (1<<27) +#define AES_CMD_FLAG_IV (1<<12) + +u8 aes_mode = 0; + +void AES_EnableDecrypt(const u8 *key, const u8 *iv) +{ + const u32 *aes_iv = (const u32*)iv; + const u32 *aes_key = (const u32*)key; + /* Reset Engine */ + write32(HW_AES_CMD, 0x00000000); + while ((read32(HW_AES_CMD) & AES_CMD_FLAG_EXEC) != 0); + /* write in IV and Key */ + u8 i; + for(i = 0; i < 4; ++i) + { + write32(HW_AES_IV, *(aes_iv+i)); + write32(HW_AES_KEY, *(aes_key+i)); + } + /* set mode back to 0 */ + aes_mode = 0; +} + +#define AES_LIMIT 0x1000 +static u8 AES_BUF[AES_LIMIT*16] ATTRIBUTE_ALIGN(16); /* 64KB */ +void AES_Decrypt(u8 *inbuf, u8 *outbuf, u16 num_blocks) +{ + /* split cause of limit */ + u32 buf_pos = 0; + u16 blocks_done = 0; + u32 buf_done = 0; + u16 blocks_full = num_blocks; + while(blocks_done < blocks_full) + { + /* Calculate Position */ + blocks_done = blocks_full; + if(blocks_done > AES_LIMIT) + blocks_done = AES_LIMIT; + buf_done = blocks_done * 16; + /* Copy into our aligned buffer */ + memcpy(AES_BUF, (inbuf + buf_pos), buf_done); + /* Flush and Invalidate */ + DCFlushRange(AES_BUF, buf_done); + ICInvalidateRange(AES_BUF, buf_done); + /* set location */ + write32(HW_AES_SRC, (u32)MEM_VIRTUAL_TO_PHYSICAL(AES_BUF)); + write32(HW_AES_DEST, (u32)MEM_VIRTUAL_TO_PHYSICAL(AES_BUF)); + /* enable engine, set size, set iv flag and enable decryption */ + write32(HW_AES_CMD, AES_CMD_FLAG_ENA | AES_CMD_FLAG_DEC | AES_CMD_FLAG_EXEC | + ((aes_mode == 0) ? 0 : AES_CMD_FLAG_IV) | (blocks_done - 1)); + while (read32(HW_AES_CMD) & AES_CMD_FLAG_EXEC); + /* set down num blocks */ + blocks_full -= blocks_done; + /* increase aes mode to keep iv */ + if(aes_mode == 0) aes_mode++; + /* flush and write outbuf */ + DCFlushRange(AES_BUF, buf_done); + memcpy((outbuf + buf_pos), AES_BUF, buf_done); + /* increase block pos */ + buf_pos += buf_done; + } +} diff --git a/source/hw/aes.h b/source/hw/aes.h new file mode 100644 index 00000000..3ddbe878 --- /dev/null +++ b/source/hw/aes.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * Copyright (C) 2013 FIX94 + * + * 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#ifndef __AES_H__ +#define __AES_H__ + +void AES_EnableDecrypt(const u8 *key, const u8 *iv); +void AES_Decrypt(u8 *inbuf, u8 *outbuf, u16 num_blocks); + +#endif diff --git a/source/hw/sha1.c b/source/hw/sha1.c new file mode 100644 index 00000000..b7df9e25 --- /dev/null +++ b/source/hw/sha1.c @@ -0,0 +1,174 @@ +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +#define SHA1HANDSOFF + +#include +#include +#include +#include +#include +#include +#include "loader/utils.h" +#include "memory/memory.h" +#include "sha1.h" + +//should be divisibly by four +#define BLOCKSIZE 32 + +#define SHA_CMD_FLAG_EXEC (1<<31) +#define SHA_CMD_FLAG_IRQ (1<<30) +#define SHA_CMD_FLAG_ERR (1<<29) +#define SHA_CMD_AREA_BLOCK ((1<<10) - 1) + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +static void SHA1Transforml(unsigned long state[5], unsigned char buffer[64], u32 len) +{ + /* Copy context->state[] to working vars */ + write32(HW_SHA1_H0, state[0]); + write32(HW_SHA1_H1, state[1]); + write32(HW_SHA1_H2, state[2]); + write32(HW_SHA1_H3, state[3]); + write32(HW_SHA1_H4, state[4]); + + static u32 num_blocks; + num_blocks = len; + + // assign block to local copy which is 64-byte aligned + static u8 block[64*BLOCKSIZE] ATTRIBUTE_ALIGN(64); + // for further improvments! + // u8 *block = memalign(64, 64*num_blocks); + memcpy(block, buffer, 64*num_blocks); + + // royal flush :) + DCFlushRange(block, 64*num_blocks); + + // tell sha1 controller the block source address + write32(HW_SHA1_SRC, MEM_VIRTUAL_TO_PHYSICAL(block)); + + // tell sha1 controller number of blocks + if (num_blocks != 0) + num_blocks--; + write32(HW_SHA1_CMD, (read32(HW_SHA1_CMD) & ~(SHA_CMD_AREA_BLOCK)) | num_blocks); + + // fire up hashing and wait till its finished + write32(HW_SHA1_CMD, read32(HW_SHA1_CMD) | SHA_CMD_FLAG_EXEC); + while (read32(HW_SHA1_CMD) & SHA_CMD_FLAG_EXEC); + + // free the aligned data + // free(block); + + /* Add the working vars back into context.state[] */ + state[0] = read32(HW_SHA1_H0); + state[1] = read32(HW_SHA1_H1); + state[2] = read32(HW_SHA1_H2); + state[3] = read32(HW_SHA1_H3); + state[4] = read32(HW_SHA1_H4); +} + +static void SHA1Transform(unsigned long state[5], unsigned char buffer[64]) +{ + SHA1Transforml(state, buffer, 1); +} + +/* SHA1Init - Initialize new context */ + +void SHA1Init(SHA1_CTX* context) +{ + /* reset sha-1 engine */ + write32(HW_SHA1_CMD, read32(HW_SHA1_CMD) & ~(SHA_CMD_FLAG_EXEC)); + while ((read32(HW_SHA1_CMD) & SHA_CMD_FLAG_EXEC) != 0); + + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + +/* Run your data through this. */ + +void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len) +{ + unsigned int i, j; + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) + context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + // try bigger blocks at once + for ( ; i + 63 + ((BLOCKSIZE-1)*64) < len; i += (64 + (BLOCKSIZE-1)*64)) { + SHA1Transforml(context->state, &data[i], BLOCKSIZE); + } + for ( ; i + 63 + (((BLOCKSIZE/2)-1)*64) < len; i += (64 + ((BLOCKSIZE/2)-1)*64)) { + SHA1Transforml(context->state, &data[i], BLOCKSIZE/2); + } + for ( ; i + 63 + (((BLOCKSIZE/4)-1)*64) < len; i += (64 + ((BLOCKSIZE/4)-1)*64)) { + SHA1Transforml(context->state, &data[i], BLOCKSIZE/4); + } + for ( ; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + +/* Add padding and return the message digest. */ + +void SHA1Final(unsigned char digest[20], SHA1_CTX* context) +{ + unsigned long i, j; + unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + + SHA1Update(context, (unsigned char *)"\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1Update(context, (unsigned char *)"\0", 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + /* Wipe variables */ + i = j = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(&finalcount, 0, 8); +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ + SHA1Transform(context->state, context->buffer); +#endif +} + +void SHA1(unsigned char *ptr, unsigned int size, unsigned char *outbuf) +{ + SHA1_CTX ctx; + + SHA1Init(&ctx); + SHA1Update(&ctx, ptr, size); + SHA1Final(outbuf, &ctx); +} diff --git a/source/loader/sha1.h b/source/hw/sha1.h similarity index 64% rename from source/loader/sha1.h rename to source/hw/sha1.h index 253d4695..9b27f178 100644 --- a/source/loader/sha1.h +++ b/source/hw/sha1.h @@ -1,12 +1,15 @@ -typedef struct { - unsigned long state[5]; - unsigned long count[2]; - unsigned char buffer[64]; -} SHA1_CTX; - -void SHA1Transform(unsigned long state[5], unsigned char buffer[64]); -void SHA1Init(SHA1_CTX* context); -void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len); -void SHA1Final(unsigned char digest[20], SHA1_CTX* context); - -void SHA1(unsigned char *ptr, unsigned int size, unsigned char *outbuf); + +#ifndef __SHA1_H__ +#define __SHA1_H__ + +typedef struct { + unsigned long state[5]; + unsigned long count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +void SHA1Init(SHA1_CTX* context); +void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len); +void SHA1Final(unsigned char digest[20], SHA1_CTX* context); + +#endif diff --git a/source/libwbfs/rijndael.c b/source/libwbfs/rijndael.c deleted file mode 100644 index 1b1edcc4..00000000 --- a/source/libwbfs/rijndael.c +++ /dev/null @@ -1,445 +0,0 @@ -/* Rijndael Block Cipher - rijndael.c - - Written by Mike Scott 21st April 1999 - mike@compapp.dcu.ie - - Permission for free direct or derivative use is granted subject - to compliance with any conditions that the originators of the - algorithm place on its exploitation. - - */ - -#include -#include -#include "gecko/gecko.hpp" -#include "loader/utils.h" -#define u8 unsigned char /* 8 bits */ -#define u32 unsigned long /* 32 bits */ -#define u64 unsigned long long - -/* rotates x one bit to the left */ - -#define ROTL(x) (((x)>>7)|((x)<<1)) - -/* Rotates 32-bit word left by 1, 2 or 3 byte */ - -#define ROTL8(x) (((x)<<8)|((x)>>24)) -#define ROTL16(x) (((x)<<16)|((x)>>16)) -#define ROTL24(x) (((x)<<24)|((x)>>8)) - -/* Fixed Data */ - -static u8 InCo[4] = { 0xB, 0xD, 0x9, 0xE }; /* Inverse Coefficients */ - -static u8 fbsub[256]; -static u8 rbsub[256]; -static u8 ptab[256], ltab[256]; -static u32 ftable[256]; -static u32 rtable[256]; -static u32 rco[30]; - -/* Parameter-dependent data */ - -int Nk, Nb, Nr; -u8 fi[24], ri[24]; -u32 fkey[120]; -u32 rkey[120]; - -static u32 pack(u8 *b) -{ /* pack bytes into a 32-bit Word */ - return ((u32 ) b[3] << 24) | ((u32 ) b[2] << 16) | ((u32 ) b[1] << 8) | (u32 ) b[0]; -} - -static void unpack(u32 a, u8 *b) -{ /* unpack bytes from a word */ - b[0] = (u8 ) a; - b[1] = (u8 ) (a >> 8); - b[2] = (u8 ) (a >> 16); - b[3] = (u8 ) (a >> 24); -} - -static u8 xtime(u8 a) -{ - u8 b; - if (a & 0x80) - b = 0x1B; - else b = 0; - a <<= 1; - a ^= b; - return a; -} - -static u8 bmul(u8 x, u8 y) -{ /* x.y= AntiLog(Log(x) + Log(y)) */ - if (x && y) - return ptab[(ltab[x] + ltab[y]) % 255]; - else return 0; -} - -static u32 SubByte(u32 a) -{ - u8 b[4]; - unpack(a, b); - b[0] = fbsub[b[0]]; - b[1] = fbsub[b[1]]; - b[2] = fbsub[b[2]]; - b[3] = fbsub[b[3]]; - return pack(b); -} - -static u8 product(u32 x, u32 y) -{ /* dot product of two 4-byte arrays */ - u8 xb[4], yb[4]; - unpack(x, xb); - unpack(y, yb); - return bmul(xb[0], yb[0]) ^ bmul(xb[1], yb[1]) ^ bmul(xb[2], yb[2]) ^ bmul(xb[3], yb[3]); -} - -static u32 InvMixCol(u32 x) -{ /* matrix Multiplication */ - u32 y, m; - u8 b[4]; - - m = pack(InCo); - b[3] = product(m, x); - m = ROTL24( m ); - b[2] = product(m, x); - m = ROTL24( m ); - b[1] = product(m, x); - m = ROTL24( m ); - b[0] = product(m, x); - y = pack(b); - return y; -} - -u8 ByteSub(u8 x) -{ - u8 y = ptab[255 - ltab[x]]; /* multiplicative inverse */ - x = y; - x = ROTL( x ); - y ^= x; - x = ROTL( x ); - y ^= x; - x = ROTL( x ); - y ^= x; - x = ROTL( x ); - y ^= x; - y ^= 0x63; - return y; -} - -void gentables(void) -{ /* generate tables */ - int i; - u8 y, b[4]; - - /* use 3 as primitive root to generate power and log tables */ - - ltab[0] = 0; - ptab[0] = 1; - ltab[1] = 0; - ptab[1] = 3; - ltab[3] = 1; - for (i = 2; i < 256; i++) - { - ptab[i] = ptab[i - 1] ^ xtime(ptab[i - 1]); - ltab[ptab[i]] = i; - } - - /* affine transformation:- each bit is xored with itself shifted one bit */ - - fbsub[0] = 0x63; - rbsub[0x63] = 0; - for (i = 1; i < 256; i++) - { - y = ByteSub((u8 ) i); - fbsub[i] = y; - rbsub[y] = i; - } - - for (i = 0, y = 1; i < 30; i++) - { - rco[i] = y; - y = xtime(y); - } - - /* calculate forward and reverse tables */ - for (i = 0; i < 256; i++) - { - y = fbsub[i]; - b[3] = y ^ xtime(y); - b[2] = y; - b[1] = y; - b[0] = xtime(y); - ftable[i] = pack(b); - - y = rbsub[i]; - b[3] = bmul(InCo[0], y); - b[2] = bmul(InCo[1], y); - b[1] = bmul(InCo[2], y); - b[0] = bmul(InCo[3], y); - rtable[i] = pack(b); - } -} - -void gkey(int nb, int nk, char *key) -{ /* blocksize=32*nb bits. Key=32*nk bits */ - /* currently nb,bk = 4, 6 or 8 */ - /* key comes as 4*Nk bytes */ - /* Key Scheduler. Create expanded encryption key */ - int i, j, k, m, N; - int C1, C2, C3; - u32 CipherKey[8]; - - Nb = nb; - Nk = nk; - - /* Nr is number of rounds */ - if (Nb >= Nk) - Nr = 6 + Nb; - else Nr = 6 + Nk; - - C1 = 1; - if (Nb < 8) - { - C2 = 2; - C3 = 3; - } - else - { - C2 = 3; - C3 = 4; - } - - /* pre-calculate forward and reverse increments */ - for (m = j = 0; j < nb; j++, m += 3) - { - fi[m] = (j + C1) % nb; - fi[m + 1] = (j + C2) % nb; - fi[m + 2] = (j + C3) % nb; - ri[m] = (nb + j - C1) % nb; - ri[m + 1] = (nb + j - C2) % nb; - ri[m + 2] = (nb + j - C3) % nb; - } - - N = Nb * (Nr + 1); - - for (i = j = 0; i < Nk; i++, j += 4) - { - CipherKey[i] = pack((u8 *) &key[j]); - } - for (i = 0; i < Nk; i++) - fkey[i] = CipherKey[i]; - for (j = Nk, k = 0; j < N; j += Nk, k++) - { - fkey[j] = fkey[j - Nk] ^ SubByte(ROTL24( fkey[j-1] )) ^ rco[k]; - if (Nk <= 6) - { - for (i = 1; i < Nk && (i + j) < N; i++) - fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; - } - else - { - for (i = 1; i < 4 && (i + j) < N; i++) - fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; - if ((j + 4) < N) fkey[j + 4] = fkey[j + 4 - Nk] ^ SubByte(fkey[j + 3]); - for (i = 5; i < Nk && (i + j) < N; i++) - fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; - } - - } - - /* now for the expanded decrypt key in reverse order */ - - for (j = 0; j < Nb; j++) - rkey[j + N - Nb] = fkey[j]; - for (i = Nb; i < N - Nb; i += Nb) - { - k = N - Nb - i; - for (j = 0; j < Nb; j++) - rkey[k + j] = InvMixCol(fkey[i + j]); - } - for (j = N - Nb; j < N; j++) - rkey[j - N + Nb] = fkey[j]; -} - -/* There is an obvious time/space trade-off possible here. * - * Instead of just one ftable[], I could have 4, the other * - * 3 pre-rotated to save the ROTL8, ROTL16 and ROTL24 overhead */ - -void encrypt(char *buff) -{ - int i, j, k, m; - u32 a[8], b[8], *x, *y, *t; - - for (i = j = 0; i < Nb; i++, j += 4) - { - a[i] = pack((u8 *) &buff[j]); - a[i] ^= fkey[i]; - } - k = Nb; - x = a; - y = b; - - /* State alternates between a and b */ - for (i = 1; i < Nr; i++) - { /* Nr is number of rounds. May be odd. */ - - /* if Nb is fixed - unroll this next - loop and hard-code in the values of fi[] */ - - for (m = j = 0; j < Nb; j++, m += 3) - { /* deal with each 32-bit element of the State */ - /* This is the time-critical bit */ - y[j] = fkey[k++] ^ ftable[(u8 ) x[j]] ^ ROTL8( ftable[( u8 )( x[fi[m]] >> 8 )] ) - ^ ROTL16( ftable[( u8 )( x[fi[m+1]] >> 16 )] ) ^ ROTL24( ftable[x[fi[m+2]] >> 24] ); - } - t = x; - x = y; - y = t; /* swap pointers */ - } - - /* Last Round - unroll if possible */ - for (m = j = 0; j < Nb; j++, m += 3) - { - y[j] = fkey[k++] ^ (u32 ) fbsub[(u8 ) x[j]] ^ ROTL8( ( u32 )fbsub[( u8 )( x[fi[m]] >> 8 )] ) - ^ ROTL16( ( u32 )fbsub[( u8 )( x[fi[m+1]] >> 16 )] ) ^ ROTL24( ( u32 )fbsub[x[fi[m+2]] >> 24] ); - } - for (i = j = 0; i < Nb; i++, j += 4) - { - unpack(y[i], (u8 *) &buff[j]); - x[i] = y[i] = 0; /* clean up stack */ - } - return; -} - -void decrypt(char *buff) -{ - int i, j, k, m; - u32 a[8], b[8], *x, *y, *t; - - for (i = j = 0; i < Nb; i++, j += 4) - { - a[i] = pack((u8 *) &buff[j]); - a[i] ^= rkey[i]; - } - k = Nb; - x = a; - y = b; - - /* State alternates between a and b */ - for (i = 1; i < Nr; i++) - { /* Nr is number of rounds. May be odd. */ - - /* if Nb is fixed - unroll this next - loop and hard-code in the values of ri[] */ - - for (m = j = 0; j < Nb; j++, m += 3) - { /* This is the time-critical bit */ - y[j] = rkey[k++] ^ rtable[(u8 ) x[j]] ^ ROTL8( rtable[( u8 )( x[ri[m]] >> 8 )] ) - ^ ROTL16( rtable[( u8 )( x[ri[m+1]] >> 16 )] ) ^ ROTL24( rtable[x[ri[m+2]] >> 24] ); - } - t = x; - x = y; - y = t; /* swap pointers */ - } - - /* Last Round - unroll if possible */ - for (m = j = 0; j < Nb; j++, m += 3) - { - y[j] = rkey[k++] ^ (u32 ) rbsub[(u8 ) x[j]] ^ ROTL8( ( u32 )rbsub[( u8 )( x[ri[m]] >> 8 )] ) - ^ ROTL16( ( u32 )rbsub[( u8 )( x[ri[m+1]] >> 16 )] ) ^ ROTL24( ( u32 )rbsub[x[ri[m+2]] >> 24] ); - } - for (i = j = 0; i < Nb; i++, j += 4) - { - unpack(y[i], (u8 *) &buff[j]); - x[i] = y[i] = 0; /* clean up stack */ - } - return; -} - -void aes_set_key(u8 *key) -{ - gentables(); - gkey(4, 4, (char*) key); -} - -// CBC mode decryption -void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, u64 len) -{ - u8 block[16]; - u32 blockno = 0, i; - - //printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len); - - for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) - { - u32 fraction; - if (blockno == (len / sizeof(block))) // last block - { - fraction = len % sizeof(block); - if (fraction == 0) break; - memset(block, 0, sizeof(block)); - } - else fraction = 16; - - // debug_printf("block %d: fraction = %d\n", blockno, fraction); - memcpy(block, inbuf + blockno * sizeof(block), fraction); - decrypt((char*) block); - u8 *ctext_ptr; - if (blockno == 0) - ctext_ptr = iv; - else ctext_ptr = inbuf + (blockno - 1) * sizeof(block); - - for (i = 0; i < fraction; i++) - outbuf[blockno * sizeof(block) + i] = ctext_ptr[i] ^ block[i]; - // debug_printf("Block %d output: ", blockno); - // hexdump(outbuf + blockno*sizeof(block), 16); - } -} - -// CBC mode encryption -void aes_encrypt(u8 *iv, u8 *inbuf, u8 *outbuf, u64 len) -{ - u8 block[16]; - u32 blockno = 0, i; - - // debug_printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len); - - for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) - { - u32 fraction; - if (blockno == (len / sizeof(block))) // last block - { - fraction = len % sizeof(block); - if (fraction == 0) break; - memset(block, 0, sizeof(block)); - } - else fraction = 16; - - // debug_printf("block %d: fraction = %d\n", blockno, fraction); - memcpy(block, inbuf + blockno * sizeof(block), fraction); - - for (i = 0; i < fraction; i++) - block[i] = inbuf[blockno * sizeof(block) + i] ^ iv[i]; - - encrypt((char*) block); - memcpy(iv, block, sizeof(block)); - memcpy(outbuf + blockno * sizeof(block), block, sizeof(block)); - // debug_printf("Block %d output: ", blockno); - // hexdump(outbuf + blockno*sizeof(block), 16); - } -} - - -// CBC mode decryption -#define WAD_BUF 0x10000 - -void aes_decrypt_partial(u8 *inbuf, u8 *outbuf, u8 block[16], u8 *ctext_ptr, u32 tmp_blockno) -{ - memcpy(block, inbuf + tmp_blockno * 16, 16); - decrypt((char*)block); - u32 i; - for(i = 0; i < 16; i++) - outbuf[tmp_blockno * 16 + i] = ctext_ptr[i] ^ block[i]; -} diff --git a/source/libwbfs/wiidisc.c b/source/libwbfs/wiidisc.c index 74d577ed..7626d00d 100644 --- a/source/libwbfs/wiidisc.c +++ b/source/libwbfs/wiidisc.c @@ -4,9 +4,7 @@ // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt #include "wiidisc.h" - -void aes_set_key(u8 *key); -void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, u64 len); +#include "hw/aes.h" int wd_last_error = 0; @@ -15,19 +13,19 @@ int wd_get_last_error(void) return wd_last_error; } +static const u8 common_key[16] = { + 0xeb, 0xe4, 0x2a, 0x22, 0x5e, 0x85, 0x93, 0xe4, + 0x48, 0xd9, 0xc5, 0x45, 0x73, 0x81, 0xaa, 0xf7 +}; + +//korean common key +static const u8 korean_key[16] = { + 0x63, 0xb8, 0x2b, 0xb4, 0xf4, 0x61, 0x4e, 0x2e, + 0x13, 0xf2, 0xfe, 0xfb, 0xba, 0x4c, 0x9b, 0x7e +}; + void decrypt_title_key(u8 *tik, u8 *title_key) { - u8 common_key[16] = { - 0xeb, 0xe4, 0x2a, 0x22, 0x5e, 0x85, 0x93, 0xe4, - 0x48, 0xd9, 0xc5, 0x45, 0x73, 0x81, 0xaa, 0xf7 - }; - - //korean common key - u8 korean_key[16]={ - 0x63, 0xb8, 0x2b, 0xb4, 0xf4, 0x61, 0x4e, 0x2e, - 0x13, 0xf2, 0xfe, 0xfb, 0xba, 0x4c, 0x9b, 0x7e - }; - u8 iv[16]; wbfs_memset(iv, 0, sizeof iv); @@ -38,13 +36,13 @@ void decrypt_title_key(u8 *tik, u8 *title_key) u8 korean_flag = tik[0x01f1]; if(korean_flag == 1) - aes_set_key(korean_key); + AES_EnableDecrypt(korean_key, iv); else - aes_set_key(common_key); + AES_EnableDecrypt(common_key, iv); - //_aes_cbc_dec(common_key, iv, tik + 0x01bf, 16, title_key); - aes_decrypt(iv, tik + 0x01bf, title_key, 16); + AES_Decrypt(tik + 0x01bf, title_key, 1); } + static u32 _be32(const u8 *p) { return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; @@ -90,8 +88,8 @@ static void partition_read_block(wiidisc_t *d, u32 blockno, u8 *block) // decrypt data memcpy(iv, raw + 0x3d0, 16); - aes_set_key(d->disc_key); - aes_decrypt(iv, raw + 0x400, block, 0x7c00); + AES_EnableDecrypt(d->disc_key, iv); + AES_Decrypt(raw + 0x400, block, 0x7c0); } static void partition_read(wiidisc_t *d, u32 offset, u8 *data, u32 len, int fake) diff --git a/source/loader/sha1.c b/source/loader/sha1.c deleted file mode 100644 index 410715a1..00000000 --- a/source/loader/sha1.c +++ /dev/null @@ -1,172 +0,0 @@ -/* -SHA-1 in C -By Steve Reid -100% Public Domain - -Test Vectors (from FIPS PUB 180-1) -"abc" - A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D -"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 -A million repetitions of "a" - 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F -*/ - -/* #define LITTLE_ENDIAN * This should be #define'd if true. */ -#define SHA1HANDSOFF - -#include -#include -#include "sha1.h" - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -/* blk0() and blk() perform the initial expand. */ -/* I got the idea of expanding during the round function from SSLeay */ -#ifdef LITTLE_ENDIAN -#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ - |(rol(block->l[i],8)&0x00FF00FF)) -#else -#define blk0(i) block->l[i] -#endif -#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ - ^block->l[(i+2)&15]^block->l[i&15],1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); - - -/* Hash a single 512-bit block. This is the core of the algorithm. */ - -void SHA1Transform(unsigned long state[5], unsigned char buffer[64]) -{ -unsigned long a, b, c, d, e; -typedef union { - unsigned char c[64]; - unsigned long l[16]; -} CHAR64LONG16; -CHAR64LONG16* block; -#ifdef SHA1HANDSOFF -static unsigned char workspace[64]; - block = (CHAR64LONG16*)workspace; - memcpy(block, buffer, 64); -#else - block = (CHAR64LONG16*)buffer; -#endif - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Wipe variables */ - a = b = c = d = e = 0; -} - - -/* SHA1Init - Initialize new context */ - -void SHA1Init(SHA1_CTX* context) -{ - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} - - -/* Run your data through this. */ - -void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len) -{ -unsigned int i, j; - - j = (context->count[0] >> 3) & 63; - if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; - context->count[1] += (len >> 29); - if ((j + len) > 63) { - memcpy(&context->buffer[j], data, (i = 64-j)); - SHA1Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) { - SHA1Transform(context->state, &data[i]); - } - j = 0; - } - else i = 0; - memcpy(&context->buffer[j], &data[i], len - i); -} - - -/* Add padding and return the message digest. */ - -void SHA1Final(unsigned char digest[20], SHA1_CTX* context) -{ -unsigned long i, j; -unsigned char finalcount[8]; - - for (i = 0; i < 8; i++) { - finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] - >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ - } - SHA1Update(context, (unsigned char *)"\200", 1); - while ((context->count[0] & 504) != 448) { - SHA1Update(context, (unsigned char *)"\0", 1); - } - SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ - for (i = 0; i < 20; i++) { - digest[i] = (unsigned char) - ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); - } - /* Wipe variables */ - i = j = 0; - memset(context->buffer, 0, 64); - memset(context->state, 0, 20); - memset(context->count, 0, 8); - memset(&finalcount, 0, 8); -#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ - SHA1Transform(context->state, context->buffer); -#endif -} - -void SHA1(unsigned char *ptr, unsigned int size, unsigned char *outbuf) { - SHA1_CTX ctx; - - SHA1Init(&ctx); - SHA1Update(&ctx, ptr, size); - SHA1Final(outbuf, &ctx); -} - diff --git a/source/loader/sys.c b/source/loader/sys.c index c617b197..245a0588 100644 --- a/source/loader/sys.c +++ b/source/loader/sys.c @@ -7,7 +7,6 @@ #include #include -#include "sha1.h" #include "fs.h" #include "mload.h" #include "sys.h" diff --git a/source/loader/utils.h b/source/loader/utils.h index e8e3bc48..2a2b6e86 100644 --- a/source/loader/utils.h +++ b/source/loader/utils.h @@ -20,10 +20,6 @@ #define TITLE_UPPER(x) ((u32)((x) >> 32)) #define TITLE_LOWER(x) ((u32)(x) & 0xFFFFFFFF) -#define Write8(addr, val) *(u8 *)addr = val; DCFlushRange((void *)addr, sizeof(u8)); -#define Write16(addr, val) *(u16 *)addr = val; DCFlushRange((void *)addr, sizeof(u16)); -#define Write32(addr, val) *(u32 *)addr = val; DCFlushRange((void *)addr, sizeof(u32)); - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/source/memory/memory.h b/source/memory/memory.h index a8465d73..e87895d7 100644 --- a/source/memory/memory.h +++ b/source/memory/memory.h @@ -37,4 +37,18 @@ #define HW_AHBPROT ((vu32*)0xCD800064) #define MEM_PROT ((vu32)0xCD8B420A) +#define HW_AES_CMD ((vu32)0x0D020000) +#define HW_AES_SRC ((vu32)0x0D020004) +#define HW_AES_DEST ((vu32)0x0D020008) +#define HW_AES_KEY ((vu32)0x0D02000C) +#define HW_AES_IV ((vu32)0x0D020010) + +#define HW_SHA1_CMD ((vu32)0x0D030000) +#define HW_SHA1_SRC ((vu32)0x0D030004) +#define HW_SHA1_H0 ((vu32)0x0D030008) +#define HW_SHA1_H1 ((vu32)0x0D03000C) +#define HW_SHA1_H2 ((vu32)0x0D030010) +#define HW_SHA1_H3 ((vu32)0x0D030014) +#define HW_SHA1_H4 ((vu32)0x0D030018) + #endif diff --git a/source/menu/menu_wad.cpp b/source/menu/menu_wad.cpp index d6d4766c..d6aa20c4 100644 --- a/source/menu/menu_wad.cpp +++ b/source/menu/menu_wad.cpp @@ -19,10 +19,8 @@ #include "channel/nand.hpp" extern "C" { -#include "loader/sha1.h" -extern void aes_set_key(u8 *key); -extern void aes_decrypt_partial(u8 *inbuf, u8 *outbuf, u8 block[16], - u8 *ctext_ptr, u32 tmp_blockno); +#include "hw/sha1.h" +#include "hw/aes.h" }; #define WAD_BUF 0x10000 @@ -94,7 +92,6 @@ int installWad(const char *path) gprintf("Decrypting key\n"); u8 tik_key[16]; decrypt_title_key(tik_buf, tik_key); - aes_set_key(tik_key); gprintf("Reading tmd\n"); signed_blob *tmd_buf = (signed_blob*)MEM2_alloc(hdr.tmd_len); @@ -145,6 +142,7 @@ int installWad(const char *path) new_uid_file[chans].TitleID = tid; new_uid_file[chans].uid = 0x1000+chans; fsop_WriteFile(fmt("%s/sys/uid.sys", EmuNAND), new_uid_file, new_uid_size); + MEM2_free(new_uid_buf); } /* clear old tik */ fsop_deleteFile(fmt("%s/ticket/%08x/%08x.tik", EmuNAND, (u32)(tid>>32), (u32)tid&0xFFFFFFFF)); @@ -162,15 +160,15 @@ int installWad(const char *path) fsop_MakeFolder(fmt("%s/title/%08x/%08x/data", EmuNAND, (u32)(tid>>32), (u32)tid&0xFFFFFFFF)); } int hash_errors = 0; - + u8 *AES_WAD_Buf = (u8*)MEM2_alloc(WAD_BUF); /* decrypt and write app files */ for(u16 cnt = 0; cnt < tmd_ptr->num_contents; cnt++) { - u8 iv[16]; + u8 aes_iv[16]; + memset(aes_iv, 0, 16); const tmd_content *content = &tmd_ptr->contents[cnt]; u16 content_index = content->index; - memset(iv, 0, 16); - memcpy(iv, &content_index, 2); + memcpy(aes_iv, &content_index, 2); /* longass filename */ FILE *app_file = NULL; s32 fd = -1; @@ -195,16 +193,10 @@ int installWad(const char *path) gprintf("Writing Real NAND File %s\n", ISFS_Path); } u64 read = 0; - u8 *encBuf = (u8*)MEM2_alloc(WAD_BUF); - u8 *decBuf = (u8*)MEM2_alloc(WAD_BUF); - - u8 block[16]; - u8 prev_block[16]; - u8 *ctext_ptr = iv; SHA1_CTX ctx; SHA1Init(&ctx); - + AES_EnableDecrypt(tik_key, aes_iv); u32 size_enc_full = ALIGN(16, content->size); while(read < size_enc_full) { @@ -212,27 +204,18 @@ int installWad(const char *path) if (size_enc > WAD_BUF) size_enc = WAD_BUF; - memset(encBuf, 0, WAD_BUF); - fread(encBuf, size_enc, 1, wad_file); + u16 num_blocks = (size_enc / 16); + fread(AES_WAD_Buf, size_enc, 1, wad_file); + AES_Decrypt(AES_WAD_Buf, AES_WAD_Buf, num_blocks); - u32 partnr = 0; - u32 lastnr = (size_enc / sizeof(block)); - - for(partnr = 0; partnr < lastnr; partnr++) - { - aes_decrypt_partial(encBuf, decBuf, block, ctext_ptr, partnr); - memcpy(prev_block, encBuf + (partnr * 16), 16); - ctext_ptr = prev_block; - } - /* we need to work with the real size here */ u64 size_dec = (content->size - read); if(size_dec > WAD_BUF) size_dec = WAD_BUF; - SHA1Update(&ctx, decBuf, size_dec); + SHA1Update(&ctx, AES_WAD_Buf, size_dec); if(mios == false) - fwrite(decBuf, size_dec, 1, app_file); + fwrite(AES_WAD_Buf, size_dec, 1, app_file); else if(fd >= 0) - ISFS_Write(fd, decBuf, size_dec); + ISFS_Write(fd, AES_WAD_Buf, size_dec); /* dont forget to increase the read size */ read += size_enc; mainMenu.update_pThread(size_enc); @@ -254,6 +237,8 @@ int installWad(const char *path) hash_errors++; } } + MEM2_free(AES_WAD_Buf); + if(mios == false) { fsop_WriteFile(fmt("%s/ticket/%08x/%08x.tik", EmuNAND, (u32)(tid>>32), (u32)tid&0xFFFFFFFF), tik_buf, hdr.tik_len); diff --git a/wiiflow.pnproj b/wiiflow.pnproj index d90e6245..f81b4b26 100644 --- a/wiiflow.pnproj +++ b/wiiflow.pnproj @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/wiiflow.pnps b/wiiflow.pnps index eba498cf..8456ab6d 100644 --- a/wiiflow.pnps +++ b/wiiflow.pnps @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file