Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand Down
25 changes: 25 additions & 0 deletions cmake/encrypt.cmake
Original file line number Diff line number Diff line change
@@ -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()
3 changes: 3 additions & 0 deletions src/disc/gc_iso.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#define _FILE_OFFSET_BITS 64
#define _POSIX_C_SOURCE 200809L

#include "gc_disc_internal.h"
#include <stdio.h>
#include <string.h>
Expand Down
3 changes: 3 additions & 0 deletions src/disc/gc_wbfs.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#define _FILE_OFFSET_BITS 64
#define _POSIX_C_SOURCE 200809L

#include "gc_disc_internal.h"
#include "siphon_log.h"
#include <stdlib.h>
Expand Down
50 changes: 6 additions & 44 deletions src/disc/gc_wii.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
#include "gc_disc_internal.h"
#include "siphon_log.h"
#include "aes.h"
#include <stdlib.h>
#include <string.h>

#if defined(SIPHON_USE_COMMONCRYPTO)
#include <CommonCrypto/CommonCrypto.h>
#endif
#include "encrypt/platform.h"

#define WII_CLUSTER 0x8000u
#define WII_CLUSTER_HASH 0x0400u
Expand All @@ -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] = {
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
}
Expand All @@ -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;
}
Expand All @@ -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) {
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down
File renamed without changes.
File renamed without changes.
93 changes: 93 additions & 0 deletions src/encrypt/platform.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#include "platform.h"
#include <string.h>

#if defined(SIPHON_USE_COMMONCRYPTO)
#include <CommonCrypto/CommonCrypto.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) {
size_t outLen;
CCCrypt(kCCDecrypt, kCCAlgorithmAES128, 0,
key, kCCKeySizeAES128, iv,
in, len, out, len, &outLen);
}

#elif defined(SIPHON_USE_AESNI)
#include <wmmintrin.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) {
__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 <arm_neon.h>
#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
12 changes: 12 additions & 0 deletions src/encrypt/platform.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

#ifndef SIPHON_PLATFORM_H
#define SIPHON_PLATFORM_H

#include <stdint.h>
#include <stddef.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);

#endif
2 changes: 1 addition & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 5 additions & 5 deletions test/test_aes.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "aes.h"
#include "encrypt/platform.h"
#include <stdio.h>
#include <string.h>

Expand All @@ -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;
}
}
Loading