From eda18c8396acd5ac2a95b67cfd16ec3e6370b306 Mon Sep 17 00:00:00 2001 From: lammmab Date: Fri, 29 May 2026 22:47:31 -0400 Subject: [PATCH 1/2] aes --- CMakeLists.txt | 13 ++---- cmake/encrypt.cmake | 25 ++++++++++ src/disc/gc_iso.c | 3 ++ src/disc/gc_wbfs.c | 3 ++ src/disc/gc_wii.c | 50 +++----------------- src/{disc => encrypt}/aes.c | 0 src/{disc => encrypt}/aes.h | 0 src/encrypt/platform.c | 93 +++++++++++++++++++++++++++++++++++++ src/encrypt/platform.h | 12 +++++ test/test_aes.c | 10 ++-- 10 files changed, 152 insertions(+), 57 deletions(-) create mode 100644 cmake/encrypt.cmake rename src/{disc => encrypt}/aes.c (100%) rename src/{disc => encrypt}/aes.h (100%) create mode 100644 src/encrypt/platform.c create mode 100644 src/encrypt/platform.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c44a3a3..939d83a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,20 +51,17 @@ add_library(gc_disc STATIC src/disc/gc_wia.c src/disc/gc_wbfs.c src/disc/gc_rvz.c - src/disc/aes.c src/disc/gc_wii.c src/disc/lzma.c + src/encrypt/aes.c + src/encrypt/platform.c ) -target_include_directories(gc_disc PUBLIC include PRIVATE src/disc) +target_include_directories(gc_disc PUBLIC include PRIVATE src) target_link_libraries(gc_disc PRIVATE ZLIB::ZLIB PUBLIC gc_util Confluence::confluence) -if(APPLE) - option(SIPHON_USE_COMMONCRYPTO "Use Apple CommonCrypto for Wii AES" ON) - if(SIPHON_USE_COMMONCRYPTO) - target_compile_definitions(gc_disc PRIVATE SIPHON_USE_COMMONCRYPTO=1) - endif() -endif() +include(cmake/encrypt.cmake) +siphon_apply_crypto_backend(gc_disc) if(ZSTD_FOUND) target_include_directories(gc_disc PRIVATE ${ZSTD_INCLUDE_DIRS}) diff --git a/cmake/encrypt.cmake b/cmake/encrypt.cmake new file mode 100644 index 0000000..767218e --- /dev/null +++ b/cmake/encrypt.cmake @@ -0,0 +1,25 @@ +function(siphon_apply_crypto_backend target) + if(APPLE) + target_compile_definitions(${target} PRIVATE SIPHON_USE_COMMONCRYPTO=1) + message(STATUS "CRYPTO: CommonCrypto (Apple)") + + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64|i[3-6]86)$") + target_compile_definitions(${target} PRIVATE SIPHON_USE_AESNI=1) + if(MSVC) + else() + target_compile_options(${target} PRIVATE -maes) + endif() + message(STATUS "CRYPTO: AES-NI (x86)") + + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)$") + target_compile_definitions(${target} PRIVATE SIPHON_USE_ARM_CRYPTO=1) + if(NOT MSVC) + target_compile_options(${target} PRIVATE -march=armv8-a+crypto) + endif() + message(STATUS "CRYPTO: ARMv8 Crypto (ARM64)") + + else() + message(STATUS "CRYPTO: tiny-AES-c (portable fallback)") + endif() + +endfunction() \ No newline at end of file diff --git a/src/disc/gc_iso.c b/src/disc/gc_iso.c index 8758f52..ee28838 100644 --- a/src/disc/gc_iso.c +++ b/src/disc/gc_iso.c @@ -1,3 +1,6 @@ +#define _FILE_OFFSET_BITS 64 +#define _POSIX_C_SOURCE 200809L + #include "gc_disc_internal.h" #include #include diff --git a/src/disc/gc_wbfs.c b/src/disc/gc_wbfs.c index 9808a80..1751b4e 100644 --- a/src/disc/gc_wbfs.c +++ b/src/disc/gc_wbfs.c @@ -1,3 +1,6 @@ +#define _FILE_OFFSET_BITS 64 +#define _POSIX_C_SOURCE 200809L + #include "gc_disc_internal.h" #include "siphon_log.h" #include diff --git a/src/disc/gc_wii.c b/src/disc/gc_wii.c index 9a1382e..e83344a 100644 --- a/src/disc/gc_wii.c +++ b/src/disc/gc_wii.c @@ -1,12 +1,9 @@ #include "gc_disc_internal.h" #include "siphon_log.h" -#include "aes.h" #include #include -#if defined(SIPHON_USE_COMMONCRYPTO) -#include -#endif +#include "encrypt/platform.h" #define WII_CLUSTER 0x8000u #define WII_CLUSTER_HASH 0x0400u @@ -20,9 +17,6 @@ typedef struct { uint8_t clusterEnc[WII_CLUSTER]; uint8_t clusterPlain[WII_CLUSTER_DATA]; uint64_t cachedCluster; -#if !defined(SIPHON_USE_COMMONCRYPTO) - struct AES_ctx aes; -#endif } WiiCtx; static const uint8_t WII_COMMON_KEYS[2][16] = { @@ -65,9 +59,7 @@ static int wii_probe_boot(gc_read_fn raw, GCDisc* disc, uint32_t dataStart, if (raw(disc, dataStart, cluster, WII_CLUSTER) < 0) return -1; memcpy(iv, cluster + 0x3D0, 16); memcpy(plain, cluster + WII_CLUSTER_HASH, WII_CLUSTER_DATA); - struct AES_ctx ctx; - AES_init_ctx_iv(&ctx, titleKey, iv); - AES_CBC_decrypt_buffer(&ctx, plain, WII_CLUSTER_DATA); + aes128_cbc_decrypt(titleKey, iv, plain, plain, WII_CLUSTER_DATA); memcpy(preview, plain, 6); preview[6] = '\0'; return wii_boot_valid(plain) ? 0 : 1; @@ -87,9 +79,7 @@ static int wii_find_title_key(GCDisc* disc, gc_read_fn raw, const uint8_t* ticke uint8_t iv[16] = {0}; memcpy(iv, ticket + 0x1DC, 8); memcpy(out, ticket + 0x1BF, 16); - struct AES_ctx ctx; - AES_init_ctx_iv(&ctx, commonKey, iv); - AES_CBC_decrypt_buffer(&ctx, out, 16); + aes128_cbc_decrypt(commonKey, iv, out, out, 16); return 0; } } @@ -109,9 +99,7 @@ static int wii_find_title_key(GCDisc* disc, gc_read_fn raw, const uint8_t* ticke char preview[7]; wii_common_key_by_index(order[i], commonKey); memcpy(out, ticket + 0x1BF, 16); - struct AES_ctx ctx; - AES_init_ctx_iv(&ctx, commonKey, iv); - AES_CBC_decrypt_buffer(&ctx, out, 16); + aes128_cbc_decrypt(commonKey, iv, out, out, 16); if (wii_probe_boot(raw, disc, dataStart, out, preview) == 0) return 0; } @@ -121,28 +109,10 @@ static int wii_find_title_key(GCDisc* disc, gc_read_fn raw, const uint8_t* ticke } static void wii_decrypt_cluster(const uint8_t titleKey[16], -#if !defined(SIPHON_USE_COMMONCRYPTO) - struct AES_ctx* aes, -#endif const uint8_t* enc, uint8_t* plain) { uint8_t iv[16]; memcpy(iv, enc + 0x3D0, 16); - -#if defined(SIPHON_USE_COMMONCRYPTO) - size_t outLen = 0; - CCStatus st = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, 0, - titleKey, kCCKeySizeAES128, iv, - enc + WII_CLUSTER_HASH, WII_CLUSTER_DATA, - plain, WII_CLUSTER_DATA, &outLen); - if (st != kCCSuccess || outLen != WII_CLUSTER_DATA) { - siphon_log("Wii: CCCrypt failed status=%d outLen=%zu", (int)st, outLen); - memset(plain, 0, WII_CLUSTER_DATA); - } -#else - memcpy(plain, enc + WII_CLUSTER_HASH, WII_CLUSTER_DATA); - AES_ctx_set_iv(aes, iv); - AES_CBC_decrypt_buffer(aes, plain, WII_CLUSTER_DATA); -#endif + aes128_cbc_decrypt(titleKey, iv, enc + WII_CLUSTER_HASH, plain, WII_CLUSTER_DATA); } static int wii_read(GCDisc* disc, uint64_t offset, void* buf, size_t size) { @@ -161,11 +131,7 @@ static int wii_read(GCDisc* disc, uint64_t offset, void* buf, size_t size) { return -1; } - wii_decrypt_cluster(w->titleKey, -#if !defined(SIPHON_USE_COMMONCRYPTO) - &w->aes, -#endif - w->clusterEnc, w->clusterPlain); + wii_decrypt_cluster(w->titleKey, w->clusterEnc, w->clusterPlain); w->cachedCluster = cluster; } @@ -246,10 +212,6 @@ int gc_wii_wrap(GCDisc* disc) { return -1; } -#if !defined(SIPHON_USE_COMMONCRYPTO) - AES_init_ctx_key(&w->aes, w->titleKey); -#endif - disc->wii = w; disc->read = wii_read; disc->offsetShift = 2; diff --git a/src/disc/aes.c b/src/encrypt/aes.c similarity index 100% rename from src/disc/aes.c rename to src/encrypt/aes.c diff --git a/src/disc/aes.h b/src/encrypt/aes.h similarity index 100% rename from src/disc/aes.h rename to src/encrypt/aes.h diff --git a/src/encrypt/platform.c b/src/encrypt/platform.c new file mode 100644 index 0000000..0efb38d --- /dev/null +++ b/src/encrypt/platform.c @@ -0,0 +1,93 @@ +#include "platform.h" +#include + +#if defined(SIPHON_USE_COMMONCRYPTO) +#include + +void aes128_cbc_decrypt(const uint8_t key[16], const uint8_t iv[16], + const uint8_t* in, uint8_t* out, size_t len) { + size_t outLen; + CCCrypt(kCCDecrypt, kCCAlgorithmAES128, 0, + key, kCCKeySizeAES128, iv, + in, len, out, len, &outLen); +} + +#elif defined(SIPHON_USE_AESNI) +#include + +void aes128_cbc_decrypt(const uint8_t key[16], const uint8_t iv[16], + const uint8_t* in, uint8_t* out, size_t len) { + __m128i rk[11]; + __m128i k = _mm_loadu_si128((const __m128i*)key); + rk[0] = k; + #define EXP(i, imm) { \ + __m128i t = _mm_aeskeygenassist_si128(rk[i-1], imm); \ + t = _mm_shuffle_epi32(t, 0xFF); \ + __m128i s = _mm_xor_si128(rk[i-1], _mm_slli_si128(rk[i-1], 4)); \ + s = _mm_xor_si128(s, _mm_slli_si128(s, 4)); \ + s = _mm_xor_si128(s, _mm_slli_si128(s, 4)); \ + rk[i] = _mm_xor_si128(s, t); } + EXP(1,0x01) EXP(2,0x02) EXP(3,0x04) EXP(4,0x08) + EXP(5,0x10) EXP(6,0x20) EXP(7,0x40) EXP(8,0x80) + EXP(9,0x1b) EXP(10,0x36) + #undef EXP + + __m128i drk[11]; + drk[0] = rk[10]; + for (int i = 1; i < 10; i++) drk[i] = _mm_aesimc_si128(rk[10-i]); + drk[10] = rk[0]; + + __m128i feedback = _mm_loadu_si128((const __m128i*)iv); + for (size_t i = 0; i < len; i += 16) { + __m128i ct = _mm_loadu_si128((const __m128i*)(in + i)); + __m128i pt = _mm_xor_si128(ct, drk[0]); + for (int r = 1; r < 10; r++) pt = _mm_aesdec_si128(pt, drk[r]); + pt = _mm_aesdeclast_si128(pt, drk[10]); + pt = _mm_xor_si128(pt, feedback); + _mm_storeu_si128((__m128i*)(out + i), pt); + feedback = ct; + } +} + +#elif defined(SIPHON_USE_ARM_CRYPTO) +#include +#include "aes.h" + +void aes128_cbc_decrypt(const uint8_t key[16], const uint8_t iv[16], + const uint8_t* in, uint8_t* out, size_t len) { + uint8_t rkbuf[176]; + struct AES_ctx ctx; + AES_init_ctx_key(&ctx, key); + memcpy(rkbuf, ctx.RoundKey, 176); + + uint8x16_t rk[11]; + for (int i = 0; i < 11; i++) rk[i] = vld1q_u8(rkbuf + i * 16); + + uint8x16_t feedback = vld1q_u8(iv); + for (size_t i = 0; i < len; i += 16) { + uint8x16_t ct = vld1q_u8(in + i); + uint8x16_t pt = veorq_u8(ct, rk[10]); + for (int r = 9; r > 0; r--) { + pt = vaesdq_u8(pt, vdupq_n_u8(0)); + pt = vaesimcq_u8(pt); + pt = veorq_u8(pt, rk[r]); + } + pt = vaesdq_u8(pt, vdupq_n_u8(0)); + pt = veorq_u8(pt, rk[0]); + pt = veorq_u8(pt, feedback); + vst1q_u8(out + i, pt); + feedback = ct; + } +} + +#else +#include "aes.h" + +void aes128_cbc_decrypt(const uint8_t key[16], const uint8_t iv[16], + const uint8_t* in, uint8_t* out, size_t len) { + struct AES_ctx ctx; + AES_init_ctx_iv(&ctx, key, iv); + if (out != in) memcpy(out, in, len); + AES_CBC_decrypt_buffer(&ctx, out, len); +} +#endif \ No newline at end of file diff --git a/src/encrypt/platform.h b/src/encrypt/platform.h new file mode 100644 index 0000000..8ffcf13 --- /dev/null +++ b/src/encrypt/platform.h @@ -0,0 +1,12 @@ +#pragma once + +#ifndef SIPHON_PLATFORM_H +#define SIPHON_PLATFORM_H + +#include +#include + +void aes128_cbc_decrypt(const uint8_t key[16], const uint8_t iv[16], + const uint8_t* in, uint8_t* out, size_t len); + +#endif \ No newline at end of file diff --git a/test/test_aes.c b/test/test_aes.c index 6b73fc9..836f01c 100644 --- a/test/test_aes.c +++ b/test/test_aes.c @@ -1,4 +1,4 @@ -#include "aes.h" +#include "encrypt/platform.h" #include #include @@ -11,13 +11,13 @@ int main(void) { 0xdc,0x11,0x85,0x97,0x19,0x6a,0x0b,0x32}; uint8_t expect[16] = {0x32,0x43,0xf6,0xa8,0x88,0x5a,0x30,0x8d, 0x31,0x31,0x98,0xa2,0xe0,0x37,0x07,0x34}; - struct AES_ctx ctx; - AES_init_ctx_iv(&ctx, key, iv); - AES_CBC_decrypt_buffer(&ctx, buf, 16); + + aes128_cbc_decrypt(key, iv, buf, buf, 16); + if (memcmp(buf, expect, 16) != 0) { fprintf(stderr, "AES CBC decrypt mismatch\n"); return 1; } printf("aes ok\n"); return 0; -} +} \ No newline at end of file From 44fb43064e32fe0630557cbd6c44ee22a920e1d1 Mon Sep 17 00:00:00 2001 From: lammmab Date: Fri, 29 May 2026 22:55:12 -0400 Subject: [PATCH 2/2] Fix aes test cmake --- test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 26a91bf..576a983 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -12,7 +12,7 @@ add_test( add_executable(test_aes test_aes.c) target_link_libraries(test_aes PRIVATE siphon) -target_include_directories(test_aes PRIVATE ${CMAKE_SOURCE_DIR}/src/disc) +target_include_directories(test_aes PRIVATE ${CMAKE_SOURCE_DIR}/src) add_test(NAME test_aes COMMAND test_aes) add_executable(test_lzma test_lzma.c)