Beispiel #1
0
u32 CryptBuffer(CryptBufferInfo *info)
{
    u8 ctr[16] __attribute__((aligned(32)));
    memcpy(ctr, info->ctr, 16);

    u8* buffer = info->buffer;
    u32 size = info->size;
    u32 mode = info->mode;

    if (info->setKeyY) {
        u8 keyY[16] __attribute__((aligned(32)));
        memcpy(keyY, info->keyY, 16);
        setup_aeskeyY(info->keyslot, keyY);
        info->setKeyY = 0;
    }
    use_aeskey(info->keyslot);

    for (u32 i = 0; i < size; i += 0x10, buffer += 0x10) {
        if (((mode & (0x7 << 27)) != AES_ECB_DECRYPT_MODE) && ((mode & (0x7 << 27)) != AES_ECB_ENCRYPT_MODE))
            set_ctr(ctr);
        if ((mode & (0x7 << 27)) == AES_CBC_DECRYPT_MODE)
            memcpy(ctr, buffer, 0x10);
        aes_decrypt((void*) buffer, (void*) buffer, 1, mode);
        if ((mode & (0x7 << 27)) == AES_CBC_ENCRYPT_MODE)
            memcpy(ctr, buffer, 0x10);
        else if ((mode & (0x7 << 27)) == AES_CTR_MODE)
            add_ctr(ctr, 0x1);
    }

    memcpy(info->ctr, ctr, 16);
    
    return 0;
}
Beispiel #2
0
u32 DecryptTitlekeys(void)
{
    EncKeysInfo *info = (EncKeysInfo*)0x20316000;

    if (!DebugFileOpen("/encTitleKeys.bin"))
        return 1;
    
    if (!DebugFileRead(info, 16, 0)) {
        FileClose();
        return 1;
    }

    if (!info->n_entries || info->n_entries > MAX_ENTRIES) {
        Debug("Too many/few entries specified: %i", info->n_entries);
        FileClose();
        return 1;
    }

    Debug("Number of entries: %i", info->n_entries);
    if (!DebugFileRead(info->entries, info->n_entries * sizeof(TitleKeyEntry), 16)) {
        FileClose();
        return 1;
    }
    
    FileClose();

    Debug("Decrypting Title Keys...");

    u8 ctr[16] __attribute__((aligned(32)));
    u8 keyY[16] __attribute__((aligned(32)));
    u32 i;
    for (i = 0; i < info->n_entries; i++) {
        memset(ctr, 0, 16);
        memcpy(ctr, info->entries[i].titleId, 8);
        set_ctr(AES_BIG_INPUT|AES_NORMAL_INPUT, ctr);
        memcpy(keyY, (void *)common_keyy[info->entries[i].commonKeyIndex], 16);
        setup_aeskey(0x3D, AES_BIG_INPUT|AES_NORMAL_INPUT, keyY);
        use_aeskey(0x3D);
        aes_decrypt(info->entries[i].encryptedTitleKey, info->entries[i].encryptedTitleKey, ctr, 1, AES_CBC_DECRYPT_MODE);
    }

    if (!DebugFileCreate("/decTitleKeys.bin", true))
        return 1;
    if (!DebugFileWrite(info, info->n_entries * sizeof(TitleKeyEntry) + 16, 0)) {
        FileClose();
        return 1;
    }
    FileClose();

    Debug("Done!");

    return 0;
}
Beispiel #3
0
ret_type CCM_decrypt(const unsigned char imsg[],    /* the plaintext input message      */ 
                unsigned char omsg[],       /* the encrypted output message     */
                const mlen_type len,        /* the length of this block (bytes) */
                CCM_ctx ctx[1])             /* the CCM context                  */
{   mlen_type   cnt = (mlen_type)-1, t_cnt = ctx->cnt, hi = ctx->md_len - t_cnt;
    
    if(len > hi)
    {
        if(len != hi + ctx->af_len)
            return CCM_msg_length_error;
    }
    else
        hi = len;
    
    while(++cnt < hi)
    {
        omsg[cnt] = imsg[cnt] ^ ctx->sii[t_cnt & BLOCK_MASK];   /* decrypt message  */ 
        ctx->cbc[t_cnt & BLOCK_MASK] ^= omsg[cnt];              /* update the CBC   */
        
        if(!(++t_cnt & BLOCK_MASK)) /* if the current encryption block is full  */
        {
            inc_ctr(ctx);
            aes_enc_blk(ctx->blk, ctx->sii, ctx->aes);  /* encrypt the CTR value    */
            aes_enc_blk(ctx->cbc, ctx->cbc, ctx->aes);  /* encrypt the running CBC  */
        }
    }

    if(t_cnt == ctx->md_len)            /* if at end of message         */
    {       
        if(t_cnt & BLOCK_MASK)          /* if a partial block remains   */
            aes_enc_blk(ctx->cbc, ctx->cbc, ctx->aes);

        set_ctr(ctx, 0);                            /* set CTR to zero  */
        aes_enc_blk(ctx->blk, ctx->sii, ctx->aes);  /* encrypt the CTR  */

        /* store the encrypted authentication value */
        for(t_cnt = 0; t_cnt < ctx->af_len; ++t_cnt)
            if(imsg[cnt + t_cnt] != (ctx->cbc[t_cnt] ^ ctx->sii[t_cnt]))
            {   
                /* if bad clear the message and authentication field    */
                memset(omsg, 0, (size_t)cnt + ctx->af_len);
                return CCM_auth_failure;
            }
    }
    else
        ctx->cnt = t_cnt;

    return (ret_type)cnt;
}
Beispiel #4
0
ret_type CCM_encrypt(const unsigned char imsg[],    /* the plaintext input message      */ 
                unsigned char omsg[],       /* the encrypted output message     */
                const mlen_type len,        /* the length of this block (bytes) */
                CCM_ctx ctx[1])             /* the CCM context                  */

{   mlen_type   cnt = (mlen_type)-1, t_cnt = ctx->cnt;

    if(len > ctx->md_len - t_cnt)
        return CCM_msg_length_error;
    
    while(++cnt < len)
    {
        ctx->cbc[t_cnt & BLOCK_MASK] ^= imsg[cnt];              /* update the CBC   */
        omsg[cnt] = imsg[cnt] ^ ctx->sii[t_cnt & BLOCK_MASK];   /* encrypt message  */

        if(!(++t_cnt & BLOCK_MASK)) /* if the current encryption block is full  */
        {
            inc_ctr(ctx);
            aes_enc_blk(ctx->blk, ctx->sii, ctx->aes);  /* encrypt the CTR value    */
            aes_enc_blk(ctx->cbc, ctx->cbc, ctx->aes);  /* encrypt the running CBC  */
        }
    }

    if(t_cnt == ctx->md_len)    /* if at end of message         */
    {
        if(t_cnt & BLOCK_MASK)  /* if a partial block remains   */
            aes_enc_blk(ctx->cbc, ctx->cbc, ctx->aes);

        set_ctr(ctx, 0);                            /* set CTR to zero  */
        aes_enc_blk(ctx->blk, ctx->sii, ctx->aes);  /* encrypt the CTR  */

        /* encrypt and store the authentication value   */
        for(t_cnt = 0; t_cnt < ctx->af_len; ++t_cnt)
            omsg[cnt + t_cnt] = ctx->cbc[t_cnt] ^ ctx->sii[t_cnt];

        cnt += ctx->af_len;
    }
    else
        ctx->cnt = t_cnt; 
    
    return (ret_type)cnt;
}
Beispiel #5
0
u32 DecryptPartition(PartitionInfo* info){
	size_t bytesWritten;
	if (info->keyY != NULL)
		setup_aeskey(info->keyslot, AES_BIG_INPUT | AES_NORMAL_INPUT, info->keyY);
	use_aeskey(info->keyslot);

	u8 ctr[16] __attribute__((aligned(32)));
	memcpy(ctr, info->ctr, 16);

	u32 size_bytes = info->size;
	for (u32 i = 0; i < size_bytes; i += BLOCK_SIZE) {
		u32 j;
		for (j = 0; (j < BLOCK_SIZE) && (i + j < size_bytes); j += 16) {
			set_ctr(AES_BIG_INPUT | AES_NORMAL_INPUT, ctr);
			aes_decrypt((void*)info->buffer + j, (void*)info->buffer + j, ctr, 1, AES_CTR_MODE);
			add_ctr(ctr, 1);
		}
	}
	return 0;
}
Beispiel #6
0
u32 DecryptPartition(PartitionInfo* info){
    size_t bytesWritten;
	if(info->keyY != NULL)
		setup_aeskey(info->keyslot, AES_BIG_INPUT|AES_NORMAL_INPUT, info->keyY);
    use_aeskey(info->keyslot);

    u8 ctr[16] __attribute__((aligned(32)));
    memcpy(ctr, info->ctr, 16);

    u32 size_bytes = info->size;
    for (u32 i = 0; i < size_bytes; i += BLOCK_SIZE) {
        u32 j;
        for (j = 0; (j < BLOCK_SIZE) && (i+j < size_bytes); j+= 16) {
            set_ctr(AES_BIG_INPUT|AES_NORMAL_INPUT, ctr);
            aes_decrypt((void*)info->buffer+j, (void*)info->buffer+j, ctr, 1, AES_CTR_MODE);
            add_ctr(ctr, 1);
			TryScreenShot(); //Putting it here allows us to take screenshots at any decryption point, since everyting loops in this
        }
    }
    return 0;
}
Beispiel #7
0
u32 DecryptBuffer(DecryptBufferInfo *info)
{
    u8 ctr[16] __attribute__((aligned(32)));
    memcpy(ctr, info->CTR, 16);

    u8* buffer = info->buffer;
    u32 size = info->size;

    if (info->setKeyY) {
        setup_aeskey(info->keyslot, AES_BIG_INPUT | AES_NORMAL_INPUT, info->keyY);
        info->setKeyY = 0;
    }
    use_aeskey(info->keyslot);

    for (u32 i = 0; i < size; i += 0x10, buffer += 0x10) {
        set_ctr(AES_BIG_INPUT | AES_NORMAL_INPUT, ctr);
        aes_decrypt((void*) buffer, (void*) buffer, ctr, 1, AES_CTR_MODE);
        add_ctr(ctr, 0x1);
    }

    memcpy(info->CTR, ctr, 16);

    return 0;
}
Beispiel #8
0
u32 NandPadgen()
{
    u8* ctrStart = FindNandCtr();
    if (ctrStart == NULL)
        return 1;

    u8 ctr[16] = {0x0};
    u32 i = 0;
    for(i = 0; i < 16; i++)
        ctr[i] = *(ctrStart + (15 - i)); //The CTR is stored backwards in memory.

    add_ctr(ctr, 0xB93000); //The CTR stored in memory would theoretically be for NAND block 0, so we need to increment it some.

    u32 keyslot = 0x0;
    u32 nand_size = 0;
    switch (GetUnitPlatform()) {
        case PLATFORM_3DS:
            keyslot = 0x4;
            nand_size = 758;
            break;
        case PLATFORM_N3DS:
            keyslot = 0x5;
            nand_size = 1055;
            break;
    }

    Debug("Creating NAND FAT16 xorpad. Size (MB): %u", nand_size);
    Debug("Filename: nand.fat16.xorpad");

    PadInfo padInfo = {.keyslot = keyslot, .setKeyY = 0, .size_mb = nand_size , .filename = "/nand.fat16.xorpad"};
    memcpy(padInfo.CTR, ctr, 16);

    u32 result = CreatePad(&padInfo);
    if(result == 0) {
        Debug("Done!");
        return 0;
    } else {
        return 1;
    }
}

u32 CreatePad(PadInfo *info)
{
    static const uint8_t zero_buf[16] __attribute__((aligned(16))) = {0};
    u8* buffer = BUFFER_ADDRESS;
    u32 result = 0;
    
    if (!FileCreate(info->filename, true)) // No DebugFileCreate() here - messages are already given
        return 1;

    if(info->setKeyY)
        setup_aeskey(info->keyslot, AES_BIG_INPUT | AES_NORMAL_INPUT, info->keyY);
    use_aeskey(info->keyslot);

    u8 ctr[16] __attribute__((aligned(32)));
    memcpy(ctr, info->CTR, 16);

    u32 size_bytes = info->size_mb * 1024*1024;
    for (u32 i = 0; i < size_bytes; i += BUFFER_MAX_SIZE) {
        u32 curr_block_size = min(BUFFER_MAX_SIZE, size_bytes - i);

        for (u32 j = 0; j < curr_block_size; j+= 16) {
            set_ctr(AES_BIG_INPUT | AES_NORMAL_INPUT, ctr);
            aes_decrypt((void*)zero_buf, (void*)buffer + j, ctr, 1, AES_CTR_MODE);
            add_ctr(ctr, 1);
        }

        ShowProgress(i, size_bytes);

        if (!DebugFileWrite((void*)buffer, curr_block_size, i)) {
            result = 1;
            break;
        }
    }

    ShowProgress(0, 0);
    FileClose();

    return result;
}

u32 NandDumper() {
    u8* buffer = BUFFER_ADDRESS;
    u32 nand_size = (GetUnitPlatform() == PLATFORM_3DS) ? 0x3AF00000 : 0x4D800000;
    u32 result = 0;

    Debug("Dumping System NAND. Size (MB): %u", nand_size / (1024 * 1024));

    if (!DebugFileCreate("/NAND.bin", true))
        return 1;

    u32 n_sectors = nand_size / NAND_SECTOR_SIZE;
    for (u32 i = 0; i < n_sectors; i += SECTORS_PER_READ) {
        ShowProgress(i, n_sectors);
        sdmmc_nand_readsectors(i, SECTORS_PER_READ, buffer);
        if(!DebugFileWrite(buffer, NAND_SECTOR_SIZE * SECTORS_PER_READ, i * NAND_SECTOR_SIZE)) {
            result = 1;
            break;
        }
    }

    ShowProgress(0, 0);
    FileClose();

    return result;
}

u32 NandPartitionsDumper() {
    u32 ctrnand_offset;
    u32 ctrnand_size;
    u32 keyslot;

    switch (GetUnitPlatform()) {
    case PLATFORM_3DS:
        ctrnand_offset = 0x0B95CA00;
        ctrnand_size = 0x2F3E3600;
        keyslot = 0x4;
        break;
    case PLATFORM_N3DS:
        ctrnand_offset = 0x0B95AE00;
        ctrnand_size = 0x41D2D200;
        keyslot = 0x5;
        break;
    }

    // see: http://3dbrew.org/wiki/Flash_Filesystem
    Debug("Dumping firm0.bin: %s!", DumpPartition("firm0.bin", 0x0B130000, 0x00400000, 0x6) == 0 ? "succeeded" : "failed");
    Debug("Dumping firm1.bin: %s!", DumpPartition("firm1.bin", 0x0B530000, 0x00400000, 0x6) == 0 ? "succeeded" : "failed");
    Debug("Dumping ctrnand.bin: %s!", DumpPartition("ctrnand.bin", ctrnand_offset, ctrnand_size, keyslot) == 0 ? "succeeded" : "failed");

    return 0;
}
Beispiel #9
0
ret_type CCM_init(
    const unsigned char key[], const unsigned long key_len, /* the key value to be used             */
    const unsigned char nonce[],                            /* the nonce value                      */
    const unsigned char auth[], const unsigned long ad_len, /* the additional authenticated data    */
    const mlen_type msg_len,                                /* message data length                  */
    const unsigned long auth_field_len,                     /* the authentication field length      */
    CCM_ctx ctx[1])                                         /* the CCM context                      */
{   aes_32t    cnt;

    if(aes_enc_key(key, key_len, ctx->aes) == aes_bad)
        return CCM_bad_key;                 /* bad key value                        */

    if(auth_field_len < 2 || auth_field_len > 16 || (auth_field_len & 1))
        return CCM_bad_auth_field_length;   /* illegal authentication field size    */

    if(ad_len >= 65536ul - 256ul)
        return CCM_bad_auth_data_length;    /* too much added authetication data    */

    /* save length values and compile the blocks for the running CBC and CTR values */
    ctx->md_len = msg_len;
    ctx->af_len = auth_field_len;

#ifndef LONG_MESSAGES
    ctx->blk[0] = (ctx->md_len & 0xff000000 ? 3 : 
                   ctx->md_len & 0xffff0000 ? 2 : 1);
#else
    ctx->blk[0] = (ctx->md_len & 0xff00000000000000 ? 7 : 
                   ctx->md_len & 0xffff000000000000 ? 6 : 
                   ctx->md_len & 0xffffff0000000000 ? 5 : 
                   ctx->md_len & 0xffffffff00000000 ? 4 : 
                   ctx->md_len & 0xffffffffff000000 ? 3 : 
                   ctx->md_len & 0xffffffffffff0000 ? 2 : 1);
#endif

    /* move the nonce into the block    */
    for(cnt = 0; cnt < (aes_32t)BLOCK_SIZE - ctx->blk[0] - 2; ++cnt)
        ctx->blk[cnt + 1] = nonce[cnt];

    set_ctr(ctx, ctx->md_len);              /* set message length value     */
    memcpy(ctx->cbc, ctx->blk, BLOCK_SIZE); /* and copy into running CBC    */
    ctx->cbc[0] |= (ad_len ? 0x40 : 0) + ((auth_field_len - 2) << 2);
    set_ctr(ctx, 1);                        /* initial counter value = 1    */

    aes_enc_blk(ctx->cbc, ctx->cbc, ctx->aes);  /* encrypt the cbc block    */
    aes_enc_blk(ctx->blk, ctx->sii, ctx->aes);  /* encrypt counter block    */

    if(ad_len)              /* if there is additional authentication data   */
    {
        cnt = 0;            /* set the two byte length field for the data   */
        ctx->cbc[0] ^= (aes_08t)(ad_len >> 8);
        ctx->cbc[1] ^= (aes_08t) ad_len;
        
        while(cnt < ad_len) /* perform the CBC calculation on the data      */
        {   
            /* xor data into the running CBC block                          */
            ctx->cbc[(cnt + 2) & BLOCK_MASK] ^= auth[cnt];

            /* if CBC block is full or at end of the authentication data    */
            if(!((++cnt + 2) & BLOCK_MASK) || cnt == ad_len)
                aes_enc_blk(ctx->cbc, ctx->cbc, ctx->aes); 
        }
    }

    ctx->cnt = 0;
    return CCM_ok;
}
Beispiel #10
0
uint32_t NcchPadgen()
{
	uint32_t result;
	File pf;
	NcchInfo *info = (NcchInfo*)0x20316000;

	const char *filename = "/ncchinfo.bin";
	wchar_t wfilename[14];
	mbstowcs(wfilename, filename, 14);
	if (!FileOpen(&pf, filename, 0)) {
		print(strings[STR_ERROR_OPENING], filename+1);
		return 1;
	}
	FileRead(&pf, info, 16, 0);

	if (info->ncch_info_version != 0xF0000003) {
        	print(strings[STR_WRONG], filename+1, strings[STR_VERSION]);
		return 0;
	}
	if (!info->n_entries || info->n_entries > MAXENTRIES) {
        	print(strings[STR_WRONG], filename+1, strings[STR_ENTRIES_COUNT]);
		return 0;
	}
	FileRead(&pf, info->entries, info->n_entries * sizeof(NcchInfoEntry), 16);
	FileClose(&pf);

	print(strings[STR_PROCESSING], wfilename+1);
	ConsoleShow();
	for(uint32_t i = 0; i < info->n_entries; i++) {
		PadInfo padInfo = {.setKeyY = 1, .size_mb = info->entries[i].size_mb};
		memcpy(padInfo.CTR, info->entries[i].CTR, 16);
		memcpy(padInfo.keyY, info->entries[i].keyY, 16);
		memcpy(padInfo.filename, info->entries[i].filename, 112);

		if(info->entries[i].uses7xCrypto)
			padInfo.keyslot = 0x25;
		else
			padInfo.keyslot = 0x2C;

		result = CreatePad(&padInfo, i);
		if (result) return 1;
	}

	return 0;
}

uint32_t SdPadgen()
{
	size_t bytesRead;
	uint32_t result;
	File fp;
	SdInfo *info = (SdInfo*)0x20316000;

	uint8_t movable_seed[0x120] = {0};
	const char *filename = "/movable.sed";
	wchar_t wfilename[13];
	mbstowcs(wfilename, filename, 13);
	// Load console 0x34 keyY from movable.sed if present on SD card
	if (FileOpen(&fp, filename, 0)) {
		bytesRead = FileRead(&fp, &movable_seed, 0x120, 0);
		FileClose(&fp);
		if (bytesRead != 0x120) {
			print(strings[STR_WRONG], filename+1, strings[STR_SIZE]);
			return 1;
		}
		if (memcmp(movable_seed, "SEED", 4) != 0) {
			print(strings[STR_WRONG], filename+1, strings[STR_CONTENT]);
			return 1;
		}
		setup_aeskey(0x34, AES_BIG_INPUT|AES_NORMAL_INPUT, &movable_seed[0x110]);
		use_aeskey(0x34);
	}

	filename = "/SDinfo.bin";
	if (!FileOpen(&fp, filename, 0)) {
		print(strings[STR_ERROR_OPENING], filename+1);
		return 1;
	}
	bytesRead = FileRead(&fp, info, 4, 0);

	if (!info->n_entries || info->n_entries > MAXENTRIES) {
        	print(strings[STR_WRONG], filename+1, strings[STR_ENTRIES_COUNT]);
		return 1;
	}

       	print(strings[STR_PROCESSING], wfilename+1);
	ConsoleShow();

	bytesRead = FileRead(&fp, info->entries, info->n_entries * sizeof(SdInfoEntry), 4);
	FileClose(&fp);

	for(uint32_t i = 0; i < info->n_entries; i++) {
		PadInfo padInfo = {.keyslot = 0x34, .setKeyY = 0, .size_mb = info->entries[i].size_mb};
		memcpy(padInfo.CTR, info->entries[i].CTR, 16);
		memcpy(padInfo.filename, info->entries[i].filename, 180);

		result = CreatePad(&padInfo, i);
		if (result)
			return 1;
	}

	return 0;
}

static const uint8_t zero_buf[16] __attribute__((aligned(16))) = {0};

uint32_t CreatePad(PadInfo *info, int index)
{
	File pf;
	#define BUFFER_ADDR ((volatile uint8_t*)0x21000000)
	#define BLOCK_SIZE  (4*1024*1024)

	if (!FileOpen(&pf, info->filename, 1))
		return 1;

	if(info->setKeyY != 0)
		setup_aeskey(info->keyslot, AES_BIG_INPUT|AES_NORMAL_INPUT, info->keyY);
	use_aeskey(info->keyslot);

	uint8_t ctr[16] __attribute__((aligned(32)));
	memcpy(ctr, info->CTR, 16);

	uint32_t size_bytes = info->size_mb*1024*1024;
	uint32_t size_100 = size_bytes/100;
	uint32_t seekpos = 0;
	for (uint32_t i = 0; i < size_bytes; i += BLOCK_SIZE) {
		uint32_t j;
		for (j = 0; (j < BLOCK_SIZE) && (i+j < size_bytes); j+= 16) {
			set_ctr(AES_BIG_INPUT|AES_NORMAL_INPUT, ctr);
			aes_decrypt((void*)zero_buf, (void*)BUFFER_ADDR+j, ctr, 1, AES_CTR_MODE);
			add_ctr(ctr, 1);
		}

		print(strings[STR_GENERATING], strings[STR_PAD]);
		print(L"%i : %i%%", index, (i+j)/size_100);
		ConsolePrevLine();
		ConsolePrevLine();
		ConsoleShow();
		FileWrite(&pf, (void*)BUFFER_ADDR, j, seekpos);
		seekpos += j;
	}

	FileClose(&pf);
	return 0;
}