void encode_block(BYTE* counter, BYTE* dst, BYTE round_key[ROUND_KEY_SIZE][BLOCK_SIZE]){ unsigned char temp[BLOCK_SIZE]; xor_key(counter, temp, round_key[0]); for(int i = 1; i < ROUNDS; i++){ sub_bytes(temp, dst); shift_rows(dst, temp); mix_columns(temp, dst); xor_key(dst, temp, round_key[i]); } sub_bytes(temp,dst); shift_rows(dst,temp); xor_key(temp,dst,round_key[ROUNDS]); }
void decode_block(BYTE* counter, BYTE* dst, BYTE round_key[ROUND_KEY_SIZE][BLOCK_SIZE]){ unsigned char temp[BLOCK_SIZE]; xor_key(counter,temp,round_key[ROUNDS]); //memcpy(dst, round_key[ROUNDS], 16); shift_rows_inv(temp,dst); sub_bytes_inv(dst,temp); for(int i = ROUNDS-1; i > 0; i--){ xor_key(temp, dst, round_key[i]); mix_columns_inv(dst, temp); shift_rows_inv(temp, dst); sub_bytes_inv(dst, temp); } xor_key(temp, dst, round_key[0]); }
void sha1_ctr_encrypt(u8 *data, int size, int offset, u8 *sha1_key) { u8 ikey[0x40], xkey[0x14]; int i; memcpy(ikey, sha1_key, 0x40); for(i=0; i<offset; i+=16){ key_inc(ikey+0x38, 7); } for(i=0; i<size; i+=16){ SHA1(ikey, 0x40, xkey); xor_key(data+i, xkey, 16); key_inc(ikey+0x38, 7); } }
/* aes_ctr_encrypt */ void aes_ctr_encrypt(u8 *data, int size, int offset, u8 *file_key, u8 *aes_key) { AES_ctx cpkg; u8 ikey[16], xkey[16]; int i; AES_set_key(&cpkg, aes_key, 128); memcpy(ikey, file_key, 16); for(i=0; i<offset; i+=16){ key_inc(ikey, 15); } for(i=0; i<size; i+=16){ memcpy(xkey, ikey, 16); AES_encrypt(&cpkg, xkey, xkey); xor_key(data+i, xkey, 16); key_inc(ikey, 15); } }
int validate_dev_klic(const u8* klicensee, NPD_HEADER *npd) { unsigned char dev[0x60] = { 0 }; unsigned char key[0x10] = { 0 }; // Build the dev buffer (first 0x60 bytes of NPD header in big-endian). memcpy(dev, npd, 0x60); // Fix endianness. int version = swap32(npd->version); int license = swap32(npd->license); int type = swap32(npd->type); memcpy(dev + 0x4, &version, 4); memcpy(dev + 0x8, &license, 4); memcpy(dev + 0xC, &type, 4); // Check for an empty dev_hash (can't validate if devklic is NULL); bool isDevklicEmpty = true; for (int i = 0; i < 0x10; i++) { if (klicensee[i] != 0) { isDevklicEmpty = false; break; } } if (isDevklicEmpty) { // Allow empty dev hash. return 1; } else { // Generate klicensee xor key. xor_key(key, klicensee, NP_OMAC_KEY_2); // Hash with generated key and compare with dev_hash. return cmac_hash_compare(key, 0x10, dev, 0x60, npd->dev_hash, 0x10); } }
void AES::srtp_decode(BYTE* src, BYTE* dst, BYTE* key, BYTE* iv, int length){ LOG_MSG("AES::srtp_decode(%s, %s, %s, %s, %d)",src,dst,key,iv,length); BYTE counter[BLOCK_SIZE] = {0}; memcpy(counter, iv, BLOCK_SIZE); unsigned char round_key[ROUND_KEY_SIZE][BLOCK_SIZE]; expand_key(key,round_key); int i = 0, j = 0; for( ; i < length; i+=BLOCK_SIZE){ decode_block(counter, dst+i, round_key); xor_key(dst+i,dst+i,src+i); update_counter(counter); } BYTE last_block[BLOCK_SIZE]; decode_block(counter, last_block, round_key); for(i=i-BLOCK_SIZE; i < length; i++, j++){ dst[i] = last_block[j] ^ src[i]; } }
bool EDATADecrypter::ReadHeader() { edata_file.seek(0); // Read in the NPD and EDAT/SDAT headers. read_npd_edat_header(&edata_file, npdHeader, edatHeader); unsigned char npd_magic[4] = { 0x4E, 0x50, 0x44, 0x00 }; //NPD0 if (memcmp(&npdHeader.magic, npd_magic, 4)) { return false; } // Check for SDAT flag. if ((edatHeader.flags & SDAT_FLAG) == SDAT_FLAG) { // Generate SDAT key. xor_key(dec_key.data(), npdHeader.dev_hash, SDAT_KEY); } else { // verify key if (validate_dev_klic(dev_key.data(), &npdHeader) == 0) { LOG_ERROR(LOADER, "EDAT: Failed validating klic"); return false; } // Select EDAT key. if ((npdHeader.license & 0x3) == 0x3) // Type 3: Use supplied devklic. dec_key = std::move(dev_key); else if ((npdHeader.license & 0x2) == 0x2) // Type 2: Use key from RAP file (RIF key). { dec_key = std::move(rif_key); if (dec_key == std::array<u8, 0x10>{0}) { LOG_WARNING(LOADER, "EDAT: Empty Dec key!"); } } else if ((npdHeader.license & 0x1) == 0x1) // Type 1: Use network activation. { LOG_ERROR(LOADER, "EDAT: Network license not supported!"); return false; } } edata_file.seek(0); // k the ecdsa_verify function in this check_data function takes a ridiculous amount of time // like it slows down load time by a factor of x20, at least, so its ignored for now /*if (check_data(dec_key.data(), &edatHeader, &npdHeader, &sdata_file, false)) { return false; }*/ file_size = edatHeader.file_size; total_blocks = (u32)((edatHeader.file_size + edatHeader.block_size - 1) / edatHeader.block_size); return true; }
bool extract_all_data(const fs::file* input, const fs::file* output, const char* input_file_name, unsigned char* devklic, unsigned char* rifkey, bool verbose) { // Setup NPD and EDAT/SDAT structs. NPD_HEADER NPD; EDAT_HEADER EDAT; // Read in the NPD and EDAT/SDAT headers. read_npd_edat_header(input, NPD, EDAT); unsigned char npd_magic[4] = {0x4E, 0x50, 0x44, 0x00}; //NPD0 if (memcmp(&NPD.magic, npd_magic, 4)) { LOG_ERROR(LOADER, "EDAT: %s has invalid NPD header or already decrypted.", input_file_name); return 1; } if (verbose) { LOG_NOTICE(LOADER, "NPD HEADER"); LOG_NOTICE(LOADER, "NPD version: %d", NPD.version); LOG_NOTICE(LOADER, "NPD license: %d", NPD.license); LOG_NOTICE(LOADER, "NPD type: %d", NPD.type); } // Set decryption key. u8 key[0x10] = { 0 }; // Check EDAT/SDAT flag. if ((EDAT.flags & SDAT_FLAG) == SDAT_FLAG) { if (verbose) { LOG_NOTICE(LOADER, "SDAT HEADER"); LOG_NOTICE(LOADER, "SDAT flags: 0x%08X", EDAT.flags); LOG_NOTICE(LOADER, "SDAT block size: 0x%08X", EDAT.block_size); LOG_NOTICE(LOADER, "SDAT file size: 0x%08X", (u64)EDAT.file_size); } // Generate SDAT key. xor_key(key, NPD.dev_hash, SDAT_KEY); } else { if (verbose) { LOG_NOTICE(LOADER, "EDAT HEADER"); LOG_NOTICE(LOADER, "EDAT flags: 0x%08X", EDAT.flags); LOG_NOTICE(LOADER, "EDAT block size: 0x%08X", EDAT.block_size); LOG_NOTICE(LOADER, "EDAT file size: 0x%08X", (u64)EDAT.file_size); } // Perform header validation (EDAT only). char real_file_name[MAX_PATH]; extract_file_name(input_file_name, real_file_name); if (!validate_npd_hashes(real_file_name, devklic, &NPD, verbose)) { // Ignore header validation in DEBUG data. if ((EDAT.flags & EDAT_DEBUG_DATA_FLAG) != EDAT_DEBUG_DATA_FLAG) { LOG_ERROR(LOADER, "EDAT: NPD hash validation failed!"); return 1; } } // Select EDAT key. if ((NPD.license & 0x3) == 0x3) // Type 3: Use supplied devklic. memcpy(key, devklic, 0x10); else if ((NPD.license & 0x2) == 0x2) // Type 2: Use key from RAP file (RIF key). { memcpy(key, rifkey, 0x10); // Make sure we don't have an empty RIF key. int i, test = 0; for (i = 0; i < 0x10; i++) { if (key[i] != 0) { test = 1; break; } } if (!test) { LOG_ERROR(LOADER, "EDAT: A valid RAP file is needed for this EDAT file!"); return 1; } } else if ((NPD.license & 0x1) == 0x1) // Type 1: Use network activation. { LOG_ERROR(LOADER, "EDAT: Network license not supported!"); return 1; } if (verbose) { int i; LOG_NOTICE(LOADER, "DEVKLIC: "); for (i = 0; i < 0x10; i++) LOG_NOTICE(LOADER, "%02X", devklic[i]); LOG_NOTICE(LOADER, "RIF KEY: "); for (i = 0; i < 0x10; i++) LOG_NOTICE(LOADER, "%02X", rifkey[i]); } } if (verbose) { int i; LOG_NOTICE(LOADER, "DECRYPTION KEY: "); for (i = 0; i < 0x10; i++) LOG_NOTICE(LOADER, "%02X", key[i]); } input->seek(0); if (check_data(key, &EDAT, &NPD, input, verbose)) { LOG_ERROR(LOADER, "EDAT: Data parsing failed!"); return 1; } input->seek(0); if (decrypt_data(input, output, &EDAT, &NPD, key, verbose)) { LOG_ERROR(LOADER, "EDAT: Data decryption failed!"); return 1; } return 0; }