-using the wii internal hardware from now on to decode and hash files, that saves code, space and speed, these processes are used for banner loading, wii game installing and wii wad channel installing

This commit is contained in:
fix94.1 2013-10-27 18:36:07 +00:00
parent 42ab1941f1
commit 609bf29dbb
14 changed files with 353 additions and 687 deletions

View File

@ -28,6 +28,7 @@ SOURCES := source \
source/gc \
source/gecko \
source/gui \
source/hw \
source/homebrew \
source/libwbfs \
source/list \

90
source/hw/aes.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <string.h>
#include <gctypes.h>
#include <malloc.h>
#include <ogc/cache.h>
#include <ogc/system.h>
#include <ogc/machine/processor.h>
#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;
}
}

23
source/hw/aes.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
****************************************************************************/
#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

174
source/hw/sha1.c Normal file
View File

@ -0,0 +1,174 @@
/*
SHA-1 in C
By Steve Reid <steve@edmweb.com>
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 <string.h>
#include <gctypes.h>
#include <malloc.h>
#include <ogc/cache.h>
#include <ogc/system.h>
#include <ogc/machine/processor.h>
#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);
}

View File

@ -1,12 +1,15 @@
#ifndef __SHA1_H__
#define __SHA1_H__
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);
#endif

View File

@ -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 <stdio.h>
#include <string.h>
#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];
}

View File

@ -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)

View File

@ -1,172 +0,0 @@
/*
SHA-1 in C
By Steve Reid <steve@edmweb.com>
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 <stdio.h>
#include <string.h>
#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);
}

View File

@ -7,7 +7,6 @@
#include <stdlib.h>
#include <string.h>
#include "sha1.h"
#include "fs.h"
#include "mload.h"
#include "sys.h"

View File

@ -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 */

View File

@ -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

View File

@ -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);

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<pd><ViewState><e p="Wiiflow" x="true"></e><e p="Wiiflow\resources" x="false"></e><e p="Wiiflow\data" x="false"></e><e p="Wiiflow\scripts" x="false"></e><e p="Wiiflow\source" x="false"></e><e p="Wiiflow\wii" x="false"></e><e p="Wiiflow\docs" x="false"></e><e p="Wiiflow\portlibs" x="false"></e></ViewState></pd>
<pd><ViewState><e p="Wiiflow" x="true"></e><e p="Wiiflow\resources" x="true"></e><e p="Wiiflow\resources\theme_pngs" x="false"></e><e p="Wiiflow\data" x="false"></e><e p="Wiiflow\resources\wiiflow_game_booter" x="true"></e><e p="Wiiflow\wii" x="false"></e><e p="Wiiflow\docs" x="false"></e><e p="Wiiflow\portlibs" x="false"></e><e p="Wiiflow\resources\app_booter" x="false"></e><e p="Wiiflow\resources\wiiflow_game_booter\build" x="false"></e><e p="Wiiflow\source\libwbfs" x="false"></e><e p="Wiiflow\resources\wiiflow_game_booter\source" x="true"></e><e p="Wiiflow\scripts" x="false"></e><e p="Wiiflow\source" x="true"></e><e p="Wiiflow\source\booter" x="false"></e><e p="Wiiflow\source\network" x="false"></e><e p="Wiiflow\source\banner" x="false"></e><e p="Wiiflow\source\channel" x="false"></e><e p="Wiiflow\source\menu" x="false"></e><e p="Wiiflow\source\cheats" x="false"></e><e p="Wiiflow\source\config" x="false"></e><e p="Wiiflow\source\devicemounter" x="false"></e><e p="Wiiflow\source\fileOps" x="false"></e><e p="Wiiflow\source\gc" x="false"></e><e p="Wiiflow\source\gecko" x="false"></e><e p="Wiiflow\source\gui" x="false"></e><e p="Wiiflow\source\homebrew" x="false"></e><e p="Wiiflow\source\hw" x="true"></e><e p="Wiiflow\source\list" x="false"></e><e p="Wiiflow\source\loader" x="false"></e><e p="Wiiflow\source\memory" x="true"></e><e p="Wiiflow\source\music" x="false"></e><e p="Wiiflow\source\plugin" x="false"></e><e p="Wiiflow\source\unzip" x="false"></e><e p="Wiiflow\source\wstringEx" x="false"></e></ViewState></pd>