2020-12-22 00:16:09 +01:00
|
|
|
|
// Copyright (C) 2014 Hykem <hykem@hotmail.com>
|
2021-05-02 13:56:32 +05:30
|
|
|
|
// Licensed under the terms of the GNU GPL, version 2.0 or later versions.
|
|
|
|
|
|
// http://www.gnu.org/licenses/gpl-2.0.txt
|
2014-04-12 11:42:20 +02:00
|
|
|
|
|
2017-06-18 23:47:24 +03:00
|
|
|
|
#include "utils.h"
|
2020-11-19 21:02:39 +01:00
|
|
|
|
#include "aes.h"
|
|
|
|
|
|
#include "sha1.h"
|
2022-06-06 22:06:42 +02:00
|
|
|
|
#include "sha256.h"
|
2021-07-27 11:04:46 +02:00
|
|
|
|
#include "key_vault.h"
|
2025-11-14 22:22:01 +01:00
|
|
|
|
#include <charconv>
|
|
|
|
|
|
#include <cstdlib>
|
2017-06-18 23:47:24 +03:00
|
|
|
|
#include <cstring>
|
2025-11-14 22:22:01 +01:00
|
|
|
|
#include <cstdio>
|
|
|
|
|
|
#include <ctime>
|
2025-12-08 11:43:15 +01:00
|
|
|
|
#include "Utilities/StrFmt.h"
|
2020-03-04 17:08:40 +03:00
|
|
|
|
#include "Utilities/StrUtil.h"
|
2020-09-25 09:42:41 +03:00
|
|
|
|
#include "Utilities/File.h"
|
2014-10-01 14:57:44 +01:00
|
|
|
|
|
2017-01-23 17:41:47 +01:00
|
|
|
|
#include <memory>
|
2020-03-04 17:08:40 +03:00
|
|
|
|
#include <string>
|
|
|
|
|
|
#include <string_view>
|
2021-05-30 15:10:46 +01:00
|
|
|
|
#include <span>
|
2017-01-23 17:41:47 +01:00
|
|
|
|
|
2019-11-28 21:18:37 +03:00
|
|
|
|
// Auxiliary functions (endian swap, xor).
|
2014-04-12 11:42:20 +02:00
|
|
|
|
|
2026-04-22 15:06:02 +02:00
|
|
|
|
// Bytes conversion auxiliary function.
|
2026-06-14 08:24:56 +02:00
|
|
|
|
void bytes_to_hex(std::string& hex_str, const unsigned char* data, usz data_length)
|
2026-04-22 15:06:02 +02:00
|
|
|
|
{
|
2026-06-14 08:24:56 +02:00
|
|
|
|
const usz str_length = data_length * 2;
|
2026-04-22 15:06:02 +02:00
|
|
|
|
|
|
|
|
|
|
hex_str.resize(str_length);
|
|
|
|
|
|
|
2026-06-14 08:24:56 +02:00
|
|
|
|
for (usz i = 0; i < str_length; i += 2)
|
2026-04-22 15:06:02 +02:00
|
|
|
|
{
|
|
|
|
|
|
const auto [ptr, err] = std::to_chars(hex_str.data() + i, hex_str.data() + i + 2, *data++, 16);
|
|
|
|
|
|
if (err != std::errc())
|
|
|
|
|
|
{
|
|
|
|
|
|
fmt::throw_exception("Failed to read bytes: %s", std::make_error_code(err).message());
|
|
|
|
|
|
}
|
2026-05-07 05:38:57 +02:00
|
|
|
|
|
|
|
|
|
|
// Padding handling for values ​​< 0x10 (e.g. 0x05 becomes "5" instead of "05")
|
|
|
|
|
|
// If to_chars only writes 1 character, we move to the right and put '0'
|
|
|
|
|
|
if (ptr == &hex_str[i] + 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
hex_str[i + 1] = hex_str[i];
|
|
|
|
|
|
hex_str[i] = '0';
|
|
|
|
|
|
}
|
2026-04-22 15:06:02 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Hex string conversion auxiliary function.
|
2026-06-14 08:24:56 +02:00
|
|
|
|
void hex_to_bytes(unsigned char* data, std::string_view hex_str, usz str_length, std::string* error)
|
2014-04-12 11:42:20 +02:00
|
|
|
|
{
|
2026-06-14 08:24:56 +02:00
|
|
|
|
const usz strn_length = (str_length > 0) ? str_length : hex_str.size();
|
2014-03-03 04:48:07 +00:00
|
|
|
|
|
|
|
|
|
|
// Don't convert if the string length is odd.
|
2017-06-18 23:47:24 +03:00
|
|
|
|
if ((strn_length % 2) == 0)
|
2014-03-03 04:48:07 +00:00
|
|
|
|
{
|
2026-06-14 08:24:56 +02:00
|
|
|
|
for (usz i = 0; i < strn_length; i += 2)
|
2014-03-03 04:48:07 +00:00
|
|
|
|
{
|
2025-11-14 22:22:01 +01:00
|
|
|
|
const auto [ptr, err] = std::from_chars(hex_str.data() + i, hex_str.data() + i + 2, *data++, 16);
|
|
|
|
|
|
if (err != std::errc())
|
|
|
|
|
|
{
|
2026-06-14 08:24:56 +02:00
|
|
|
|
std::string msg = fmt::format("Failed to read hex string: %s (hex='%s')", std::make_error_code(err).message(), hex_str);
|
|
|
|
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
|
|
{
|
|
|
|
|
|
*error = std::move(msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
fmt::throw_exception("%s", msg);
|
|
|
|
|
|
}
|
2025-11-14 22:22:01 +01:00
|
|
|
|
}
|
2014-03-03 04:48:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2014-03-30 21:09:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Crypto functions (AES128-CBC, AES128-ECB, SHA1-HMAC and AES-CMAC).
|
2026-07-01 08:42:17 +02:00
|
|
|
|
void aescbc128_decrypt(const unsigned char *key, unsigned char *iv, const unsigned char *in, unsigned char *out, usz len)
|
2014-03-30 21:09:49 +01:00
|
|
|
|
{
|
|
|
|
|
|
aes_context ctx;
|
|
|
|
|
|
aes_setkey_dec(&ctx, key, 128);
|
|
|
|
|
|
aes_crypt_cbc(&ctx, AES_DECRYPT, len, iv, in, out);
|
|
|
|
|
|
|
|
|
|
|
|
// Reset the IV.
|
|
|
|
|
|
memset(iv, 0, 0x10);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-01 08:42:17 +02:00
|
|
|
|
void aescbc128_encrypt(const unsigned char *key, unsigned char *iv, const unsigned char *in, unsigned char *out, usz len)
|
2014-10-01 14:57:44 +01:00
|
|
|
|
{
|
|
|
|
|
|
aes_context ctx;
|
|
|
|
|
|
aes_setkey_enc(&ctx, key, 128);
|
|
|
|
|
|
aes_crypt_cbc(&ctx, AES_ENCRYPT, len, iv, in, out);
|
|
|
|
|
|
|
|
|
|
|
|
// Reset the IV.
|
|
|
|
|
|
memset(iv, 0, 0x10);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-01 08:42:17 +02:00
|
|
|
|
void aesecb128_encrypt(const unsigned char *key, const unsigned char *in, unsigned char *out)
|
2014-03-30 21:09:49 +01:00
|
|
|
|
{
|
|
|
|
|
|
aes_context ctx;
|
|
|
|
|
|
aes_setkey_enc(&ctx, key, 128);
|
|
|
|
|
|
aes_crypt_ecb(&ctx, AES_ENCRYPT, in, out);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-01 08:42:17 +02:00
|
|
|
|
bool hmac_hash_compare(const unsigned char *key, int key_len, const unsigned char *in, usz in_len, const unsigned char *hash, usz hash_len)
|
2014-03-30 21:09:49 +01:00
|
|
|
|
{
|
2021-04-09 21:12:47 +02:00
|
|
|
|
const std::unique_ptr<u8[]> out(new u8[key_len]);
|
2014-03-30 21:09:49 +01:00
|
|
|
|
|
2017-03-06 18:59:05 -06:00
|
|
|
|
sha1_hmac(key, key_len, in, in_len, out.get());
|
2014-04-12 11:42:20 +02:00
|
|
|
|
|
2017-03-06 18:59:05 -06:00
|
|
|
|
return std::memcmp(out.get(), hash, hash_len) == 0;
|
2014-03-30 21:09:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-01 08:42:17 +02:00
|
|
|
|
void hmac_hash_forge(const unsigned char *key, int key_len, const unsigned char *in, usz in_len, unsigned char *hash)
|
2014-10-01 14:57:44 +01:00
|
|
|
|
{
|
|
|
|
|
|
sha1_hmac(key, key_len, in, in_len, hash);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-01 08:42:17 +02:00
|
|
|
|
bool cmac_hash_compare(const unsigned char *key, int key_len, const unsigned char *in, usz in_len, const unsigned char *hash, usz hash_len)
|
2014-03-30 21:09:49 +01:00
|
|
|
|
{
|
2021-04-09 21:12:47 +02:00
|
|
|
|
const std::unique_ptr<u8[]> out(new u8[key_len]);
|
2014-03-30 21:09:49 +01:00
|
|
|
|
|
|
|
|
|
|
aes_context ctx;
|
|
|
|
|
|
aes_setkey_enc(&ctx, key, 128);
|
2017-03-06 18:59:05 -06:00
|
|
|
|
aes_cmac(&ctx, in_len, in, out.get());
|
2014-04-12 11:42:20 +02:00
|
|
|
|
|
2017-03-06 18:59:05 -06:00
|
|
|
|
return std::memcmp(out.get(), hash, hash_len) == 0;
|
2014-03-30 21:09:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-01 08:42:17 +02:00
|
|
|
|
void cmac_hash_forge(const unsigned char *key, int /*key_len*/, const unsigned char *in, usz in_len, unsigned char *hash)
|
2014-03-30 21:09:49 +01:00
|
|
|
|
{
|
2014-10-01 14:57:44 +01:00
|
|
|
|
aes_context ctx;
|
|
|
|
|
|
aes_setkey_enc(&ctx, key, 128);
|
|
|
|
|
|
aes_cmac(&ctx, in_len, in, hash);
|
2014-04-12 11:42:20 +02:00
|
|
|
|
}
|
2014-10-01 14:57:44 +01:00
|
|
|
|
|
2026-06-14 06:25:39 +02:00
|
|
|
|
char* extract_file_name(std::string_view file_path, char real_file_name[CRYPTO_MAX_PATH])
|
2014-10-01 14:57:44 +01:00
|
|
|
|
{
|
2026-06-14 06:25:39 +02:00
|
|
|
|
if (const auto pos = file_path.find_last_of(fs::delim); pos != umax)
|
2020-03-04 22:39:50 +02:00
|
|
|
|
{
|
2026-06-14 06:25:39 +02:00
|
|
|
|
file_path.remove_prefix(pos + 1);
|
2020-03-04 22:39:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-30 15:10:46 +01:00
|
|
|
|
std::span r(real_file_name, CRYPTO_MAX_PATH);
|
2026-06-14 06:25:39 +02:00
|
|
|
|
strcpy_trunc(r, file_path);
|
2014-10-01 14:57:44 +01:00
|
|
|
|
return real_file_name;
|
2016-02-02 00:52:27 +03:00
|
|
|
|
}
|
2021-04-18 19:33:38 +01:00
|
|
|
|
|
2022-06-06 22:06:42 +02:00
|
|
|
|
std::string sha256_get_hash(const char* data, usz size, bool lower_case)
|
|
|
|
|
|
{
|
|
|
|
|
|
u8 res_hash[32];
|
|
|
|
|
|
mbedtls_sha256_context ctx;
|
|
|
|
|
|
mbedtls_sha256_init(&ctx);
|
|
|
|
|
|
mbedtls_sha256_starts_ret(&ctx, 0);
|
|
|
|
|
|
mbedtls_sha256_update_ret(&ctx, reinterpret_cast<const unsigned char*>(data), size);
|
|
|
|
|
|
mbedtls_sha256_finish_ret(&ctx, res_hash);
|
|
|
|
|
|
|
|
|
|
|
|
std::string res_hash_string("0000000000000000000000000000000000000000000000000000000000000000");
|
|
|
|
|
|
|
|
|
|
|
|
for (usz index = 0; index < 32; index++)
|
|
|
|
|
|
{
|
|
|
|
|
|
const auto pal = lower_case ? "0123456789abcdef" : "0123456789ABCDEF";
|
|
|
|
|
|
res_hash_string[index * 2] = pal[res_hash[index] >> 4];
|
|
|
|
|
|
res_hash_string[(index * 2) + 1] = pal[res_hash[index] & 15];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return res_hash_string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-04-18 19:33:38 +01:00
|
|
|
|
void mbedtls_zeroize(void *v, size_t n)
|
|
|
|
|
|
{
|
|
|
|
|
|
static void *(*const volatile unop_memset)(void *, int, size_t) = &memset;
|
|
|
|
|
|
(void)unop_memset(v, 0, n);
|
|
|
|
|
|
}
|
2021-07-27 11:04:46 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// SC passphrase crypto
|
|
|
|
|
|
|
|
|
|
|
|
void sc_form_key(const u8* sc_key, const std::array<u8, PASSPHRASE_KEY_LEN>& laid_paid, u8* key)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (u32 i = 0; i < PASSPHRASE_KEY_LEN; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
key[i] = static_cast<u8>(sc_key[i] ^ laid_paid[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::array<u8, PASSPHRASE_KEY_LEN> sc_combine_laid_paid(s64 laid, s64 paid)
|
|
|
|
|
|
{
|
|
|
|
|
|
const std::string paid_laid = fmt::format("%016llx%016llx", laid, paid);
|
|
|
|
|
|
std::array<u8, PASSPHRASE_KEY_LEN> out{};
|
2025-11-23 06:11:36 +01:00
|
|
|
|
hex_to_bytes(out.data(), paid_laid, PASSPHRASE_KEY_LEN * 2);
|
2021-07-27 11:04:46 +02:00
|
|
|
|
return out;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::array<u8, PASSPHRASE_KEY_LEN> vtrm_get_laid_paid_from_type(int type)
|
|
|
|
|
|
{
|
|
|
|
|
|
// No idea what this type stands for
|
|
|
|
|
|
switch (type)
|
|
|
|
|
|
{
|
|
|
|
|
|
case 0: return sc_combine_laid_paid(0xFFFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFFFL);
|
|
|
|
|
|
case 1: return sc_combine_laid_paid(LAID_2, 0x1070000000000001L);
|
|
|
|
|
|
case 2: return sc_combine_laid_paid(LAID_2, 0x0000000000000000L);
|
|
|
|
|
|
case 3: return sc_combine_laid_paid(LAID_2, PAID_69);
|
|
|
|
|
|
default:
|
|
|
|
|
|
fmt::throw_exception("vtrm_get_laid_paid_from_type: Wrong type specified (type=%d)", type);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::array<u8, PASSPHRASE_KEY_LEN> vtrm_portability_laid_paid()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 107000002A000001
|
|
|
|
|
|
return sc_combine_laid_paid(0x0000000000000000L, 0x0000000000000000L);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-01 08:42:17 +02:00
|
|
|
|
int sc_decrypt(const u8* sc_key, const std::array<u8, PASSPHRASE_KEY_LEN>& laid_paid, u8* iv, const u8* input, u8* output)
|
2021-07-27 11:04:46 +02:00
|
|
|
|
{
|
|
|
|
|
|
aes_context ctx;
|
|
|
|
|
|
u8 key[PASSPHRASE_KEY_LEN];
|
|
|
|
|
|
sc_form_key(sc_key, laid_paid, key);
|
|
|
|
|
|
aes_setkey_dec(&ctx, key, 128);
|
|
|
|
|
|
return aes_crypt_cbc(&ctx, AES_DECRYPT, PASSPHRASE_OUT_LEN, iv, input, output);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-01 08:42:17 +02:00
|
|
|
|
int vtrm_decrypt(int type, u8* iv, const u8* input, u8* output)
|
2021-07-27 11:04:46 +02:00
|
|
|
|
{
|
|
|
|
|
|
return sc_decrypt(SC_ISO_SERIES_KEY_2, vtrm_get_laid_paid_from_type(type), iv, input, output);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-01 08:42:17 +02:00
|
|
|
|
int vtrm_decrypt_master(s64 laid, s64 paid, u8* iv, const u8* input, u8* output)
|
2021-07-27 11:04:46 +02:00
|
|
|
|
{
|
|
|
|
|
|
return sc_decrypt(SC_ISO_SERIES_INTERNAL_KEY_3, sc_combine_laid_paid(laid, paid), iv, input, output);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const u8* vtrm_portability_type_mapper(int type)
|
|
|
|
|
|
{
|
|
|
|
|
|
// No idea what this type stands for
|
|
|
|
|
|
switch (type)
|
|
|
|
|
|
{
|
|
|
|
|
|
//case 0: return key_for_type_1;
|
|
|
|
|
|
case 1: return SC_ISO_SERIES_KEY_2;
|
|
|
|
|
|
case 2: return SC_ISO_SERIES_KEY_1;
|
|
|
|
|
|
case 3: return SC_KEY_FOR_MASTER_2;
|
|
|
|
|
|
default:
|
|
|
|
|
|
fmt::throw_exception("vtrm_portability_type_mapper: Wrong type specified (type=%d)", type);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-01 08:42:17 +02:00
|
|
|
|
int vtrm_decrypt_with_portability(int type, u8* iv, const u8* input, u8* output)
|
2021-07-27 11:04:46 +02:00
|
|
|
|
{
|
|
|
|
|
|
return sc_decrypt(vtrm_portability_type_mapper(type), vtrm_portability_laid_paid(), iv, input, output);
|
|
|
|
|
|
}
|