From d18b0bd7d1c8221cfbe59d1e6efc9925177d7a0a Mon Sep 17 00:00:00 2001 From: Aurora Date: Fri, 11 Nov 2016 17:44:44 +0100 Subject: [PATCH] Add dev unit support --- source/crypto.c | 17 ++++++++---- source/crypto.h | 4 +-- source/fs.c | 2 +- source/installer.c | 68 ++++++++++++++++++++++++++++++++-------------- source/installer.h | 3 +- source/types.h | 6 ++-- 6 files changed, 67 insertions(+), 33 deletions(-) diff --git a/source/crypto.c b/source/crypto.c index 688c64f..103c32a 100755 --- a/source/crypto.c +++ b/source/crypto.c @@ -283,6 +283,11 @@ const u8 __attribute__((aligned(4))) key2s[5][AES_BLOCK_SIZE] = { {0xA5, 0x25, 0x87, 0x11, 0x8F, 0x42, 0x9F, 0x3D, 0x65, 0x1D, 0xDD, 0x58, 0x0B, 0x6D, 0xF2, 0x17} }; +const u8 __attribute__((aligned(4))) devKey2s[2][AES_BLOCK_SIZE] = { + {0xFF, 0x77, 0xA0, 0x9A, 0x99, 0x81, 0xE9, 0x48, 0xEC, 0x51, 0xC9, 0x32, 0x5D, 0x14, 0xEC, 0x25}, + {0x59, 0x5B, 0x98, 0x5B, 0xD7, 0x74, 0x58, 0x7F, 0x89, 0x30, 0x85, 0x70, 0xD6, 0x24, 0x49, 0x1E} +}; + void getNandCtr(void) { u8 __attribute__((aligned(4))) cid[AES_BLOCK_SIZE]; @@ -357,12 +362,12 @@ void writeFirm(u8 *inbuf, bool isFirm1, u32 size) sdmmc_nand_writesectors(offset / 0x200, size / 0x200, inbuf); } -void setupKeyslot0x11(const void *otp, bool isA9lh) +void setupKeyslot0x11(const void *otp) { u8 __attribute__((aligned(4))) shasum[SHA_256_HASH_SIZE]; //If booting via A9LH, use the leftover contents of the SHA register - if(isA9lh) memcpy(shasum, (void *)REG_SHA_HASH, sizeof(shasum)); + if(ISA9LH) memcpy(shasum, (void *)REG_SHA_HASH, sizeof(shasum)); //Otherwise, calculate the otp.bin hash else sha(shasum, otp, 0x90, SHA_256_MODE); @@ -381,10 +386,10 @@ void generateSector(u8 *keySector, u32 mode) memcpy(keySector + AES_BLOCK_SIZE, keySector, AES_BLOCK_SIZE); break; case 2: - memcpy(keySector + AES_BLOCK_SIZE, key2s[0], AES_BLOCK_SIZE); + memcpy(keySector + AES_BLOCK_SIZE, !ISDEVUNIT ? key2s[0] : devKey2s[0], AES_BLOCK_SIZE); break; default: - memcpy(keySector + AES_BLOCK_SIZE, key2s[1], AES_BLOCK_SIZE); + memcpy(keySector + AES_BLOCK_SIZE, !ISDEVUNIT ? key2s[1] : devKey2s[1], AES_BLOCK_SIZE); break; } @@ -397,12 +402,12 @@ void generateSector(u8 *keySector, u32 mode) } } -void getSector(u8 *keySector, bool isA9lh) +void getSector(u8 *keySector) { //Read keysector from NAND sdmmc_nand_readsectors(0x96, 1, keySector); - if(isA9lh) + if(ISA9LH || ISDEVUNIT) { //Decrypt key sector aes_use_keyslot(0x11); diff --git a/source/crypto.h b/source/crypto.h index fd21e74..f68dfc9 100755 --- a/source/crypto.h +++ b/source/crypto.h @@ -84,8 +84,8 @@ void ctrNandInit(void); int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf); void readFirm0(u8 *outbuf, u32 size); void writeFirm(u8 *inbuf, bool isFirm1, u32 size); -void setupKeyslot0x11(const void *otp, bool isA9lh); +void setupKeyslot0x11(const void *otp); void generateSector(u8 *keySector, u32 mode); -void getSector(u8 *keySector, bool isA9lh); +void getSector(u8 *keySector); bool verifyHash(const void *data, u32 size, const u8 *hash); u32 decryptExeFs(Cxi *cxi); \ No newline at end of file diff --git a/source/fs.c b/source/fs.c index 3c06020..61f5be2 100644 --- a/source/fs.c +++ b/source/fs.c @@ -119,7 +119,7 @@ u32 firmRead(void *dest) u32 tempVersion = hexAtoi(info.altname, 8); //FIRM is equal or newer than 11.0 - if(tempVersion >= (ISN3DS ? 0x21 : 0x52)) ret = tempVersion <= (ISN3DS ? 0x26 : 0x56) ? 5 : 2; + if(!ISDEVUNIT && tempVersion >= (ISN3DS ? 0x21 : 0x52)) ret = tempVersion <= (ISN3DS ? 0x26 : 0x56) ? 5 : 2; //Found an older cxi if(tempVersion < firmVersion) firmVersion = tempVersion; diff --git a/source/installer.c b/source/installer.c index 08cb4cf..9e7216a 100755 --- a/source/installer.c +++ b/source/installer.c @@ -13,15 +13,15 @@ #include "fatfs/sdmmc/sdmmc.h" #include "../build/bundled.h" -static const u8 sectorHash[SHA_256_HASH_SIZE] = { +static const u8 sectorHashRetail[SHA_256_HASH_SIZE] = { 0x82, 0xF2, 0x73, 0x0D, 0x2C, 0x2D, 0xA3, 0xF3, 0x01, 0x65, 0xF9, 0x87, 0xFD, 0xCC, 0xAC, 0x5C, 0xBA, 0xB2, 0x4B, 0x4E, 0x5F, 0x65, 0xC9, 0x81, 0xCD, 0x7B, 0xE6, 0xF4, 0x38, 0xE6, 0xD9, 0xD3 }, - firm0Hash[SHA_256_HASH_SIZE] = { + firm0HashRetail[SHA_256_HASH_SIZE] = { 0x6E, 0x4D, 0x14, 0xAD, 0x51, 0x50, 0xA5, 0x9A, 0x87, 0x59, 0x62, 0xB7, 0x09, 0x0A, 0x3C, 0x74, 0x4F, 0x72, 0x4B, 0xBD, 0x97, 0x39, 0x33, 0xF2, 0x11, 0xC9, 0x35, 0x22, 0xC8, 0xBB, 0x1C, 0x7D }, - firm0A9lhHash[SHA_256_HASH_SIZE] = { + firm0A9lhHashRetail[SHA_256_HASH_SIZE] = { 0x79, 0x3D, 0x35, 0x7B, 0x8F, 0xF1, 0xFC, 0xF0, 0x8F, 0xB6, 0xDB, 0x51, 0x31, 0xD4, 0xA7, 0x74, 0x8E, 0xF0, 0x4A, 0xB1, 0xA6, 0x7F, 0xCD, 0xAB, 0x0C, 0x0A, 0xC0, 0x69, 0xA7, 0x9D, 0xC5, 0x04 }, @@ -33,7 +33,7 @@ static const u8 sectorHash[SHA_256_HASH_SIZE] = { 0xD8, 0x2D, 0xB7, 0xB4, 0x38, 0x2B, 0x07, 0x88, 0x99, 0x77, 0x91, 0x0C, 0xC6, 0xEC, 0x6D, 0x87, 0x7D, 0x21, 0x79, 0x23, 0xD7, 0x60, 0xAF, 0x4E, 0x8B, 0x3A, 0xAB, 0xB2, 0x63, 0xE4, 0x21, 0xC6 }, - firm1Hash[SHA_256_HASH_SIZE] = { + firm1HashRetail[SHA_256_HASH_SIZE] = { 0xD2, 0x53, 0xC1, 0xCC, 0x0A, 0x5F, 0xFA, 0xC6, 0xB3, 0x83, 0xDA, 0xC1, 0x82, 0x7C, 0xFB, 0x3B, 0x2D, 0x3D, 0x56, 0x6C, 0x6A, 0x1A, 0x8E, 0x52, 0x54, 0xE3, 0x89, 0xC2, 0x95, 0x06, 0x23, 0xE5 }, @@ -44,6 +44,22 @@ static const u8 sectorHash[SHA_256_HASH_SIZE] = { firm104N3DSHash[SHA_256_HASH_SIZE] = { 0x2D, 0x6B, 0xCC, 0xCE, 0x3B, 0x81, 0xD7, 0xCA, 0x67, 0x17, 0x90, 0x33, 0x35, 0x4D, 0xFA, 0xA5, 0x70, 0xF4, 0x7A, 0x99, 0xBB, 0x60, 0x0C, 0x2F, 0x34, 0x90, 0xFF, 0x10, 0xD4, 0x4C, 0x97, 0x42 +}, + sectorHashDev[SHA_256_HASH_SIZE] = { + 0xB2, 0x91, 0xD9, 0xB1, 0x33, 0x05, 0x79, 0x0D, 0x47, 0xC6, 0x06, 0x98, 0x4C, 0x67, 0xC3, 0x70, + 0x09, 0x54, 0xE3, 0x85, 0xDE, 0x47, 0x55, 0xAF, 0xC6, 0xCB, 0x1D, 0x8D, 0xC7, 0x84, 0x5A, 0x64 +}, + firm0HashDev[SHA_256_HASH_SIZE] = { + 0xCD, 0x62, 0xA6, 0x58, 0x40, 0x1B, 0x8B, 0x8F, 0xD3, 0x2C, 0x72, 0x58, 0xD8, 0x24, 0x21, 0x36, + 0xCF, 0x83, 0x40, 0xA3, 0x34, 0x8E, 0xED, 0x33, 0x0A, 0x1A, 0x16, 0x04, 0x49, 0xC9, 0x74, 0x3E +}, + firm0A9lhHashDev[SHA_256_HASH_SIZE] = { + 0x60, 0xBB, 0xD1, 0x35, 0x44, 0x2F, 0xBD, 0x47, 0x69, 0xBF, 0x36, 0x4B, 0x0B, 0x79, 0x6E, 0x4C, + 0xE1, 0xB2, 0xDB, 0x7A, 0xAD, 0xF0, 0x04, 0x31, 0xCB, 0xBD, 0x54, 0xD3, 0x99, 0x8C, 0x9C, 0xD2 +}, + firm1HashDev[SHA_256_HASH_SIZE] = { + 0xCD, 0x87, 0x85, 0x33, 0x76, 0xCA, 0x2A, 0x3F, 0xFC, 0x24, 0x4C, 0x29, 0x95, 0x8B, 0xA8, 0x34, + 0xF2, 0x38, 0x14, 0x58, 0x10, 0x83, 0x56, 0x4F, 0x0D, 0x5A, 0xDB, 0x29, 0x12, 0xD8, 0xA9, 0x84 }; u32 posY; @@ -92,7 +108,7 @@ static inline void installer(bool isOtpless) shutdown(1, "Error: failed to mount the SD card"); //If making a first install on O3DS, we need the OTP - if(!ISA9LH && !ISN3DS) + if(!ISA9LH && (ISDEVUNIT || !ISN3DS)) { const char otpPath[] = "a9lh/otp.bin"; @@ -112,7 +128,7 @@ static inline void installer(bool isOtpless) } //Setup the key sector de/encryption with the SHA register or otp.bin - if(ISA9LH || !ISN3DS) setupKeyslot0x11(otp, ISA9LH); + if(ISA9LH || (!ISDEVUNIT && !ISN3DS)) setupKeyslot0x11(otp); //Calculate the CTR for the 3DS partitions getNandCtr(); @@ -126,21 +142,26 @@ static inline void installer(bool isOtpless) } //If booting from A9LH or on N3DS, we can use the key sector from NAND - if(ISA9LH || ISN3DS) getSector(keySector, ISA9LH); + if(ISA9LH || ISN3DS) getSector(keySector); else { //Read decrypted key sector if(fileRead(keySector, "a9lh/secret_sector.bin", sizeof(keySector)) != sizeof(keySector)) shutdown(1, "Error: secret_sector.bin doesn't exist or has\na wrong size"); - if(!verifyHash(keySector, sizeof(keySector), sectorHash)) + if(!verifyHash(keySector, sizeof(keySector), !ISDEVUNIT ? sectorHashRetail : sectorHashDev)) shutdown(1, "Error: secret_sector.bin is invalid or corrupted"); } if(ISA9LH && !isOtpless) { u32 i; - for(i = 1; i < 5; i++) - if(memcmp(keySector + AES_BLOCK_SIZE, key2s[i], AES_BLOCK_SIZE) == 0) break; + + if(!ISDEVUNIT) + { + for(i = 1; i < 5; i++) + if(memcmp(keySector + AES_BLOCK_SIZE, key2s[i], AES_BLOCK_SIZE) == 0) break; + } + else i = memcmp(keySector + AES_BLOCK_SIZE, devKey2s[1], AES_BLOCK_SIZE) == 0 ? 1 : 5; switch(i) { @@ -159,18 +180,18 @@ static inline void installer(bool isOtpless) break; } - if(!verifyHash((void *)FIRM0_OFFSET, SECTION2_POSITION, firm0A9lhHash)) + if(!verifyHash((void *)FIRM0_OFFSET, SECTION2_POSITION, !ISDEVUNIT ? firm0A9lhHashRetail : firm0A9lhHashDev)) { - if(!verifyHash((void *)FIRM0_OFFSET, SECTION2_POSITION, firm090A9lhHash)) + if(ISDEVUNIT || !verifyHash((void *)FIRM0_OFFSET, SECTION2_POSITION, firm090A9lhHash)) shutdown(1, "Error: NAND FIRM0 is invalid"); updateFirm0 = true; } } - if(!ISA9LH || updateKey2 || isOtpless) generateSector(keySector, (!ISA9LH && ISN3DS) ? 1 : 0); + if(!ISA9LH || updateKey2 || isOtpless) generateSector(keySector, (!ISA9LH && ISN3DS && !ISDEVUNIT) ? 1 : 0); - if(!ISA9LH && ISN3DS) + if(!ISA9LH && ISN3DS && !ISDEVUNIT) { //Read 10.0 FIRM0 if(fileRead((void *)FIRM0_100_OFFSET, "a9lh/firm0_100.bin", FIRM0100_SIZE) != FIRM0100_SIZE) @@ -184,7 +205,7 @@ static inline void installer(bool isOtpless) //Read FIRM0 if(fileRead((void *)FIRM0_OFFSET, "a9lh/firm0.bin", FIRM0_SIZE) != FIRM0_SIZE) shutdown(1, "Error: firm0.bin doesn't exist or has a wrong size"); - if(!verifyHash((void *)FIRM0_OFFSET, FIRM0_SIZE, firm0Hash)) + if(!verifyHash((void *)FIRM0_OFFSET, FIRM0_SIZE, !ISDEVUNIT ? firm0HashRetail : firm0HashDev)) shutdown(1, "Error: firm0.bin is invalid or corrupted"); } @@ -193,7 +214,7 @@ static inline void installer(bool isOtpless) //Read FIRM1 if(fileRead((void *)FIRM1_OFFSET, "a9lh/firm1.bin", FIRM1_SIZE) != FIRM1_SIZE) shutdown(1, "Error: firm1.bin doesn't exist or has a wrong size"); - if(!verifyHash((void *)FIRM1_OFFSET, FIRM1_SIZE, firm1Hash)) + if(!verifyHash((void *)FIRM1_OFFSET, FIRM1_SIZE, !ISDEVUNIT ? firm1HashRetail : firm1HashDev)) shutdown(1, "Error: firm1.bin is invalid or corrupted"); } @@ -254,7 +275,7 @@ static inline void installer(bool isOtpless) if(!ISA9LH || updateFirm1) writeFirm((u8 *)FIRM1_OFFSET, true, FIRM1_SIZE); if(!ISA9LH || updateKey2 || isOtpless) sdmmc_nand_writesectors(0x96, 1, keySector); - if(!ISA9LH && ISN3DS) + if(!ISA9LH && ISN3DS && !ISDEVUNIT) { const u8 ldrAndBranch[] = {0x00, 0x00, 0x9F, 0xE5, 0x10, 0xFF, 0x2F, 0xE1, 0x00, 0x80, 0xFF, 0x01}; @@ -278,12 +299,17 @@ static inline void uninstaller(void) //New 3DSes need a key sector with a proper key2, Old 3DSes have a blank key sector if(ISN3DS) { - setupKeyslot0x11(NULL, true); - getSector(keySector, true); + setupKeyslot0x11(NULL); + getSector(keySector); u32 i; - for(i = 1; i < 5; i++) - if(memcmp(keySector + AES_BLOCK_SIZE, key2s[i], AES_BLOCK_SIZE) == 0) break; + + if(!ISDEVUNIT) + { + for(i = 1; i < 5; i++) + if(memcmp(keySector + AES_BLOCK_SIZE, key2s[i], AES_BLOCK_SIZE) == 0) break; + } + else i = memcmp(keySector + AES_BLOCK_SIZE, devKey2s[1], AES_BLOCK_SIZE) == 0 ? 1 : 5; if(i == 5) shutdown(1, "Error: the OTP hash or the NAND key sector\nare invalid"); diff --git a/source/installer.h b/source/installer.h index 7d6d7f3..5a8025b 100644 --- a/source/installer.h +++ b/source/installer.h @@ -21,7 +21,8 @@ #define MAX_STAGE2_SIZE 0x89A00 extern u32 magic; -extern const u8 key2s[5][AES_BLOCK_SIZE]; +extern const u8 key2s[5][AES_BLOCK_SIZE], + devKey2s[2][AES_BLOCK_SIZE]; static inline void installer(bool isOtpless); static inline void uninstaller(void); \ No newline at end of file diff --git a/source/types.h b/source/types.h index 0ad40e7..dfc61a9 100644 --- a/source/types.h +++ b/source/types.h @@ -18,10 +18,12 @@ typedef volatile u16 vu16; typedef volatile u32 vu32; typedef volatile u64 vu64; +#define CFG_UNITINFO (*(vu8 *)0x10010010) #define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC) #define PDN_SPI_CNT (*(vu32 *)0x101401C0) -#define ISN3DS (PDN_MPCORE_CFG == 7) -#define ISA9LH (!PDN_SPI_CNT) +#define ISN3DS (PDN_MPCORE_CFG == 7) +#define ISDEVUNIT (CFG_UNITINFO != 0) +#define ISA9LH (!PDN_SPI_CNT) #include "3dsheaders.h" \ No newline at end of file