2019-06-18 17:00:44 +00:00
|
|
|
/*
|
2023-11-03 23:21:46 +00:00
|
|
|
Copyright 2016-2023 melonDS team
|
2019-06-18 17:00:44 +00:00
|
|
|
|
|
|
|
This file is part of melonDS.
|
|
|
|
|
|
|
|
melonDS 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.
|
|
|
|
|
|
|
|
melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/.
|
|
|
|
*/
|
2019-06-19 12:24:49 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "DSi.h"
|
2023-10-11 15:20:05 +00:00
|
|
|
#include "DSi_NAND.h"
|
2019-06-19 12:24:49 +00:00
|
|
|
#include "DSi_AES.h"
|
2019-07-24 16:48:52 +00:00
|
|
|
#include "Platform.h"
|
2019-06-19 12:24:49 +00:00
|
|
|
|
2023-11-25 17:32:09 +00:00
|
|
|
namespace melonDS
|
|
|
|
{
|
2023-03-23 17:04:38 +00:00
|
|
|
using Platform::Log;
|
|
|
|
using Platform::LogLevel;
|
2019-06-19 12:24:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
#define _printhex(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[z]); printf("\n"); }
|
2019-06-19 23:36:10 +00:00
|
|
|
#define _printhex2(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[z]); }
|
2019-06-19 12:24:49 +00:00
|
|
|
|
2019-07-02 21:46:39 +00:00
|
|
|
#define _printhexR(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[((size)-1)-z]); printf("\n"); }
|
|
|
|
#define _printhex2R(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[((size)-1)-z]); }
|
|
|
|
|
2019-06-19 12:24:49 +00:00
|
|
|
|
2023-11-28 22:16:41 +00:00
|
|
|
DSi_AES::DSi_AES(melonDS::DSi& dsi) : DSi(dsi)
|
2019-06-19 12:24:49 +00:00
|
|
|
{
|
|
|
|
const u8 zero[16] = {0};
|
|
|
|
AES_init_ctx_iv(&Ctx, zero, zero);
|
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
DSi_AES::~DSi_AES()
|
2019-06-19 12:24:49 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::Reset()
|
2019-06-19 12:24:49 +00:00
|
|
|
{
|
|
|
|
Cnt = 0;
|
|
|
|
|
|
|
|
BlkCnt = 0;
|
2021-08-24 15:46:20 +00:00
|
|
|
RemExtra = 0;
|
2019-06-19 12:24:49 +00:00
|
|
|
RemBlocks = 0;
|
|
|
|
|
2019-06-19 23:36:10 +00:00
|
|
|
OutputFlush = false;
|
|
|
|
|
2019-06-19 12:24:49 +00:00
|
|
|
InputDMASize = 0;
|
|
|
|
OutputDMASize = 0;
|
|
|
|
AESMode = 0;
|
|
|
|
|
2020-12-30 22:37:46 +00:00
|
|
|
InputFIFO.Clear();
|
|
|
|
OutputFIFO.Clear();
|
2019-06-19 12:24:49 +00:00
|
|
|
|
2019-07-02 21:46:39 +00:00
|
|
|
memset(IV, 0, sizeof(IV));
|
|
|
|
|
|
|
|
memset(MAC, 0, sizeof(MAC));
|
|
|
|
|
2019-06-19 12:24:49 +00:00
|
|
|
memset(KeyNormal, 0, sizeof(KeyNormal));
|
|
|
|
memset(KeyX, 0, sizeof(KeyX));
|
|
|
|
memset(KeyY, 0, sizeof(KeyY));
|
|
|
|
|
|
|
|
memset(CurKey, 0, sizeof(CurKey));
|
2019-07-02 21:46:39 +00:00
|
|
|
memset(CurMAC, 0, sizeof(CurMAC));
|
2019-06-19 12:24:49 +00:00
|
|
|
|
2020-08-24 22:17:22 +00:00
|
|
|
memset(OutputMAC, 0, sizeof(OutputMAC));
|
|
|
|
OutputMACDue = false;
|
|
|
|
|
2019-10-19 14:03:59 +00:00
|
|
|
// initialize keys
|
Refactor how save data (including SD cards) is initialized (#1898)
* Remove `FATStorage::Open` and `FATStorage::Close`
- That's what the constructor and destructor are for, respectively
* Add `FATStorage::IsReadOnly`
* Slight cleanup of `FATStorage`
- Make it move-constructible and move-assignable
- Represent the absence of a sync directory with `std::optional`, not an empty string
- Add `FATStorageArgs` for later use
* Refactor `CartHomebrew` to accept an optional `FATStorageArgs`
- `CartHomebrew` uses it to load an SD card image
- Not passing a `FATStorage` directly because we won't know if we need to load the card until we parse the ROM
- Store the `FATStorage` inside a `std::optional` instead of a pointer
- `CartHomebrew::Reset` no longer reloads the SD card; the frontend needs to set it with the `SetSDCard` method
* Close `NANDImage::CurFile` when move-assigning
- Whoops
* Add `Args.h`
- To construct a `NDS` or `DSi` with arguments
- Mostly intended for system files
* Fix incorrect `final` placement
* Refactor how `DSi`'s NAND and SD card are set
- Provide them via a `DSiArgs` argument in the constructor
- Give `DSi_MMCStorage` ownership of the `NANDImage` or `FATStorage` as needed, and expose getters/setters
- Replace `DSi_SDHost::Ports` with a `array<unique_ptr, 2>` to reduce the risk of leaks
- Store `DSi_MMCStorage`'s disk images in a `std::variant`
- The SD card and NAND image are no longer reset in `Reset()`; the frontend will need to do that itself
* Add getters/setters on `DSi` itself for its storage media
* Remove newly-unused `Platform::ConfigEntry`s
* Use `DSi::SetNAND` in the frontend
* Add `EmuThread::NeedToRecreateConsole`
* Document `NDSArgs` and give its fields default values
* Refactor how system files are loaded upon construction
- Pass `NDSArgs&&` into `NDS`'s constructor
- Use `std::array` for the emulator's BIOS images and the built-in FreeBIOS, to simplify copying and comparison
- Initialize the BIOS, firmware, and SD cards from `NDSArgs` or `DSiArgs`
- Add a new default constructor for `NDS` (not `DSi`) that initializes the DS with default system files
- Embed `FirmwareMem::Firmware` directly instead of in a `unique_ptr`
- `SPIHost` now takes a `Firmware&&` that it forwards to `FirmwareMem`
- Add `Firmware` getters/setters plus `const` variants for `NDS`, `Firmware`, and `FirmwareMem`
- Simplify installation of firmware
* Initialize the DSi BIOS in the constructor
- Change `DSi::ARM9iBIOS` and `ARM7iBIOS` to `std::array`
* Update the frontend to reflect the core's changes
* Remove `DSi_SDHost::CloseHandles`
* Pass `nullopt` instead of the empty string when folder sync is off
* Deduplicate ROM extraction logic
- `LoadGBAROM` and `LoadROM` now delegate to `LoadROMData`
- Also use `unique_ptr` instead of `new[]`
* Oops, missed some `get()`'s
* Move `NDS::IsLoadedARM9BIOSBuiltIn` to the header
- So it's likelier to be inlined
- Same for the ARM7 version
* Remove `NDS::SetConsoleType`
* Add `NDS::SetFirmware`
* Move `GBACart::SetupSave` to be `protected`
- It was only ever used inside the class
* Rename `GBACart::LoadSave` to `SetSaveMemory`
- Same for the cart slot
* Declare `GBACartSlot` as a friend of `GBACart::CartCommon`
* Revise `GBACartSlot`'s getters and setters
- Rename `InsertROM` and `LoadROM` to `SetCart`
- Add a `GetCart` method
* Clean up getters and setters for NDS and GBA carts
* Clean up how carts are inserted into the slots
- Remove setters that operate directly on pointers, to simplify error-handling (use ParseROM instead)
- Add overloads for all carts that accept a `const u8*` (to copy the ROM data) and a `unique_ptr<u8[]>` (to move the ROM data)
- Store all ROM and RAM data in `unique_ptr`
- Default-initialize all fields
- Simplify constructors and destructors, inheriting where applicable
* Refactor GBA save data insertion
- Make `SetupSave` private and non-virtual and move its logic to be in `SetSaveMemory`
- Add overloads for setting save data in the constructor
- Update the SRAM completely in `SetSaveMemory`
* Clean up `NDSCart::CartCommon::SetSaveMemory`
- Move its declaration next to the other `SaveMemory` methods
- Move its (empty) implementation to the header
* Add some comments
* Add Utils.cpp and Utils.h
* Rename some functions in Utils for clarity
* Add `GBACart::ParseROM` and `NDSCart::ParseROM` overloads that accept `unique_ptr<u8[]>`
- The `u8*` overloads delegate to these new overloads
- Also move `SetupSave` for both kinds of carts to be private non-virtual methods
* Finalize the `NDSCart` refactor
- Add `NDSCartArgs` to pass to `ParseROM`
- Add SRAM arguments for all retail carts
- Initialize SRAM inside the constructor
- Delegate to other constructors where possible
* Replace `ROMManager::NDSSave` and `GBASave` with `unique_ptr`
* Make both cart slots return the previously-inserted cart in `EjectCart`
- Primarily intended for reusing carts when resetting the console
* Make `NDS::EjectCart` return the old cart
* Initialize both cart slots with the provided ROM (if any)
* Make `NDS::EjectGBACart` return the ejected cart
* Clean up some comments in Args.h
* Rename `ROMManager::LoadBIOS` to `BootToMenu`
- Clarifies the intent
* Add `ROMManager::LoadDLDISDCard`
* Add a doc comment
* Refactor how the `NDS` is created or updated
- Rewrite `CreateConsole` to read from `Config` and load system files, but accept carts as arguments
- Fail without creating an `NDS` if any required system file doesn't load
- Add `UpdateConsole`, which delegates to `CreateConsole` if switching modes or starting the app
- Use `std::variant` to indicate whether a cart should be removed, inserted, or reused
- Load all system files (plus SD cards) in `UpdateConsole`
- Eject the cart and reinsert it into the new console if applicable
* Respect some more `Config` settings in the `Load*` functions
* Remove `InstallNAND` in favor of `LoadNAND`
* Fix some potential bugs in `LoadROMData`
* Oops, forgot to delete the definition of `InstallNAND`
* Add functions to get `FATStorageArgs`
- Not the cards themselves, but to get the arguments you _would_ use to load the cards
* Refactor `ROMManager::LoadROM`
- Load the ROM and save data before trying to initialize the console
* Clean up `ROMManager::Reset` and `BootToMenu`
- Let `EmuThread::UpdateConsole` do the heavy lifting
* Clean up `LoadGBAROM`
* Remove some unused functions
* Set the default DSi BIOS to be broken in `DSiArgs`
* Respect `Config::DSiFullBIOSBoot` when loading DSi BIOS files
* Remove some more unused functions
* Remove redundant `virtual` specifiers
* Refactor `NDSCart::CartCommon::Type()` to return a member instead of a constant
- One less virtual dispatch
- The cart type is read in `NDSCartSlot::DoSavestate`, which is a path downstream (due to rewinding)
* Remove a hash that I computed for debugging purposes
* Make `ByteSwap` `constexpr`
* Remove an unused `#include`
* Remove unnecessary functions from the NDS carts
- Mostly overrides that added nothing
* Default-initialize all NDSCart fields
* Make `GBACart::Type()` not rely on virtual dispatch
- `GBACartSlot::DoSavestate` calls it, and savestates can be a hot path downstream
* Don't forget to reset the base class in `CartGameSolarSensor::Reset()`
* Remove redundant `virtual` specifiers
* Default-initialize some fields in `GBACart`
* Fix ROMs not loading from archives in the frontend
- Whoops
* Change how the `Firmware` member is declared
* Forgot an include in Utils.cpp
* Rename `FirmwareMem::Firmware` to `FirmwareData` to fix a build error on Linux
- One of these days I'll convince you people to let me use `camelCaseMemberNames`
* Add `override` to places in `DSi_MMCStorage` that warrant it
* Fix firmware saving on the frontend
- Remove `GetConfigString` and `ConfigEntry::WifiSettingsPath` while I'm at it
* Add a non-const `GetNAND()`
2023-12-04 16:57:22 +00:00
|
|
|
u64 consoleid = DSi.SDMMC.GetNAND()->GetConsoleID();
|
2019-10-19 14:03:59 +00:00
|
|
|
|
2020-06-01 21:13:38 +00:00
|
|
|
// slot 0: modcrypt
|
|
|
|
*(u32*)&KeyX[0][0] = 0x746E694E;
|
|
|
|
*(u32*)&KeyX[0][4] = 0x6F646E65;
|
|
|
|
|
|
|
|
// slot 1: 'Tad'/dev.kp
|
|
|
|
*(u32*)&KeyX[1][0] = 0x4E00004A;
|
|
|
|
*(u32*)&KeyX[1][4] = 0x4A00004E;
|
2023-10-11 15:20:05 +00:00
|
|
|
*(u32*)&KeyX[1][8] = (u32)(consoleid >> 32) ^ 0xC80C4B72;
|
|
|
|
*(u32*)&KeyX[1][12] = (u32)consoleid;
|
2020-06-01 21:13:38 +00:00
|
|
|
|
|
|
|
// slot 3: console-unique eMMC crypto
|
2023-10-11 15:20:05 +00:00
|
|
|
*(u32*)&KeyX[3][0] = (u32)consoleid;
|
|
|
|
*(u32*)&KeyX[3][4] = (u32)consoleid ^ 0x24EE6906;
|
|
|
|
*(u32*)&KeyX[3][8] = (u32)(consoleid >> 32) ^ 0xE65B601D;
|
|
|
|
*(u32*)&KeyX[3][12] = (u32)(consoleid >> 32);
|
2020-06-01 21:13:38 +00:00
|
|
|
*(u32*)&KeyY[3][0] = 0x0AB9DC76;
|
|
|
|
*(u32*)&KeyY[3][4] = 0xBD4DC4D3;
|
|
|
|
*(u32*)&KeyY[3][8] = 0x202DDD1D;
|
2019-06-19 12:24:49 +00:00
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::DoSavestate(Savestate* file)
|
2022-01-07 13:00:43 +00:00
|
|
|
{
|
|
|
|
file->Section("AESi");
|
|
|
|
|
|
|
|
file->Var32(&Cnt);
|
|
|
|
|
|
|
|
file->Var32(&BlkCnt);
|
|
|
|
file->Var32(&RemExtra);
|
|
|
|
file->Var32(&RemBlocks);
|
|
|
|
|
|
|
|
file->Bool32(&OutputFlush);
|
|
|
|
|
|
|
|
file->Var32(&InputDMASize);
|
|
|
|
file->Var32(&OutputDMASize);
|
|
|
|
file->Var32(&AESMode);
|
|
|
|
|
|
|
|
InputFIFO.DoSavestate(file);
|
|
|
|
OutputFIFO.DoSavestate(file);
|
|
|
|
|
|
|
|
file->VarArray(IV, 16);
|
|
|
|
|
|
|
|
file->VarArray(MAC, 16);
|
|
|
|
|
|
|
|
file->VarArray(KeyNormal, 4*16);
|
|
|
|
file->VarArray(KeyX, 4*16);
|
|
|
|
file->VarArray(KeyY, 4*16);
|
|
|
|
|
|
|
|
file->VarArray(CurKey, 16);
|
|
|
|
file->VarArray(CurMAC, 16);
|
|
|
|
|
|
|
|
file->VarArray(OutputMAC, 16);
|
|
|
|
file->Bool32(&OutputMACDue);
|
|
|
|
|
|
|
|
file->VarArray(Ctx.RoundKey, AES_keyExpSize);
|
|
|
|
file->VarArray(Ctx.Iv, AES_BLOCKLEN);
|
|
|
|
}
|
|
|
|
|
2019-06-19 12:24:49 +00:00
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::ProcessBlock_CCM_Extra()
|
2021-08-24 15:46:20 +00:00
|
|
|
{
|
|
|
|
u8 data[16];
|
|
|
|
u8 data_rev[16];
|
|
|
|
|
|
|
|
*(u32*)&data[0] = InputFIFO.Read();
|
|
|
|
*(u32*)&data[4] = InputFIFO.Read();
|
|
|
|
*(u32*)&data[8] = InputFIFO.Read();
|
|
|
|
*(u32*)&data[12] = InputFIFO.Read();
|
|
|
|
|
2023-08-28 18:01:15 +00:00
|
|
|
Bswap128(data_rev, data);
|
2021-08-24 15:46:20 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < 16; i++) CurMAC[i] ^= data_rev[i];
|
|
|
|
AES_ECB_encrypt(&Ctx, CurMAC);
|
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::ProcessBlock_CCM_Decrypt()
|
2019-07-02 21:46:39 +00:00
|
|
|
{
|
|
|
|
u8 data[16];
|
|
|
|
u8 data_rev[16];
|
|
|
|
|
2020-12-30 22:37:46 +00:00
|
|
|
*(u32*)&data[0] = InputFIFO.Read();
|
|
|
|
*(u32*)&data[4] = InputFIFO.Read();
|
|
|
|
*(u32*)&data[8] = InputFIFO.Read();
|
|
|
|
*(u32*)&data[12] = InputFIFO.Read();
|
2019-07-02 21:46:39 +00:00
|
|
|
|
|
|
|
//printf("AES-CCM: "); _printhex2(data, 16);
|
|
|
|
|
2023-08-28 18:01:15 +00:00
|
|
|
Bswap128(data_rev, data);
|
2020-06-21 10:20:02 +00:00
|
|
|
|
2019-07-02 21:46:39 +00:00
|
|
|
AES_CTR_xcrypt_buffer(&Ctx, data_rev, 16);
|
2020-06-21 10:20:02 +00:00
|
|
|
for (int i = 0; i < 16; i++) CurMAC[i] ^= data_rev[i];
|
|
|
|
AES_ECB_encrypt(&Ctx, CurMAC);
|
|
|
|
|
2023-08-28 18:01:15 +00:00
|
|
|
Bswap128(data, data_rev);
|
2020-06-21 10:20:02 +00:00
|
|
|
|
|
|
|
//printf(" -> "); _printhex2(data, 16);
|
|
|
|
|
2020-12-30 22:37:46 +00:00
|
|
|
OutputFIFO.Write(*(u32*)&data[0]);
|
|
|
|
OutputFIFO.Write(*(u32*)&data[4]);
|
|
|
|
OutputFIFO.Write(*(u32*)&data[8]);
|
|
|
|
OutputFIFO.Write(*(u32*)&data[12]);
|
2020-06-21 10:20:02 +00:00
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::ProcessBlock_CCM_Encrypt()
|
2020-06-21 10:20:02 +00:00
|
|
|
{
|
|
|
|
u8 data[16];
|
|
|
|
u8 data_rev[16];
|
|
|
|
|
2020-12-30 22:37:46 +00:00
|
|
|
*(u32*)&data[0] = InputFIFO.Read();
|
|
|
|
*(u32*)&data[4] = InputFIFO.Read();
|
|
|
|
*(u32*)&data[8] = InputFIFO.Read();
|
|
|
|
*(u32*)&data[12] = InputFIFO.Read();
|
2020-06-21 10:20:02 +00:00
|
|
|
|
|
|
|
//printf("AES-CCM: "); _printhex2(data, 16);
|
|
|
|
|
2023-08-28 18:01:15 +00:00
|
|
|
Bswap128(data_rev, data);
|
2019-07-02 21:46:39 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < 16; i++) CurMAC[i] ^= data_rev[i];
|
2020-06-21 10:20:02 +00:00
|
|
|
AES_CTR_xcrypt_buffer(&Ctx, data_rev, 16);
|
2019-07-02 21:46:39 +00:00
|
|
|
AES_ECB_encrypt(&Ctx, CurMAC);
|
|
|
|
|
2023-08-28 18:01:15 +00:00
|
|
|
Bswap128(data, data_rev);
|
2019-07-02 21:46:39 +00:00
|
|
|
|
|
|
|
//printf(" -> "); _printhex2(data, 16);
|
|
|
|
|
2020-12-30 22:37:46 +00:00
|
|
|
OutputFIFO.Write(*(u32*)&data[0]);
|
|
|
|
OutputFIFO.Write(*(u32*)&data[4]);
|
|
|
|
OutputFIFO.Write(*(u32*)&data[8]);
|
|
|
|
OutputFIFO.Write(*(u32*)&data[12]);
|
2019-07-02 21:46:39 +00:00
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::ProcessBlock_CTR()
|
2019-06-19 12:24:49 +00:00
|
|
|
{
|
|
|
|
u8 data[16];
|
|
|
|
u8 data_rev[16];
|
|
|
|
|
2020-12-30 22:37:46 +00:00
|
|
|
*(u32*)&data[0] = InputFIFO.Read();
|
|
|
|
*(u32*)&data[4] = InputFIFO.Read();
|
|
|
|
*(u32*)&data[8] = InputFIFO.Read();
|
|
|
|
*(u32*)&data[12] = InputFIFO.Read();
|
2019-06-19 12:24:49 +00:00
|
|
|
|
2019-06-19 23:36:10 +00:00
|
|
|
//printf("AES-CTR: "); _printhex2(data, 16);
|
2019-06-19 12:24:49 +00:00
|
|
|
|
2023-08-28 18:01:15 +00:00
|
|
|
Bswap128(data_rev, data);
|
2019-06-19 12:24:49 +00:00
|
|
|
AES_CTR_xcrypt_buffer(&Ctx, data_rev, 16);
|
2023-08-28 18:01:15 +00:00
|
|
|
Bswap128(data, data_rev);
|
2019-06-19 12:24:49 +00:00
|
|
|
|
2019-06-19 23:36:10 +00:00
|
|
|
//printf(" -> "); _printhex(data, 16);
|
2019-06-19 12:24:49 +00:00
|
|
|
|
2020-12-30 22:37:46 +00:00
|
|
|
OutputFIFO.Write(*(u32*)&data[0]);
|
|
|
|
OutputFIFO.Write(*(u32*)&data[4]);
|
|
|
|
OutputFIFO.Write(*(u32*)&data[8]);
|
|
|
|
OutputFIFO.Write(*(u32*)&data[12]);
|
2019-06-19 12:24:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-12-12 10:07:22 +00:00
|
|
|
u32 DSi_AES::ReadCnt() const
|
2019-06-19 12:24:49 +00:00
|
|
|
{
|
|
|
|
u32 ret = Cnt;
|
|
|
|
|
2020-12-30 22:37:46 +00:00
|
|
|
ret |= InputFIFO.Level();
|
|
|
|
ret |= (OutputFIFO.Level() << 5);
|
2020-06-01 14:24:59 +00:00
|
|
|
|
2019-06-19 12:24:49 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::WriteCnt(u32 val)
|
2020-06-01 14:24:59 +00:00
|
|
|
{
|
2019-06-19 12:24:49 +00:00
|
|
|
u32 oldcnt = Cnt;
|
|
|
|
Cnt = val & 0xFC1FF000;
|
|
|
|
|
2019-06-19 23:36:10 +00:00
|
|
|
/*if (val & (3<<10))
|
|
|
|
{
|
|
|
|
if (val & (1<<11)) OutputFlush = true;
|
|
|
|
Update();
|
|
|
|
}*/
|
2019-06-19 12:24:49 +00:00
|
|
|
|
2019-06-20 20:42:28 +00:00
|
|
|
u32 dmasize_in[4] = {0, 4, 8, 12};
|
|
|
|
u32 dmasize_out[4] = {4, 8, 12, 16};
|
|
|
|
InputDMASize = dmasize_in[(val >> 12) & 0x3];
|
|
|
|
OutputDMASize = dmasize_out[(val >> 14) & 0x3];
|
2019-06-19 12:24:49 +00:00
|
|
|
|
|
|
|
AESMode = (val >> 28) & 0x3;
|
|
|
|
|
|
|
|
if (val & (1<<24))
|
|
|
|
{
|
|
|
|
u32 slot = (val >> 26) & 0x3;
|
|
|
|
memcpy(CurKey, KeyNormal[slot], 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(oldcnt & (1<<31)) && (val & (1<<31)))
|
|
|
|
{
|
|
|
|
// transfer start (checkme)
|
2021-08-24 15:46:20 +00:00
|
|
|
RemExtra = (AESMode < 2) ? (BlkCnt & 0xFFFF) : 0;
|
2019-06-19 12:24:49 +00:00
|
|
|
RemBlocks = BlkCnt >> 16;
|
2019-06-19 17:19:51 +00:00
|
|
|
|
2020-08-24 22:17:22 +00:00
|
|
|
OutputMACDue = false;
|
|
|
|
|
2023-03-23 17:04:38 +00:00
|
|
|
if (AESMode == 0 && (!(val & (1<<20)))) Log(LogLevel::Debug, "AES: CCM-DECRYPT MAC FROM WRFIFO, TODO\n");
|
2020-06-21 10:20:02 +00:00
|
|
|
|
2021-08-24 15:46:20 +00:00
|
|
|
if ((RemBlocks > 0) || (RemExtra > 0))
|
2019-10-19 14:03:59 +00:00
|
|
|
{
|
|
|
|
u8 key[16];
|
|
|
|
u8 iv[16];
|
2019-07-02 21:46:39 +00:00
|
|
|
|
2023-08-28 18:01:15 +00:00
|
|
|
Bswap128(key, CurKey);
|
|
|
|
Bswap128(iv, IV);
|
2019-07-02 21:46:39 +00:00
|
|
|
|
2019-10-19 14:03:59 +00:00
|
|
|
if (AESMode < 2)
|
|
|
|
{
|
|
|
|
u32 maclen = (val >> 16) & 0x7;
|
|
|
|
if (maclen < 1) maclen = 1;
|
2019-07-02 21:46:39 +00:00
|
|
|
|
2019-10-19 14:03:59 +00:00
|
|
|
iv[0] = 0x02;
|
|
|
|
for (int i = 0; i < 12; i++) iv[1+i] = iv[4+i];
|
|
|
|
iv[13] = 0x00;
|
|
|
|
iv[14] = 0x00;
|
|
|
|
iv[15] = 0x01;
|
2019-07-02 21:46:39 +00:00
|
|
|
|
2019-10-19 14:03:59 +00:00
|
|
|
AES_init_ctx_iv(&Ctx, key, iv);
|
2019-07-02 21:46:39 +00:00
|
|
|
|
2019-10-19 14:03:59 +00:00
|
|
|
iv[0] |= (maclen << 3) | ((BlkCnt & 0xFFFF) ? (1<<6) : 0);
|
|
|
|
iv[13] = RemBlocks >> 12;
|
|
|
|
iv[14] = RemBlocks >> 4;
|
|
|
|
iv[15] = RemBlocks << 4;
|
2019-07-02 21:46:39 +00:00
|
|
|
|
2019-10-19 14:03:59 +00:00
|
|
|
memcpy(CurMAC, iv, 16);
|
|
|
|
AES_ECB_encrypt(&Ctx, CurMAC);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
AES_init_ctx_iv(&Ctx, key, iv);
|
|
|
|
}
|
|
|
|
|
2023-11-28 22:16:41 +00:00
|
|
|
DSi.CheckNDMAs(1, 0x2A);
|
2019-07-02 21:46:39 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-10-19 14:03:59 +00:00
|
|
|
// no blocks to process? oh well. mark it finished
|
|
|
|
// CHECKME: does this trigger any IRQ or shit?
|
2019-07-02 21:46:39 +00:00
|
|
|
|
2019-10-19 14:03:59 +00:00
|
|
|
Cnt &= ~(1<<31);
|
|
|
|
}
|
2019-06-19 12:24:49 +00:00
|
|
|
}
|
|
|
|
|
2021-08-24 15:46:20 +00:00
|
|
|
//printf("AES CNT: %08X / mode=%d key=%d inDMA=%d outDMA=%d blocks=%d (BLKCNT=%08X)\n",
|
|
|
|
// val, AESMode, (val >> 26) & 0x3, InputDMASize, OutputDMASize, RemBlocks, BlkCnt);
|
2019-06-19 12:24:49 +00:00
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::WriteBlkCnt(u32 val)
|
2020-06-01 14:24:59 +00:00
|
|
|
{
|
2019-06-19 12:24:49 +00:00
|
|
|
BlkCnt = val;
|
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
u32 DSi_AES::ReadOutputFIFO()
|
2019-06-19 12:24:49 +00:00
|
|
|
{
|
2023-03-23 17:04:38 +00:00
|
|
|
if (OutputFIFO.IsEmpty()) Log(LogLevel::Warn, "!!! AES OUTPUT FIFO EMPTY\n");
|
2019-07-02 21:46:39 +00:00
|
|
|
|
2020-12-30 22:37:46 +00:00
|
|
|
u32 ret = OutputFIFO.Read();
|
2019-06-19 19:57:08 +00:00
|
|
|
|
2019-06-19 23:36:10 +00:00
|
|
|
if (Cnt & (1<<31))
|
|
|
|
{
|
|
|
|
CheckInputDMA();
|
|
|
|
CheckOutputDMA();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-12-30 22:37:46 +00:00
|
|
|
if (OutputFIFO.Level() > 0)
|
2023-11-28 22:16:41 +00:00
|
|
|
DSi.CheckNDMAs(1, 0x2B);
|
2019-06-19 23:36:10 +00:00
|
|
|
else
|
2023-11-28 22:16:41 +00:00
|
|
|
DSi.StopNDMAs(1, 0x2B);
|
2020-08-24 22:17:22 +00:00
|
|
|
|
2020-12-30 22:37:46 +00:00
|
|
|
if (OutputMACDue && OutputFIFO.Level() <= 12)
|
2020-08-24 22:17:22 +00:00
|
|
|
{
|
2020-12-30 22:37:46 +00:00
|
|
|
OutputFIFO.Write(*(u32*)&OutputMAC[0]);
|
|
|
|
OutputFIFO.Write(*(u32*)&OutputMAC[4]);
|
|
|
|
OutputFIFO.Write(*(u32*)&OutputMAC[8]);
|
|
|
|
OutputFIFO.Write(*(u32*)&OutputMAC[12]);
|
2020-08-24 22:17:22 +00:00
|
|
|
OutputMACDue = false;
|
|
|
|
}
|
2019-06-19 23:36:10 +00:00
|
|
|
}
|
|
|
|
|
2019-06-19 17:19:51 +00:00
|
|
|
return ret;
|
2019-06-19 12:24:49 +00:00
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::WriteInputFIFO(u32 val)
|
2019-06-19 12:24:49 +00:00
|
|
|
{
|
|
|
|
// TODO: add some delay to processing
|
|
|
|
|
2023-03-23 17:04:38 +00:00
|
|
|
if (InputFIFO.IsFull()) Log(LogLevel::Warn, "!!! AES INPUT FIFO FULL\n");
|
2019-07-02 21:46:39 +00:00
|
|
|
|
2020-12-30 22:37:46 +00:00
|
|
|
InputFIFO.Write(val);
|
2019-06-19 12:24:49 +00:00
|
|
|
|
|
|
|
if (!(Cnt & (1<<31))) return;
|
|
|
|
|
2019-06-19 19:57:08 +00:00
|
|
|
Update();
|
2019-06-19 17:19:51 +00:00
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::CheckInputDMA()
|
2019-06-19 17:19:51 +00:00
|
|
|
{
|
2021-08-24 15:46:20 +00:00
|
|
|
if (RemBlocks == 0 && RemExtra == 0) return;
|
2019-06-19 23:36:10 +00:00
|
|
|
|
2020-12-30 22:37:46 +00:00
|
|
|
if (InputFIFO.Level() <= InputDMASize)
|
2019-06-19 17:19:51 +00:00
|
|
|
{
|
|
|
|
// trigger input DMA
|
2023-11-28 22:16:41 +00:00
|
|
|
DSi.CheckNDMAs(1, 0x2A);
|
2019-06-19 17:19:51 +00:00
|
|
|
}
|
2019-06-19 19:57:08 +00:00
|
|
|
|
|
|
|
Update();
|
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::CheckOutputDMA()
|
2019-06-19 19:57:08 +00:00
|
|
|
{
|
2020-12-30 22:37:46 +00:00
|
|
|
if (OutputFIFO.Level() >= OutputDMASize)
|
2019-06-19 19:57:08 +00:00
|
|
|
{
|
|
|
|
// trigger output DMA
|
2023-11-28 22:16:41 +00:00
|
|
|
DSi.CheckNDMAs(1, 0x2B);
|
2019-06-19 19:57:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::Update()
|
2019-06-19 19:57:08 +00:00
|
|
|
{
|
2021-08-24 15:46:20 +00:00
|
|
|
if (RemExtra > 0)
|
2019-06-19 19:57:08 +00:00
|
|
|
{
|
2021-08-24 15:46:20 +00:00
|
|
|
while (InputFIFO.Level() >= 4 && RemExtra > 0)
|
2019-06-19 19:57:08 +00:00
|
|
|
{
|
2021-08-24 15:46:20 +00:00
|
|
|
ProcessBlock_CCM_Extra();
|
|
|
|
RemExtra--;
|
2019-06-19 19:57:08 +00:00
|
|
|
}
|
2021-08-24 15:46:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (RemExtra == 0)
|
|
|
|
{
|
|
|
|
while (InputFIFO.Level() >= 4 && OutputFIFO.Level() <= 12 && RemBlocks > 0)
|
|
|
|
{
|
|
|
|
switch (AESMode)
|
|
|
|
{
|
|
|
|
case 0: ProcessBlock_CCM_Decrypt(); break;
|
|
|
|
case 1: ProcessBlock_CCM_Encrypt(); break;
|
|
|
|
case 2:
|
|
|
|
case 3: ProcessBlock_CTR(); break;
|
|
|
|
}
|
2019-06-19 19:57:08 +00:00
|
|
|
|
2021-08-24 15:46:20 +00:00
|
|
|
RemBlocks--;
|
|
|
|
}
|
2019-06-19 19:57:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CheckOutputDMA();
|
2019-06-19 20:08:35 +00:00
|
|
|
|
2021-08-24 15:46:20 +00:00
|
|
|
if (RemBlocks == 0 && RemExtra == 0)
|
2019-06-19 20:08:35 +00:00
|
|
|
{
|
2019-07-02 21:46:39 +00:00
|
|
|
if (AESMode == 0)
|
|
|
|
{
|
|
|
|
Ctx.Iv[13] = 0x00;
|
|
|
|
Ctx.Iv[14] = 0x00;
|
2019-08-07 10:57:12 +00:00
|
|
|
Ctx.Iv[15] = 0x00;
|
2019-07-02 21:46:39 +00:00
|
|
|
AES_CTR_xcrypt_buffer(&Ctx, CurMAC, 16);
|
|
|
|
|
|
|
|
//printf("FINAL MAC: "); _printhexR(CurMAC, 16);
|
|
|
|
//printf("INPUT MAC: "); _printhex(MAC, 16);
|
|
|
|
|
|
|
|
Cnt |= (1<<21);
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
|
|
{
|
|
|
|
if (CurMAC[15-i] != MAC[i]) Cnt &= ~(1<<21);
|
|
|
|
}
|
|
|
|
}
|
2020-06-21 10:20:02 +00:00
|
|
|
else if (AESMode == 1)
|
|
|
|
{
|
|
|
|
Ctx.Iv[13] = 0x00;
|
|
|
|
Ctx.Iv[14] = 0x00;
|
|
|
|
Ctx.Iv[15] = 0x00;
|
|
|
|
AES_CTR_xcrypt_buffer(&Ctx, CurMAC, 16);
|
|
|
|
|
2023-08-28 18:01:15 +00:00
|
|
|
Bswap128(OutputMAC, CurMAC);
|
2021-08-24 15:46:20 +00:00
|
|
|
|
|
|
|
if (OutputFIFO.Level() <= 12)
|
|
|
|
{
|
|
|
|
OutputFIFO.Write(*(u32*)&OutputMAC[0]);
|
|
|
|
OutputFIFO.Write(*(u32*)&OutputMAC[4]);
|
|
|
|
OutputFIFO.Write(*(u32*)&OutputMAC[8]);
|
|
|
|
OutputFIFO.Write(*(u32*)&OutputMAC[12]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
OutputMACDue = true;
|
2020-06-21 10:20:02 +00:00
|
|
|
|
|
|
|
// CHECKME
|
|
|
|
Cnt &= ~(1<<21);
|
|
|
|
}
|
2019-07-02 21:46:39 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// CHECKME
|
|
|
|
Cnt &= ~(1<<21);
|
|
|
|
}
|
2020-06-01 14:24:59 +00:00
|
|
|
|
2019-06-19 20:08:35 +00:00
|
|
|
Cnt &= ~(1<<31);
|
2023-11-28 22:16:41 +00:00
|
|
|
if (Cnt & (1<<30)) DSi.SetIRQ2(IRQ2_DSi_AES);
|
|
|
|
DSi.StopNDMAs(1, 0x2A);
|
2019-06-19 23:36:10 +00:00
|
|
|
|
2020-12-30 22:37:46 +00:00
|
|
|
if (!OutputFIFO.IsEmpty())
|
2023-11-28 22:16:41 +00:00
|
|
|
DSi.CheckNDMAs(1, 0x2B);
|
2019-06-19 23:36:10 +00:00
|
|
|
else
|
2023-11-28 22:16:41 +00:00
|
|
|
DSi.StopNDMAs(1, 0x2B);
|
2019-06-19 23:36:10 +00:00
|
|
|
OutputFlush = false;
|
2019-06-19 20:08:35 +00:00
|
|
|
}
|
2019-06-19 12:24:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::WriteIV(u32 offset, u32 val, u32 mask)
|
2019-06-19 12:24:49 +00:00
|
|
|
{
|
|
|
|
u32 old = *(u32*)&IV[offset];
|
|
|
|
|
|
|
|
*(u32*)&IV[offset] = (old & ~mask) | (val & mask);
|
|
|
|
|
|
|
|
//printf("AES: IV: "); _printhex(IV, 16);
|
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::WriteMAC(u32 offset, u32 val, u32 mask)
|
2019-06-19 12:24:49 +00:00
|
|
|
{
|
2019-07-02 21:46:39 +00:00
|
|
|
u32 old = *(u32*)&MAC[offset];
|
|
|
|
|
|
|
|
*(u32*)&MAC[offset] = (old & ~mask) | (val & mask);
|
|
|
|
|
|
|
|
//printf("AES: MAC: "); _printhex(MAC, 16);
|
2019-06-19 12:24:49 +00:00
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::ROL16(u8* val, u32 n)
|
|
|
|
{
|
|
|
|
u32 n_coarse = n >> 3;
|
|
|
|
u32 n_fine = n & 7;
|
|
|
|
u8 tmp[16];
|
|
|
|
|
|
|
|
for (u32 i = 0; i < 16; i++)
|
|
|
|
{
|
|
|
|
tmp[i] = val[(i - n_coarse) & 0xF];
|
|
|
|
}
|
|
|
|
|
|
|
|
for (u32 i = 0; i < 16; i++)
|
|
|
|
{
|
|
|
|
val[i] = (tmp[i] << n_fine) | (tmp[(i - 1) & 0xF] >> (8-n_fine));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DSi_AES::DeriveNormalKey(u8* keyX, u8* keyY, u8* normalkey)
|
2019-06-19 12:24:49 +00:00
|
|
|
{
|
|
|
|
const u8 key_const[16] = {0xFF, 0xFE, 0xFB, 0x4E, 0x29, 0x59, 0x02, 0x58, 0x2A, 0x68, 0x0F, 0x5F, 0x1A, 0x4F, 0x3E, 0x79};
|
|
|
|
u8 tmp[16];
|
|
|
|
|
|
|
|
for (int i = 0; i < 16; i++)
|
2021-08-24 15:46:20 +00:00
|
|
|
tmp[i] = keyX[i] ^ keyY[i];
|
2019-06-19 12:24:49 +00:00
|
|
|
|
|
|
|
u32 carry = 0;
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
|
|
{
|
|
|
|
u32 res = tmp[i] + key_const[15-i] + carry;
|
|
|
|
tmp[i] = res & 0xFF;
|
|
|
|
carry = res >> 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
ROL16(tmp, 42);
|
|
|
|
|
2021-08-24 15:46:20 +00:00
|
|
|
memcpy(normalkey, tmp, 16);
|
2019-06-19 12:24:49 +00:00
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::WriteKeyNormal(u32 slot, u32 offset, u32 val, u32 mask)
|
2019-06-19 12:24:49 +00:00
|
|
|
{
|
|
|
|
u32 old = *(u32*)&KeyNormal[slot][offset];
|
|
|
|
|
|
|
|
*(u32*)&KeyNormal[slot][offset] = (old & ~mask) | (val & mask);
|
2019-07-02 21:46:39 +00:00
|
|
|
|
|
|
|
//printf("KeyNormal(%d): ", slot); _printhex(KeyNormal[slot], 16);
|
2019-06-19 12:24:49 +00:00
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::WriteKeyX(u32 slot, u32 offset, u32 val, u32 mask)
|
2019-06-19 12:24:49 +00:00
|
|
|
{
|
|
|
|
u32 old = *(u32*)&KeyX[slot][offset];
|
|
|
|
|
|
|
|
*(u32*)&KeyX[slot][offset] = (old & ~mask) | (val & mask);
|
2019-07-02 21:46:39 +00:00
|
|
|
|
|
|
|
//printf("KeyX(%d): ", slot); _printhex(KeyX[slot], 16);
|
2019-06-19 12:24:49 +00:00
|
|
|
}
|
|
|
|
|
2023-11-04 16:46:52 +00:00
|
|
|
void DSi_AES::WriteKeyY(u32 slot, u32 offset, u32 val, u32 mask)
|
2019-06-19 12:24:49 +00:00
|
|
|
{
|
|
|
|
u32 old = *(u32*)&KeyY[slot][offset];
|
|
|
|
|
|
|
|
*(u32*)&KeyY[slot][offset] = (old & ~mask) | (val & mask);
|
|
|
|
|
2019-07-02 21:46:39 +00:00
|
|
|
//printf("[%08X] KeyY(%d): ", NDS::GetPC(1), slot); _printhex(KeyY[slot], 16);
|
|
|
|
|
2019-06-19 12:24:49 +00:00
|
|
|
if (offset >= 0xC)
|
|
|
|
{
|
2021-08-24 15:46:20 +00:00
|
|
|
DeriveNormalKey(KeyX[slot], KeyY[slot], KeyNormal[slot]);
|
2019-06-19 12:24:49 +00:00
|
|
|
}
|
|
|
|
}
|
2023-11-25 17:32:09 +00:00
|
|
|
|
|
|
|
}
|