Compare commits

...

8 Commits

Author SHA1 Message Date
Nagi
744d480a37 Merge 1e762aa3f4 into 35aa153d6c 2021-11-04 19:14:10 +03:00
Hanjie Wu
1e762aa3f4 add license information 2021-10-22 23:23:13 +08:00
Hanjie Wu
7ead7f26df replace C type conversion with static_cast 2021-10-22 15:42:26 +08:00
Hanjie Wu
1e32807794 fix core.lib's openssl link problems 2021-10-22 01:20:55 +08:00
Hanjie Wu
dc9517051d fix AESCipher encryption & use unique_ptr for EVP_CIPHER_CONTEXT 2021-10-22 01:20:54 +08:00
Hanjie Wu
95681010f2 add aes crypto tests 2021-10-22 01:20:54 +08:00
Hanjie Wu
3cef0ccd3e add crypto tests 2021-10-22 01:20:54 +08:00
Hanjie Wu
3cfa516e16 implement openssl crypto backend 2021-10-22 01:20:54 +08:00
17 changed files with 443 additions and 85 deletions

View File

@@ -33,6 +33,8 @@ option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
option(YUZU_USE_OPENSSL_CRYPTO "Use OpenSSL/libressl for cryptography backend" ON)
# Default to a Release build
get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE)

View File

@@ -36,10 +36,6 @@ add_subdirectory(glad)
# inih
add_subdirectory(inih)
# mbedtls
add_subdirectory(mbedtls EXCLUDE_FROM_ALL)
target_include_directories(mbedtls PUBLIC ./mbedtls/include)
# MicroProfile
add_library(microprofile INTERFACE)
target_include_directories(microprofile INTERFACE ./microprofile)
@@ -93,10 +89,11 @@ endif()
# Sirit
add_subdirectory(sirit)
if (ENABLE_WEB_SERVICE)
if (ENABLE_WEB_SERVICE OR YUZU_USE_OPENSSL_CRYPTO)
find_package(OpenSSL 1.1)
if (OPENSSL_FOUND)
set(OPENSSL_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
set(YUZU_CRYPTO_BACKEND OpenSSL::Crypto)
else()
# LibreSSL
set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
@@ -107,7 +104,10 @@ if (ENABLE_WEB_SERVICE)
get_directory_property(OPENSSL_LIBRARIES
DIRECTORY libressl
DEFINITION OPENSSL_LIBS)
target_include_directories(crypto INTERFACE ./libressl/include)
set(YUZU_CRYPTO_BACKEND crypto)
endif()
set(YUZU_CRYPTO_DEFINITION -DYUZU_USE_OPENSSL_CRYPTO)
# httplib
add_library(httplib INTERFACE)
@@ -117,8 +117,18 @@ if (ENABLE_WEB_SERVICE)
if (WIN32)
target_link_libraries(httplib INTERFACE crypt32 cryptui ws2_32)
endif()
else()
# mbedtls
add_subdirectory(mbedtls EXCLUDE_FROM_ALL)
target_include_directories(mbedtls PUBLIC ./mbedtls/include)
set(YUZU_CRYPTO_BACKEND mbedtls)
set(YUZU_CRYPTO_DEFINITION -DYUZU_USE_MBEDTLS_CRYPTO)
endif()
add_library(crypto-backend INTERFACE)
target_compile_definitions(crypto-backend INTERFACE ${YUZU_CRYPTO_DEFINITION})
target_link_libraries(crypto-backend INTERFACE ${YUZU_CRYPTO_BACKEND})
# Opus
find_package(opus 1.3)
if (NOT opus_FOUND)

View File

@@ -22,8 +22,12 @@ add_library(core STATIC
core_timing_util.h
cpu_manager.cpp
cpu_manager.h
crypto/aes_util.cpp
crypto/aes_util_mbedtls.cpp
crypto/aes_util_openssl.cpp
crypto/aes_util.h
crypto/crypto.h
crypto/crypto_mbedtls.cpp
crypto/crypto_openssl.cpp
crypto/encryption_layer.cpp
crypto/encryption_layer.h
crypto/key_manager.cpp
@@ -682,7 +686,7 @@ endif()
create_target_directory_groups(core)
target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus)
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json Opus::Opus crypto-backend)
if (ENABLE_WEB_SERVICE)
target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE)

View File

@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#ifdef YUZU_USE_MBEDTLS_CRYPTO
#include <array>
#include <mbedtls/cipher.h>
#include "common/assert.h"
@@ -128,3 +130,5 @@ void AESCipher<Key, KeySize>::SetIV(std::span<const u8> data) {
template class AESCipher<Key128>;
template class AESCipher<Key256>;
} // namespace Core::Crypto
#endif

View File

@@ -0,0 +1,115 @@
// Copyright 2021 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#ifdef YUZU_USE_OPENSSL_CRYPTO
#include <map>
#include <memory>
#include <vector>
#include <openssl/evp.h>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/crypto/aes_util.h"
#include "core/crypto/key_manager.h"
namespace Core::Crypto {
namespace {
using NintendoTweak = std::array<u8, 16>;
NintendoTweak CalculateNintendoTweak(std::size_t sector_id) {
NintendoTweak out{};
for (std::size_t i = 0xF; i <= 0xF; --i) {
out[i] = sector_id & 0xFF;
sector_id >>= 8;
}
return out;
}
} // Anonymous namespace
struct EvpCipherContextFree {
void operator()(EVP_CIPHER_CTX* ctx) {
EVP_CIPHER_CTX_free(ctx);
}
};
using EvpCipherContext = std::unique_ptr<EVP_CIPHER_CTX, EvpCipherContextFree>;
struct CipherContext {
const EVP_CIPHER* cipher;
EvpCipherContext ctx;
std::vector<u8> key;
std::vector<u8> iv;
CipherContext(EVP_CIPHER_CTX* ctx_in) : ctx(ctx_in) {}
};
const static std::map<Mode, decltype(&EVP_aes_128_ctr)> cipher_map = {
{Mode::CTR, EVP_aes_128_ctr}, {Mode::ECB, EVP_aes_128_ecb}, {Mode::XTS, EVP_aes_128_xts}};
template <typename Key, std::size_t KeySize>
Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode)
: ctx(std::make_unique<CipherContext>(EVP_CIPHER_CTX_new())) {
ASSERT_MSG((ctx->ctx.get() != NULL), "Failed to initialize OpenSSL ciphers.");
ctx->cipher = cipher_map.at(mode)();
ctx->key.resize(KeySize);
std::memcpy(ctx->key.data(), key.data(), KeySize);
}
template <typename Key, std::size_t KeySize>
AESCipher<Key, KeySize>::~AESCipher() = default;
template <typename Key, std::size_t KeySize>
void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* dest, Op op) const {
EVP_CIPHER_CTX_reset(ctx->ctx.get());
EVP_CipherInit(ctx->ctx.get(), ctx->cipher, ctx->key.data(), ctx->iv.data(),
op == Op::Encrypt ? 1 : 0);
EVP_CIPHER_CTX_set_padding(ctx->ctx.get(), 0);
int written, last_written;
if (EVP_CIPHER_mode(ctx->cipher) == EVP_CIPH_XTS_MODE) {
EVP_CipherUpdate(ctx->ctx.get(), dest, &written, src, static_cast<int>(size));
if (written != static_cast<int>(size)) {
LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.",
size, written);
}
} else {
std::size_t block_size = EVP_CIPHER_block_size(ctx->cipher);
std::size_t remain = size % block_size;
EVP_CipherUpdate(ctx->ctx.get(), dest, &written, src, static_cast<int>(size - remain));
if (remain != 0) {
std::vector<u8> block(block_size);
std::memcpy(block.data(), src + size - remain, remain);
EVP_CipherUpdate(ctx->ctx.get(), dest + written, &last_written, block.data(),
static_cast<int>(block_size));
written += last_written;
}
if (written != static_cast<int>(size)) {
LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.",
size, written + last_written);
}
}
}
template <typename Key, std::size_t KeySize>
void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, std::size_t size, u8* dest,
std::size_t sector_id, std::size_t sector_size, Op op) {
ASSERT_MSG(size % sector_size == 0, "XTS decryption size must be a multiple of sector size.");
for (std::size_t i = 0; i < size; i += sector_size) {
SetIV(CalculateNintendoTweak(sector_id++));
Transcode(src + i, sector_size, dest + i, op);
}
}
template <typename Key, std::size_t KeySize>
void AESCipher<Key, KeySize>::SetIV(std::span<const u8> data) {
ctx->iv.resize(data.size());
std::memcpy(ctx->iv.data(), data.data(), data.size());
}
template class AESCipher<Key128>;
template class AESCipher<Key256>;
} // namespace Core::Crypto
#endif

26
src/core/crypto/crypto.h Normal file
View File

@@ -0,0 +1,26 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <cstdlib>
#include "common/common_types.h"
bool CalculateHMACSHA256(u8* out, const u8* key, std::size_t key_length, const u8* data,
std::size_t data_length);
void CalculateMD5(const u8* data, std::size_t data_length, u8* hash);
void CalculateSHA256(const u8* data, std::size_t data_length, u8* hash);
// CMAC with AES-128, key_length = 16 bytes
void CalculateCMAC(const u8* source, size_t size, const u8* key, u8* cmac);
// Calculate m = (s^d) mod n
void CalculateModExp(const u8* d, std::size_t d_length, const u8* n, std::size_t n_length,
const u8* s, std::size_t s_length, u8* m, std::size_t m_length);
void GenerateRandomBytesWithSeed(u8* out, std::size_t out_length, const u8* seed,
std::size_t seed_length);

View File

@@ -0,0 +1,82 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#ifdef YUZU_USE_MBEDTLS_CRYPTO
#include <mbedtls/bignum.h>
#include <mbedtls/cmac.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/md.h>
#include <mbedtls/md5.h>
#include <mbedtls/sha256.h>
#include "common/assert.h"
#include "core/crypto/crypto.h"
bool CalculateHMACSHA256(u8* out, const u8* key, std::size_t key_length, const u8* data,
std::size_t data_length) {
mbedtls_md_context_t context;
mbedtls_md_init(&context);
if (mbedtls_md_setup(&context, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1) ||
mbedtls_md_hmac_starts(&context, key, key_length) ||
mbedtls_md_hmac_update(&context, data, data_length) ||
mbedtls_md_hmac_finish(&context, out)) {
mbedtls_md_free(&context);
return false;
}
mbedtls_md_free(&context);
return true;
}
void CalculateMD5(const u8* data, std::size_t data_length, u8* hash) {
mbedtls_md5_ret(data, data_length, hash);
}
void CalculateSHA256(const u8* data, std::size_t data_length, u8* hash) {
mbedtls_sha256_ret(data, data_length, hash, 0);
}
void CalculateCMAC(const u8* source, size_t size, const u8* key, u8* cmac) {
mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), key, 128, source,
size, cmac);
}
void CalculateModExp(const u8* d, std::size_t d_length, const u8* n, std::size_t n_length,
const u8* s, std::size_t s_length, u8* m, std::size_t m_length) {
mbedtls_mpi D; // RSA Private Exponent
mbedtls_mpi N; // RSA Modulus
mbedtls_mpi S; // Input
mbedtls_mpi M; // Output
mbedtls_mpi_init(&D);
mbedtls_mpi_init(&N);
mbedtls_mpi_init(&S);
mbedtls_mpi_init(&M);
mbedtls_mpi_read_binary(&D, d, d_length);
mbedtls_mpi_read_binary(&N, n, n_length);
mbedtls_mpi_read_binary(&S, s, s_length);
mbedtls_mpi_exp_mod(&M, &S, &D, &N, nullptr);
mbedtls_mpi_write_binary(&M, m, m_length);
}
void GenerateRandomBytesWithSeed(u8* out, std::size_t out_length, const u8* seed,
std::size_t seed_length) {
mbedtls_entropy_context entropy;
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ctr_drbg_init(&ctr_drbg);
ASSERT(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, seed, seed_length));
ASSERT(mbedtls_ctr_drbg_random(&ctr_drbg, out, out_length) == 0);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
}
#endif

View File

@@ -0,0 +1,62 @@
// Copyright 2021 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#ifdef YUZU_USE_OPENSSL_CRYPTO
#include <openssl/bn.h>
#include <openssl/cmac.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
#include "common/assert.h"
#include "core/crypto/crypto.h"
bool CalculateHMACSHA256(u8* out, const u8* key, std::size_t key_length, const u8* data,
std::size_t data_length) {
HMAC(EVP_sha256(), key, static_cast<int>(key_length), data, data_length, out, NULL);
return true;
}
void CalculateMD5(const u8* data, std::size_t data_length, u8* hash) {
EVP_Digest(data, data_length, hash, NULL, EVP_md5(), NULL);
}
void CalculateSHA256(const u8* data, std::size_t data_length, u8* hash) {
EVP_Digest(data, data_length, hash, NULL, EVP_sha256(), NULL);
}
void CalculateCMAC(const u8* source, size_t size, const u8* key, u8* cmac) {
size_t outlen;
CMAC_CTX* ctx = CMAC_CTX_new();
CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL);
CMAC_Update(ctx, source, size);
CMAC_Final(ctx, cmac, &outlen);
CMAC_CTX_free(ctx);
}
void CalculateModExp(const u8* d, std::size_t d_length, const u8* n, std::size_t n_length,
const u8* s, std::size_t s_length, u8* m, std::size_t m_length) {
BN_CTX* ctx = BN_CTX_new();
BN_CTX_start(ctx);
BIGNUM* D = BN_CTX_get(ctx);
BIGNUM* N = BN_CTX_get(ctx);
BIGNUM* S = BN_CTX_get(ctx);
BIGNUM* M = BN_CTX_get(ctx);
BN_bin2bn(d, static_cast<int>(d_length), D);
BN_bin2bn(n, static_cast<int>(n_length), N);
BN_bin2bn(s, static_cast<int>(s_length), S);
BN_mod_exp(M, S, D, N, ctx);
BN_bn2bin(M, m);
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
void GenerateRandomBytesWithSeed(u8* out, std::size_t out_length, const u8* seed,
std::size_t seed_length) {
RAND_seed(static_cast<const void*>(seed), static_cast<int>(seed_length));
ASSERT(RAND_bytes(out, static_cast<int>(out_length)) == 1);
}
#endif

View File

@@ -13,10 +13,6 @@
#include <string_view>
#include <tuple>
#include <vector>
#include <mbedtls/bignum.h>
#include <mbedtls/cipher.h>
#include <mbedtls/cmac.h>
#include <mbedtls/sha256.h>
#include "common/common_funcs.h"
#include "common/fs/file.h"
#include "common/fs/fs.h"
@@ -26,6 +22,7 @@
#include "common/settings.h"
#include "common/string_util.h"
#include "core/crypto/aes_util.h"
#include "core/crypto/crypto.h"
#include "core/crypto/key_manager.h"
#include "core/crypto/partition_data_manager.h"
#include "core/file_sys/content_archive.h"
@@ -485,7 +482,7 @@ static std::array<u8, target_size> MGF1(const std::array<u8, in_size>& seed) {
while (out.size() < target_size) {
out.resize(out.size() + 0x20);
seed_exp[in_size + 3] = static_cast<u8>(i);
mbedtls_sha256_ret(seed_exp.data(), seed_exp.size(), out.data() + out.size() - 0x20, 0);
CalculateSHA256(seed_exp.data(), seed_exp.size(), out.data() + out.size() - 0x20);
++i;
}
@@ -530,24 +527,10 @@ std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket,
return std::make_pair(rights_id, ticket.GetData().title_key_common);
}
mbedtls_mpi D; // RSA Private Exponent
mbedtls_mpi N; // RSA Modulus
mbedtls_mpi S; // Input
mbedtls_mpi M; // Output
mbedtls_mpi_init(&D);
mbedtls_mpi_init(&N);
mbedtls_mpi_init(&S);
mbedtls_mpi_init(&M);
mbedtls_mpi_read_binary(&D, key.decryption_key.data(), key.decryption_key.size());
mbedtls_mpi_read_binary(&N, key.modulus.data(), key.modulus.size());
mbedtls_mpi_read_binary(&S, ticket.GetData().title_key_block.data(), 0x100);
mbedtls_mpi_exp_mod(&M, &S, &D, &N, nullptr);
std::array<u8, 0x100> rsa_step;
mbedtls_mpi_write_binary(&M, rsa_step.data(), rsa_step.size());
CalculateModExp(key.decryption_key.data(), key.decryption_key.size(), key.modulus.data(),
key.modulus.size(), ticket.GetData().title_key_block.data(), 0x100,
rsa_step.data(), rsa_step.size());
u8 m_0 = rsa_step[0];
std::array<u8, 0x20> m_1;
@@ -895,14 +878,6 @@ void KeyManager::DeriveSDSeedLazy() {
}
}
static Key128 CalculateCMAC(const u8* source, size_t size, const Key128& key) {
Key128 out{};
mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), key.data(),
key.size() * 8, source, size, out.data());
return out;
}
void KeyManager::DeriveBase() {
if (!BaseDeriveNecessary()) {
return;
@@ -968,7 +943,8 @@ void KeyManager::DeriveBase() {
key, GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC)));
SetKey(S128KeyType::KeyblobMAC, mac_key, i);
Key128 cmac = CalculateCMAC(encrypted_keyblobs[i].data() + 0x10, 0xA0, mac_key);
Key128 cmac;
CalculateCMAC(encrypted_keyblobs[i].data() + 0x10, 0xA0, mac_key.data(), cmac.data());
if (std::memcmp(cmac.data(), encrypted_keyblobs[i].data(), cmac.size()) != 0) {
continue;
}

View File

@@ -11,7 +11,6 @@
#include <array>
#include <cctype>
#include <cstring>
#include <mbedtls/sha256.h>
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
@@ -19,6 +18,7 @@
#include "common/logging/log.h"
#include "common/string_util.h"
#include "common/swap.h"
#include "core/crypto/crypto.h"
#include "core/crypto/key_manager.h"
#include "core/crypto/partition_data_manager.h"
#include "core/crypto/xts_encryption_layer.h"
@@ -180,7 +180,7 @@ std::array<u8, key_size> FindKeyFromHex(const std::vector<u8>& binary,
std::array<u8, 0x20> temp{};
for (size_t i = 0; i < binary.size() - key_size; ++i) {
mbedtls_sha256_ret(binary.data() + i, key_size, temp.data(), 0);
CalculateSHA256(binary.data() + i, key_size, temp.data());
if (temp != hash)
continue;
@@ -208,7 +208,7 @@ static std::array<Key128, 0x20> FindEncryptedMasterKeyFromHex(const std::vector<
AESCipher<Key128> cipher(key, Mode::ECB);
for (size_t i = 0; i < binary.size() - 0x10; ++i) {
cipher.Transcode(binary.data() + i, dec_temp.size(), dec_temp.data(), Op::Decrypt);
mbedtls_sha256_ret(dec_temp.data(), dec_temp.size(), temp.data(), 0);
CalculateSHA256(dec_temp.data(), dec_temp.size(), temp.data());
for (size_t k = 0; k < out.size(); ++k) {
if (temp == master_key_hashes[k]) {

View File

@@ -5,11 +5,11 @@
#include <algorithm>
#include <random>
#include <regex>
#include <mbedtls/sha256.h>
#include "common/assert.h"
#include "common/fs/path_util.h"
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "core/crypto/crypto.h"
#include "core/crypto/key_manager.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/common_funcs.h"
@@ -64,7 +64,7 @@ static std::string GetRelativePathFromNcaID(const std::array<u8, 16>& nca_id, bo
}
Core::Crypto::SHA256Hash hash{};
mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0);
CalculateSHA256(nca_id.data(), nca_id.size(), hash.data());
const auto format_str =
fmt::runtime(cnmt_suffix ? "/000000{:02X}/{}.cnmt.nca" : "/000000{:02X}/{}.nca");
@@ -146,7 +146,7 @@ bool PlaceholderCache::Create(const NcaID& id, u64 size) const {
}
Core::Crypto::SHA256Hash hash{};
mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0);
CalculateSHA256(id.data(), id.size(), hash.data());
const auto dirname = fmt::format("000000{:02X}", hash[0]);
const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
@@ -170,7 +170,7 @@ bool PlaceholderCache::Delete(const NcaID& id) const {
}
Core::Crypto::SHA256Hash hash{};
mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0);
CalculateSHA256(id.data(), id.size(), hash.data());
const auto dirname = fmt::format("000000{:02X}", hash[0]);
const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
@@ -652,7 +652,7 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
const OptionalHeader opt_header{0, 0};
ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca.GetType()), {}};
const auto& data = nca.GetBaseFile()->ReadBytes(0x100000);
mbedtls_sha256_ret(data.data(), data.size(), c_rec.hash.data(), 0);
CalculateSHA256(data.data(), data.size(), c_rec.hash.data());
std::memcpy(&c_rec.nca_id, &c_rec.hash, 16);
const CNMT new_cnmt(header, opt_header, {c_rec}, {});
if (!RawInstallYuzuMeta(new_cnmt)) {
@@ -727,7 +727,7 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti
id = *override_id;
} else {
const auto& data = in->ReadBytes(0x100000);
mbedtls_sha256_ret(data.data(), data.size(), hash.data(), 0);
CalculateSHA256(data.data(), data.size(), hash.data());
memcpy(id.data(), hash.data(), 16);
}

View File

@@ -8,13 +8,11 @@
#include <regex>
#include <string>
#include <mbedtls/md.h>
#include <mbedtls/sha256.h>
#include "common/fs/path_util.h"
#include "common/hex_util.h"
#include "common/string_util.h"
#include "core/crypto/aes_util.h"
#include "core/crypto/crypto.h"
#include "core/crypto/key_manager.h"
#include "core/crypto/xts_encryption_layer.h"
#include "core/file_sys/content_archive.h"
@@ -29,19 +27,8 @@ constexpr u64 NAX_HEADER_PADDING_SIZE = 0x4000;
template <typename SourceData, typename SourceKey, typename Destination>
static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t key_length,
const SourceData* data, std::size_t data_length) {
mbedtls_md_context_t context;
mbedtls_md_init(&context);
if (mbedtls_md_setup(&context, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1) ||
mbedtls_md_hmac_starts(&context, reinterpret_cast<const u8*>(key), key_length) ||
mbedtls_md_hmac_update(&context, reinterpret_cast<const u8*>(data), data_length) ||
mbedtls_md_hmac_finish(&context, reinterpret_cast<u8*>(out))) {
mbedtls_md_free(&context);
return false;
}
mbedtls_md_free(&context);
return true;
return CalculateHMACSHA256(reinterpret_cast<u8*>(out), reinterpret_cast<const u8*>(key),
key_length, reinterpret_cast<const u8*>(data), data_length);
}
NAX::NAX(VirtualFile file_)
@@ -66,7 +53,7 @@ NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id)
: header(std::make_unique<NAXHeader>()),
file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
Core::Crypto::SHA256Hash hash{};
mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0);
CalculateSHA256(nca_id.data(), nca_id.size(), hash.data());
status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0],
Common::HexToString(nca_id, false)));
}

View File

@@ -3,12 +3,12 @@
// Refer to the license.txt file included.
#include <cctype>
#include <mbedtls/md5.h>
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/crypto/crypto.h"
#include "core/file_sys/vfs.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_process.h"
@@ -46,7 +46,7 @@ u64 GetCurrentBuildID(const Core::System::CurrentBuildProcessID& id) {
BCATDigest DigestFile(const FileSys::VirtualFile& file) {
BCATDigest out{};
const auto bytes = file->ReadAllBytes();
mbedtls_md5_ret(bytes.data(), bytes.size(), out.data());
CalculateMD5(bytes.data(), bytes.size(), out.data());
return out;
}

View File

@@ -4,12 +4,12 @@
#include <memory>
#include <fmt/format.h>
#include <mbedtls/sha256.h>
#include "common/alignment.h"
#include "common/hex_util.h"
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/crypto/crypto.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_process.h"
@@ -469,7 +469,7 @@ public:
system.Memory().ReadBlock(nro_address, nro_data.data(), nro_size);
SHA256Hash hash{};
mbedtls_sha256_ret(nro_data.data(), nro_data.size(), hash.data(), 0);
CalculateSHA256(nro_data.data(), nro_data.size(), hash.data());
// NRO Hash is already loaded
if (std::any_of(nro.begin(), nro.end(), [&hash](const std::pair<VAddr, NROInfo>& info) {

View File

@@ -4,9 +4,6 @@
#include <array>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include "common/assert.h"
#include "common/common_types.h"
#include "common/fs/file.h"
@@ -15,6 +12,7 @@
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/crypto/crypto.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/loader/loader.h"
@@ -31,22 +29,11 @@ namespace Telemetry = Common::Telemetry;
static u64 GenerateTelemetryId() {
u64 telemetry_id{};
mbedtls_entropy_context entropy;
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_context ctr_drbg;
constexpr std::array<char, 18> personalization{{"yuzu Telemetry ID"}};
mbedtls_ctr_drbg_init(&ctr_drbg);
ASSERT(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
reinterpret_cast<const unsigned char*>(personalization.data()),
personalization.size()) == 0);
ASSERT(mbedtls_ctr_drbg_random(&ctr_drbg, reinterpret_cast<unsigned char*>(&telemetry_id),
sizeof(u64)) == 0);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
GenerateRandomBytesWithSeed((u8*)&telemetry_id, sizeof(u64),
reinterpret_cast<const u8*>(personalization.data()),
personalization.size());
return telemetry_id;
}

View File

@@ -7,6 +7,7 @@ add_executable(tests
common/ring_buffer.cpp
common/unique_function.cpp
core/core_timing.cpp
core/crypto.cpp
core/network/network.cpp
tests.cpp
video_core/buffer_base.cpp

102
src/tests/core/crypto.cpp Normal file
View File

@@ -0,0 +1,102 @@
// Copyright 2021 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <catch2/catch.hpp>
#include <array>
#include <cstring>
#include "common/common_types.h"
#include "core/crypto/aes_util.h"
#include "core/crypto/crypto.h"
constexpr static u8 msg[] = "The quick brown fox jumps over the lazy dog";
constexpr static u8 key[] = "key";
TEST_CASE("MD5", "[core]") {
constexpr u8 hash[] = "\x9e\x10\x7d\x9d\x37\x2b\xb6\x82\x6b\xd8\x1d\x35\x42\xa4\x19\xd6";
u8 md[16];
CalculateMD5((const u8*)msg, sizeof(msg) - 1, md);
REQUIRE(std::memcmp(md, hash, 16) == 0);
}
TEST_CASE("SHA256", "[core]") {
constexpr u8 hash[] = "\xd7\xa8\xfb\xb3\x07\xd7\x80\x94\x69\xca\x9a\xbc\xb0\x08\x2e\x4f\x8d"
"\x56\x51\xe4\x6d\x3c\xdb\x76\x2d\x02\xd0\xbf\x37\xc9\xe5\x92";
u8 md[32];
CalculateSHA256((const u8*)msg, sizeof(msg) - 1, md);
REQUIRE(std::memcmp(md, hash, 32) == 0);
}
TEST_CASE("HAMCSHA256", "[core]") {
constexpr u8 hash[] = "\xf7\xbc\x83\xf4\x30\x53\x84\x24\xb1\x32\x98\xe6\xaa\x6f\xb1\x43\xef\x4d"
"\x59\xa1\x49\x46\x17\x59\x97\x47\x9d\xbc\x2d\x1a\x3c\xd8";
u8 md[32];
CalculateHMACSHA256(md, key, sizeof(key) - 1, msg, sizeof(msg) - 1);
REQUIRE(std::memcmp(md, hash, 32) == 0);
}
TEST_CASE("CMAC-AES", "[core]") {
constexpr u8 cmac_key[] = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c";
constexpr u8 cmac_msg1[] = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a";
constexpr u8 cmac_msg2[] =
"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a\xae\x2d\x8a\x57\x1e\x03"
"\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19"
"\x1a\x0a\x52\xef\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10";
constexpr u8 cmac_hash1[] = "\x07\x0a\x16\xb4\x6b\x4d\x41\x44\xf7\x9b\xdd\x9d\xd0\x4a\x28\x7c";
constexpr u8 cmac_hash2[] = "\x51\xf0\xbe\xbf\x7e\x3b\x9d\x92\xfc\x49\x74\x17\x79\x36\x3c\xfe";
u8 cmac_md1[16], cmac_md2[16];
CalculateCMAC(cmac_msg1, sizeof(cmac_msg1) - 1, cmac_key, cmac_md1);
CalculateCMAC(cmac_msg2, sizeof(cmac_msg2) - 1, cmac_key, cmac_md2);
REQUIRE(std::memcmp(cmac_md1, cmac_hash1, 16) == 0);
REQUIRE(std::memcmp(cmac_md2, cmac_hash2, 16) == 0);
}
constexpr static std::array<u8, 16> aes_key = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
constexpr static std::array<u8, 16> aes_iv = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
constexpr static u8 aes_plain[] =
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
"\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00";
TEST_CASE("AES-128-CTR", "[core]") {
constexpr u8 aes_cipher[] = "\x0a\x95\x09\xb6\x45\x6b\xf6\x42\xf9\xca\x9e\x53\xca\x5e\xe4\x55"
"\x0d\x6d\xe1\x98\x6d\x12\x7b\x9e\x9d\xdc\xf8\x0b\x48\xa6\x0e\xdc";
u8 aes_encrypted[32];
Core::Crypto::AESCipher cipher(aes_key, Core::Crypto::Mode::CTR);
cipher.SetIV(aes_iv);
cipher.Transcode(aes_plain, 32, aes_encrypted, Core::Crypto::Op::Encrypt);
REQUIRE(std::memcmp(aes_encrypted, aes_cipher, 32) == 0);
}
TEST_CASE("AES-128-ECB", "[core]") {
constexpr u8 aes_cipher[] = "\x0a\x94\x0b\xb5\x41\x6e\xf0\x45\xf1\xc3\x94\x58\xc6\x53\xea\x5a"
"\x20\xa9\xf9\x92\xb4\x4c\x5b\xe8\x04\x1f\xfc\xdc\x6c\xae\x99\x6a";
u8 aes_encrypted[32];
Core::Crypto::AESCipher cipher(aes_key, Core::Crypto::Mode::ECB);
cipher.Transcode(aes_plain, 32, aes_encrypted, Core::Crypto::Op::Encrypt);
REQUIRE(std::memcmp(aes_encrypted, aes_cipher, 32) == 0);
}
constexpr static std::array<u8, 32> aes_xts_key = {
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0};
TEST_CASE("AES-128-XTS", "[core]") {
constexpr u8 aes_cipher[] = "\x25\x06\xfe\xf2\x0b\x39\xfa\xec\x5a\x69\x93\x41\x60\x95\xb5\xef"
"\x00\x75\xdd\x61\xb9\x9e\x5f\xeb\xbe\xdf\xb3\x2e\x04\xb5\x0c\xa7";
u8 aes_encrypted[32];
Core::Crypto::AESCipher cipher(aes_xts_key, Core::Crypto::Mode::XTS);
cipher.XTSTranscode(aes_plain, 32, aes_encrypted, 0, 16, Core::Crypto::Op::Encrypt);
REQUIRE(std::memcmp(aes_encrypted, aes_cipher, 32) == 0);
}