WiiFlow_Lite/source/hw/aes.c

95 lines
2.9 KiB
C

/****************************************************************************
* 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_ResetEngine(void)
{
/* Reset Engine */
write32(HW_AES_CMD, 0x00000000);
while ((read32(HW_AES_CMD) & AES_CMD_FLAG_EXEC) != 0);
}
void AES_EnableDecrypt(const u8 *key, const u8 *iv)
{
const u32 *aes_iv = (const u32*)iv;
const u32 *aes_key = (const u32*)key;
/* 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));
}
}
#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)
{
/* set mode back to 0 */
aes_mode = 0;
/* 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;
}
}