mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-12 02:52:32 +00:00
exo2: tentative (read: bugged) SmcComputeCmac, SmcGenerateSpecificAesKey, SmcGetSecureData
This commit is contained in:
parent
e0dbfc69a8
commit
aa50944568
7 changed files with 316 additions and 7 deletions
|
@ -19,12 +19,14 @@
|
||||||
#include "../secmon_misc.hpp"
|
#include "../secmon_misc.hpp"
|
||||||
#include "secmon_smc_aes.hpp"
|
#include "secmon_smc_aes.hpp"
|
||||||
#include "secmon_smc_se_lock.hpp"
|
#include "secmon_smc_se_lock.hpp"
|
||||||
|
#include "secmon_user_page_mapper.hpp"
|
||||||
|
|
||||||
namespace ams::secmon::smc {
|
namespace ams::secmon::smc {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr inline auto AesKeySize = se::AesBlockSize;
|
constexpr inline auto AesKeySize = se::AesBlockSize;
|
||||||
|
constexpr inline size_t CmacSizeMax = 4_KB;
|
||||||
|
|
||||||
enum SealKey {
|
enum SealKey {
|
||||||
SealKey_LoadAesKey = 0,
|
SealKey_LoadAesKey = 0,
|
||||||
|
@ -54,6 +56,22 @@ namespace ams::secmon::smc {
|
||||||
CipherMode_Cmac = 3,
|
CipherMode_Cmac = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum SpecificAesKey {
|
||||||
|
SpecificAesKey_CalibrationEncryption0 = 0,
|
||||||
|
SpecificAesKey_CalibrationEncryption1 = 1,
|
||||||
|
|
||||||
|
SpecificAesKey_Count,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SecureData {
|
||||||
|
SecureData_Calibration = 0,
|
||||||
|
SecureData_SafeMode = 1,
|
||||||
|
SecureData_UserSystemProperEncryption = 2,
|
||||||
|
SecureData_UserSystem = 3,
|
||||||
|
|
||||||
|
SecureData_Count,
|
||||||
|
};
|
||||||
|
|
||||||
struct GenerateAesKekOption {
|
struct GenerateAesKekOption {
|
||||||
using IsDeviceUnique = util::BitPack32::Field<0, 1, bool>;
|
using IsDeviceUnique = util::BitPack32::Field<0, 1, bool>;
|
||||||
using KeyTypeIndex = util::BitPack32::Field<1, 4, KeyType>;
|
using KeyTypeIndex = util::BitPack32::Field<1, 4, KeyType>;
|
||||||
|
@ -93,6 +111,54 @@ namespace ams::secmon::smc {
|
||||||
[SealKey_LoadEsClientCertKey] = { 0x89, 0x96, 0x43, 0x9A, 0x7C, 0xD5, 0x59, 0x55, 0x24, 0xD5, 0x24, 0x18, 0xAB, 0x6C, 0x04, 0x61 },
|
[SealKey_LoadEsClientCertKey] = { 0x89, 0x96, 0x43, 0x9A, 0x7C, 0xD5, 0x59, 0x55, 0x24, 0xD5, 0x24, 0x18, 0xAB, 0x6C, 0x04, 0x61 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr const u8 CalibrationKeySource[AesKeySize] = {
|
||||||
|
0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const u8 SecureDataSource[AesKeySize] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const u8 SecureDataCounters[][AesKeySize] = {
|
||||||
|
[SecureData_Calibration] = { 0x3C, 0xD5, 0x92, 0xEC, 0x68, 0x31, 0x4A, 0x06, 0xD4, 0x1B, 0x0C, 0xD9, 0xF6, 0x2E, 0xD9, 0xE9 },
|
||||||
|
[SecureData_SafeMode] = { 0x50, 0x81, 0xCF, 0x77, 0x18, 0x11, 0xD7, 0x0D, 0x13, 0x29, 0x60, 0xED, 0x4B, 0x21, 0x3E, 0xFC },
|
||||||
|
[SecureData_UserSystemProperEncryption] = { 0x98, 0xCB, 0x4C, 0xEB, 0x15, 0xF1, 0x4A, 0x5A, 0x7A, 0x86, 0xB6, 0xF1, 0x94, 0x66, 0xF4, 0x9D },
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const u8 SecureDataTweaks[][AesKeySize] = {
|
||||||
|
[SecureData_Calibration] = { 0xAC, 0xCA, 0x9A, 0xCA, 0xFF, 0x2E, 0xB9, 0x22, 0xCC, 0x1F, 0x4F, 0xAD, 0xDD, 0x77, 0x21, 0x1E },
|
||||||
|
[SecureData_SafeMode] = { 0x6E, 0xF8, 0x2A, 0x1A, 0xE0, 0x4F, 0xC3, 0x20, 0x08, 0x7B, 0xBA, 0x50, 0xC0, 0xCD, 0x7B, 0x39 },
|
||||||
|
[SecureData_UserSystemProperEncryption] = { 0x6D, 0x02, 0x56, 0x2D, 0xF4, 0x3D, 0x0A, 0x15, 0xB1, 0x34, 0x5C, 0xC2, 0x84, 0x4C, 0xD4, 0x28 },
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const u8 *GetSecureDataCounter(SecureData which) {
|
||||||
|
switch (which) {
|
||||||
|
case SecureData_Calibration:
|
||||||
|
return SecureDataCounters[SecureData_Calibration];
|
||||||
|
case SecureData_SafeMode:
|
||||||
|
return SecureDataCounters[SecureData_SafeMode];
|
||||||
|
case SecureData_UserSystem:
|
||||||
|
case SecureData_UserSystemProperEncryption:
|
||||||
|
return SecureDataCounters[SecureData_UserSystemProperEncryption];
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const u8 *GetSecureDataTweak(SecureData which) {
|
||||||
|
switch (which) {
|
||||||
|
case SecureData_Calibration:
|
||||||
|
return SecureDataTweaks[SecureData_Calibration];
|
||||||
|
case SecureData_SafeMode:
|
||||||
|
return SecureDataTweaks[SecureData_SafeMode];
|
||||||
|
case SecureData_UserSystem:
|
||||||
|
case SecureData_UserSystemProperEncryption:
|
||||||
|
return SecureDataTweaks[SecureData_UserSystemProperEncryption];
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constexpr uintptr_t LinkedListAddressMinimum = secmon::MemoryRegionDram.GetAddress();
|
constexpr uintptr_t LinkedListAddressMinimum = secmon::MemoryRegionDram.GetAddress();
|
||||||
constexpr size_t LinkedListAddressRangeSize = 4_MB - 2_KB;
|
constexpr size_t LinkedListAddressRangeSize = 4_MB - 2_KB;
|
||||||
constexpr uintptr_t LinkedListAddressMaximum = LinkedListAddressMinimum + LinkedListAddressRangeSize;
|
constexpr uintptr_t LinkedListAddressMaximum = LinkedListAddressMinimum + LinkedListAddressRangeSize;
|
||||||
|
@ -152,6 +218,20 @@ namespace ams::secmon::smc {
|
||||||
return Slot;
|
return Slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetSecureDataImpl(u8 *dst, SecureData which, bool tweak) {
|
||||||
|
/* Compute the appropriate AES-CTR. */
|
||||||
|
se::ComputeAes128Ctr(dst, AesKeySize, pkg1::AesKeySlot_Device, SecureDataSource, AesKeySize, GetSecureDataCounter(which), AesKeySize);
|
||||||
|
|
||||||
|
/* Tweak, if we should. */
|
||||||
|
if (tweak) {
|
||||||
|
const u8 * const tweak = GetSecureDataTweak(which);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < AesKeySize; ++i) {
|
||||||
|
dst[i] ^= tweak[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SmcResult GenerateAesKekImpl(SmcArguments &args) {
|
SmcResult GenerateAesKekImpl(SmcArguments &args) {
|
||||||
/* Decode arguments. */
|
/* Decode arguments. */
|
||||||
u8 kek_source[AesKeySize];
|
u8 kek_source[AesKeySize];
|
||||||
|
@ -281,6 +361,85 @@ namespace ams::secmon::smc {
|
||||||
return SmcResult::Success;
|
return SmcResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SmcResult GenerateSpecificAesKeyImpl(SmcArguments &args) {
|
||||||
|
/* Decode arguments. */
|
||||||
|
u8 key_source[AesKeySize];
|
||||||
|
std::memcpy(key_source, std::addressof(args.r[1]), sizeof(key_source));
|
||||||
|
|
||||||
|
const int generation = GetTargetFirmware() >= TargetFirmware_4_0_0 ? std::max<int>(static_cast<int>(args.r[3]) - 1, pkg1::KeyGeneration_1_0_0) : pkg1::KeyGeneration_1_0_0;
|
||||||
|
const auto which = static_cast<SpecificAesKey>(args.r[4]);
|
||||||
|
|
||||||
|
/* Validate arguments. */
|
||||||
|
SMC_R_UNLESS(pkg1::IsValidKeyGeneration(generation), InvalidArgument);
|
||||||
|
SMC_R_UNLESS(which < SpecificAesKey_Count, InvalidArgument);
|
||||||
|
|
||||||
|
/* Generate the specific aes key. */
|
||||||
|
u8 output_key[AesKeySize];
|
||||||
|
if (fuse::GetPatchVersion() >= fuse::PatchVersion_Odnx02A2) {
|
||||||
|
const int slot = PrepareDeviceMasterKey(generation);
|
||||||
|
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, slot, CalibrationKeySource, sizeof(CalibrationKeySource));
|
||||||
|
se::DecryptAes128(output_key, sizeof(output_key), pkg1::AesKeySlot_Smc, key_source, sizeof(key_source));
|
||||||
|
} else {
|
||||||
|
GetSecureDataImpl(output_key, SecureData_Calibration, which == SpecificAesKey_CalibrationEncryption1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the key to output. */
|
||||||
|
std::memcpy(std::addressof(args.r[1]), output_key, sizeof(output_key));
|
||||||
|
return SmcResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult ComputeCmacImpl(SmcArguments &args) {
|
||||||
|
/* Decode arguments. */
|
||||||
|
const int slot = args.r[1];
|
||||||
|
const uintptr_t data_address = args.r[2];
|
||||||
|
const uintptr_t data_size = args.r[3];
|
||||||
|
|
||||||
|
/* Declare buffer for user data. */
|
||||||
|
alignas(8) u8 user_data[CmacSizeMax];
|
||||||
|
|
||||||
|
/* Validate arguments. */
|
||||||
|
SMC_R_UNLESS(pkg1::IsUserAesKeySlot(slot), InvalidArgument);
|
||||||
|
SMC_R_UNLESS(data_size <= sizeof(user_data), InvalidArgument);
|
||||||
|
|
||||||
|
/* Map the user data, and copy to stack. */
|
||||||
|
{
|
||||||
|
UserPageMapper mapper(data_address);
|
||||||
|
SMC_R_UNLESS(mapper.Map(), InvalidArgument);
|
||||||
|
SMC_R_UNLESS(mapper.CopyFromUser(user_data, data_address, data_size), InvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure the SE sees consistent data. */
|
||||||
|
hw::FlushDataCache(user_data, data_size);
|
||||||
|
hw::DataSynchronizationBarrierInnerShareable();
|
||||||
|
|
||||||
|
/* Compute the mac. */
|
||||||
|
{
|
||||||
|
u8 mac[se::AesBlockSize];
|
||||||
|
se::ComputeAes128Cmac(mac, sizeof(mac), slot, user_data, data_size);
|
||||||
|
|
||||||
|
std::memcpy(std::addressof(args.r[1]), mac, sizeof(mac));
|
||||||
|
}
|
||||||
|
|
||||||
|
return SmcResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmcResult GetSecureDataImpl(SmcArguments &args) {
|
||||||
|
/* Decode arguments. */
|
||||||
|
const auto which = static_cast<SecureData>(args.r[1]);
|
||||||
|
|
||||||
|
/* Validate arguments/conditions. */
|
||||||
|
SMC_R_UNLESS(fuse::GetPatchVersion() < fuse::PatchVersion_Odnx02A2, NotImplemented);
|
||||||
|
SMC_R_UNLESS(which < SecureData_Count, NotImplemented);
|
||||||
|
|
||||||
|
/* Use a temporary buffer. */
|
||||||
|
u8 secure_data[AesKeySize];
|
||||||
|
GetSecureDataImpl(secure_data, which, false);
|
||||||
|
|
||||||
|
/* Copy out. */
|
||||||
|
std::memcpy(std::addressof(args.r[1]), secure_data, sizeof(secure_data));
|
||||||
|
return SmcResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SmcResult SmcGenerateAesKek(SmcArguments &args) {
|
SmcResult SmcGenerateAesKek(SmcArguments &args) {
|
||||||
|
@ -296,13 +455,11 @@ namespace ams::secmon::smc {
|
||||||
}
|
}
|
||||||
|
|
||||||
SmcResult SmcGenerateSpecificAesKey(SmcArguments &args) {
|
SmcResult SmcGenerateSpecificAesKey(SmcArguments &args) {
|
||||||
/* TODO */
|
return LockSecurityEngineAndInvoke(args, GenerateSpecificAesKeyImpl);
|
||||||
return SmcResult::NotImplemented;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SmcResult SmcComputeCmac(SmcArguments &args) {
|
SmcResult SmcComputeCmac(SmcArguments &args) {
|
||||||
/* TODO */
|
return LockSecurityEngineAndInvoke(args, ComputeCmacImpl);
|
||||||
return SmcResult::NotImplemented;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SmcResult SmcLoadPreparedAesKey(SmcArguments &args) {
|
SmcResult SmcLoadPreparedAesKey(SmcArguments &args) {
|
||||||
|
@ -310,4 +467,10 @@ namespace ams::secmon::smc {
|
||||||
return SmcResult::NotImplemented;
|
return SmcResult::NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 'Tis the last rose of summer, / Left blooming alone; */
|
||||||
|
/* Oh! who would inhabit / This bleak world alone? */
|
||||||
|
SmcResult SmcGetSecureData(SmcArguments &args) {
|
||||||
|
return LockSecurityEngineAndInvoke(args, GetSecureDataImpl);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,4 +26,6 @@ namespace ams::secmon::smc {
|
||||||
SmcResult SmcComputeCmac(SmcArguments &args);
|
SmcResult SmcComputeCmac(SmcArguments &args);
|
||||||
SmcResult SmcLoadPreparedAesKey(SmcArguments &args);
|
SmcResult SmcLoadPreparedAesKey(SmcArguments &args);
|
||||||
|
|
||||||
|
SmcResult SmcGetSecureData(SmcArguments &args);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,11 @@ namespace ams::secmon::smc {
|
||||||
{ 0xF0000201, Restriction_None, SmcIramCopy },
|
{ 0xF0000201, Restriction_None, SmcIramCopy },
|
||||||
{ 0xF0000002, Restriction_None, SmcReadWriteRegister },
|
{ 0xF0000002, Restriction_None, SmcReadWriteRegister },
|
||||||
{ 0xF0000003, Restriction_None, SmcWriteAddress },
|
{ 0xF0000003, Restriction_None, SmcWriteAddress },
|
||||||
{ 0xF0000003, Restriction_None, SmcGetEmummcConfig },
|
{ 0xF0000404, Restriction_None, SmcGetEmummcConfig },
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const HandlerInfo GetSecureDataHandlerInfo = {
|
||||||
|
0x67891234, Restriction_None, SmcGetSecureData
|
||||||
};
|
};
|
||||||
|
|
||||||
constinit HandlerTable g_handler_tables[] = {
|
constinit HandlerTable g_handler_tables[] = {
|
||||||
|
@ -163,6 +167,11 @@ namespace ams::secmon::smc {
|
||||||
InvalidSmcError(id);
|
InvalidSmcError(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Provide support for legacy SmcGetSecureData. */
|
||||||
|
if (id == GetSecureDataHandlerInfo.function_id) {
|
||||||
|
return g_handler_tables[HandlerType_User];
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if we're a user SMC. */
|
/* Check if we're a user SMC. */
|
||||||
if (type == HandlerType_User) {
|
if (type == HandlerType_User) {
|
||||||
/* Nintendo uses OEM SMCs. */
|
/* Nintendo uses OEM SMCs. */
|
||||||
|
@ -181,6 +190,11 @@ namespace ams::secmon::smc {
|
||||||
}
|
}
|
||||||
|
|
||||||
const HandlerInfo &GetHandlerInfo(const HandlerTable &table, u64 id) {
|
const HandlerInfo &GetHandlerInfo(const HandlerTable &table, u64 id) {
|
||||||
|
/* Provide support for legacy SmcGetSecureData. */
|
||||||
|
if (id == GetSecureDataHandlerInfo.function_id) {
|
||||||
|
return GetSecureDataHandlerInfo;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get and check the index. */
|
/* Get and check the index. */
|
||||||
const auto index = util::BitPack64{id}.Get<SmcFunctionId::FunctionId>();
|
const auto index = util::BitPack64{id}.Get<SmcFunctionId::FunctionId>();
|
||||||
if (AMS_UNLIKELY(index >= table.count)) {
|
if (AMS_UNLIKELY(index >= table.count)) {
|
||||||
|
|
|
@ -43,6 +43,10 @@ namespace ams::fuse {
|
||||||
HardwareState_Undefined = 2,
|
HardwareState_Undefined = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum PatchVersion {
|
||||||
|
PatchVersion_Odnx02A2 = (SocType_Erista << 12) | 0x07F,
|
||||||
|
};
|
||||||
|
|
||||||
enum DramId {
|
enum DramId {
|
||||||
DramId_IcosaSamsung4GB = 0,
|
DramId_IcosaSamsung4GB = 0,
|
||||||
DramId_IcosaHynix4GB = 1,
|
DramId_IcosaHynix4GB = 1,
|
||||||
|
@ -96,6 +100,7 @@ namespace ams::fuse {
|
||||||
HardwareType GetHardwareType();
|
HardwareType GetHardwareType();
|
||||||
HardwareState GetHardwareState();
|
HardwareState GetHardwareState();
|
||||||
u64 GetDeviceId();
|
u64 GetDeviceId();
|
||||||
|
PatchVersion GetPatchVersion();
|
||||||
QuestState GetQuestState();
|
QuestState GetQuestState();
|
||||||
pmic::Regulator GetRegulator();
|
pmic::Regulator GetRegulator();
|
||||||
int GetDeviceUniqueKeyGeneration();
|
int GetDeviceUniqueKeyGeneration();
|
||||||
|
|
|
@ -35,6 +35,9 @@ namespace ams::se {
|
||||||
|
|
||||||
void ComputeAes128Ctr(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size);
|
void ComputeAes128Ctr(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size);
|
||||||
|
|
||||||
|
void ComputeAes128Cmac(void *dst, size_t dst_size, int slot, const void *src, size_t src_size);
|
||||||
|
void ComputeAes256Cmac(void *dst, size_t dst_size, int slot, const void *src, size_t src_size);
|
||||||
|
|
||||||
void EncryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler);
|
void EncryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler);
|
||||||
void DecryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler);
|
void DecryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler);
|
||||||
void ComputeAes128CtrAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler);
|
void ComputeAes128CtrAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler);
|
||||||
|
|
|
@ -281,6 +281,11 @@ namespace ams::fuse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PatchVersion GetPatchVersion() {
|
||||||
|
const auto patch_version = reg::Read(GetChipRegisters().FUSE_SOC_SPEEDO_1_CALIB);
|
||||||
|
return static_cast<PatchVersion>(static_cast<int>(GetSocType() << 12) | patch_version);
|
||||||
|
}
|
||||||
|
|
||||||
QuestState GetQuestState() {
|
QuestState GetQuestState() {
|
||||||
return static_cast<QuestState>(util::BitPack32{GetOdmWord(4)}.Get<OdmWord4::QuestState>());
|
return static_cast<QuestState>(util::BitPack32{GetOdmWord(4)}.Get<OdmWord4::QuestState>());
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,14 @@ namespace ams::se {
|
||||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BOTTOM),
|
SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BOTTOM),
|
||||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE));
|
SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE));
|
||||||
|
|
||||||
|
constexpr inline u32 AesConfigCmac = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0),
|
||||||
|
SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE),
|
||||||
|
SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL),
|
||||||
|
SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, INIT_AESOUT),
|
||||||
|
SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, MEMORY),
|
||||||
|
SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, TOP),
|
||||||
|
SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, ENABLE));
|
||||||
|
|
||||||
constexpr inline u32 AesConfigCbcEncrypt = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0),
|
constexpr inline u32 AesConfigCbcEncrypt = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0),
|
||||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE),
|
SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE),
|
||||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL),
|
SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL),
|
||||||
|
@ -117,7 +125,7 @@ namespace ams::se {
|
||||||
SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_IV_SEL, ORIGINAL_IV),
|
SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_IV_SEL, ORIGINAL_IV),
|
||||||
SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, i));
|
SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, i));
|
||||||
|
|
||||||
/* Set the key word. */
|
/* Set the iv word. */
|
||||||
SE->SE_CRYPTO_KEYTABLE_DATA = *(iv_u32++);
|
SE->SE_CRYPTO_KEYTABLE_DATA = *(iv_u32++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,6 +176,107 @@ namespace ams::se {
|
||||||
ExecuteOperationSingleBlock(SE, dst, dst_size, src, src_size);
|
ExecuteOperationSingleBlock(SE, dst, dst_size, src, src_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExpandSubkey(u8 *subkey) {
|
||||||
|
/* Shift everything left one bit. */
|
||||||
|
u8 prev = 0;
|
||||||
|
for (int i = AesBlockSize - 1; i >= 0; --i) {
|
||||||
|
const u8 top = (subkey[i] >> 7);
|
||||||
|
subkey[i] = ((subkey[i] << 1) | top);
|
||||||
|
prev = top;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And xor with Rb if necessary. */
|
||||||
|
if (prev != 0) {
|
||||||
|
subkey[AesBlockSize - 1] ^= 0x87;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetCmacResult(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size) {
|
||||||
|
const int num_words = dst_size / sizeof(u32);
|
||||||
|
for (int i = 0; i < num_words; ++i) {
|
||||||
|
reg::Write(static_cast<u32 *>(dst) + i, reg::Read(SE->SE_HASH_RESULT[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComputeAesCmac(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, AesMode mode) {
|
||||||
|
/* Validate input. */
|
||||||
|
AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount);
|
||||||
|
|
||||||
|
/* Get the engine. */
|
||||||
|
auto *SE = GetRegisters();
|
||||||
|
|
||||||
|
/* Determine mac extents. */
|
||||||
|
const int num_blocks = util::DivideUp(src_size, AesBlockSize);
|
||||||
|
const size_t last_block_size = (src_size == 0) ? 0 : (src_size - ((num_blocks - 1) * AesBlockSize));
|
||||||
|
|
||||||
|
/* Create subkey. */
|
||||||
|
u8 subkey[AesBlockSize];
|
||||||
|
{
|
||||||
|
/* Encrypt zeroes. */
|
||||||
|
std::memset(subkey, 0, sizeof(subkey));
|
||||||
|
EncryptAes(subkey, sizeof(subkey), slot, subkey, sizeof(subkey), mode);
|
||||||
|
|
||||||
|
/* Expand. */
|
||||||
|
ExpandSubkey(subkey);
|
||||||
|
|
||||||
|
/* Account for last block. */
|
||||||
|
if (last_block_size) {
|
||||||
|
ExpandSubkey(subkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure for AES-CMAC. */
|
||||||
|
SetConfig(SE, true, SE_CONFIG_DST_HASH_REG);
|
||||||
|
SetAesConfig(SE, slot, true, AesConfigCmac);
|
||||||
|
UpdateAesMode(SE, mode);
|
||||||
|
|
||||||
|
/* Set the IV to zero. */
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
/* Select the keyslot. */
|
||||||
|
reg::Write(SE->SE_CRYPTO_KEYTABLE_ADDR, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, slot),
|
||||||
|
SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_KEYIV_SEL, IV),
|
||||||
|
SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_IV_SEL, ORIGINAL_IV),
|
||||||
|
SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, i));
|
||||||
|
|
||||||
|
/* Set the iv word. */
|
||||||
|
SE->SE_CRYPTO_KEYTABLE_DATA = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle blocks before the last. */
|
||||||
|
if (num_blocks > 1) {
|
||||||
|
SetBlockCount(SE, num_blocks - 1);
|
||||||
|
ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, src, src_size);
|
||||||
|
reg::ReadWrite(SE->SE_CRYPTO_CONFIG, SE_REG_BITS_ENUM(CRYPTO_CONFIG_IV_SELECT, UPDATED));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle the last block. */
|
||||||
|
{
|
||||||
|
SetBlockCount(SE, 1);
|
||||||
|
|
||||||
|
/* Create the last block. */
|
||||||
|
u8 last_block[AesBlockSize];
|
||||||
|
if (last_block_size < sizeof(last_block)) {
|
||||||
|
std::memset(last_block, 0, sizeof(last_block));
|
||||||
|
last_block[last_block_size] = 0x80;
|
||||||
|
}
|
||||||
|
std::memcpy(last_block, static_cast<const u8 *>(src) + src_size - last_block_size, last_block_size);
|
||||||
|
|
||||||
|
/* Xor with the subkey. */
|
||||||
|
for (size_t i = 0; i < AesBlockSize; ++i) {
|
||||||
|
last_block[i] ^= subkey[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure the SE sees correct data. */
|
||||||
|
hw::FlushDataCache(last_block, sizeof(last_block));
|
||||||
|
hw::DataSynchronizationBarrierInnerShareable();
|
||||||
|
|
||||||
|
ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, last_block, sizeof(last_block));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the output. */
|
||||||
|
GetCmacResult(SE, dst, dst_size);
|
||||||
|
}
|
||||||
|
|
||||||
void ComputeAes128Async(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, DoneHandler handler, u32 config, bool encrypt, volatile SecurityEngineRegisters *SE) {
|
void ComputeAes128Async(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, DoneHandler handler, u32 config, bool encrypt, volatile SecurityEngineRegisters *SE) {
|
||||||
/* If nothing to decrypt, succeed. */
|
/* If nothing to decrypt, succeed. */
|
||||||
if (size == 0) { return; }
|
if (size == 0) { return; }
|
||||||
|
@ -328,6 +437,14 @@ namespace ams::se {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ComputeAes128Cmac(void *dst, size_t dst_size, int slot, const void *src, size_t src_size) {
|
||||||
|
return ComputeAesCmac(dst, dst_size, slot, src, src_size, AesMode_Aes128);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComputeAes256Cmac(void *dst, size_t dst_size, int slot, const void *src, size_t src_size) {
|
||||||
|
return ComputeAesCmac(dst, dst_size, slot, src, src_size, AesMode_Aes256);
|
||||||
|
}
|
||||||
|
|
||||||
void EncryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler) {
|
void EncryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler) {
|
||||||
/* Validate the iv. */
|
/* Validate the iv. */
|
||||||
AMS_ABORT_UNLESS(iv_size == AesBlockSize);
|
AMS_ABORT_UNLESS(iv_size == AesBlockSize);
|
||||||
|
|
Loading…
Reference in a new issue