int AESContext::cryptCBC(State & state, mbedtls_aes_context * context){ Stack * stack = state.stack; if (stack->is<LUA_TNUMBER>(1) && stack->is<LUA_TSTRING>(2) && stack->is<LUA_TSTRING>(3)){ std::string ivStr = stack->toLString(2); std::string input = stack->toLString(3); size_t length = input.length(); if (((length % 16) == 0) && (ivStr.length() == 16)){ int mode = stack->to<int>(1); unsigned char iv[16]; unsigned char * output = new unsigned char[length]; memcpy(iv, ivStr.c_str(), 16); int result = mbedtls_aes_crypt_cbc(context, mode, length, iv, reinterpret_cast<const unsigned char *>(input.c_str()), output); if (result == 0){ stack->pushLString(std::string(reinterpret_cast<char*>(iv), 16)); stack->pushLString(std::string(reinterpret_cast<char*>(output), length)); delete[] output; return 2; } else{ stack->push<int>(result); delete[] output; return 1; } } else{ stack->push<bool>(false); return 1; } } return 0; }
std::vector<u8> CNANDContentLoader::AESDecode(const u8* key, u8* iv, const u8* src, u32 size) { mbedtls_aes_context aes_ctx; std::vector<u8> buffer(size); mbedtls_aes_setkey_dec(&aes_ctx, key, 128); mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, size, iv, src, buffer.data()); return buffer; }
//AES/CBC/PKCS5Padding //key只能是16、24、32个ASSCII字符组成的串儿 unsigned char* aes_cbc_pkcs5padding_decode(unsigned char *input, size_t inputLength, size_t *outputLength, const char *key) { size_t keyLength = strlen(key); printf("keyLength = %zu\n", keyLength); if (keyLength != 32 && keyLength != 24 && keyLength != 16) { perror("key必须是16、24、32个ASSCII字符组成的串\n"); return NULL; } mbedtls_aes_context aes; //初始向量,一般是一个随机数组成的,长度必须是块大小,一个块是16字节,也就是16个ASCII字符 unsigned char iv[16]; memcpy(iv, key, keyLength); //解密后的数据长度 unsigned char *output = (unsigned char *)calloc(inputLength, sizeof(unsigned char)); //设置加密的key,并初始化 mbedtls_aes_setkey_dec(&aes, (unsigned char*)key, keyLength * 8); //加密数据 mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, inputLength, iv, input, output); int outputLastIndex = inputLength - 1; //取出output最后一个字节,转成数字 unsigned int lastValue = output[outputLastIndex]; printf("lastValue = %d\n", lastValue); if (lastValue > 0 && lastValue <= 16) { int j = outputLastIndex; while(output[j] == lastValue) { j--; } printf("j = %d\n", j); *outputLength = j + 1; outputLastIndex = j; } size_t inputHexLength = 2 * inputLength + 1; char inputHex[inputHexLength]; memset(inputHex, 0, inputHexLength); bytes2HexStr(inputHex, input, inputLength); size_t outputHexLength = 2 * inputLength + 1; char outputHex[outputHexLength]; memset(outputHex, 0, outputHexLength); bytes2HexStr(outputHex, output, inputLength); printf("aesDecode(%s, %s)=%s\n", inputHex, key, outputHex); return output; }
bool CVolumeWiiCrypted::Read(u64 _ReadOffset, u64 _Length, u8* _pBuffer, bool decrypt) const { if (m_pReader == nullptr) return false; if (!decrypt) return m_pReader->Read(_ReadOffset, _Length, _pBuffer); FileMon::FindFilename(_ReadOffset); std::vector<u8> read_buffer(s_block_total_size); while (_Length > 0) { // Calculate block offset u64 Block = _ReadOffset / s_block_data_size; u64 Offset = _ReadOffset % s_block_data_size; if (m_LastDecryptedBlockOffset != Block) { // Read the current block if (!m_pReader->Read(m_VolumeOffset + m_dataOffset + Block * s_block_total_size, s_block_total_size, read_buffer.data())) return false; // Decrypt the block's data. // 0x3D0 - 0x3DF in m_pBuffer will be overwritten, // but that won't affect anything, because we won't // use the content of m_pBuffer anymore after this mbedtls_aes_crypt_cbc(m_AES_ctx.get(), MBEDTLS_AES_DECRYPT, s_block_data_size, &read_buffer[0x3D0], &read_buffer[s_block_header_size], m_LastDecryptedBlock); m_LastDecryptedBlockOffset = Block; // The only thing we currently use from the 0x000 - 0x3FF part // of the block is the IV (at 0x3D0), but it also contains SHA-1 // hashes that IOS uses to check that discs aren't tampered with. // http://wiibrew.org/wiki/Wii_Disc#Encrypted } // Copy the decrypted data u64 MaxSizeToCopy = s_block_data_size - Offset; u64 CopySize = (_Length > MaxSizeToCopy) ? MaxSizeToCopy : _Length; memcpy(_pBuffer, &m_LastDecryptedBlock[Offset], (size_t)CopySize); // Update offsets _Length -= CopySize; _pBuffer += CopySize; _ReadOffset += CopySize; } return true; }
int compute_cmac_( mbedtls_aes_context *ctx, const unsigned char *input, size_t length, unsigned char param, unsigned char mac[16] ) { unsigned char buf[16], iv[16]; memset(buf, 0, sizeof(buf)); buf[15] = param; memset(iv, 0, sizeof(iv)); length += 16; unsigned char pad[16]; memset(pad, 0, sizeof(pad)); mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, pad, pad); gf128_double_(pad); if (length & 15) { gf128_double_(pad); pad[length & 15] ^= 0x80; } const unsigned char *tmp_input = buf; while (length > 16) { mbedtls_aes_crypt_cbc(ctx, MBEDTLS_AES_ENCRYPT, 16, iv, tmp_input, buf); if (tmp_input == buf) { tmp_input = input; } else { tmp_input += 16; } length -= 16; } size_t i; for (i = 0; i < length; i++) pad[i] ^= tmp_input[i]; mbedtls_aes_crypt_cbc(ctx, MBEDTLS_AES_ENCRYPT, 16, iv, pad, mac); return 0; }
bool mgos_vfs_fs_spiffs_decrypt_block(spiffs_obj_id obj_id, uint32_t offset, void *data, uint32_t len) { if (len % 16 != 0) return false; uint8_t *p = (uint8_t *) data; while (len > 0) { uint32_t iv[4] = {0xdeadbeef, obj_id, 0x900df00d, offset}; if (mbedtls_aes_crypt_cbc(&s_aes_ctx_dec, MBEDTLS_AES_DECRYPT, 16, (uint8_t *) iv, p, p) != 0) { return false; } p += 16; len -= 16; offset += 16; } return true; }
void VolumeKeyForPartition(IBlobReader& _rReader, u64 offset, u8* VolumeKey) { CBlobBigEndianReader Reader(_rReader); u8 SubKey[16]; _rReader.Read(offset + 0x1bf, 16, SubKey); u8 IV[16]; memset(IV, 0, 16); _rReader.Read(offset + 0x44c, 8, IV); bool usingKoreanKey = false; // Issue: 6813 // Magic value is at partition's offset + 0x1f1 (1byte) // If encrypted with the Korean key, the magic value would be 1 // Otherwise it is zero if (Reader.Read8(0x3) == 'K' && Reader.Read8(offset + 0x1f1) == 1) usingKoreanKey = true; mbedtls_aes_context AES_ctx; mbedtls_aes_setkey_dec(&AES_ctx, (usingKoreanKey ? s_master_key_korean : s_master_key), 128); mbedtls_aes_crypt_cbc(&AES_ctx, MBEDTLS_AES_DECRYPT, 16, IV, SubKey, VolumeKey); }
IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) { s32 return_error_code = IPC_SUCCESS; switch (request.request) { case IOCTL_WFSI_IMPORT_TITLE_INIT: { u32 tmd_addr = Memory::Read_U32(request.buffer_in); u32 tmd_size = Memory::Read_U32(request.buffer_in + 4); m_patch_type = static_cast<PatchType>(Memory::Read_U32(request.buffer_in + 32)); m_continue_install = Memory::Read_U32(request.buffer_in + 36); INFO_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE_INIT: patch type %d, continue install: %s", m_patch_type, m_continue_install ? "true" : "false"); if (m_patch_type == PatchType::PATCH_TYPE_2) { const std::string content_dir = StringFromFormat("/vol/%s/title/%s/%s/content", m_device_name.c_str(), m_current_group_id_str.c_str(), m_current_title_id_str.c_str()); File::Rename(WFS::NativePath(content_dir + "/default.dol"), WFS::NativePath(content_dir + "/_default.dol")); } if (!IOS::ES::IsValidTMDSize(tmd_size)) { ERROR_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE_INIT: TMD size too large (%d)", tmd_size); return_error_code = IPC_EINVAL; break; } std::vector<u8> tmd_bytes; tmd_bytes.resize(tmd_size); Memory::CopyFromEmu(tmd_bytes.data(), tmd_addr, tmd_size); m_tmd.SetBytes(std::move(tmd_bytes)); IOS::ES::TicketReader ticket = m_ios.GetES()->FindSignedTicket(m_tmd.GetTitleId()); if (!ticket.IsValid()) { return_error_code = -11028; break; } memcpy(m_aes_key, ticket.GetTitleKey(m_ios.GetIOSC()).data(), sizeof(m_aes_key)); mbedtls_aes_setkey_dec(&m_aes_ctx, m_aes_key, 128); SetImportTitleIdAndGroupId(m_tmd.GetTitleId(), m_tmd.GetGroupId()); if (m_patch_type == PatchType::PATCH_TYPE_1) CancelPatchImport(m_continue_install); else if (m_patch_type == PatchType::NOT_A_PATCH) CancelTitleImport(m_continue_install); break; } case IOCTL_WFSI_PREPARE_PROFILE: m_base_extract_path = StringFromFormat("/vol/%s/tmp/", m_device_name.c_str()); // Fall through intended. case IOCTL_WFSI_PREPARE_CONTENT: { const char* ioctl_name = request.request == IOCTL_WFSI_PREPARE_PROFILE ? "IOCTL_WFSI_PREPARE_PROFILE" : "IOCTL_WFSI_PREPARE_CONTENT"; // Initializes the IV from the index of the content in the TMD contents. u32 content_id = Memory::Read_U32(request.buffer_in + 8); IOS::ES::Content content_info; if (!m_tmd.FindContentById(content_id, &content_info)) { WARN_LOG(IOS_WFS, "%s: Content id %08x not found", ioctl_name, content_id); return_error_code = -10003; break; } memset(m_aes_iv, 0, sizeof(m_aes_iv)); m_aes_iv[0] = content_info.index >> 8; m_aes_iv[1] = content_info.index & 0xFF; INFO_LOG(IOS_WFS, "%s: Content id %08x found at index %d", ioctl_name, content_id, content_info.index); m_arc_unpacker.Reset(); break; } case IOCTL_WFSI_IMPORT_PROFILE: case IOCTL_WFSI_IMPORT_CONTENT: { const char* ioctl_name = request.request == IOCTL_WFSI_IMPORT_PROFILE ? "IOCTL_WFSI_IMPORT_PROFILE" : "IOCTL_WFSI_IMPORT_CONTENT"; u32 content_id = Memory::Read_U32(request.buffer_in + 0xC); u32 input_ptr = Memory::Read_U32(request.buffer_in + 0x10); u32 input_size = Memory::Read_U32(request.buffer_in + 0x14); INFO_LOG(IOS_WFS, "%s: %08x bytes of data at %08x from content id %d", ioctl_name, input_size, input_ptr, content_id); std::vector<u8> decrypted(input_size); mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, input_size, m_aes_iv, Memory::GetPointer(input_ptr), decrypted.data()); m_arc_unpacker.AddBytes(decrypted); break; } case IOCTL_WFSI_IMPORT_CONTENT_END: case IOCTL_WFSI_IMPORT_PROFILE_END: { const char* ioctl_name = request.request == IOCTL_WFSI_IMPORT_PROFILE_END ? "IOCTL_WFSI_IMPORT_PROFILE_END" : "IOCTL_WFSI_IMPORT_CONTENT_END"; INFO_LOG(IOS_WFS, "%s", ioctl_name); auto callback = [this](const std::string& filename, const std::vector<u8>& bytes) { INFO_LOG(IOS_WFS, "Extract: %s (%zd bytes)", filename.c_str(), bytes.size()); std::string path = WFS::NativePath(m_base_extract_path + "/" + filename); File::CreateFullPath(path); File::IOFile f(path, "wb"); if (!f) { ERROR_LOG(IOS_WFS, "Could not extract %s to %s", filename.c_str(), path.c_str()); return; } f.WriteBytes(bytes.data(), bytes.size()); }; m_arc_unpacker.Extract(callback); // Technically not needed, but let's not keep large buffers in RAM for no // reason if we can avoid it. m_arc_unpacker.Reset(); break; } case IOCTL_WFSI_FINALIZE_TITLE_INSTALL: { std::string tmd_path; if (m_patch_type == NOT_A_PATCH) { std::string title_install_dir = StringFromFormat("/vol/%s/_install/%s", m_device_name.c_str(), m_import_title_id_str.c_str()); std::string title_final_dir = StringFromFormat("/vol/%s/title/%s/%s", m_device_name.c_str(), m_import_group_id_str.c_str(), m_import_title_id_str.c_str()); File::Rename(WFS::NativePath(title_install_dir), WFS::NativePath(title_final_dir)); tmd_path = StringFromFormat("/vol/%s/title/%s/%s/meta/%016" PRIx64 ".tmd", m_device_name.c_str(), m_import_group_id_str.c_str(), m_import_title_id_str.c_str(), m_import_title_id); } else { std::string patch_dir = StringFromFormat("/vol/%s/title/%s/%s/_patch", m_device_name.c_str(), m_current_group_id_str.c_str(), m_current_title_id_str.c_str()); File::DeleteDirRecursively(WFS::NativePath(patch_dir)); tmd_path = StringFromFormat("/vol/%s/title/%s/%s/meta/%016" PRIx64 ".tmd", m_device_name.c_str(), m_current_group_id_str.c_str(), m_current_title_id_str.c_str(), m_import_title_id); } File::IOFile tmd_file(WFS::NativePath(tmd_path), "wb"); tmd_file.WriteBytes(m_tmd.GetBytes().data(), m_tmd.GetBytes().size()); break; } case IOCTL_WFSI_FINALIZE_PATCH_INSTALL: { INFO_LOG(IOS_WFS, "IOCTL_WFSI_FINALIZE_PATCH_INSTALL"); if (m_patch_type != NOT_A_PATCH) { std::string current_title_dir = StringFromFormat("/vol/%s/title/%s/%s", m_device_name.c_str(), m_current_group_id_str.c_str(), m_current_title_id_str.c_str()); std::string patch_dir = current_title_dir + "/_patch"; File::CopyDir(WFS::NativePath(patch_dir), WFS::NativePath(current_title_dir), true); } break; } case IOCTL_WFSI_DELETE_TITLE: // Bytes 0-4: ?? // Bytes 4-8: game id // Bytes 1c-1e: title id? WARN_LOG(IOS_WFS, "IOCTL_WFSI_DELETE_TITLE: unimplemented"); break; case IOCTL_WFSI_GET_VERSION: INFO_LOG(IOS_WFS, "IOCTL_WFSI_GET_VERSION"); Memory::Write_U32(0x20, request.buffer_out); break; case IOCTL_WFSI_IMPORT_TITLE_CANCEL: { INFO_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE_CANCEL"); bool continue_install = Memory::Read_U32(request.buffer_in) != 0; if (m_patch_type == PatchType::NOT_A_PATCH) return_error_code = CancelTitleImport(continue_install); else if (m_patch_type == PatchType::PATCH_TYPE_1 || m_patch_type == PatchType::PATCH_TYPE_2) return_error_code = CancelPatchImport(continue_install); else return_error_code = WFS_EINVAL; m_tmd = {}; break; } case IOCTL_WFSI_INIT: { INFO_LOG(IOS_WFS, "IOCTL_WFSI_INIT"); u64 tid; if (GetIOS()->GetES()->GetTitleId(&tid) < 0) { ERROR_LOG(IOS_WFS, "IOCTL_WFSI_INIT: Could not get title id."); return_error_code = IPC_EINVAL; break; } IOS::ES::TMDReader tmd = GetIOS()->GetES()->FindInstalledTMD(tid); SetCurrentTitleIdAndGroupId(tmd.GetTitleId(), tmd.GetGroupId()); break; } case IOCTL_WFSI_SET_DEVICE_NAME: INFO_LOG(IOS_WFS, "IOCTL_WFSI_SET_DEVICE_NAME"); m_device_name = Memory::GetString(request.buffer_in); break; case IOCTL_WFSI_APPLY_TITLE_PROFILE: { INFO_LOG(IOS_WFS, "IOCTL_WFSI_APPLY_TITLE_PROFILE"); if (m_patch_type == NOT_A_PATCH) { std::string install_directory = StringFromFormat("/vol/%s/_install", m_device_name.c_str()); if (!m_continue_install && File::IsDirectory(WFS::NativePath(install_directory))) { File::DeleteDirRecursively(WFS::NativePath(install_directory)); } m_base_extract_path = StringFromFormat("%s/%s/content", install_directory.c_str(), m_import_title_id_str.c_str()); File::CreateFullPath(WFS::NativePath(m_base_extract_path)); File::CreateDir(WFS::NativePath(m_base_extract_path)); for (auto dir : {"work", "meta", "save"}) { std::string path = StringFromFormat("%s/%s/%s", install_directory.c_str(), m_import_title_id_str.c_str(), dir); File::CreateDir(WFS::NativePath(path)); } std::string group_path = StringFromFormat("/vol/%s/title/%s", m_device_name.c_str(), m_import_group_id_str.c_str()); File::CreateFullPath(WFS::NativePath(group_path)); File::CreateDir(WFS::NativePath(group_path)); } else { m_base_extract_path = StringFromFormat("/vol/%s/title/%s/%s/_patch/content", m_device_name.c_str(), m_current_group_id_str.c_str(), m_current_title_id_str.c_str()); File::CreateFullPath(WFS::NativePath(m_base_extract_path)); File::CreateDir(WFS::NativePath(m_base_extract_path)); } break; } case IOCTL_WFSI_GET_TMD: { u64 subtitle_id = Memory::Read_U64(request.buffer_in); u32 address = Memory::Read_U32(request.buffer_in + 24); INFO_LOG(IOS_WFS, "IOCTL_WFSI_GET_TMD: subtitle ID %016" PRIx64, subtitle_id); u32 tmd_size; return_error_code = GetTmd(m_current_group_id, m_current_title_id, subtitle_id, address, &tmd_size); Memory::Write_U32(tmd_size, request.buffer_out); break; } case IOCTL_WFSI_GET_TMD_ABSOLUTE: { u64 subtitle_id = Memory::Read_U64(request.buffer_in); u32 address = Memory::Read_U32(request.buffer_in + 24); u16 group_id = Memory::Read_U16(request.buffer_in + 36); u32 title_id = Memory::Read_U32(request.buffer_in + 32); INFO_LOG(IOS_WFS, "IOCTL_WFSI_GET_TMD_ABSOLUTE: tid %08x, gid %04x, subtitle ID %016" PRIx64, title_id, group_id, subtitle_id); u32 tmd_size; return_error_code = GetTmd(group_id, title_id, subtitle_id, address, &tmd_size); Memory::Write_U32(tmd_size, request.buffer_out); break; } case IOCTL_WFSI_SET_FST_BUFFER: { INFO_LOG(IOS_WFS, "IOCTL_WFSI_SET_FST_BUFFER: address %08x, size %08x", request.buffer_in, request.buffer_in_size); break; } case IOCTL_WFSI_NOOP: break; case IOCTL_WFSI_LOAD_DOL: { std::string path = StringFromFormat("/vol/%s/title/%s/%s/content", m_device_name.c_str(), m_current_group_id_str.c_str(), m_current_title_id_str.c_str()); u32 dol_addr = Memory::Read_U32(request.buffer_in + 0x18); u32 max_dol_size = Memory::Read_U32(request.buffer_in + 0x14); u16 dol_extension_id = Memory::Read_U16(request.buffer_in + 0x1e); if (dol_extension_id == 0) { path += "/default.dol"; } else { path += StringFromFormat("/extension%d.dol", dol_extension_id); } INFO_LOG(IOS_WFS, "IOCTL_WFSI_LOAD_DOL: loading %s at address %08x (size %d)", path.c_str(), dol_addr, max_dol_size); File::IOFile fp(WFS::NativePath(path), "rb"); if (!fp) { WARN_LOG(IOS_WFS, "IOCTL_WFSI_LOAD_DOL: no such file or directory: %s", path.c_str()); return_error_code = WFS_ENOENT; break; } u32 real_dol_size = fp.GetSize(); if (dol_addr == 0) { // Write the expected size to the size parameter, in the input. Memory::Write_U32(real_dol_size, request.buffer_in + 0x14); } else { fp.ReadBytes(Memory::GetPointer(dol_addr), max_dol_size); } Memory::Write_U32(real_dol_size, request.buffer_out); break; } case IOCTL_WFSI_CHECK_HAS_SPACE: WARN_LOG(IOS_WFS, "IOCTL_WFSI_CHECK_HAS_SPACE: returning true"); // TODO(wfs): implement this properly. // 1 is returned if there is free space, 0 otherwise. // // WFSI builds a path depending on the import state // /vol/VOLUME_ID/title/GROUP_ID/GAME_ID // /vol/VOLUME_ID/_install/GAME_ID // then removes everything after the last path separator ('/') // it then calls WFSISrvGetFreeBlkNum (ioctl 0x5a, aliased to 0x5b) with that path. // If the ioctl fails, WFSI returns 0. // If the ioctl succeeds, WFSI returns 0 or 1 depending on the three u32s in the input buffer // and the three u32s returned by WFSSRV (TODO: figure out what it does) return_error_code = 1; break; default: // TODO(wfs): Should be returning an error. However until we have // everything properly stubbed it's easier to simulate the methods // succeeding. request.DumpUnknown(GetDeviceName(), LogTypes::IOS, LogTypes::LWARNING); Memory::Memset(request.buffer_out, 0, request.buffer_out_size); break; } return GetDefaultReply(return_error_code); }
int main( int argc, char *argv[] ) { int i; unsigned char tmp[200]; char title[TITLE_LEN]; todo_list todo; #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) unsigned char alloc_buf[HEAP_SIZE] = { 0 }; #endif if( argc <= 1 ) { memset( &todo, 1, sizeof( todo ) ); } else { memset( &todo, 0, sizeof( todo ) ); for( i = 1; i < argc; i++ ) { if( strcmp( argv[i], "md4" ) == 0 ) todo.md4 = 1; else if( strcmp( argv[i], "md5" ) == 0 ) todo.md5 = 1; else if( strcmp( argv[i], "ripemd160" ) == 0 ) todo.ripemd160 = 1; else if( strcmp( argv[i], "sha1" ) == 0 ) todo.sha1 = 1; else if( strcmp( argv[i], "sha256" ) == 0 ) todo.sha256 = 1; else if( strcmp( argv[i], "sha512" ) == 0 ) todo.sha512 = 1; else if( strcmp( argv[i], "arc4" ) == 0 ) todo.arc4 = 1; else if( strcmp( argv[i], "des3" ) == 0 ) todo.des3 = 1; else if( strcmp( argv[i], "des" ) == 0 ) todo.des = 1; else if( strcmp( argv[i], "aes_cbc" ) == 0 ) todo.aes_cbc = 1; else if( strcmp( argv[i], "aes_gcm" ) == 0 ) todo.aes_gcm = 1; else if( strcmp( argv[i], "aes_ccm" ) == 0 ) todo.aes_ccm = 1; else if( strcmp( argv[i], "aes_cmac" ) == 0 ) todo.aes_cmac = 1; else if( strcmp( argv[i], "des3_cmac" ) == 0 ) todo.des3_cmac = 1; else if( strcmp( argv[i], "camellia" ) == 0 ) todo.camellia = 1; else if( strcmp( argv[i], "blowfish" ) == 0 ) todo.blowfish = 1; else if( strcmp( argv[i], "havege" ) == 0 ) todo.havege = 1; else if( strcmp( argv[i], "ctr_drbg" ) == 0 ) todo.ctr_drbg = 1; else if( strcmp( argv[i], "hmac_drbg" ) == 0 ) todo.hmac_drbg = 1; else if( strcmp( argv[i], "rsa" ) == 0 ) todo.rsa = 1; else if( strcmp( argv[i], "dhm" ) == 0 ) todo.dhm = 1; else if( strcmp( argv[i], "ecdsa" ) == 0 ) todo.ecdsa = 1; else if( strcmp( argv[i], "ecdh" ) == 0 ) todo.ecdh = 1; else { mbedtls_printf( "Unrecognized option: %s\n", argv[i] ); mbedtls_printf( "Available options: " OPTIONS ); } } } mbedtls_printf( "\n" ); #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) mbedtls_memory_buffer_alloc_init( alloc_buf, sizeof( alloc_buf ) ); #endif memset( buf, 0xAA, sizeof( buf ) ); memset( tmp, 0xBB, sizeof( tmp ) ); #if defined(MBEDTLS_MD4_C) if( todo.md4 ) TIME_AND_TSC( "MD4", mbedtls_md4_ret( buf, BUFSIZE, tmp ) ); #endif #if defined(MBEDTLS_MD5_C) if( todo.md5 ) TIME_AND_TSC( "MD5", mbedtls_md5_ret( buf, BUFSIZE, tmp ) ); #endif #if defined(MBEDTLS_RIPEMD160_C) if( todo.ripemd160 ) TIME_AND_TSC( "RIPEMD160", mbedtls_ripemd160_ret( buf, BUFSIZE, tmp ) ); #endif #if defined(MBEDTLS_SHA1_C) if( todo.sha1 ) TIME_AND_TSC( "SHA-1", mbedtls_sha1_ret( buf, BUFSIZE, tmp ) ); #endif #if defined(MBEDTLS_SHA256_C) if( todo.sha256 ) TIME_AND_TSC( "SHA-256", mbedtls_sha256_ret( buf, BUFSIZE, tmp, 0 ) ); #endif #if defined(MBEDTLS_SHA512_C) if( todo.sha512 ) TIME_AND_TSC( "SHA-512", mbedtls_sha512_ret( buf, BUFSIZE, tmp, 0 ) ); #endif #if defined(MBEDTLS_ARC4_C) if( todo.arc4 ) { mbedtls_arc4_context arc4; mbedtls_arc4_init( &arc4 ); mbedtls_arc4_setup( &arc4, tmp, 32 ); TIME_AND_TSC( "ARC4", mbedtls_arc4_crypt( &arc4, BUFSIZE, buf, buf ) ); mbedtls_arc4_free( &arc4 ); } #endif #if defined(MBEDTLS_DES_C) #if defined(MBEDTLS_CIPHER_MODE_CBC) if( todo.des3 ) { mbedtls_des3_context des3; mbedtls_des3_init( &des3 ); mbedtls_des3_set3key_enc( &des3, tmp ); TIME_AND_TSC( "3DES", mbedtls_des3_crypt_cbc( &des3, MBEDTLS_DES_ENCRYPT, BUFSIZE, tmp, buf, buf ) ); mbedtls_des3_free( &des3 ); } if( todo.des ) { mbedtls_des_context des; mbedtls_des_init( &des ); mbedtls_des_setkey_enc( &des, tmp ); TIME_AND_TSC( "DES", mbedtls_des_crypt_cbc( &des, MBEDTLS_DES_ENCRYPT, BUFSIZE, tmp, buf, buf ) ); mbedtls_des_free( &des ); } #endif /* MBEDTLS_CIPHER_MODE_CBC */ #if defined(MBEDTLS_CMAC_C) if( todo.des3_cmac ) { unsigned char output[8]; const mbedtls_cipher_info_t *cipher_info; memset( buf, 0, sizeof( buf ) ); memset( tmp, 0, sizeof( tmp ) ); cipher_info = mbedtls_cipher_info_from_type( MBEDTLS_CIPHER_DES_EDE3_ECB ); TIME_AND_TSC( "3DES-CMAC", mbedtls_cipher_cmac( cipher_info, tmp, 192, buf, BUFSIZE, output ) ); } #endif /* MBEDTLS_CMAC_C */ #endif /* MBEDTLS_DES_C */ #if defined(MBEDTLS_AES_C) #if defined(MBEDTLS_CIPHER_MODE_CBC) if( todo.aes_cbc ) { int keysize; mbedtls_aes_context aes; mbedtls_aes_init( &aes ); for( keysize = 128; keysize <= 256; keysize += 64 ) { mbedtls_snprintf( title, sizeof( title ), "AES-CBC-%d", keysize ); memset( buf, 0, sizeof( buf ) ); memset( tmp, 0, sizeof( tmp ) ); mbedtls_aes_setkey_enc( &aes, tmp, keysize ); TIME_AND_TSC( title, mbedtls_aes_crypt_cbc( &aes, MBEDTLS_AES_ENCRYPT, BUFSIZE, tmp, buf, buf ) ); } mbedtls_aes_free( &aes ); } #endif #if defined(MBEDTLS_GCM_C) if( todo.aes_gcm ) { int keysize; mbedtls_gcm_context gcm; mbedtls_gcm_init( &gcm ); for( keysize = 128; keysize <= 256; keysize += 64 ) { mbedtls_snprintf( title, sizeof( title ), "AES-GCM-%d", keysize ); memset( buf, 0, sizeof( buf ) ); memset( tmp, 0, sizeof( tmp ) ); mbedtls_gcm_setkey( &gcm, MBEDTLS_CIPHER_ID_AES, tmp, keysize ); TIME_AND_TSC( title, mbedtls_gcm_crypt_and_tag( &gcm, MBEDTLS_GCM_ENCRYPT, BUFSIZE, tmp, 12, NULL, 0, buf, buf, 16, tmp ) ); mbedtls_gcm_free( &gcm ); } } #endif #if defined(MBEDTLS_CCM_C) if( todo.aes_ccm ) { int keysize; mbedtls_ccm_context ccm; mbedtls_ccm_init( &ccm ); for( keysize = 128; keysize <= 256; keysize += 64 ) { mbedtls_snprintf( title, sizeof( title ), "AES-CCM-%d", keysize ); memset( buf, 0, sizeof( buf ) ); memset( tmp, 0, sizeof( tmp ) ); mbedtls_ccm_setkey( &ccm, MBEDTLS_CIPHER_ID_AES, tmp, keysize ); TIME_AND_TSC( title, mbedtls_ccm_encrypt_and_tag( &ccm, BUFSIZE, tmp, 12, NULL, 0, buf, buf, tmp, 16 ) ); mbedtls_ccm_free( &ccm ); } } #endif #if defined(MBEDTLS_CMAC_C) if( todo.aes_cmac ) { unsigned char output[16]; const mbedtls_cipher_info_t *cipher_info; mbedtls_cipher_type_t cipher_type; int keysize; for( keysize = 128, cipher_type = MBEDTLS_CIPHER_AES_128_ECB; keysize <= 256; keysize += 64, cipher_type++ ) { mbedtls_snprintf( title, sizeof( title ), "AES-CMAC-%d", keysize ); memset( buf, 0, sizeof( buf ) ); memset( tmp, 0, sizeof( tmp ) ); cipher_info = mbedtls_cipher_info_from_type( cipher_type ); TIME_AND_TSC( title, mbedtls_cipher_cmac( cipher_info, tmp, keysize, buf, BUFSIZE, output ) ); } memset( buf, 0, sizeof( buf ) ); memset( tmp, 0, sizeof( tmp ) ); TIME_AND_TSC( "AES-CMAC-PRF-128", mbedtls_aes_cmac_prf_128( tmp, 16, buf, BUFSIZE, output ) ); } #endif /* MBEDTLS_CMAC_C */ #endif /* MBEDTLS_AES_C */ #if defined(MBEDTLS_CAMELLIA_C) && defined(MBEDTLS_CIPHER_MODE_CBC) if( todo.camellia ) { int keysize; mbedtls_camellia_context camellia; mbedtls_camellia_init( &camellia ); for( keysize = 128; keysize <= 256; keysize += 64 ) { mbedtls_snprintf( title, sizeof( title ), "CAMELLIA-CBC-%d", keysize ); memset( buf, 0, sizeof( buf ) ); memset( tmp, 0, sizeof( tmp ) ); mbedtls_camellia_setkey_enc( &camellia, tmp, keysize ); TIME_AND_TSC( title, mbedtls_camellia_crypt_cbc( &camellia, MBEDTLS_CAMELLIA_ENCRYPT, BUFSIZE, tmp, buf, buf ) ); } mbedtls_camellia_free( &camellia ); } #endif #if defined(MBEDTLS_BLOWFISH_C) && defined(MBEDTLS_CIPHER_MODE_CBC) if( todo.blowfish ) { int keysize; mbedtls_blowfish_context blowfish; mbedtls_blowfish_init( &blowfish ); for( keysize = 128; keysize <= 256; keysize += 64 ) { mbedtls_snprintf( title, sizeof( title ), "BLOWFISH-CBC-%d", keysize ); memset( buf, 0, sizeof( buf ) ); memset( tmp, 0, sizeof( tmp ) ); mbedtls_blowfish_setkey( &blowfish, tmp, keysize ); TIME_AND_TSC( title, mbedtls_blowfish_crypt_cbc( &blowfish, MBEDTLS_BLOWFISH_ENCRYPT, BUFSIZE, tmp, buf, buf ) ); } mbedtls_blowfish_free( &blowfish ); } #endif #if defined(MBEDTLS_HAVEGE_C) if( todo.havege ) { mbedtls_havege_state hs; mbedtls_havege_init( &hs ); TIME_AND_TSC( "HAVEGE", mbedtls_havege_random( &hs, buf, BUFSIZE ) ); mbedtls_havege_free( &hs ); } #endif #if defined(MBEDTLS_CTR_DRBG_C) if( todo.ctr_drbg ) { mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ctr_drbg_init( &ctr_drbg ); if( mbedtls_ctr_drbg_seed( &ctr_drbg, myrand, NULL, NULL, 0 ) != 0 ) mbedtls_exit(1); TIME_AND_TSC( "CTR_DRBG (NOPR)", if( mbedtls_ctr_drbg_random( &ctr_drbg, buf, BUFSIZE ) != 0 ) mbedtls_exit(1) ); if( mbedtls_ctr_drbg_seed( &ctr_drbg, myrand, NULL, NULL, 0 ) != 0 ) mbedtls_exit(1); mbedtls_ctr_drbg_set_prediction_resistance( &ctr_drbg, MBEDTLS_CTR_DRBG_PR_ON ); TIME_AND_TSC( "CTR_DRBG (PR)", if( mbedtls_ctr_drbg_random( &ctr_drbg, buf, BUFSIZE ) != 0 ) mbedtls_exit(1) ); mbedtls_ctr_drbg_free( &ctr_drbg ); }
static NO_INLINE JsVar *jswrap_crypto_AEScrypt(JsVar *message, JsVar *key, JsVar *options, bool encrypt) { int err; unsigned char iv[16]; // initialisation vector memset(iv, 0, 16); CryptoMode mode = CM_CBC; if (jsvIsObject(options)) { JsVar *ivVar = jsvObjectGetChild(options, "iv", 0); if (ivVar) { jsvIterateCallbackToBytes(ivVar, iv, sizeof(iv)); jsvUnLock(ivVar); } JsVar *modeVar = jsvObjectGetChild(options, "mode", 0); if (!jsvIsUndefined(modeVar)) mode = jswrap_crypto_getMode(modeVar); jsvUnLock(modeVar); if (mode == CM_NONE) return 0; } else if (!jsvIsUndefined(options)) { jsError("'options' must be undefined, or an Object"); return 0; } mbedtls_aes_context aes; mbedtls_aes_init( &aes ); JSV_GET_AS_CHAR_ARRAY(messagePtr, messageLen, message); if (!messagePtr) return 0; JSV_GET_AS_CHAR_ARRAY(keyPtr, keyLen, key); if (!keyPtr) return 0; if (encrypt) err = mbedtls_aes_setkey_enc( &aes, (unsigned char*)keyPtr, (unsigned int)keyLen*8 ); else err = mbedtls_aes_setkey_dec( &aes, (unsigned char*)keyPtr, (unsigned int)keyLen*8 ); if (err) { jswrap_crypto_error(err); return 0; } char *outPtr = 0; JsVar *outVar = jsvNewArrayBufferWithPtr((unsigned int)messageLen, &outPtr); if (!outPtr) { jsError("Not enough memory for result"); return 0; } switch (mode) { case CM_CBC: err = mbedtls_aes_crypt_cbc( &aes, encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT, messageLen, iv, (unsigned char*)messagePtr, (unsigned char*)outPtr ); break; case CM_CFB: err = mbedtls_aes_crypt_cfb8( &aes, encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT, messageLen, iv, (unsigned char*)messagePtr, (unsigned char*)outPtr ); break; case CM_CTR: { size_t nc_off = 0; unsigned char nonce_counter[16]; unsigned char stream_block[16]; memset(nonce_counter, 0, sizeof(nonce_counter)); memset(stream_block, 0, sizeof(stream_block)); err = mbedtls_aes_crypt_ctr( &aes, messageLen, &nc_off, nonce_counter, stream_block, (unsigned char*)messagePtr, (unsigned char*)outPtr ); break; } case CM_ECB: { size_t i = 0; while (!err && i+15 < messageLen) { err = mbedtls_aes_crypt_ecb( &aes, encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT, (unsigned char*)&messagePtr[i], (unsigned char*)&outPtr[i] ); i += 16; } break; } default: err = MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE; break; } mbedtls_aes_free( &aes ); if (!err) { return outVar; } else { jswrap_crypto_error(err); jsvUnLock(outVar); return 0; } }
//AES/CBC/PKCS5Padding //input可以是任意长度 //key只能是16、24、32个ASSCII字符组成的串儿 unsigned char* aes_cbc_pkcs5padding_encode(const char *input, const char *key, size_t *outputLength) { size_t keyLength = strlen(key); printf("keyLength = %zu\n", keyLength); if (keyLength != 32 && keyLength != 24 && keyLength != 16) { perror("key必须是16、24、32个ASSCII字符组成的串\n"); return NULL; } mbedtls_aes_context aes; //获取到输入的要加密的内容的长度 size_t inputLength = strlen(input); printf("input = %s, inputLength = %zu\n", input, inputLength); //看看需要分成多少个块,即使输入的数据是16的整数倍,也要补充16个字节的整数16 size_t n = inputLength / 16 + 1; //https://tools.ietf.org/html/rfc8018#appendix-B.2.5 int padding = 16 - inputLength % 8; //用于加密的的数据长度:字节数,此字节数正好等于输出的字节数 int needInputLength = 16 * n; *outputLength = needInputLength; //初始向量,一般是一个随机数组成的,长度必须是块大小,一个块是16字节,也就是16个ASCII字符 unsigned char iv[16]; memcpy(iv, key, keyLength); unsigned char *toBeEncryptBytes = (unsigned char *)calloc(needInputLength + 1, sizeof(unsigned char)); memcpy(toBeEncryptBytes, (unsigned char *)input, inputLength); //填充数据 for (int i = 0; i < padding; i++) { toBeEncryptBytes[inputLength + i] = padding; } toBeEncryptBytes[needInputLength] = '\0'; //加密后的数据长度 unsigned char *output = (unsigned char *)calloc(needInputLength, sizeof(unsigned char)); //设置加密的key,并初始化 mbedtls_aes_setkey_enc(&aes, (unsigned char*)key, keyLength * 8); //加密数据 mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, needInputLength, iv, toBeEncryptBytes, output); char outputHex[ 2 * needInputLength + 1]; memset(outputHex, 0, 2 * needInputLength + 1); bytes2HexStr(outputHex, output, needInputLength); printf("aesEncode(%s, %s)=%s\n", toBeEncryptBytes, key, outputHex); if (NULL != toBeEncryptBytes) { free(toBeEncryptBytes); toBeEncryptBytes = NULL; } return output; }
static int aes_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, size_t length, unsigned char *iv, const unsigned char *input, unsigned char *output ) { return mbedtls_aes_crypt_cbc( (mbedtls_aes_context *) ctx, operation, length, iv, input, output ); }
bool CVolumeWiiCrypted::CheckIntegrity() const { // Get partition data size u32 partSizeDiv4; Read(m_VolumeOffset + 0x2BC, 4, (u8*)&partSizeDiv4, false); u64 partDataSize = (u64)Common::swap32(partSizeDiv4) * 4; u32 nClusters = (u32)(partDataSize / 0x8000); for (u32 clusterID = 0; clusterID < nClusters; ++clusterID) { u64 clusterOff = m_VolumeOffset + m_dataOffset + (u64)clusterID * 0x8000; // Read and decrypt the cluster metadata u8 clusterMDCrypted[0x400]; u8 clusterMD[0x400]; u8 IV[16] = {0}; if (!m_pReader->Read(clusterOff, 0x400, clusterMDCrypted)) { NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: could not read metadata", clusterID); return false; } mbedtls_aes_crypt_cbc(m_AES_ctx.get(), MBEDTLS_AES_DECRYPT, 0x400, IV, clusterMDCrypted, clusterMD); // Some clusters have invalid data and metadata because they aren't // meant to be read by the game (for example, holes between files). To // try to avoid reporting errors because of these clusters, we check // the 0x00 paddings in the metadata. // // This may cause some false negatives though: some bad clusters may be // skipped because they are *too* bad and are not even recognized as // valid clusters. To be improved. bool meaningless = false; for (u32 idx = 0x26C; idx < 0x280; ++idx) if (clusterMD[idx] != 0) meaningless = true; if (meaningless) continue; u8 clusterData[0x7C00]; if (!Read((u64)clusterID * 0x7C00, 0x7C00, clusterData, true)) { NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: could not read data", clusterID); return false; } for (u32 hashID = 0; hashID < 31; ++hashID) { u8 hash[20]; mbedtls_sha1(clusterData + hashID * 0x400, 0x400, hash); // Note that we do not use strncmp here if (memcmp(hash, clusterMD + hashID * 20, 20)) { NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: hash %d is invalid", clusterID, hashID); return false; } } } return true; }
/** * Block symmetric ciphers. * Please note that linker-override is possible, but dynamic override is generally * preferable to avoid clobbering all symmetric support. * * @param uint8_t* Buffer containing plaintext. * @param int Length of plaintext. * @param uint8_t* Target buffer for ciphertext. * @param int Length of output. * @param uint8_t* Buffer containing the symmetric key. * @param int Length of the key, in bits. * @param uint8_t* IV. Caller's responsibility to use correct size. * @param Cipher The cipher by which to encrypt. * @param uint32_t Options to the optionation. * @return true if the root function ought to defer. */ int __attribute__((weak)) wrapped_sym_cipher(uint8_t* in, int in_len, uint8_t* out, int out_len, uint8_t* key, int key_len, uint8_t* iv, Cipher ci, uint32_t opts) { if (cipher_deferred_handling(ci)) { // If overriden by user implementation. return _sym_overrides[ci](in, in_len, out, out_len, key, key_len, iv, ci, opts); } int8_t ret = -1; switch (ci) { #if defined(MBEDTLS_AES_C) case Cipher::SYM_AES_256_CBC: case Cipher::SYM_AES_192_CBC: case Cipher::SYM_AES_128_CBC: { mbedtls_aes_context ctx; if (opts & OP_ENCRYPT) { mbedtls_aes_setkey_enc(&ctx, key, (unsigned int) key_len); } else { mbedtls_aes_setkey_dec(&ctx, key, (unsigned int) key_len); } ret = mbedtls_aes_crypt_cbc(&ctx, _cipher_opcode(ci, opts), in_len, iv, in, out); mbedtls_aes_free(&ctx); } break; #endif #if defined(MBEDTLS_RSA_C) case Cipher::ASYM_RSA: { mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ctr_drbg_init(&ctr_drbg); size_t olen = 0; mbedtls_pk_context ctx; mbedtls_pk_init(&ctx); if (opts & OP_ENCRYPT) { ret = mbedtls_pk_encrypt(&ctx, in, in_len, out, &olen, out_len, mbedtls_ctr_drbg_random, &ctr_drbg); } else { ret = mbedtls_pk_decrypt(&ctx, in, in_len, out, &olen, out_len, mbedtls_ctr_drbg_random, &ctr_drbg); } mbedtls_pk_free(&ctx); } break; #endif #if defined(MBEDTLS_BLOWFISH_C) case Cipher::SYM_BLOWFISH_CBC: { mbedtls_blowfish_context ctx; mbedtls_blowfish_setkey(&ctx, key, key_len); ret = mbedtls_blowfish_crypt_cbc(&ctx, _cipher_opcode(ci, opts), in_len, iv, in, out); mbedtls_blowfish_free(&ctx); } break; #endif #if defined(WRAPPED_SYM_NULL) case Cipher::SYM_NULL: memcpy(out, in, in_len); ret = 0; break; #endif default: break; } return ret; }