@ -4,11 +4,6 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// NOTE TO FUTURE MAINTAINERS:
// When a new version of switch cryptography is released,
// hash the new keyblob source and master key and add the hashes to
// the arrays below.
# include <algorithm>
# include <array>
# include <cctype>
@ -49,178 +44,7 @@ struct Package2Header {
} ;
static_assert ( sizeof ( Package2Header ) = = 0x200 , " Package2Header has incorrect size. " ) ;
// clang-format off
constexpr std : : array source_hashes {
AsArray ( " B24BD293259DBC7AC5D63F88E60C59792498E6FC5443402C7FFE87EE8B61A3F0 " ) , // keyblob_mac_key_source
AsArray ( " 7944862A3A5C31C6720595EFD302245ABD1B54CCDCF33000557681E65C5664A4 " ) , // master_key_source
AsArray ( " 21E2DF100FC9E094DB51B47B9B1D6E94ED379DB8B547955BEF8FE08D8DD35603 " ) , // package2_key_source
AsArray ( " FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085 " ) , // aes_kek_generation_source
AsArray ( " FBD10056999EDC7ACDB96098E47E2C3606230270D23281E671F0F389FC5BC585 " ) , // aes_key_generation_source
AsArray ( " C48B619827986C7F4E3081D59DB2B460C84312650E9A8E6B458E53E8CBCA4E87 " ) , // titlekek_source
AsArray ( " 04AD66143C726B2A139FB6B21128B46F56C553B2B3887110304298D8D0092D9E " ) , // key_area_key_application_source
AsArray ( " FD434000C8FF2B26F8E9A9D2D2C12F6BE5773CBB9DC86300E1BD99F8EA33A417 " ) , // key_area_key_ocean_source
AsArray ( " 1F17B1FD51AD1C2379B58F152CA4912EC2106441E51722F38700D5937A1162F7 " ) , // key_area_key_system_source
AsArray ( " 6B2ED877C2C52334AC51E59ABFA7EC457F4A7D01E46291E9F2EAA45F011D24B7 " ) , // sd_card_kek_source
AsArray ( " D482743563D3EA5DCDC3B74E97C9AC8A342164FA041A1DC80F17F6D31E4BC01C " ) , // sd_card_save_key_source
AsArray ( " 2E751CECF7D93A2B957BD5FFCB082FD038CC2853219DD3092C6DAB9838F5A7CC " ) , // sd_card_nca_key_source
AsArray ( " 1888CAED5551B3EDE01499E87CE0D86827F80820EFB275921055AA4E2ABDFFC2 " ) , // header_kek_source
AsArray ( " 8F783E46852DF6BE0BA4E19273C4ADBAEE16380043E1B8C418C4089A8BD64AA6 " ) , // header_key_source
AsArray ( " D1757E52F1AE55FA882EC690BC6F954AC46A83DC22F277F8806BD55577C6EED7 " ) , // rsa_kek_seed3
AsArray ( " FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085 " ) , // rsa_kek_mask0
} ;
// clang-format on
// clang-format off
constexpr std : : array keyblob_source_hashes {
AsArray ( " 8A06FE274AC491436791FDB388BCDD3AB9943BD4DEF8094418CDAC150FD73786 " ) , // keyblob_key_source_00
AsArray ( " 2D5CAEB2521FEF70B47E17D6D0F11F8CE2C1E442A979AD8035832C4E9FBCCC4B " ) , // keyblob_key_source_01
AsArray ( " 61C5005E713BAE780641683AF43E5F5C0E03671117F702F401282847D2FC6064 " ) , // keyblob_key_source_02
AsArray ( " 8E9795928E1C4428E1B78F0BE724D7294D6934689C11B190943923B9D5B85903 " ) , // keyblob_key_source_03
AsArray ( " 95FA33AF95AFF9D9B61D164655B32710ED8D615D46C7D6CC3CC70481B686B402 " ) , // keyblob_key_source_04
AsArray ( " 3F5BE7B3C8B1ABD8C10B4B703D44766BA08730562C172A4FE0D6B866B3E2DB3E " ) , // keyblob_key_source_05
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_06
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_07
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_08
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_09
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_0A
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_0B
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_0C
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_0D
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_0E
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_0F
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_10
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_11
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_12
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_13
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_14
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_15
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_16
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_17
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_18
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_19
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_1A
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_1B
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_1C
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_1D
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_1E
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // keyblob_key_source_1F
} ;
// clang-format on
// clang-format off
constexpr std : : array master_key_hashes {
AsArray ( " 0EE359BE3C864BB0782E1D70A718A0342C551EED28C369754F9C4F691BECF7CA " ) , // master_key_00
AsArray ( " 4FE707B7E4ABDAF727C894AAF13B1351BFE2AC90D875F73B2E20FA94B9CC661E " ) , // master_key_01
AsArray ( " 79277C0237A2252EC3DFAC1F7C359C2B3D121E9DB15BB9AB4C2B4408D2F3AE09 " ) , // master_key_02
AsArray ( " 4F36C565D13325F65EE134073C6A578FFCB0008E02D69400836844EAB7432754 " ) , // master_key_03
AsArray ( " 75FF1D95D26113550EE6FCC20ACB58E97EDEB3A2FF52543ED5AEC63BDCC3DA50 " ) , // master_key_04
AsArray ( " EBE2BCD6704673EC0F88A187BB2AD9F1CC82B718C389425941BDC194DC46B0DD " ) , // master_key_05
AsArray ( " 9497E6779F5D840F2BBA1DE4E95BA1D6F21EFC94717D5AE5CA37D7EC5BD37A19 " ) , // master_key_06
AsArray ( " 4EC96B8CB01B8DCE382149443430B2B6EBCB2983348AFA04A25E53609DABEDF6 " ) , // master_key_07
AsArray ( " 2998E2E23609BC2675FF062A2D64AF5B1B78DFF463B24119D64A1B64F01B2D51 " ) , // master_key_08
AsArray ( " 9D486A98067C44B37CF173D3BF577891EB6081FF6B4A166347D9DBBF7025076B " ) , // master_key_09
AsArray ( " 4EC5A237A75A083A9C5F6CF615601522A7F822D06BD4BA32612C9CEBBB29BD45 " ) , // master_key_0A
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_0B
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_0C
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_0D
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_0E
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_0F
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_10
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_11
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_12
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_13
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_14
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_15
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_16
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_17
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_18
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_19
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_1A
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_1B
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_1C
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_1D
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_1E
AsArray ( " 0000000000000000000000000000000000000000000000000000000000000000 " ) , // master_key_1F
} ;
// clang-format on
static constexpr u8 CalculateMaxKeyblobSourceHash ( ) {
const auto is_zero = [ ] ( const auto & data ) {
// TODO: Replace with std::all_of whenever mingw decides to update their
// libraries to include the constexpr variant of it.
for ( const auto element : data ) {
if ( element ! = 0 ) {
return false ;
}
}
return true ;
} ;
for ( s8 i = 0x1F ; i > = 0 ; - - i ) {
if ( ! is_zero ( keyblob_source_hashes [ i ] ) ) {
return static_cast < u8 > ( i + 1 ) ;
}
}
return 0 ;
}
const u8 PartitionDataManager : : MAX_KEYBLOB_SOURCE_HASH = CalculateMaxKeyblobSourceHash ( ) ;
template < size_t key_size = 0x10 >
std : : array < u8 , key_size > FindKeyFromHex ( const std : : vector < u8 > & binary ,
const std : : array < u8 , 0x20 > & hash ) {
if ( binary . size ( ) < key_size )
return { } ;
std : : array < u8 , 0x20 > temp { } ;
for ( size_t i = 0 ; i < binary . size ( ) - key_size ; + + i ) {
mbedtls_sha256 ( binary . data ( ) + i , key_size , temp . data ( ) , 0 ) ;
if ( temp ! = hash )
continue ;
std : : array < u8 , key_size > out { } ;
std : : memcpy ( out . data ( ) , binary . data ( ) + i , key_size ) ;
return out ;
}
return { } ;
}
std : : array < u8 , 16 > FindKeyFromHex16 ( const std : : vector < u8 > & binary , std : : array < u8 , 32 > hash ) {
return FindKeyFromHex < 0x10 > ( binary , hash ) ;
}
static std : : array < Key128 , 0x20 > FindEncryptedMasterKeyFromHex ( const std : : vector < u8 > & binary ,
const Key128 & key ) {
if ( binary . size ( ) < 0x10 )
return { } ;
SHA256Hash temp { } ;
Key128 dec_temp { } ;
std : : array < Key128 , 0x20 > out { } ;
AESCipher < Key128 > cipher ( key , Mode : : ECB ) ;
for ( size_t i = 0 ; i < binary . size ( ) - 0x10 ; + + i ) {
cipher . Transcode ( binary . data ( ) + i , dec_temp . size ( ) , dec_temp . data ( ) , Op : : Decrypt ) ;
mbedtls_sha256 ( dec_temp . data ( ) , dec_temp . size ( ) , temp . data ( ) , 0 ) ;
for ( size_t k = 0 ; k < out . size ( ) ; + + k ) {
if ( temp = = master_key_hashes [ k ] ) {
out [ k ] = dec_temp ;
break ;
}
}
}
return out ;
}
const u8 PartitionDataManager : : MAX_KEYBLOB_SOURCE_HASH = 32 ;
static FileSys : : VirtualFile FindFileInDirWithNames ( const FileSys : : VirtualDir & dir ,
const std : : string & name ) {
@ -287,52 +111,10 @@ std::vector<u8> PartitionDataManager::GetSecureMonitor() const {
return secure_monitor_bytes ;
}
std : : array < u8 , 16 > PartitionDataManager : : GetPackage2KeySource ( ) const {
return FindKeyFromHex ( secure_monitor_bytes , source_hashes [ 2 ] ) ;
}
std : : array < u8 , 16 > PartitionDataManager : : GetAESKekGenerationSource ( ) const {
return FindKeyFromHex ( secure_monitor_bytes , source_hashes [ 3 ] ) ;
}
std : : array < u8 , 16 > PartitionDataManager : : GetTitlekekSource ( ) const {
return FindKeyFromHex ( secure_monitor_bytes , source_hashes [ 5 ] ) ;
}
std : : array < std : : array < u8 , 16 > , 32 > PartitionDataManager : : GetTZMasterKeys (
std : : array < u8 , 0x10 > master_key ) const {
return FindEncryptedMasterKeyFromHex ( secure_monitor_bytes , master_key ) ;
}
std : : array < u8 , 16 > PartitionDataManager : : GetRSAKekSeed3 ( ) const {
return FindKeyFromHex ( secure_monitor_bytes , source_hashes [ 14 ] ) ;
}
std : : array < u8 , 16 > PartitionDataManager : : GetRSAKekMask0 ( ) const {
return FindKeyFromHex ( secure_monitor_bytes , source_hashes [ 15 ] ) ;
}
std : : vector < u8 > PartitionDataManager : : GetPackage1Decrypted ( ) const {
return package1_decrypted_bytes ;
}
std : : array < u8 , 16 > PartitionDataManager : : GetMasterKeySource ( ) const {
return FindKeyFromHex ( package1_decrypted_bytes , source_hashes [ 1 ] ) ;
}
std : : array < u8 , 16 > PartitionDataManager : : GetKeyblobMACKeySource ( ) const {
return FindKeyFromHex ( package1_decrypted_bytes , source_hashes [ 0 ] ) ;
}
std : : array < u8 , 16 > PartitionDataManager : : GetKeyblobKeySource ( std : : size_t revision ) const {
if ( keyblob_source_hashes [ revision ] = = SHA256Hash { } ) {
LOG_WARNING ( Crypto ,
" No keyblob source hash for crypto revision {:02X}! Cannot derive keys... " ,
revision ) ;
}
return FindKeyFromHex ( package1_decrypted_bytes , keyblob_source_hashes [ revision ] ) ;
}
bool PartitionDataManager : : HasFuses ( ) const {
return fuses ! = nullptr ;
}
@ -444,46 +226,10 @@ const std::vector<u8>& PartitionDataManager::GetPackage2FSDecompressed(Package2T
return package2_fs . at ( static_cast < size_t > ( type ) ) ;
}
std : : array < u8 , 16 > PartitionDataManager : : GetKeyAreaKeyApplicationSource ( Package2Type type ) const {
return FindKeyFromHex ( package2_fs . at ( static_cast < size_t > ( type ) ) , source_hashes [ 6 ] ) ;
}
std : : array < u8 , 16 > PartitionDataManager : : GetKeyAreaKeyOceanSource ( Package2Type type ) const {
return FindKeyFromHex ( package2_fs . at ( static_cast < size_t > ( type ) ) , source_hashes [ 7 ] ) ;
}
std : : array < u8 , 16 > PartitionDataManager : : GetKeyAreaKeySystemSource ( Package2Type type ) const {
return FindKeyFromHex ( package2_fs . at ( static_cast < size_t > ( type ) ) , source_hashes [ 8 ] ) ;
}
std : : array < u8 , 16 > PartitionDataManager : : GetSDKekSource ( Package2Type type ) const {
return FindKeyFromHex ( package2_fs . at ( static_cast < size_t > ( type ) ) , source_hashes [ 9 ] ) ;
}
std : : array < u8 , 32 > PartitionDataManager : : GetSDSaveKeySource ( Package2Type type ) const {
return FindKeyFromHex < 0x20 > ( package2_fs . at ( static_cast < size_t > ( type ) ) , source_hashes [ 10 ] ) ;
}
std : : array < u8 , 32 > PartitionDataManager : : GetSDNCAKeySource ( Package2Type type ) const {
return FindKeyFromHex < 0x20 > ( package2_fs . at ( static_cast < size_t > ( type ) ) , source_hashes [ 11 ] ) ;
}
std : : array < u8 , 16 > PartitionDataManager : : GetHeaderKekSource ( Package2Type type ) const {
return FindKeyFromHex ( package2_fs . at ( static_cast < size_t > ( type ) ) , source_hashes [ 12 ] ) ;
}
std : : array < u8 , 32 > PartitionDataManager : : GetHeaderKeySource ( Package2Type type ) const {
return FindKeyFromHex < 0x20 > ( package2_fs . at ( static_cast < size_t > ( type ) ) , source_hashes [ 13 ] ) ;
}
const std : : vector < u8 > & PartitionDataManager : : GetPackage2SPLDecompressed ( Package2Type type ) const {
return package2_spl . at ( static_cast < size_t > ( type ) ) ;
}
std : : array < u8 , 16 > PartitionDataManager : : GetAESKeyGenerationSource ( Package2Type type ) const {
return FindKeyFromHex ( package2_spl . at ( static_cast < size_t > ( type ) ) , source_hashes [ 4 ] ) ;
}
bool PartitionDataManager : : HasProdInfo ( ) const {
return prodinfo ! = nullptr ;
}