Merge pull request #4484 from lioncash/aesutil
aes_util: Allow SetIV() to be non-allocating
This commit is contained in:
commit
35c1607f23
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <mbedtls/cipher.h>
|
#include <mbedtls/cipher.h>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
@ -10,8 +11,10 @@
|
||||||
|
|
||||||
namespace Core::Crypto {
|
namespace Core::Crypto {
|
||||||
namespace {
|
namespace {
|
||||||
std::vector<u8> CalculateNintendoTweak(std::size_t sector_id) {
|
using NintendoTweak = std::array<u8, 16>;
|
||||||
std::vector<u8> out(0x10);
|
|
||||||
|
NintendoTweak CalculateNintendoTweak(std::size_t sector_id) {
|
||||||
|
NintendoTweak out{};
|
||||||
for (std::size_t i = 0xF; i <= 0xF; --i) {
|
for (std::size_t i = 0xF; i <= 0xF; --i) {
|
||||||
out[i] = sector_id & 0xFF;
|
out[i] = sector_id & 0xFF;
|
||||||
sector_id >>= 8;
|
sector_id >>= 8;
|
||||||
|
@ -63,13 +66,6 @@ AESCipher<Key, KeySize>::~AESCipher() {
|
||||||
mbedtls_cipher_free(&ctx->decryption_context);
|
mbedtls_cipher_free(&ctx->decryption_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Key, std::size_t KeySize>
|
|
||||||
void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) {
|
|
||||||
ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, iv.data(), iv.size()) ||
|
|
||||||
mbedtls_cipher_set_iv(&ctx->decryption_context, iv.data(), iv.size())) == 0,
|
|
||||||
"Failed to set IV on mbedtls ciphers.");
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Key, std::size_t KeySize>
|
template <typename Key, std::size_t KeySize>
|
||||||
void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* dest, Op op) const {
|
void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* dest, Op op) const {
|
||||||
auto* const context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context;
|
auto* const context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context;
|
||||||
|
@ -124,6 +120,13 @@ void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, std::size_t size, u8*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Key, std::size_t KeySize>
|
||||||
|
void AESCipher<Key, KeySize>::SetIVImpl(const u8* data, std::size_t size) {
|
||||||
|
ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, data, size) ||
|
||||||
|
mbedtls_cipher_set_iv(&ctx->decryption_context, data, size)) == 0,
|
||||||
|
"Failed to set IV on mbedtls ciphers.");
|
||||||
|
}
|
||||||
|
|
||||||
template class AESCipher<Key128>;
|
template class AESCipher<Key128>;
|
||||||
template class AESCipher<Key256>;
|
template class AESCipher<Key256>;
|
||||||
} // namespace Core::Crypto
|
} // namespace Core::Crypto
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/file_sys/vfs.h"
|
#include "core/file_sys/vfs.h"
|
||||||
|
|
||||||
|
@ -32,10 +31,12 @@ class AESCipher {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AESCipher(Key key, Mode mode);
|
AESCipher(Key key, Mode mode);
|
||||||
|
|
||||||
~AESCipher();
|
~AESCipher();
|
||||||
|
|
||||||
void SetIV(std::vector<u8> iv);
|
template <typename ContiguousContainer>
|
||||||
|
void SetIV(const ContiguousContainer& container) {
|
||||||
|
SetIVImpl(std::data(container), std::size(container));
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Source, typename Dest>
|
template <typename Source, typename Dest>
|
||||||
void Transcode(const Source* src, std::size_t size, Dest* dest, Op op) const {
|
void Transcode(const Source* src, std::size_t size, Dest* dest, Op op) const {
|
||||||
|
@ -59,6 +60,8 @@ public:
|
||||||
std::size_t sector_size, Op op);
|
std::size_t sector_size, Op op);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void SetIVImpl(const u8* data, std::size_t size);
|
||||||
|
|
||||||
std::unique_ptr<CipherContext> ctx;
|
std::unique_ptr<CipherContext> ctx;
|
||||||
};
|
};
|
||||||
} // namespace Core::Crypto
|
} // namespace Core::Crypto
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "core/crypto/ctr_encryption_layer.h"
|
#include "core/crypto/ctr_encryption_layer.h"
|
||||||
|
@ -10,8 +11,7 @@ namespace Core::Crypto {
|
||||||
|
|
||||||
CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_,
|
CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_,
|
||||||
std::size_t base_offset)
|
std::size_t base_offset)
|
||||||
: EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR),
|
: EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR) {}
|
||||||
iv(16, 0) {}
|
|
||||||
|
|
||||||
std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const {
|
std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const {
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
|
@ -39,9 +39,8 @@ std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t o
|
||||||
return read + Read(data + read, length - read, offset + read);
|
return read + Read(data + read, length - read, offset + read);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTREncryptionLayer::SetIV(const std::vector<u8>& iv_) {
|
void CTREncryptionLayer::SetIV(const IVData& iv_) {
|
||||||
const auto length = std::min(iv_.size(), iv.size());
|
iv = iv_;
|
||||||
iv.assign(iv_.cbegin(), iv_.cbegin() + length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTREncryptionLayer::UpdateIV(std::size_t offset) const {
|
void CTREncryptionLayer::UpdateIV(std::size_t offset) const {
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <array>
|
||||||
|
|
||||||
#include "core/crypto/aes_util.h"
|
#include "core/crypto/aes_util.h"
|
||||||
#include "core/crypto/encryption_layer.h"
|
#include "core/crypto/encryption_layer.h"
|
||||||
#include "core/crypto/key_manager.h"
|
#include "core/crypto/key_manager.h"
|
||||||
|
@ -14,18 +15,20 @@ namespace Core::Crypto {
|
||||||
// Sits on top of a VirtualFile and provides CTR-mode AES decription.
|
// Sits on top of a VirtualFile and provides CTR-mode AES decription.
|
||||||
class CTREncryptionLayer : public EncryptionLayer {
|
class CTREncryptionLayer : public EncryptionLayer {
|
||||||
public:
|
public:
|
||||||
|
using IVData = std::array<u8, 16>;
|
||||||
|
|
||||||
CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, std::size_t base_offset);
|
CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, std::size_t base_offset);
|
||||||
|
|
||||||
std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
|
std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
|
||||||
|
|
||||||
void SetIV(const std::vector<u8>& iv);
|
void SetIV(const IVData& iv);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::size_t base_offset;
|
std::size_t base_offset;
|
||||||
|
|
||||||
// Must be mutable as operations modify cipher contexts.
|
// Must be mutable as operations modify cipher contexts.
|
||||||
mutable AESCipher<Key128> cipher;
|
mutable AESCipher<Key128> cipher;
|
||||||
mutable std::vector<u8> iv;
|
mutable IVData iv{};
|
||||||
|
|
||||||
void UpdateIV(std::size_t offset) const;
|
void UpdateIV(std::size_t offset) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -346,10 +346,9 @@ FileSys::VirtualFile PartitionDataManager::GetPackage2Raw(Package2Type type) con
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool AttemptDecrypt(const std::array<u8, 16>& key, Package2Header& header) {
|
static bool AttemptDecrypt(const std::array<u8, 16>& key, Package2Header& header) {
|
||||||
const std::vector<u8> iv(header.header_ctr.begin(), header.header_ctr.end());
|
|
||||||
Package2Header temp = header;
|
Package2Header temp = header;
|
||||||
AESCipher<Key128> cipher(key, Mode::CTR);
|
AESCipher<Key128> cipher(key, Mode::CTR);
|
||||||
cipher.SetIV(iv);
|
cipher.SetIV(header.header_ctr);
|
||||||
cipher.Transcode(&temp.header_ctr, sizeof(Package2Header) - 0x100, &temp.header_ctr,
|
cipher.Transcode(&temp.header_ctr, sizeof(Package2Header) - 0x100, &temp.header_ctr,
|
||||||
Op::Decrypt);
|
Op::Decrypt);
|
||||||
if (temp.magic == Common::MakeMagic('P', 'K', '2', '1')) {
|
if (temp.magic == Common::MakeMagic('P', 'K', '2', '1')) {
|
||||||
|
@ -388,7 +387,7 @@ void PartitionDataManager::DecryptPackage2(const std::array<Key128, 0x20>& packa
|
||||||
auto c = a->ReadAllBytes();
|
auto c = a->ReadAllBytes();
|
||||||
|
|
||||||
AESCipher<Key128> cipher(package2_keys[revision], Mode::CTR);
|
AESCipher<Key128> cipher(package2_keys[revision], Mode::CTR);
|
||||||
cipher.SetIV({header.section_ctr[1].begin(), header.section_ctr[1].end()});
|
cipher.SetIV(header.section_ctr[1]);
|
||||||
cipher.Transcode(c.data(), c.size(), c.data(), Op::Decrypt);
|
cipher.Transcode(c.data(), c.size(), c.data(), Op::Decrypt);
|
||||||
|
|
||||||
const auto ini_file = std::make_shared<FileSys::VectorVfsFile>(c);
|
const auto ini_file = std::make_shared<FileSys::VectorVfsFile>(c);
|
||||||
|
|
|
@ -495,9 +495,10 @@ VirtualFile NCA::Decrypt(const NCASectionHeader& s_header, VirtualFile in, u64 s
|
||||||
|
|
||||||
auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>(std::move(in), *key,
|
auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>(std::move(in), *key,
|
||||||
starting_offset);
|
starting_offset);
|
||||||
std::vector<u8> iv(16);
|
Core::Crypto::CTREncryptionLayer::IVData iv{};
|
||||||
for (u8 i = 0; i < 8; ++i)
|
for (std::size_t i = 0; i < 8; ++i) {
|
||||||
iv[i] = s_header.raw.section_ctr[0x8 - i - 1];
|
iv[i] = s_header.raw.section_ctr[8 - i - 1];
|
||||||
|
}
|
||||||
out->SetIV(iv);
|
out->SetIV(iv);
|
||||||
return std::static_pointer_cast<VfsFile>(out);
|
return std::static_pointer_cast<VfsFile>(out);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
@ -66,7 +67,7 @@ std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const {
|
||||||
Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(key, Core::Crypto::Mode::CTR);
|
Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(key, Core::Crypto::Mode::CTR);
|
||||||
|
|
||||||
// Calculate AES IV
|
// Calculate AES IV
|
||||||
std::vector<u8> iv(16);
|
std::array<u8, 16> iv{};
|
||||||
auto subsection_ctr = subsection.ctr;
|
auto subsection_ctr = subsection.ctr;
|
||||||
auto offset_iv = section_offset + base_offset;
|
auto offset_iv = section_offset + base_offset;
|
||||||
for (std::size_t i = 0; i < section_ctr.size(); ++i)
|
for (std::size_t i = 0; i < section_ctr.size(); ++i)
|
||||||
|
|
Reference in New Issue