Skip to content
Open
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
60 changes: 60 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
cmake_minimum_required(VERSION 3.16)

project(ExCrypt LANGUAGES C CXX)

include(CTest)

add_library(ExCrypt STATIC
src/excrypt.h
src/excrypt_aes.c
src/excrypt_aes.h
src/excrypt_bn.c
src/excrypt_bn.h
src/excrypt_bn_key.cpp
src/excrypt_bn_mod.cpp
src/excrypt_bn_pkcs1.cpp
src/excrypt_bn_rsa.cpp
src/excrypt_bn_sig.c
src/excrypt_des.c
src/excrypt_des.h
src/excrypt_des_data.h
src/excrypt_ecc.c
src/excrypt_ecc.h
src/excrypt_md5.c
src/excrypt_md5.h
src/excrypt_mem.cpp
src/excrypt_mem.h
src/excrypt_parve.c
src/excrypt_parve.h
src/excrypt_rc4.c
src/excrypt_rc4.h
src/excrypt_rotsum.c
src/excrypt_rotsum.h
src/excrypt_sha.c
src/excrypt_sha.h
src/excrypt_sha2.c
src/excrypt_sha2.h
src/exkeys.cpp
src/exkeys.h
src/fp61.hpp
src/rijndael.c
src/rijndael.h)

target_include_directories(ExCrypt PUBLIC src)

target_compile_features(ExCrypt PUBLIC c_std_11 cxx_std_17)

set_target_properties(ExCrypt PROPERTIES POSITION_INDEPENDENT_CODE ON)

# Enable AES-NI and SSE4.1 flags for excrypt_aes.c
if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang" AND (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|i[3-6]86"))
set_source_files_properties(src/excrypt_aes.c PROPERTIES COMPILE_OPTIONS "-maes;-msse4.1")
endif()

if(WIN32)
target_link_libraries(ExCrypt PUBLIC bcrypt)
endif()

if(BUILD_TESTING)
add_subdirectory(tests)
endif()
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ It's been designed to be as closely compatible to those functions as possible -

As such, it should only be used where compatibility with existing Xbox 360 code/data is required.

### Contents
## Contents

The goal of ExCrypt is to implement XeCrypt functions known to be used on the Xbox 360.

We only target XeCrypt functions that are exported from the kernel, used during X360 boot, or included inside a game/app.

For a list of XeCrypt targets, their status, and any implementation-specific notes, take a look at the [implementation status page](https://github.com/emoose/ExCrypt/issues/5).

### Implementation
## Implementation

Code has to make sure to set the exact same state variables & return values as the 360 functions do.

Expand All @@ -27,3 +27,14 @@ Some effort to make the code a bit more readable, rather than just a straight as
We only target x86 & x64 - maybe other platforms in the future, but for now there's not much use in supporting anything else.

Where possible, making use of existing, well-known crypto code is always preferrable to needing to write your own (unless some XeCrypt oddity somehow prevents it, that is)

## Building

ExCrypt.sln is a Visual Studio 2019 solution that can be upgraded to later versions of Visual Studio if desired.

Building via [CMake](https://cmake.org/download/) is the recommended method. After installing CMake, you can build ExCrypt with the following commands run from the root of the repository:

```bash
cmake -S . -B build
cmake --build build
```
2 changes: 1 addition & 1 deletion src/excrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ extern "C" {

#define ROTL64(data, bits) (((data) << (bits)) | ((data) >> (64 - (bits))))

#ifndef _MSC_VER
#if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__MINGW64__)
#define _byteswap_ulong __builtin_bswap32
#define _byteswap_uint64 __builtin_bswap64
#endif
Expand Down
2 changes: 1 addition & 1 deletion src/excrypt_bn_pkcs1.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include <string.h>
#include <cstring>
#include <stdlib.h>
#include <stdint.h>
#include <algorithm>
Expand Down
2 changes: 2 additions & 0 deletions src/excrypt_bn_rsa.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "excrypt.h"

#include <cstring>

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
Expand Down
4 changes: 2 additions & 2 deletions src/excrypt_sha2.c
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ void ExCryptSha256Final(EXCRYPT_SHA256_STATE* state, uint8_t* output, uint32_t o

/* extract the hash value as bytes in case the hash buffer is */
/* misaligned for 32-bit words */
for (i = 0; i < min(output_size, 0x20); ++i)
for (i = 0; i < (output_size < 0x20 ? output_size : 0x20); ++i)
output[i] = ((state->hash[i >> 2] >> (8 * (~i & 3))) & 0xff);
}

Expand Down Expand Up @@ -693,7 +693,7 @@ void ExCryptSha512Final(EXCRYPT_SHA512_STATE* state, uint8_t* output, uint32_t o

/* extract the hash value as bytes in case the hash buffer is */
/* misaligned for 32-bit words */
for (i = 0; i < min(output_size, 0x40); ++i)
for (i = 0; i < (output_size < 0x40 ? output_size : 0x40); ++i)
output[i] = ((state->hash[i >> 3] >> (8 * (~i & 7))) & 0xff);
}

Expand Down
7 changes: 5 additions & 2 deletions src/exkeys.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#include <cstring>
#include <memory>
#include <map>
#include <vector>

#include <algorithm>
#include <stdio.h>
#include "portable_io.h"
#include "excrypt.h"

std::map<uint32_t, std::tuple<uint32_t, uint32_t>> kExKeyProperties = {
Expand Down Expand Up @@ -246,7 +249,7 @@ uint32_t ExKeysGetConsoleID(uint8_t* raw_bytes, char* hex_string)
uint64_t counter = 0;
for (int i = 0; i < 5; i++)
counter = console_cert[2 + i] + counter * 0x100;
sprintf_s(string, 0x10, "%011llu%llx", counter >> 4, counter & 0xF);
snprintf(string, 0x10, "%011llu%llx", counter >> 4, counter & 0xF);
memcpy(hex_string, string, 0xC);
}
return 0;
Expand Down
16 changes: 16 additions & 0 deletions src/portable_io.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "portable_io.h"
#include <errno.h>

#ifndef fopen_s
int fopen_s(FILE** file_p, const char* filename, const char* mode)
{
if (!file_p || !filename || !mode)
return -1;

*file_p = fopen(filename, mode);
if (!*file_p)
return errno;

return 0;
}
#endif
8 changes: 8 additions & 0 deletions src/portable_io.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

#include <stdint.h>
#include <stdio.h>

#ifndef fopen_s
int fopen_s(FILE** pFile, const char* filename, const char* mode);
#endif
13 changes: 13 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.16)


add_executable(ExCryptTests
common.c
tests.c
test_aes.c
test_sha.c
test_rc4.c
tests.h)

target_link_libraries(ExCryptTests PRIVATE ExCrypt)
add_test(NAME ExCryptTests COMMAND ExCryptTests)
32 changes: 32 additions & 0 deletions tests/common.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "tests.h"

int expect_bytes(const char* name, const uint8_t* actual, const uint8_t* expected, size_t size)
{
if (memcmp(actual, expected, size) == 0)
{
return 0;
}

fprintf(stderr, "%s failed\n", name);
fprintf(stderr, " actual: ");

for (size_t index = 0; index < size; index++)
{
fprintf(stderr, "%02x", actual[index]);
}

fprintf(stderr, "\n expected: ");

for (size_t index = 0; index < size; index++)
{
fprintf(stderr, "%02x", expected[index]);
}

fprintf(stderr, "\n");

return 1;
}
58 changes: 58 additions & 0 deletions tests/test_aes.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "tests.h"
#include "excrypt.h"

int test_aes(void)
{
static const uint8_t key[16] = {
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
};

static const uint8_t input[64] = {
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
};

static const uint8_t ecb_expected[16] = {
0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60, 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97
};

static const uint8_t iv[16] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};

static const uint8_t cbc_expected[64] = {
0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d,
0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2,
0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16,
0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7
};

EXCRYPT_AES_STATE state;
uint8_t output[64];
uint8_t feed[16];
int failures = 0;

ExCryptAesKey(&state, key);
ExCryptAesEcb(&state, input, output, 1);
failures += expect_bytes("AES ECB encryption", output, ecb_expected, 16);

ExCryptAesEcb(&state, output, output, 0);
failures += expect_bytes("AES ECB decryption", output, input, 16);

memcpy(feed, iv, sizeof(feed));
ExCryptAesCbc(&state, input, sizeof(input), output, feed, 1);
failures += expect_bytes("AES CBC encryption", output, cbc_expected, sizeof(output));

memcpy(feed, iv, sizeof(feed));
ExCryptAesCbc(&state, output, sizeof(output), output, feed, 0);
failures += expect_bytes("AES CBC decryption", output, input, sizeof(input));

return failures;
}
32 changes: 32 additions & 0 deletions tests/test_rc4.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "tests.h"
#include "excrypt.h"

int test_rc4(void)
{
static const uint8_t key[] = "Key";
static const uint8_t plaintext[] = "Plaintext";
static const uint8_t expected[] = { 0xbb, 0xf3, 0x16, 0xe8, 0xd9, 0x40, 0xaf, 0x0a, 0xd3 };

uint8_t output[sizeof(plaintext) - 1];

EXCRYPT_RC4_STATE state;
int failures = 0;

memcpy(output, plaintext, sizeof(output));
ExCryptRc4(key, sizeof(key) - 1, output, sizeof(output));

failures += expect_bytes("RC4 one-shot", output, expected, sizeof(output));

memcpy(output, plaintext, sizeof(output));
ExCryptRc4Key(&state, key, sizeof(key) - 1);
ExCryptRc4Ecb(&state, output, 4);
ExCryptRc4Ecb(&state, output + 4, sizeof(output) - 4);

failures += expect_bytes("RC4 streaming", output, expected, sizeof(output));

return failures;
}
29 changes: 29 additions & 0 deletions tests/test_sha.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "tests.h"
#include "excrypt.h"

int test_sha(void)
{
static const uint8_t expected[20] = {
0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e, 0x25,
0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d
};

EXCRYPT_SHA_STATE state;
uint8_t output[20];
int failures;

ExCryptSha((const uint8_t*)"a", 1, (const uint8_t*)"b", 1, (const uint8_t*)"c", 1, output, sizeof(output));
failures = expect_bytes("SHA-1 one-shot", output, expected, sizeof(output));

ExCryptShaInit(&state);
ExCryptShaUpdate(&state, (const uint8_t*)"a", 1);
ExCryptShaUpdate(&state, (const uint8_t*)"bc", 2);
ExCryptShaFinal(&state, output, sizeof(output));

failures += expect_bytes("SHA-1 streaming", output, expected, sizeof(output));
return failures;
}
14 changes: 14 additions & 0 deletions tests/tests.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "tests.h"
#include <stdio.h>

int main(void)
{
int failures = test_aes() + test_sha() + test_rc4();
if (failures != 0)
{
return 1;
}

printf("AES, SHA-1, and RC4 tests passed\n");
return 0;
}
9 changes: 9 additions & 0 deletions tests/tests.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

#include <stdint.h>
#include <stddef.h>

int expect_bytes(const char* name, const uint8_t* actual, const uint8_t* expected, size_t size);
int test_aes(void);
int test_sha(void);
int test_rc4(void);