summaryrefslogtreecommitdiff
path: root/src/core/crypto/aes_util.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2018-08-04 14:33:11 -0400
committerGravatar GitHub2018-08-04 14:33:11 -0400
commit2b06301dbfbfe79687219bf7783a6d1b47695401 (patch)
tree222cc27ecbc7f7e86d2edef8d36436600dee7d7a /src/core/crypto/aes_util.cpp
parentMerge pull request #919 from lioncash/sign (diff)
parentAdd missing parameter to files.push_back() (diff)
downloadyuzu-2b06301dbfbfe79687219bf7783a6d1b47695401.tar.gz
yuzu-2b06301dbfbfe79687219bf7783a6d1b47695401.tar.xz
yuzu-2b06301dbfbfe79687219bf7783a6d1b47695401.zip
Merge pull request #849 from DarkLordZach/xci
XCI and Encrypted NCA Support
Diffstat (limited to 'src/core/crypto/aes_util.cpp')
-rw-r--r--src/core/crypto/aes_util.cpp112
1 files changed, 112 insertions, 0 deletions
diff --git a/src/core/crypto/aes_util.cpp b/src/core/crypto/aes_util.cpp
new file mode 100644
index 000000000..4690af5f8
--- /dev/null
+++ b/src/core/crypto/aes_util.cpp
@@ -0,0 +1,112 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <mbedtls/cipher.h>
6#include "core/crypto/aes_util.h"
7#include "core/crypto/key_manager.h"
8
9namespace Core::Crypto {
10
11static_assert(static_cast<size_t>(Mode::CTR) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_CTR),
12 "CTR has incorrect value.");
13static_assert(static_cast<size_t>(Mode::ECB) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_ECB),
14 "ECB has incorrect value.");
15static_assert(static_cast<size_t>(Mode::XTS) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_XTS),
16 "XTS has incorrect value.");
17
18// Structure to hide mbedtls types from header file
19struct CipherContext {
20 mbedtls_cipher_context_t encryption_context;
21 mbedtls_cipher_context_t decryption_context;
22};
23
24template <typename Key, size_t KeySize>
25Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode)
26 : ctx(std::make_unique<CipherContext>()) {
27 mbedtls_cipher_init(&ctx->encryption_context);
28 mbedtls_cipher_init(&ctx->decryption_context);
29
30 ASSERT_MSG((mbedtls_cipher_setup(
31 &ctx->encryption_context,
32 mbedtls_cipher_info_from_type(static_cast<mbedtls_cipher_type_t>(mode))) ||
33 mbedtls_cipher_setup(
34 &ctx->decryption_context,
35 mbedtls_cipher_info_from_type(static_cast<mbedtls_cipher_type_t>(mode)))) == 0,
36 "Failed to initialize mbedtls ciphers.");
37
38 ASSERT(
39 !mbedtls_cipher_setkey(&ctx->encryption_context, key.data(), KeySize * 8, MBEDTLS_ENCRYPT));
40 ASSERT(
41 !mbedtls_cipher_setkey(&ctx->decryption_context, key.data(), KeySize * 8, MBEDTLS_DECRYPT));
42 //"Failed to set key on mbedtls ciphers.");
43}
44
45template <typename Key, size_t KeySize>
46AESCipher<Key, KeySize>::~AESCipher() {
47 mbedtls_cipher_free(&ctx->encryption_context);
48 mbedtls_cipher_free(&ctx->decryption_context);
49}
50
51template <typename Key, size_t KeySize>
52void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) {
53 ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, iv.data(), iv.size()) ||
54 mbedtls_cipher_set_iv(&ctx->decryption_context, iv.data(), iv.size())) == 0,
55 "Failed to set IV on mbedtls ciphers.");
56}
57
58template <typename Key, size_t KeySize>
59void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op op) {
60 size_t written = 0;
61
62 const auto context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context;
63
64 mbedtls_cipher_reset(context);
65
66 if (mbedtls_cipher_get_cipher_mode(context) == MBEDTLS_MODE_XTS) {
67 mbedtls_cipher_update(context, src, size, dest, &written);
68 if (written != size)
69 LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.",
70 size, written);
71 } else {
72 const auto block_size = mbedtls_cipher_get_block_size(context);
73
74 for (size_t offset = 0; offset < size; offset += block_size) {
75 auto length = std::min<size_t>(block_size, size - offset);
76 mbedtls_cipher_update(context, src + offset, length, dest + offset, &written);
77 if (written != length)
78 LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.",
79 length, written);
80 }
81 }
82
83 mbedtls_cipher_finish(context, nullptr, nullptr);
84}
85
86template <typename Key, size_t KeySize>
87void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id,
88 size_t sector_size, Op op) {
89 if (size % sector_size > 0) {
90 LOG_CRITICAL(Crypto, "Data size must be a multiple of sector size.");
91 return;
92 }
93
94 for (size_t i = 0; i < size; i += sector_size) {
95 SetIV(CalculateNintendoTweak(sector_id++));
96 Transcode<u8, u8>(src + i, sector_size, dest + i, op);
97 }
98}
99
100template <typename Key, size_t KeySize>
101std::vector<u8> AESCipher<Key, KeySize>::CalculateNintendoTweak(size_t sector_id) {
102 std::vector<u8> out(0x10);
103 for (size_t i = 0xF; i <= 0xF; --i) {
104 out[i] = sector_id & 0xFF;
105 sector_id >>= 8;
106 }
107 return out;
108}
109
110template class AESCipher<Key128>;
111template class AESCipher<Key256>;
112} // namespace Core::Crypto \ No newline at end of file