Add C version

This commit is contained in:
Li 2022-06-01 00:30:51 +12:00
parent f4aceaac7e
commit 793df0c426
6 changed files with 1889 additions and 1 deletions

1095
c_version/aes.c Normal file

File diff suppressed because it is too large Load Diff

126
c_version/aes.h Normal file
View File

@ -0,0 +1,126 @@
/*********************************************************************
* Filename: aes.h
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Defines the API for the corresponding AES implementation.
*********************************************************************/
#ifndef AES_H
#define AES_H
/*************************** HEADER FILES ***************************/
#include <stddef.h>
/****************************** MACROS ******************************/
#define AES_BLOCK_SIZE 16 // AES operates on 16 bytes at a time
/**************************** DATA TYPES ****************************/
typedef unsigned char BYTE; // 8-bit byte
typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
/*********************** FUNCTION DECLARATIONS **********************/
///////////////////
// AES
///////////////////
// Key setup must be done before any AES en/de-cryption functions can be used.
void aes_key_setup(const BYTE key[], // The key, must be 128, 192, or 256 bits
WORD w[], // Output key schedule to be used later
int keysize); // Bit length of the key, 128, 192, or 256
void aes_encrypt(const BYTE in[], // 16 bytes of plaintext
BYTE out[], // 16 bytes of ciphertext
const WORD key[], // From the key setup
int keysize); // Bit length of the key, 128, 192, or 256
void aes_decrypt(const BYTE in[], // 16 bytes of ciphertext
BYTE out[], // 16 bytes of plaintext
const WORD key[], // From the key setup
int keysize); // Bit length of the key, 128, 192, or 256
///////////////////
// AES - CBC
///////////////////
int aes_encrypt_cbc(const BYTE in[], // Plaintext
size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
BYTE out[], // Ciphertext, same length as plaintext
const WORD key[], // From the key setup
int keysize, // Bit length of the key, 128, 192, or 256
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
// Only output the CBC-MAC of the input.
int aes_encrypt_cbc_mac(const BYTE in[], // plaintext
size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
BYTE out[], // Output MAC
const WORD key[], // From the key setup
int keysize, // Bit length of the key, 128, 192, or 256
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
///////////////////
// AES - CTR
///////////////////
void increment_iv(BYTE iv[], // Must be a multiple of AES_BLOCK_SIZE
int counter_size); // Bytes of the IV used for counting (low end)
void aes_encrypt_ctr(const BYTE in[], // Plaintext
size_t in_len, // Any byte length
BYTE out[], // Ciphertext, same length as plaintext
const WORD key[], // From the key setup
int keysize, // Bit length of the key, 128, 192, or 256
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
void aes_decrypt_ctr(const BYTE in[], // Ciphertext
size_t in_len, // Any byte length
BYTE out[], // Plaintext, same length as ciphertext
const WORD key[], // From the key setup
int keysize, // Bit length of the key, 128, 192, or 256
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
///////////////////
// AES - CCM
///////////////////
// Returns True if the input parameters do not violate any constraint.
int aes_encrypt_ccm(const BYTE plaintext[], // IN - Plaintext.
WORD plaintext_len, // IN - Plaintext length.
const BYTE associated_data[], // IN - Associated Data included in authentication, but not encryption.
unsigned short associated_data_len, // IN - Associated Data length in bytes.
const BYTE nonce[], // IN - The Nonce to be used for encryption.
unsigned short nonce_len, // IN - Nonce length in bytes.
BYTE ciphertext[], // OUT - Ciphertext, a concatination of the plaintext and the MAC.
WORD *ciphertext_len, // OUT - The length of the ciphertext, always plaintext_len + mac_len.
WORD mac_len, // IN - The desired length of the MAC, must be 4, 6, 8, 10, 12, 14, or 16.
const BYTE key[], // IN - The AES key for encryption.
int keysize); // IN - The length of the key in bits. Valid values are 128, 192, 256.
// Returns True if the input parameters do not violate any constraint.
// Use mac_auth to ensure decryption/validation was preformed correctly.
// If authentication does not succeed, the plaintext is zeroed out. To overwride
// this, call with mac_auth = NULL. The proper proceedure is to decrypt with
// authentication enabled (mac_auth != NULL) and make a second call to that
// ignores authentication explicitly if the first call failes.
int aes_decrypt_ccm(const BYTE ciphertext[], // IN - Ciphertext, the concatination of encrypted plaintext and MAC.
WORD ciphertext_len, // IN - Ciphertext length in bytes.
const BYTE assoc[], // IN - The Associated Data, required for authentication.
unsigned short assoc_len, // IN - Associated Data length in bytes.
const BYTE nonce[], // IN - The Nonce to use for decryption, same one as for encryption.
unsigned short nonce_len, // IN - Nonce length in bytes.
BYTE plaintext[], // OUT - The plaintext that was decrypted. Will need to be large enough to hold ciphertext_len - mac_len.
WORD *plaintext_len, // OUT - Length in bytes of the output plaintext, always ciphertext_len - mac_len .
WORD mac_len, // IN - The length of the MAC that was calculated.
int *mac_auth, // OUT - TRUE if authentication succeeded, FALSE if it did not. NULL pointer will ignore the authentication.
const BYTE key[], // IN - The AES key for decryption.
int keysize); // IN - The length of the key in BITS. Valid values are 128, 192, 256.
///////////////////
// Test functions
///////////////////
int aes_test();
int aes_ecb_test();
int aes_cbc_test();
int aes_ctr_test();
int aes_ccm_test();
#include "aes.c"
#endif // AES_H

416
c_version/main.c Normal file
View File

@ -0,0 +1,416 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "aes.h"
#include "md5.c"
#define DEBUG 1
#define PSSE_BLOCK_SIZE (0x8000)
#define PSSE_SIG_BLOCK_SIZE (0x80000)
#define PSSE_SIG_SIZE (0x400)
#define AES_KEY_SIZE (0x10)
#define AES_IV_SIZE (0x10)
const uint8_t header_iv[AES_IV_SIZE] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; // IV for the encrypted PSSE Header
const uint8_t header_key[AES_KEY_SIZE] = {0x4E, 0x29, 0x8B, 0x40, 0xF5, 0x31, 0xF4, 0x69, 0xD2, 0x1F, 0x75, 0xB1, 0x33, 0xC3, 0x07, 0xBE}; // Key used to decrypt the encrypted PSSE Header
const uint8_t runtime_title_key[AES_KEY_SIZE] = {0xA8, 0x69, 0x3C, 0x4D, 0xF0, 0xAE, 0xED, 0xBC, 0x9A, 0xBF, 0xD8, 0x21, 0x36, 0x92, 0x91, 0x2D}; // Header used to decrypt runtime libaries, eg. Sce.PlayStation.Core.dll.
const uint8_t header_key_psmdev[AES_KEY_SIZE] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; // Key used to decrypt the encrypted PSSE Header in PSM dev,
const char* runtime_content_id = "IP9100-NPXS10074_00-0000000000000000";
static char title_content_id[0x30];
static uint8_t title_iv[AES_IV_SIZE];
static uint8_t title_key[AES_KEY_SIZE];
// psse header
typedef struct psse_header{
char magic[0x4];
uint32_t version;
uint64_t file_size;
uint32_t psse_type;
char content_id[0x2C];
uint8_t md5_hash[0x10];
uint8_t file_name[0x20];
uint8_t file_iv[0x10];
uint8_t unk[0x600];
} psse_header;
// rif header
typedef struct ScePsmDrmLicense {
char magic[0x8];
uint32_t unk1;
uint32_t unk2;
uint64_t account_id;
uint32_t unk3;
uint32_t unk4;
uint64_t start_time;
uint64_t expiration_time;
uint8_t activation_checksum[0x20];
char content_id[0x30];
uint8_t unk5[0x80];
uint8_t unk6[0x20];
uint8_t key[0x10];
uint8_t signature[0x1D0];
uint8_t rsa_signature[0x100];
} ScePsmDrmLicense;
// psse_block_ref struct
typedef struct psse_block_ref{
uint8_t block_data[PSSE_BLOCK_SIZE];
size_t block_size;
} psse_block_ref;
typedef struct decrypted_file{
uint8_t* data;
size_t file_size;
} decrypted_file;
// Debug print buffer contents
void print_buffer(char* buffer_title, uint8_t* buffer, size_t buffer_sz){
printf("[*] %s: ", buffer_title);
for(int i = 0; i < buffer_sz; i++) {
printf("%02X", buffer[i]);
}
printf("\n");
}
// Convert a path to one for whatever OS your using.
void fix_paths(char* path){
size_t sz = strlen(path);
for(int i = 0; i < sz; i++){
#ifdef _WIN32
if(path[i] == '/')
#else
if(path[i] == '\\')
#endif
{
#ifdef _WIN32
path[i] = '\\';
#else
path[i] = '/';
#endif
}
}
}
// Convert a path to one for whatever OS your using.
int is_dir(char* path){
size_t sz = strlen(path);
if(path[sz] == '/' || path[sz] == '\\')
return 1;
return 0;
}
// Reads title key and content id from a rif
// returns <0 on fail, 0 on success.
int read_rif(char* rif_path){
ScePsmDrmLicense rif;
FILE* rif_fd = fopen(rif_path, "rb");
if(rif_fd == NULL){
return -1;
}
fread(&rif, sizeof(ScePsmDrmLicense), 1, rif_fd);
fclose(rif_fd);
// Read important stuff.
strncpy(title_content_id, rif.content_id, sizeof(title_content_id));
memcpy(title_key, rif.key, sizeof(title_key));
if(strlen(title_content_id) != 0x24){
return -2;
}
return 0x0;
}
// Returns the total filesize of a file.
size_t get_file_size(char* file_path){
FILE* get_size_fd = fopen(file_path, "rb");
fseek(get_size_fd, 0, SEEK_END);
size_t size = ftell(get_size_fd);
fclose(get_size_fd);
return size;
}
// Calculate IV for this block.
uint8_t* roll_iv(uint64_t block_id) {
uint8_t* new_iv = (uint8_t*)malloc(sizeof(title_iv));
memset(new_iv,0x00, sizeof(title_iv));
memcpy(new_iv, &block_id, sizeof(uint64_t));
for(int i = 0; i < sizeof(title_iv); i++){
new_iv[i] = new_iv[i] ^ title_iv[i];
}
return new_iv;
}
// Decrypts a specific block inside a PSSE file.
psse_block_ref decrypt_block(FILE* psse_file, uint64_t block_id, uint64_t total_blocks, uint32_t file_size){
psse_block_ref ref;
memset(&ref, 0x00, sizeof(psse_block_ref));
uint8_t* new_iv = roll_iv(block_id);
uint64_t block_loc = block_id * PSSE_BLOCK_SIZE;
size_t total_read = PSSE_BLOCK_SIZE;
uint64_t trim_to = total_read;
if(block_id == 0){ // Skip to filedata
block_loc = sizeof(psse_header);
total_read -= sizeof(psse_header);
trim_to = total_read;
}
else if(block_loc % PSSE_SIG_BLOCK_SIZE == 0){ // Skip signature block
block_loc += PSSE_SIG_SIZE;
total_read -= PSSE_SIG_SIZE;
trim_to = total_read;
}
uint64_t rd_amt = ((block_loc - sizeof(psse_header)) - (PSSE_SIG_SIZE*(block_loc / PSSE_SIG_BLOCK_SIZE))); // Total amount of bytes read so far.
if (block_id >= total_blocks) { // Is this the last block?
total_read = file_size - rd_amt;
trim_to = total_read;
total_read += ((AES_BLOCK_SIZE) - (total_read % (AES_BLOCK_SIZE)));
}
uint8_t* block_data = malloc(total_read);
fseek(psse_file, block_loc, SEEK_SET);
fread(block_data, total_read, 0x1, psse_file);
ref.block_size = trim_to;
// Decrypt block
uint32_t aes_game_ctx[0x3C];
aes_key_setup(title_key, aes_game_ctx, 0x80);
aes_decrypt_cbc(block_data, total_read, ref.block_data, aes_game_ctx, 0x80, new_iv);
free(block_data);
free(new_iv);
return ref;
}
// returns decrypted data on success, empty filesize on error
decrypted_file decrypt_file(char* psse_file){
size_t total_filesize = get_file_size(psse_file);
uint64_t total_blocks = (total_filesize / 0x8000);
uint8_t title_key_copy[sizeof(title_key)];
uint32_t aes_header_ctx[0x3C];
FILE* psse_file_fd = fopen(psse_file, "rb");
decrypted_file plaintext_file;
memset(&plaintext_file, 0x00, sizeof(decrypted_file));
psse_header file_psse_header;
memset(&file_psse_header, 0x00, sizeof(psse_header));
fread(&file_psse_header, sizeof(psse_header), 0x1, psse_file_fd);
#ifdef DEBUG
printf("[*] Decrypting: %s\n", psse_file);
#endif
// Check magic number
if(!((strncmp(file_psse_header.magic, "PSSE", 0x4) == 0) || (strncmp(file_psse_header.magic, "PSME", 0x4) == 0))){
#ifdef DEBUG
printf("[*] %s Is not a valid PSSE file.\n", psse_file);
#endif
return plaintext_file;
}
// Chceck version
if(file_psse_header.version != 0x01){
#ifdef DEBUG
printf("[*] %s has unknown PSSE version %i.\n", psse_file, file_psse_header.version);
#endif
return plaintext_file;
}
// Check psse type
if(file_psse_header.psse_type != 0x01){
#ifdef DEBUG
printf("[*] %s has unknown PSSE type %i.\n", psse_file, file_psse_header.version);
#endif
return plaintext_file;
}
int psm_dev = 0;
// Check content id
if(strlen(file_psse_header.content_id) == 0x24) {
if(strcmp(file_psse_header.content_id, title_content_id) == 0){ // Retail PSM
aes_key_setup(header_key, aes_header_ctx, 0x80);
}
else if(strcmp(file_psse_header.content_id, runtime_content_id)){ // Runtime Libary
memcpy(title_key_copy, title_key, sizeof(title_key));
memcpy(title_key, runtime_title_key, sizeof(title_key));
aes_key_setup(header_key, aes_header_ctx, 0x80);
psm_dev = 1;
}
else{
return plaintext_file;
}
}
else { // Debug PSM
aes_key_setup(header_key_psmdev, aes_header_ctx, 0x80);
}
aes_decrypt_cbc(file_psse_header.file_iv, sizeof(title_iv), title_iv, aes_header_ctx, 0x80, header_iv);
char* plaintext = malloc(file_psse_header.file_size);
uintptr_t plaintext_ptr = 0;
MD5Context md5_ctx;
md5Init(&md5_ctx);
for(int i = 0; i <= total_blocks; i++){
psse_block_ref block_ref = decrypt_block(psse_file_fd, i, total_blocks, file_psse_header.file_size);
md5Update(&md5_ctx, block_ref.block_data, block_ref.block_size);
memcpy(plaintext+plaintext_ptr, block_ref.block_data, block_ref.block_size);
plaintext_ptr += block_ref.block_size;
}
md5Finalize(&md5_ctx);
if(memcmp(file_psse_header.md5_hash, md5_ctx.digest, 0x10) != 0){
#ifdef DEBUG
printf("[*] MD5 Hash did not match expected.\n");
print_buffer("Got MD5", md5_ctx.digest, 0x10);
print_buffer("Expected MD5", file_psse_header.md5_hash, 0x10);
#endif
return plaintext_file;
}
fclose(psse_file_fd);
plaintext_file.data = plaintext;
plaintext_file.file_size = file_psse_header.file_size;
if(psm_dev){
memcpy(title_key, title_key_copy, sizeof(title_key));
}
return plaintext_file;
}
int decrypt_all_files(char* application_folder, char* psse_list, size_t psse_list_sz){
uint64_t start_point = 0;
size_t sz = 0;
char rel_path[PATH_MAX];
for(uint64_t i = 0; i < psse_list_sz; i++){
if(psse_list[i] == '\r' || psse_list[i] == '\n') {
if (sz == 0){
goto next;
}
char* cur_filename = (char*)malloc(sz+1);
memset(cur_filename, 0x00, sz+1);
strncpy(cur_filename, (psse_list+start_point), sz);
memset(rel_path, 0x00, sizeof(rel_path));
snprintf(rel_path, sizeof(rel_path), "%s\\%s", application_folder, cur_filename);
free(cur_filename);
fix_paths(rel_path);
if(is_dir(rel_path)){
goto next;
}
decrypted_file dec_file = decrypt_file(rel_path);
if(dec_file.data == NULL){
#ifdef DEBUG
printf("[*] Decryption failed.\n");
#endif
return -3;
}
// Write decrypted file to disk.
FILE* dec_file_fd = fopen(rel_path, "wb");
if(dec_file_fd == NULL){
#ifdef DEBUG
printf("[*] Failed to open %s for writing.\n", rel_path);
#endif
return -4;
}
fwrite(dec_file.data, dec_file.file_size, 0x1, dec_file_fd);
fclose(dec_file_fd);
free(dec_file.data);
next:
start_point = i+1;
sz = 0;
continue;
}
sz++;
}
}
int main(int argc, char** argv)
{
memset(title_content_id, 0x00, sizeof(title_content_id));
memset(title_iv, 0x00, sizeof(title_iv));
memset(title_key, 0x00, sizeof(title_key));
if(argc <= 1){
printf("PSSE Decryptor.\n");
printf("Usage: <PSM_FOLDER>\n",argv[0]);
return 0;
}
char* psm_folder = argv[1];
char application_folder[PATH_MAX];
char psse_list[PATH_MAX];
char rif_file[PATH_MAX];
snprintf(application_folder, sizeof(application_folder), "%s\\RO\\Application", psm_folder);
snprintf(psse_list, sizeof(psse_list), "%s\\psse.list", application_folder);
snprintf(rif_file, sizeof(rif_file), "%s\\RO\\License\\FAKE.rif", psm_folder);
fix_paths(application_folder);
fix_paths(psse_list);
fix_paths(rif_file);
if(read_rif(rif_file) < 0){
printf("[*] Unable to read RIF: %s\n", rif_file);
return -1;
}
#ifdef DEBUG
print_buffer("Title Key", title_key, sizeof(title_key));
#endif
decrypted_file plaintext_psse_list = decrypt_file(psse_list);
if(plaintext_psse_list.data == NULL){
printf("[*] Decryption failed.\n");
return -2;
}
// Write decrypted psse.list.
FILE* psse_list_fd = fopen(psse_list, "wb");
fwrite(plaintext_psse_list.data, plaintext_psse_list.file_size, 0x1, psse_list_fd);
fclose(psse_list_fd);
int res = decrypt_all_files(application_folder, plaintext_psse_list.data, plaintext_psse_list.file_size);
if (res < 0){
return res;
}
free(plaintext_psse_list.data);
}

225
c_version/md5.c Normal file
View File

@ -0,0 +1,225 @@
/*
* Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm
* and modified slightly to be functionally identical but condensed into control structures.
*/
#include "md5.h"
/*
* Constants defined by the MD5 algorithm
*/
#define A 0x67452301
#define B 0xefcdab89
#define C 0x98badcfe
#define D 0x10325476
static uint32_t S[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21};
static uint32_t K[] = {0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391};
/*
* Bit-manipulation functions defined by the MD5 algorithm
*/
#define F(X, Y, Z) ((X & Y) | (~X & Z))
#define G(X, Y, Z) ((X & Z) | (Y & ~Z))
#define H(X, Y, Z) (X ^ Y ^ Z)
#define I(X, Y, Z) (Y ^ (X | ~Z))
/*
* Padding used to make the size (in bits) of the input congruent to 448 mod 512
*/
static uint8_t PADDING[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/*
* Initialize a context
*/
void md5Init(MD5Context *ctx){
ctx->size = (uint64_t)0;
ctx->buffer[0] = (uint32_t)A;
ctx->buffer[1] = (uint32_t)B;
ctx->buffer[2] = (uint32_t)C;
ctx->buffer[3] = (uint32_t)D;
}
/*
* Add some amount of input to the context
*
* If the input fills out a block of 512 bits, apply the algorithm (md5Step)
* and save the result in the buffer. Also updates the overall size.
*/
void md5Update(MD5Context *ctx, uint8_t *input_buffer, size_t input_len){
uint32_t input[16];
unsigned int offset = ctx->size % 64;
ctx->size += (uint64_t)input_len;
// Copy each byte in input_buffer into the next space in our context input
for(unsigned int i = 0; i < input_len; ++i){
ctx->input[offset++] = (uint8_t)*(input_buffer + i);
// If we've filled our context input, copy it into our local array input
// then reset the offset to 0 and fill in a new buffer.
// Every time we fill out a chunk, we run it through the algorithm
// to enable some back and forth between cpu and i/o
if(offset % 64 == 0){
for(unsigned int j = 0; j < 16; ++j){
// Convert to little-endian
// The local variable `input` our 512-bit chunk separated into 32-bit words
// we can use in calculations
input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 |
(uint32_t)(ctx->input[(j * 4) + 2]) << 16 |
(uint32_t)(ctx->input[(j * 4) + 1]) << 8 |
(uint32_t)(ctx->input[(j * 4)]);
}
md5Step(ctx->buffer, input);
offset = 0;
}
}
}
/*
* Pad the current input to get to 448 bytes, append the size in bits to the very end,
* and save the result of the final iteration into digest.
*/
void md5Finalize(MD5Context *ctx){
uint32_t input[16];
unsigned int offset = ctx->size % 64;
unsigned int padding_length = offset < 56 ? 56 - offset : (56 + 64) - offset;
// Fill in the padding andndo the changes to size that resulted from the update
md5Update(ctx, PADDING, padding_length);
ctx->size -= (uint64_t)padding_length;
// Do a final update (internal to this function)
// Last two 32-bit words are the two halves of the size (converted from bytes to bits)
for(unsigned int j = 0; j < 14; ++j){
input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 |
(uint32_t)(ctx->input[(j * 4) + 2]) << 16 |
(uint32_t)(ctx->input[(j * 4) + 1]) << 8 |
(uint32_t)(ctx->input[(j * 4)]);
}
input[14] = (uint32_t)(ctx->size * 8);
input[15] = (uint32_t)((ctx->size * 8) >> 32);
md5Step(ctx->buffer, input);
// Move the result into digest (convert from little-endian)
for(unsigned int i = 0; i < 4; ++i){
ctx->digest[(i * 4) + 0] = (uint8_t)((ctx->buffer[i] & 0x000000FF));
ctx->digest[(i * 4) + 1] = (uint8_t)((ctx->buffer[i] & 0x0000FF00) >> 8);
ctx->digest[(i * 4) + 2] = (uint8_t)((ctx->buffer[i] & 0x00FF0000) >> 16);
ctx->digest[(i * 4) + 3] = (uint8_t)((ctx->buffer[i] & 0xFF000000) >> 24);
}
}
/*
* Step on 512 bits of input with the main MD5 algorithm.
*/
void md5Step(uint32_t *buffer, uint32_t *input){
uint32_t AA = buffer[0];
uint32_t BB = buffer[1];
uint32_t CC = buffer[2];
uint32_t DD = buffer[3];
uint32_t E;
unsigned int j;
for(unsigned int i = 0; i < 64; ++i){
switch(i / 16){
case 0:
E = F(BB, CC, DD);
j = i;
break;
case 1:
E = G(BB, CC, DD);
j = ((i * 5) + 1) % 16;
break;
case 2:
E = H(BB, CC, DD);
j = ((i * 3) + 5) % 16;
break;
default:
E = I(BB, CC, DD);
j = (i * 7) % 16;
break;
}
uint32_t temp = DD;
DD = CC;
CC = BB;
BB = BB + rotateLeft(AA + E + K[i] + input[j], S[i]);
AA = temp;
}
buffer[0] += AA;
buffer[1] += BB;
buffer[2] += CC;
buffer[3] += DD;
}
/*
* Functions that will return a pointer to the hash of the provided input
*/
uint8_t* md5String(char *input){
MD5Context ctx;
md5Init(&ctx);
md5Update(&ctx, (uint8_t *)input, strlen(input));
md5Finalize(&ctx);
uint8_t *result = malloc(16);
memcpy(result, ctx.digest, 16);
return result;
}
uint8_t* md5File(FILE *file){
char *input_buffer = malloc(1024);
size_t input_size = 0;
MD5Context ctx;
md5Init(&ctx);
while((input_size = fread(input_buffer, 1, 1024, file)) > 0){
md5Update(&ctx, (uint8_t *)input_buffer, input_size);
}
md5Finalize(&ctx);
free(input_buffer);
uint8_t *result = malloc(16);
memcpy(result, ctx.digest, 16);
return result;
}
/*
* Rotates a 32-bit word left by n bits
*/
uint32_t rotateLeft(uint32_t x, uint32_t n){
return (x << n) | (x >> (32 - n));
}

26
c_version/md5.h Normal file
View File

@ -0,0 +1,26 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
typedef struct{
uint64_t size; // Size of input in bytes
uint32_t buffer[4]; // Current accumulation of hash
uint8_t input[64]; // Input to be used in the next step
uint8_t digest[16]; // Result of algorithm
}MD5Context;
void md5Init(MD5Context *ctx);
void md5Update(MD5Context *ctx, uint8_t *input, size_t input_len);
void md5Finalize(MD5Context *ctx);
void md5Step(uint32_t *buffer, uint32_t *input);
uint8_t* md5String(char *input);
uint8_t* md5File(FILE *file);
uint32_t F(uint32_t X, uint32_t Y, uint32_t Z);
uint32_t G(uint32_t X, uint32_t Y, uint32_t Z);
uint32_t H(uint32_t X, uint32_t Y, uint32_t Z);
uint32_t I(uint32_t X, uint32_t Y, uint32_t Z);
uint32_t rotateLeft(uint32_t x, uint32_t n);

View File

@ -225,7 +225,7 @@ if len(sys.argv) <= 1:
file = sys.argv[1]
fpath = file.encode("UTF-8")
# Some dumb dirbustnig shit.
# Some dumb dirbusting shit.
applications_folder = b"/RO/Application/"
license_file = os.path.normpath(fpath+b"/RO/License/FAKE.rif")
psse_list = os.path.normpath(fpath+applications_folder+b"psse.list")