From ebeea43fb806095bf0cf98b70424166d9e9eb861 Mon Sep 17 00:00:00 2001 From: B3n30 Date: Wed, 26 Feb 2020 16:43:53 +0100 Subject: [PATCH 1/3] Load RSA slot_0 data from bootrom; load and decrypt data from native firm for NCCHSecure2 keyslot --- src/core/CMakeLists.txt | 2 + src/core/hw/aes/key.cpp | 68 +++++++++++++++++++++++++-- src/core/hw/rsa/rsa.cpp | 102 ++++++++++++++++++++++++++++++++++++++++ src/core/hw/rsa/rsa.h | 36 ++++++++++++++ 4 files changed, 204 insertions(+), 4 deletions(-) create mode 100644 src/core/hw/rsa/rsa.cpp create mode 100644 src/core/hw/rsa/rsa.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ab9f52e32..8b7271fee 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -421,6 +421,8 @@ add_library(core STATIC hw/hw.h hw/lcd.cpp hw/lcd.h + hw/rsa/rsa.cpp + hw/rsa/rsa.h hw/y2r.cpp hw/y2r.h loader/3dsx.cpp diff --git a/src/core/hw/aes/key.cpp b/src/core/hw/aes/key.cpp index 37a547e5c..c61b04a2e 100644 --- a/src/core/hw/aes/key.cpp +++ b/src/core/hw/aes/key.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "common/common_paths.h" #include "common/file_util.h" @@ -17,6 +18,7 @@ #include "core/hle/service/fs/archive.h" #include "core/hw/aes/arithmetic128.h" #include "core/hw/aes/key.h" +#include "core/hw/rsa/rsa.h" namespace HW::AES { @@ -26,7 +28,7 @@ namespace { // normal key dumped from a Wii U solving the equation: // NormalKey = (((KeyX ROL 2) XOR KeyY) + constant) ROL 87 // On a real 3DS the generation for the normal key is hardware based, and thus the constant can't -// get dumped . generated normal keys are also not accesible on a 3DS. The used formula for +// get dumped. Generated normal keys are also not accesible on a 3DS. The used formula for // calculating the constant is a software implementation of what the hardware generator does. constexpr AESKey generator_constant = {{0x1F, 0xF9, 0xE9, 0xAA, 0xC5, 0xFE, 0x04, 0x08, 0x02, 0x45, 0x91, 0xDC, 0x5D, 0x52, 0x76, 0x8A}}; @@ -203,13 +205,69 @@ void LoadBootromKeys() { } void LoadNativeFirmKeysOld3DS() { + constexpr u64 native_firm_id = 0x00040138'00000002; + FileSys::NCCHArchive archive(native_firm_id, Service::FS::MediaType::NAND); + std::array exefs_filepath = {'.', 'f', 'i', 'r', 'm', 0, 0, 0}; + FileSys::Path file_path = FileSys::MakeNCCHFilePath( + FileSys::NCCHFileOpenType::NCCHData, 0, FileSys::NCCHFilePathType::ExeFS, exefs_filepath); + FileSys::Mode open_mode = {}; + open_mode.read_flag.Assign(1); + auto file_result = archive.OpenFile(file_path, open_mode); + if (file_result.Failed()) + return; + + auto firm = std::move(file_result).Unwrap(); + const std::size_t size = firm->GetSize(); + if (size != 966656) { + LOG_ERROR(HW_AES, "native firm has wrong size {}", size); + return; + } + + auto rsa = RSA::GetSlot(0); + if (!rsa) { + LOG_ERROR(HW_AES, "RSA slot is missing"); + return; + } + + std::vector firm_buffer(size); + firm->Read(0, firm_buffer.size(), firm_buffer.data()); + firm->Close(); + + constexpr std::size_t SLOT_0x25_KEY_X_SECRET_OFFSET = 934444; + constexpr std::size_t SLOT_0x25_KEY_X_SECRET_SIZE = 64; + std::vector secret_data(SLOT_0x25_KEY_X_SECRET_SIZE); + std::memcpy(secret_data.data(), firm_buffer.data() + SLOT_0x25_KEY_X_SECRET_OFFSET, + secret_data.size()); + + auto asn1 = RSA::CreateASN1Message(secret_data); + auto result = rsa.GetSignature(asn1); + if (result.size() < 0x100) { + std::vector temp; + temp.resize(0x100 - result.size()); + std::fill(temp.begin(), temp.end(), 0); + std::copy(result.begin(), result.end(), std::back_inserter(temp)); + result = temp; + } else if (result.size() > 0x100) { + std::vector temp(result.begin(), result.begin() + 0x100); + result = temp; + } + + CryptoPP::SHA256 sha; + std::array hash_result; + sha.CalculateDigest(hash_result.data(), result.data(), result.size()); + AESKey key; + std::memcpy(key.data(), hash_result.data(), sizeof(key)); + key_slots.at(0x2F).SetKeyY(key); + std::memcpy(key.data(), hash_result.data() + sizeof(key), sizeof(key)); + key_slots.at(0x25).SetKeyX(key); +} + +void LoadSaveModeNativeFirmKeysOld3DS() { // Use the save mode native firm instead of the normal mode since there are only 2 version of it // and thus we can use fixed offsets constexpr u64 save_mode_native_firm_id = 0x00040138'00000003; - // TODO(B3N30): Add the 0x25 KeyX that gets initalized by native_firm - FileSys::NCCHArchive archive(save_mode_native_firm_id, Service::FS::MediaType::NAND); std::array exefs_filepath = {'.', 'f', 'i', 'r', 'm', 0, 0, 0}; FileSys::Path file_path = FileSys::MakeNCCHFilePath( @@ -443,11 +501,13 @@ void InitKeys() { static bool initialized = false; if (initialized) return; + initialized = true; + HW::RSA::InitSlots(); LoadBootromKeys(); LoadNativeFirmKeysOld3DS(); + LoadSaveModeNativeFirmKeysOld3DS(); LoadNativeFirmKeysNew3DS(); LoadPresetKeys(); - initialized = true; } void SetKeyX(std::size_t slot_id, const AESKey& key) { diff --git a/src/core/hw/rsa/rsa.cpp b/src/core/hw/rsa/rsa.cpp new file mode 100644 index 000000000..c436ad74f --- /dev/null +++ b/src/core/hw/rsa/rsa.cpp @@ -0,0 +1,102 @@ +// Copyright 2020 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include +#include "common/common_paths.h" +#include "common/file_util.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/hw/rsa/rsa.h" + +namespace HW::RSA { + +namespace { +std::vector HexToBytes(const std::string& hex) { + std::vector bytes; + + for (unsigned int i = 0; i < hex.length(); i += 2) { + std::string byteString = hex.substr(i, 2); + u8 byte = (u8)strtol(byteString.c_str(), NULL, 16); + bytes.push_back(byte); + } + return bytes; +}; +} // namespace + +constexpr std::size_t SlotSize = 4; +std::array rsa_slots; + +std::vector RsaSlot::GetSignature(const std::vector& message) { + CryptoPP::Integer sig = + CryptoPP::ModularExponentiation(CryptoPP::Integer(message.data(), message.size()), + CryptoPP::Integer(exponent.data(), exponent.size()), + CryptoPP::Integer(modulus.data(), modulus.size())); + std::stringstream ss; + ss << std::hex << sig; + return HexToBytes(ss.str()); +} + +void InitSlots() { + static bool initialized = false; + if (initialized) + return; + initialized = true; + + const std::string filepath = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir) + BOOTROM9; + auto file = FileUtil::IOFile(filepath, "rb"); + if (!file) { + return; + } + + const std::size_t length = file.GetSize(); + if (length != 65536) { + LOG_ERROR(HW_AES, "Bootrom9 size is wrong: {}", length); + return; + } + + constexpr std::size_t RSA_MODULUS_POS = 0xB3E0; + file.Seek(RSA_MODULUS_POS, SEEK_SET); + std::vector modulus; + modulus.resize(256); + file.ReadArray(modulus.data(), modulus.size()); + + constexpr std::size_t RSA_EXPONENT_POS = 0xB4E0; + file.Seek(RSA_EXPONENT_POS, SEEK_SET); + std::vector exponent; + exponent.resize(256); + file.ReadArray(exponent.data(), exponent.size()); + + rsa_slots[0] = RsaSlot(exponent, modulus); + // TODO(B3N30): Initalize the other slots. But since they aren't used at all, we can skip them + // for now +} + +RsaSlot GetSlot(std::size_t slot_id) { + if (slot_id >= rsa_slots.size()) + return RsaSlot{}; + return rsa_slots[slot_id]; +} + +std::vector CreateASN1Message(const std::vector& data) { + static constexpr auto asn1_header = + "0001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFF003031300D060960864801650304020105000420"; + std::vector message = HexToBytes(asn1_header); + CryptoPP::SHA256 sha; + std::array hash; + sha.CalculateDigest(hash.data(), data.data(), data.size()); + std::copy(hash.begin(), hash.end(), std::back_inserter(message)); + return message; +} + +} // namespace HW::RSA \ No newline at end of file diff --git a/src/core/hw/rsa/rsa.h b/src/core/hw/rsa/rsa.h new file mode 100644 index 000000000..869d98d89 --- /dev/null +++ b/src/core/hw/rsa/rsa.h @@ -0,0 +1,36 @@ +// Copyright 2020 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include "common/common_types.h" + +namespace HW::RSA { + +class RsaSlot { +public: + RsaSlot() : init(false) {} + RsaSlot(const std::vector& exponent, const std::vector& modulus) + : init(true), exponent(exponent), modulus(modulus) {} + std::vector GetSignature(const std::vector& message); + + operator bool() const { + // TODO(B3N30): Maybe check if exponent and modulus are vailid + return init; + } + +private: + bool init; + std::vector exponent; + std::vector modulus; +}; + +void InitSlots(); + +RsaSlot GetSlot(std::size_t slot_id); + +std::vector CreateASN1Message(const std::vector& data); + +} // namespace HW::RSA \ No newline at end of file From eaaa76b922636985a624d904cc410042a5ead228 Mon Sep 17 00:00:00 2001 From: B3n30 Date: Sun, 15 Mar 2020 21:19:41 +0100 Subject: [PATCH 2/3] Adressed review comments --- src/core/hw/aes/key.cpp | 29 +++++++++++++---------------- src/core/hw/rsa/rsa.cpp | 11 ++++------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/core/hw/aes/key.cpp b/src/core/hw/aes/key.cpp index c61b04a2e..21d63f252 100644 --- a/src/core/hw/aes/key.cpp +++ b/src/core/hw/aes/key.cpp @@ -242,14 +242,11 @@ void LoadNativeFirmKeysOld3DS() { auto asn1 = RSA::CreateASN1Message(secret_data); auto result = rsa.GetSignature(asn1); if (result.size() < 0x100) { - std::vector temp; - temp.resize(0x100 - result.size()); - std::fill(temp.begin(), temp.end(), 0); - std::copy(result.begin(), result.end(), std::back_inserter(temp)); + std::vector temp(0x100); + std::copy(result.begin(), result.end(), temp.end() - result.size()); result = temp; } else if (result.size() > 0x100) { - std::vector temp(result.begin(), result.begin() + 0x100); - result = temp; + result.resize(0x100); } CryptoPP::SHA256 sha; @@ -262,13 +259,13 @@ void LoadNativeFirmKeysOld3DS() { key_slots.at(0x25).SetKeyX(key); } -void LoadSaveModeNativeFirmKeysOld3DS() { - // Use the save mode native firm instead of the normal mode since there are only 2 version of it +void LoadSafeModeNativeFirmKeysOld3DS() { + // Use the safe mode native firm instead of the normal mode since there are only 2 version of it // and thus we can use fixed offsets - constexpr u64 save_mode_native_firm_id = 0x00040138'00000003; + constexpr u64 safe_mode_native_firm_id = 0x00040138'00000003; - FileSys::NCCHArchive archive(save_mode_native_firm_id, Service::FS::MediaType::NAND); + FileSys::NCCHArchive archive(safe_mode_native_firm_id, Service::FS::MediaType::NAND); std::array exefs_filepath = {'.', 'f', 'i', 'r', 'm', 0, 0, 0}; FileSys::Path file_path = FileSys::MakeNCCHFilePath( FileSys::NCCHFileOpenType::NCCHData, 0, FileSys::NCCHFilePathType::ExeFS, exefs_filepath); @@ -281,7 +278,7 @@ void LoadSaveModeNativeFirmKeysOld3DS() { auto firm = std::move(file_result).Unwrap(); const std::size_t size = firm->GetSize(); if (size != 843776) { - LOG_ERROR(HW_AES, "save mode native firm has wrong size {}", size); + LOG_ERROR(HW_AES, "safe mode native firm has wrong size {}", size); return; } std::vector firm_buffer(size); @@ -323,16 +320,16 @@ void LoadNativeFirmKeysNew3DS() { AESKey secret_key; secret.ReadArray(secret_key.data(), secret_key.size()); - // Use the save mode native firm instead of the normal mode since there are only 1 version of it + // Use the safe mode native firm instead of the normal mode since there are only 1 version of it // and thus we can use fixed offsets - constexpr u64 save_mode_native_firm_id = 0x00040138'20000003; + constexpr u64 safe_mode_native_firm_id = 0x00040138'20000003; // TODO(B3N30): Add the 0x25 KeyX that gets initalized by native_firm // TODO(B3N30): Add the 0x18 - 0x1F KeyX that gets initalized by native_firm. This probably // requires the normal native firm with version > 9.6.0-X - FileSys::NCCHArchive archive(save_mode_native_firm_id, Service::FS::MediaType::NAND); + FileSys::NCCHArchive archive(safe_mode_native_firm_id, Service::FS::MediaType::NAND); std::array exefs_filepath = {'.', 'f', 'i', 'r', 'm', 0, 0, 0}; FileSys::Path file_path = FileSys::MakeNCCHFilePath( FileSys::NCCHFileOpenType::NCCHData, 0, FileSys::NCCHFilePathType::ExeFS, exefs_filepath); @@ -354,7 +351,7 @@ void LoadNativeFirmKeysNew3DS() { return a | b << 8 | c << 16 | d << 24; }; if (MakeMagic('F', 'I', 'R', 'M') != header.magic) { - LOG_ERROR(HW_AES, "N3DS SAVE MODE Native Firm has wrong header {}", header.magic); + LOG_ERROR(HW_AES, "N3DS SAFE MODE Native Firm has wrong header {}", header.magic); return; } @@ -505,7 +502,7 @@ void InitKeys() { HW::RSA::InitSlots(); LoadBootromKeys(); LoadNativeFirmKeysOld3DS(); - LoadSaveModeNativeFirmKeysOld3DS(); + LoadSafeModeNativeFirmKeysOld3DS(); LoadNativeFirmKeysNew3DS(); LoadPresetKeys(); } diff --git a/src/core/hw/rsa/rsa.cpp b/src/core/hw/rsa/rsa.cpp index c436ad74f..b08df31a0 100644 --- a/src/core/hw/rsa/rsa.cpp +++ b/src/core/hw/rsa/rsa.cpp @@ -10,7 +10,6 @@ #include "common/common_paths.h" #include "common/file_util.h" #include "common/logging/log.h" -#include "common/string_util.h" #include "core/hw/rsa/rsa.h" namespace HW::RSA { @@ -21,7 +20,7 @@ std::vector HexToBytes(const std::string& hex) { for (unsigned int i = 0; i < hex.length(); i += 2) { std::string byteString = hex.substr(i, 2); - u8 byte = (u8)strtol(byteString.c_str(), NULL, 16); + u8 byte = static_cast(std::strtol(byteString.c_str(), nullptr, 16)); bytes.push_back(byte); } return bytes; @@ -48,7 +47,7 @@ void InitSlots() { initialized = true; const std::string filepath = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir) + BOOTROM9; - auto file = FileUtil::IOFile(filepath, "rb"); + FileUtil::IOFile file(filepath, "rb"); if (!file) { return; } @@ -61,14 +60,12 @@ void InitSlots() { constexpr std::size_t RSA_MODULUS_POS = 0xB3E0; file.Seek(RSA_MODULUS_POS, SEEK_SET); - std::vector modulus; - modulus.resize(256); + std::vector modulus(256); file.ReadArray(modulus.data(), modulus.size()); constexpr std::size_t RSA_EXPONENT_POS = 0xB4E0; file.Seek(RSA_EXPONENT_POS, SEEK_SET); - std::vector exponent; - exponent.resize(256); + std::vector exponent(256); file.ReadArray(exponent.data(), exponent.size()); rsa_slots[0] = RsaSlot(exponent, modulus); From ab76b0b684e80362cc75422a5517c8f56aa4054a Mon Sep 17 00:00:00 2001 From: B3n30 Date: Sat, 28 Mar 2020 21:43:13 +0100 Subject: [PATCH 3/3] addressed review comments --- src/core/hw/aes/key.cpp | 2 +- src/core/hw/rsa/rsa.cpp | 38 ++++++++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/core/hw/aes/key.cpp b/src/core/hw/aes/key.cpp index 21d63f252..2148ab04c 100644 --- a/src/core/hw/aes/key.cpp +++ b/src/core/hw/aes/key.cpp @@ -233,7 +233,7 @@ void LoadNativeFirmKeysOld3DS() { firm->Read(0, firm_buffer.size(), firm_buffer.data()); firm->Close(); - constexpr std::size_t SLOT_0x25_KEY_X_SECRET_OFFSET = 934444; + constexpr std::size_t SLOT_0x25_KEY_X_SECRET_OFFSET = 933480; constexpr std::size_t SLOT_0x25_KEY_X_SECRET_SIZE = 64; std::vector secret_data(SLOT_0x25_KEY_X_SECRET_SIZE); std::memcpy(secret_data.data(), firm_buffer.data() + SLOT_0x25_KEY_X_SECRET_OFFSET, diff --git a/src/core/hw/rsa/rsa.cpp b/src/core/hw/rsa/rsa.cpp index b08df31a0..8f2c93243 100644 --- a/src/core/hw/rsa/rsa.cpp +++ b/src/core/hw/rsa/rsa.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include #include @@ -37,6 +38,11 @@ std::vector RsaSlot::GetSignature(const std::vector& message) { CryptoPP::Integer(modulus.data(), modulus.size())); std::stringstream ss; ss << std::hex << sig; + CryptoPP::HexDecoder decoder; + decoder.Put(reinterpret_cast(ss.str().data()), ss.str().size()); + decoder.MessageEnd(); + std::vector result(decoder.MaxRetrievable()); + decoder.Get(result.data(), result.size()); return HexToBytes(ss.str()); } @@ -80,19 +86,27 @@ RsaSlot GetSlot(std::size_t slot_id) { } std::vector CreateASN1Message(const std::vector& data) { - static constexpr auto asn1_header = - "0001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - "FFFFFFFFFFFFFFFFFFFFFFFF003031300D060960864801650304020105000420"; - std::vector message = HexToBytes(asn1_header); + static constexpr std::array asn1_header = { + {0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x30, 0x31, 0x30, 0x0D, 0x06, + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}}; + + std::vector message(asn1_header.begin(), asn1_header.end()); CryptoPP::SHA256 sha; - std::array hash; - sha.CalculateDigest(hash.data(), data.data(), data.size()); - std::copy(hash.begin(), hash.end(), std::back_inserter(message)); + message.resize(message.size() + CryptoPP::SHA256::DIGESTSIZE); + sha.CalculateDigest(message.data() + asn1_header.size(), data.data(), data.size()); return message; }