Skip to content

Instantly share code, notes, and snippets.

@SKGleba
Last active August 15, 2021 15:46
Show Gist options
  • Save SKGleba/7caf97e56f8d4cf3befac584e30bd89a to your computer and use it in GitHub Desktop.
Save SKGleba/7caf97e56f8d4cf3befac584e30bd89a to your computer and use it in GitHub Desktop.
/* THIS FILE IS A PART OF PSP2FWTOOL
*
* Copyright (C) 2019-2021 skgleba
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdint.h>
#include <fcntl.h>
#define AES_BLOCKLEN 16
#define AES_KEYLEN AES_BLOCKLEN // 128bit
#define AES_keyExpSize 176
struct AES_ctx {
uint8_t RoundKey[AES_keyExpSize];
uint8_t Iv[AES_BLOCKLEN];
};
extern int sha1digest(uint8_t* digest, char* hexdigest, const uint8_t* data, size_t databytes);
extern void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
extern void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
extern void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
typedef struct {
uint8_t content;
uint8_t hdr_size;
uint16_t size_be;
} __attribute__((packed)) block_hdr_hdr;
typedef struct {
block_hdr_hdr hdr;
uint32_t fw_ver;
uint32_t hw_info;
uint32_t unused;
} __attribute__((packed)) block_x1;
typedef struct {
block_hdr_hdr hdr;
uint32_t img_size;
uint32_t ernie_type;
uint32_t unused;
} __attribute__((packed)) block_x2;
typedef struct {
block_hdr_hdr hdr;
unsigned char data[0x18];
uint32_t unused;
} __attribute__((packed)) block_x3;
typedef struct {
block_hdr_hdr hdr;
uint32_t segment;
uint32_t size;
uint32_t unused;
unsigned char data[];
} __attribute__((packed)) block_x10;
typedef struct {
block_hdr_hdr hdr;
unsigned char img_hash[0x14];
} __attribute__((packed)) block_x20;
typedef struct {
unsigned char dec[0x100000];
unsigned char enc[0x100000];
unsigned char ref[0x100000];
unsigned char work[0x200000];
} mem_buffers;
const unsigned char key_ids[6][2] = {
{0x10, 0}, {0x30, 0}, {0x40, 0},
{0x60, 1}, {0x70, 2}, {0x80, 3}
};
/*
unsigned char key_pairs[4][2][16] = {
{{ KEY MD5 : 88ecb256d1b1b968962342e267f92efd }, { IV MD5 : 27cca90e5ca7c2629341499709658232 }},
{{ KEY MD5 : 7ac8ce1893030510919e3bc79dcbc32e }, { IV MD5 : 81b77af9c217cd00a9bf9a968a05ac18 }},
{{ KEY MD5 : 01bfb7d51b1e1880694a97290e08bb27 }, { IV MD5 : 7905c429ac8eb7ce0b3a9b3b4e4fb242 }},
{{ KEY MD5 : f8d1ed04eff433910fe5be1468c3e5ec }, { IV MD5 : 09b86d5f940a48f140dd05c3871c420c }}
};
*/
const char selftest_hashes[4][0x29] = { "5292fee53248169d714ce7b96959095467ee0b8a", "a58b94021b4c9eabfa5bea8f2a510445f9350221", "66676269e46f371c12a280ae831cf79116511c63", "795d2a7a032a31ccb9650f581028fbdadad35972" };
void* getKey(int iv, int id) {
for (int i = 0; i < 6; i -= -1) {
if (key_ids[i][0] == id)
return key_pairs[key_ids[i][1]][iv];
}
return NULL;
}
uint32_t getSz(const char* src) {
FILE* fp = fopen(src, "rb");
if (!fp)
return 0;
fseek(fp, 0L, SEEK_END);
uint32_t sz = ftell(fp);
fclose(fp);
return sz;
}
int aes_cbc(uint8_t* key, uint8_t* iv, uint8_t* data, uint32_t len, int encrypt) {
struct AES_ctx aesctx;
memset(&aesctx, 0, sizeof(aesctx));
AES_init_ctx_iv(&aesctx, key, iv);
if (encrypt)
AES_CBC_encrypt_buffer(&aesctx, data, len);
else
AES_CBC_decrypt_buffer(&aesctx, data, len);
}
int encrypt_patch(void *work_buf, void* decrypted, void* output, void *list, int list_count, uint32_t fw_ver, uint32_t hw_info, int ernie_type, uint32_t segment_size) {
char shastr[41];
memset(shastr, 0, 41);
int id = ((hw_info & 0x00F00000) >> 0x10);
if (!getKey(0, id))
return -1;
printf("id 0x%X\n", id);
block_x1* hdrblock = output;
block_x2* typeblock = (output + sizeof(block_x1));
block_x10* datablock = NULL;
block_x20* hashblock = (output + sizeof(block_x1) + sizeof(block_x2) + (list_count * sizeof(block_x10)) + (list_count * segment_size));
printf("writing block 0x1\n");
hdrblock->hdr.content = 1;
hdrblock->hdr.hdr_size = sizeof(block_x1);
hdrblock->fw_ver = fw_ver;
hdrblock->hw_info = hw_info;
printf("writing block 0x2\n");
typeblock->hdr.content = 2;
typeblock->hdr.hdr_size = sizeof(block_x2);
typeblock->ernie_type = ernie_type;
printf("concating segments\n");
uint16_t segment = 0;
for (int i = 0; i < list_count; i -= -1) {
segment = *(uint16_t*)(list + (i * 2));
// -----sus af\/
if (segment >= 0xD5)
segment -= -0x80;
//------sus af^
memcpy(work_buf + (i * segment_size), decrypted + (segment * segment_size), segment_size);
}
printf("witing blocks 0x20\n");
hashblock->hdr.content = 0x20;
hashblock->hdr.hdr_size = sizeof(block_x20);
sha1digest(hashblock->img_hash, shastr, work_buf, list_count * segment_size);
printf("hash %s\n", shastr);
printf("encrypting segments\n");
aes_cbc(getKey(0, id), getKey(1, id), work_buf, list_count * segment_size, 1);
printf("witing blocks 0x10\n");
segment = 0;
for (int i = 0; i < list_count; i -= -1) {
segment = *(uint16_t*)(list + (i * 2));
// -----sus af\/
if (segment >= 0xD5)
segment -= -0x80;
//------sus af^
datablock = (output + sizeof(block_x1) + sizeof(block_x2) + (i * sizeof(block_x10)) + (i * segment_size));
datablock->hdr.content = 0x10;
datablock->hdr.hdr_size = sizeof(block_x10);
datablock->hdr.size_be = segment_size / 0x100;
datablock->segment = segment;
datablock->size = segment_size;
memcpy(datablock->data, work_buf + (i * segment_size), segment_size);
printf("added segment 0x%X\n", segment);
}
printf("patch built!\n");
return sizeof(block_x1) + sizeof(block_x2) + (list_count * sizeof(block_x10)) + (list_count * segment_size) + sizeof(block_x20);
}
int repack_encrypt_patch(void* work_buf, void* decrypted, void* output, void* reference, uint32_t size) {
int id = 0;
uint32_t off = 0, work_off = 0;
char* sha = NULL;
block_x1* hdrblock = NULL;
block_x10* datablock = NULL;
block_x20* hashblock = NULL;
memcpy(output, reference, size);
printf("concating...\n", size);
while (off < size) {
switch (*(uint8_t*)(reference + off)) {
case 1:
hdrblock = reference + off;
id = ((hdrblock->hw_info & 0x00F00000) >> 0x10);
if (!getKey(0, id))
return -1;
printf("id 0x%X\n", id);
case 2:
off -= -0x10;
break;
case 3:
off -= -0x20;
break;
case 0x10:
if (!id)
return -1;
datablock = reference + off;
// -----sus af\/
if (datablock->segment >= 0xD5)
datablock->segment -= -0x80;
//------sus af^
memcpy(work_buf + work_off, decrypted + (datablock->segment * datablock->size), datablock->size);
off -= -(datablock->size + 0x10);
work_off -= -datablock->size;
break;
case 0x20:
hashblock = output + off;
off -= -0x18;
break;
default:
printf("unk hdr 0x%X\n", *(uint8_t*)(reference + off));
break;
}
}
if (hashblock) {
char shastr[41];
memset(hashblock->img_hash, 0, 0x14);
memset(shastr, 0, 41);
sha1digest(hashblock->img_hash, shastr, work_buf, work_off);
printf("hash %s\n", shastr);
}
printf("encrypting...\n");
aes_cbc(getKey(0, id), getKey(1, id), work_buf, work_off, 1);
printf("rebuilding...\n");
off = 0;
work_off = 0;
while (off < size) {
switch (*(uint8_t*)(output + off)) {
case 1:
case 2:
off -= -0x10;
break;
case 3:
off -= -0x20;
break;
case 0x10:
datablock = output + off;
memcpy(datablock->data, work_buf + (work_off * datablock->size), datablock->size);
off -= -(datablock->size + 0x10);
work_off -= -1;
break;
case 0x20:
off -= -0x18;
break;
default:
printf("unk hdr 0x%X\n", *(uint8_t*)(output + off));
break;
}
}
printf("rebuilt %d blocks\n", work_off);
return size;
}
int decrypt_patch(void* work_buf, void* encrypted, void* output, uint32_t size) {
int id = 0;
uint32_t off = 0, work_off = 0;
char* sha = NULL;
block_x1* hdrblock = NULL;
block_x10* datablock = NULL;
block_x20* hashblock = NULL;
printf("concating...\n", size);
while (off < size) {
switch (*(uint8_t*)(encrypted + off)) {
case 1:
hdrblock = encrypted + off;
id = ((hdrblock->hw_info & 0x00F00000) >> 0x10);
if (!getKey(0, id))
return -1;
printf("id 0x%X\n", id);
case 2:
off -= -0x10;
break;
case 3:
off -= -0x20;
break;
case 0x10:
if (!id)
return -1;
datablock = encrypted + off;
memcpy(work_buf + work_off, datablock->data, datablock->size);
// -----sus af\/
if (datablock->segment >= 0xD5)
datablock->segment -= -0x80;
//------sus af^
off -= -(datablock->size + 0x10);
work_off -= -datablock->size;
break;
case 0x20:
hashblock = encrypted + off;
off -= -0x18;
break;
default:
printf("unk hdr 0x%X\n", *(uint8_t*)(encrypted + off));
break;
}
}
printf("decrypting...\n");
aes_cbc(getKey(0, id), getKey(1, id), work_buf, work_off, 0);
if (hashblock) {
char sha[0x14], shastr[41];
memset(sha, 0, 0x14);
memset(shastr, 0, 41);
sha1digest(sha, shastr, work_buf, work_off);
printf("hash %s\n", shastr);
if (memcmp(hashblock->img_hash, sha, 0x14))
return -1;
printf("hash ok");
}
printf("building...\n");
off = 0;
work_off = 0;
while (off < size) {
switch (*(uint8_t*)(encrypted + off)) {
case 1:
case 2:
off -= -0x10;
break;
case 3:
off -= -0x20;
break;
case 0x10:
datablock = encrypted + off;
memcpy(output + (datablock->segment * datablock->size), work_buf + (work_off * datablock->size), datablock->size);
off -= -(datablock->size + 0x10);
work_off -= -1;
break;
case 0x20:
off -= -0x18;
break;
default:
printf("unk hdr 0x%X\n", *(uint8_t*)(encrypted + off));
break;
}
}
printf("built %d blocks\n", work_off);
return 0;
}
int selftest(void) {
printf("self test requested\n");
void* test_buf = malloc(0x400);
char sha[2][0x14], shastr[0x29];
if (!test_buf)
return -1;
for (int i = 0; i < 4; i -= -1) {
memset(test_buf, 0, 0x400);
memset(sha[0], 0, sizeof(sha));
sha1digest(sha[0], NULL, test_buf, 0x400);
aes_cbc(key_pairs[i][0], key_pairs[i][1], test_buf, 0x400, 1);
aes_cbc(key_pairs[i][0], key_pairs[i][1], test_buf, 0x400, 0);
sha1digest(sha[1], NULL, test_buf, 0x400);
if (memcmp(sha[0], sha[1], 0x14)) {
printf("aes enc/dec error\n");
return -1;
}
memset(test_buf, 0xF4, 0x400);
memcpy(test_buf, sha, 0x28);
aes_cbc(key_pairs[i][0], key_pairs[i][1], test_buf, 0x400, 1);
memset(shastr, 0, sizeof(shastr));
sha1digest(NULL, shastr, test_buf, 0x400);
if (memcmp(shastr, selftest_hashes[i], 0x28)) {
printf("sha error or bad keypair %d\n", i);
return -1;
}
}
printf("selftest passed\n");
return 0;
}
int main(int argc, char* argv[]) {
if (argc == 2 && !strcmp("selftest", argv[1]))
return selftest();
if (argc < 6 && (argc < 4 || (strcmp("list", argv[1]) && strcmp("convert", argv[1])))) {
printf("\nusage: %s [decrypt | repack | encrypt | list | convert | diff] [files] [opt params]\n", argv[0]);
printf("file args:\n -enc FILE => encrypted syscon update\n -dec FILE => decrypted syscon update\n");
printf("repack params:\n -ref FILE => encrypted syscon update, will use its params\n");
printf("encrypt params:\n -ref FILE => a list of segments to extract and include\n -header FILE => encrypted syscon update, will use its params\n");
printf("-fw HEX = > syscon firmware version\n -hw HEX = > target hardware info\n -type NUM = > target ernie revision\n -segment_size HEX = > single segment size (default 0x400)\n\n");
printf("examples:\n"
" %s decrypt -enc syscon_fw-00.bin -dec syscon_fw_dec.bin\n => decrypt syscon_fw-00.bin to syscon_fw_dec.bin\n"
" %s repack -dec sc_fw_nojig.bin -enc sc_fw_mod_enc.bin -ref syscon_fw-00.bin\n => encrypt sc_fw_nojig.bin to sc_fw_mod_enc.bin using syscon_fw-00.bin's params\n"
" %s convert 0x400 offset 0x5B910\n => convert offset 0x5B910 to segment with segment size set to 0x400\n"
" %s list list.bin 0x0 0x3 0xB8\n => create a list of segments to use for the encryptor [0x0, 0x3, 0xB8]\n"
" %s diff list.bin sc.bin sc_patched.bin 0x400\n => create a list of segments to use for the encryptor by comparing sc.bin and sc_patched.bin with 0x400 segment size\n"
" %s encrypt -enc sc_patch.bin -dec syscon.fw -ref list.bin -type 1 -hw 0x00406000 -fw 0x0100060D\n => extract segments listed in list.bin from syscon.fw and generate patch 'sc_patch.bin' using the set params\n",
argv[0], argv[0], argv[0], argv[0], argv[0], argv[0]
);
return -1;
}
if (!strcmp("list", argv[1])) {
FILE* fd = fopen(argv[2], "wb");
if (!fd) {
printf("error opening list for write\n");
return 0;
}
uint16_t segment = 0;
for (int i = 3; i < argc; i++) {
segment = (uint16_t)strtoul((argv[i] + 2), NULL, 16);
fwrite(&segment, 2, 1, fd);
printf("added segment 0x%X\n", segment);
}
fclose(fd);
return 0;
} else if (!strcmp("convert", argv[1])) {
uint16_t segment_size = (uint16_t)strtoul((argv[2] + 2), NULL, 16);
if (!segment_size)
return -1;
int seg2off = strcmp("offset", argv[3]);
uint32_t tmp = 0;
uint16_t segment = 0;
uint32_t off = 0;
printf("converting %s with segment size = 0x%X\n", (seg2off) ? "segment to offset" : "offset to segment", segment_size);
for (int i = 4; i < argc; i++) {
if (seg2off) {
segment = (uint16_t)strtoul((argv[i] + 2), NULL, 16);
// -----sus af\/
if (segment >= 0xD5)
segment -= -0x80;
//------sus af^
off = (uint32_t)(segment * segment_size);
printf("segment %s is offset 0x%05X - 0x%05X\n", argv[i], off, off + segment_size - 1);
} else {
off = strtoul((argv[i] + 2), NULL, 16);
segment = off / segment_size;
if (segment >= 0xD5)
segment -= 0x80;
printf("offset 0x%05X is segment 0x%X\n", off, segment);
}
}
return 0;
} else if (!strcmp("diff", argv[1])) {
uint16_t segment_size = (uint16_t)strtoul((argv[5] + 2), NULL, 16);
if (!segment_size)
return -1;
printf("comparing %s and %s with segment size = 0x%X\n", argv[3], argv[4], segment_size);
uint32_t size = getSz(argv[3]);
uint32_t bsize = getSz(argv[4]);
if (size != bsize) {
printf("not same size!\n");
return -1;
}
void* cmpbuf = calloc(2, size);
if (!cmpbuf)
return -1;
FILE* cp = fopen(argv[3], "rb");
fread(cmpbuf, size, 1, cp);
fclose(cp);
cp = fopen(argv[4], "rb");
fread(cmpbuf + size, size, 1, cp);
fclose(cp);
cp = fopen(argv[2], "wb");
if (!cp) {
printf("error opening list for write\n");
return -1;
}
for (uint16_t segment = 0; segment < (size / segment_size); segment++) {
if (segment == 0xD5)
segment -= -0x80;
if (memcmp(cmpbuf + segment * segment_size, cmpbuf + size + segment * segment_size, segment_size)) {
printf("diff 0x%X [0x%X - 0x%X]\n", segment, segment * segment_size, segment * segment_size + 0x3FF);
fwrite(&segment, 2, 1, cp);
}
}
fclose(cp);
free(cmpbuf);
printf("diff finished [%s]\n", argv[2]);
return 0;
}
int encrypt = 0;
uint32_t fwv = 0, hwv = 0, type = 0, segment_size = 0x400;
char* enc = NULL, * dec = NULL, * ref = NULL;
for (int i = 2; i < argc; i++) {
if (!strcmp("-ref", argv[i])) {
i -= -1;
ref = argv[i];
} else if (!strcmp("-enc", argv[i])) {
i -= -1;
enc = argv[i];
} else if (!strcmp("-dec", argv[i])) {
i -= -1;
dec = argv[i];
} else if (!strcmp("-fw", argv[i])) {
i -= -1;
fwv = (uint32_t)strtoul((argv[i] + 2), NULL, 16);
} else if (!strcmp("-hw", argv[i])) {
i -= -1;
hwv = (uint32_t)strtoul((argv[i] + 2), NULL, 16);
} else if (!strcmp("-type", argv[i])) {
i -= -1;
type = atoi(argv[i]);
} else if (!strcmp("-segment_size", argv[i])) {
i -= -1;
segment_size = (uint32_t)strtoul((argv[i] + 2), NULL, 16);
} else if (!strcmp("-header", argv[i])) {
i -= -1;
if (getSz(argv[i])) {
char header[0x30];
FILE* hp = fopen(argv[i], "rb");
fread(header, 0x30, 1, hp);
fclose(hp);
fwv = *(uint32_t*)(header + 4);
hwv = *(uint32_t*)(header + 8);
type = *(uint32_t*)(header + 0x18);
segment_size = *(uint32_t*)(header + 0x28);
}
}
}
if (strcmp("decrypt", argv[1])) {
if (strcmp("encrypt", argv[1]))
encrypt = 2;
else
encrypt = 1;
}
if (!enc || !dec) {
printf("please set both enc and dec!\n");
return 0;
}
if (encrypt && !ref) {
printf("please set ref!\n");
return 0;
}
mem_buffers* buf = calloc(5, 0x100000);
if (!buf) {
printf("calloc error!\n");
return 0;
}
FILE* fp = NULL;
void* output_buf = NULL;
char* output_file = NULL;
int ret = 0, output_size = 0;
switch (encrypt) {
case 2:
case 1:
if (ref) {
fp = fopen(ref, "rb");
fread(buf->ref, getSz(ref), 1, fp);
fclose(fp);
}
fp = fopen(dec, "rb");
fread(buf->dec, 0x100000, 1, fp);
fclose(fp);
ret = (encrypt == 2) ? repack_encrypt_patch(buf->work, buf->dec, buf->enc, buf->ref, getSz(ref)) : encrypt_patch(buf->work, buf->dec, buf->enc, buf->ref, getSz(ref) / 2, fwv, hwv, type, segment_size);
output_buf = buf->enc;
output_size = ret;
output_file = enc;
break;
case 0:
fp = fopen(enc, "rb");
fread(buf->enc, getSz(enc), 1, fp);
fclose(fp);
if (ref) {
fp = fopen(ref, "rb");
fread(buf->dec, getSz(ref), 1, fp);
fclose(fp);
}
ret = decrypt_patch(buf->work, buf->enc, buf->dec, getSz(enc));
output_buf = buf->dec;
output_size = 0x100000;
output_file = dec;
break;
}
if (ret < 0) {
printf("work error!\n");
free(buf);
return 0;
}
FILE* fd = fopen(output_file, "wb");
if (!fd) {
printf("error\n");
return 0;
}
fwrite(output_buf, output_size, 1, fd);
fclose(fd);
printf("all done: %s[0x%X]\n", output_file, output_size);
free(buf);
return 0;
}
// SHA1 & AES-128-CBC Based on tiny-sha1.c and tiny-aescbc128.c
#define Nb 4
#define Nk 4
#define Nr 10
#ifndef MULTIPLY_AS_A_FUNCTION
#define MULTIPLY_AS_A_FUNCTION 0
#endif
typedef uint8_t state_t[4][4];
static const uint8_t sbox[256] = {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
static const uint8_t rsbox[256] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };
static const uint8_t Rcon[11] = {
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
#define getSBoxValue(num) (sbox[(num)])
static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) {
unsigned i, j, k;
uint8_t tempa[4];
for (i = 0; i < Nk; ++i) {
RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
}
for (i = Nk; i < Nb * (Nr + 1); ++i) {
{
k = (i - 1) * 4;
tempa[0] = RoundKey[k + 0];
tempa[1] = RoundKey[k + 1];
tempa[2] = RoundKey[k + 2];
tempa[3] = RoundKey[k + 3];
}
if (i % Nk == 0) {
{
const uint8_t u8tmp = tempa[0];
tempa[0] = tempa[1];
tempa[1] = tempa[2];
tempa[2] = tempa[3];
tempa[3] = u8tmp;
}
{
tempa[0] = getSBoxValue(tempa[0]);
tempa[1] = getSBoxValue(tempa[1]);
tempa[2] = getSBoxValue(tempa[2]);
tempa[3] = getSBoxValue(tempa[3]);
}
tempa[0] = tempa[0] ^ Rcon[i / Nk];
}
j = i * 4; k = (i - Nk) * 4;
RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
}
}
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key) {
KeyExpansion(ctx->RoundKey, key);
}
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv) {
KeyExpansion(ctx->RoundKey, key);
memcpy(ctx->Iv, iv, AES_BLOCKLEN);
}
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv) {
memcpy(ctx->Iv, iv, AES_BLOCKLEN);
}
static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey) {
uint8_t i, j;
for (i = 0; i < 4; ++i) {
for (j = 0; j < 4; ++j) {
(*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];
}
}
}
static void SubBytes(state_t* state) {
uint8_t i, j;
for (i = 0; i < 4; ++i) {
for (j = 0; j < 4; ++j) {
(*state)[j][i] = getSBoxValue((*state)[j][i]);
}
}
}
static void ShiftRows(state_t* state) {
uint8_t temp;
temp = (*state)[0][1];
(*state)[0][1] = (*state)[1][1];
(*state)[1][1] = (*state)[2][1];
(*state)[2][1] = (*state)[3][1];
(*state)[3][1] = temp;
temp = (*state)[0][2];
(*state)[0][2] = (*state)[2][2];
(*state)[2][2] = temp;
temp = (*state)[1][2];
(*state)[1][2] = (*state)[3][2];
(*state)[3][2] = temp;
temp = (*state)[0][3];
(*state)[0][3] = (*state)[3][3];
(*state)[3][3] = (*state)[2][3];
(*state)[2][3] = (*state)[1][3];
(*state)[1][3] = temp;
}
static uint8_t xtime(uint8_t x) {
return ((x << 1) ^ (((x >> 7) & 1) * 0x1b));
}
static void MixColumns(state_t* state) {
uint8_t i;
uint8_t Tmp, Tm, t;
for (i = 0; i < 4; ++i) {
t = (*state)[i][0];
Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3];
Tm = (*state)[i][0] ^ (*state)[i][1]; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp;
Tm = (*state)[i][1] ^ (*state)[i][2]; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp;
Tm = (*state)[i][2] ^ (*state)[i][3]; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp;
Tm = (*state)[i][3] ^ t; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp;
}
}
#if MULTIPLY_AS_A_FUNCTION
static uint8_t Multiply(uint8_t x, uint8_t y) {
return (((y & 1) * x) ^
((y >> 1 & 1) * xtime(x)) ^
((y >> 2 & 1) * xtime(xtime(x))) ^
((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^
((y >> 4 & 1) * xtime(xtime(xtime(xtime(x))))));
}
#else
#define Multiply(x, y) \
( ((y & 1) * x) ^ \
((y>>1 & 1) * xtime(x)) ^ \
((y>>2 & 1) * xtime(xtime(x))) ^ \
((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \
((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \
#endif
#define getSBoxInvert(num) (rsbox[(num)])
static void InvMixColumns(state_t* state) {
int i;
uint8_t a, b, c, d;
for (i = 0; i < 4; ++i) {
a = (*state)[i][0];
b = (*state)[i][1];
c = (*state)[i][2];
d = (*state)[i][3];
(*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
(*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
(*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
(*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
}
}
static void InvSubBytes(state_t* state) {
uint8_t i, j;
for (i = 0; i < 4; ++i) {
for (j = 0; j < 4; ++j) {
(*state)[j][i] = getSBoxInvert((*state)[j][i]);
}
}
}
static void InvShiftRows(state_t* state) {
uint8_t temp;
temp = (*state)[3][1];
(*state)[3][1] = (*state)[2][1];
(*state)[2][1] = (*state)[1][1];
(*state)[1][1] = (*state)[0][1];
(*state)[0][1] = temp;
temp = (*state)[0][2];
(*state)[0][2] = (*state)[2][2];
(*state)[2][2] = temp;
temp = (*state)[1][2];
(*state)[1][2] = (*state)[3][2];
(*state)[3][2] = temp;
temp = (*state)[0][3];
(*state)[0][3] = (*state)[1][3];
(*state)[1][3] = (*state)[2][3];
(*state)[2][3] = (*state)[3][3];
(*state)[3][3] = temp;
}
static void Cipher(state_t* state, const uint8_t* RoundKey) {
uint8_t round = 0;
AddRoundKey(0, state, RoundKey);
for (round = 1; ; ++round) {
SubBytes(state);
ShiftRows(state);
if (round == Nr) {
break;
}
MixColumns(state);
AddRoundKey(round, state, RoundKey);
}
AddRoundKey(Nr, state, RoundKey);
}
static void InvCipher(state_t* state, const uint8_t* RoundKey) {
uint8_t round = 0;
AddRoundKey(Nr, state, RoundKey);
for (round = (Nr - 1); ; --round) {
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(round, state, RoundKey);
if (round == 0) {
break;
}
InvMixColumns(state);
}
}
static void XorWithIv(uint8_t* buf, const uint8_t* Iv) {
uint8_t i;
for (i = 0; i < AES_BLOCKLEN; ++i) {
buf[i] ^= Iv[i];
}
}
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) {
size_t i;
uint8_t* Iv = ctx->Iv;
for (i = 0; i < length; i += AES_BLOCKLEN) {
XorWithIv(buf, Iv);
Cipher((state_t*)buf, ctx->RoundKey);
Iv = buf;
buf += AES_BLOCKLEN;
}
memcpy(ctx->Iv, Iv, AES_BLOCKLEN);
}
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) {
size_t i;
uint8_t storeNextIv[AES_BLOCKLEN];
for (i = 0; i < length; i += AES_BLOCKLEN) {
memcpy(storeNextIv, buf, AES_BLOCKLEN);
InvCipher((state_t*)buf, ctx->RoundKey);
XorWithIv(buf, ctx->Iv);
memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN);
buf += AES_BLOCKLEN;
}
}
int sha1digest(uint8_t* digest, char* hexdigest, const uint8_t* data, size_t databytes) {
#define SHA1ROTATELEFT(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
uint32_t W[80];
uint32_t H[] = { 0x67452301,
0xEFCDAB89,
0x98BADCFE,
0x10325476,
0xC3D2E1F0 };
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
uint32_t e;
uint32_t f = 0;
uint32_t k = 0;
uint32_t idx;
uint32_t lidx;
uint32_t widx;
uint32_t didx = 0;
int32_t wcount;
uint32_t temp;
uint64_t databits = ((uint64_t)databytes) * 8;
uint32_t loopcount = (databytes + 8) / 64 + 1;
uint32_t tailbytes = 64 * loopcount - databytes;
uint8_t datatail[128] = { 0 };
if (!digest && !hexdigest)
return -1;
if (!data)
return -1;
datatail[0] = 0x80;
datatail[tailbytes - 8] = (uint8_t)(databits >> 56 & 0xFF);
datatail[tailbytes - 7] = (uint8_t)(databits >> 48 & 0xFF);
datatail[tailbytes - 6] = (uint8_t)(databits >> 40 & 0xFF);
datatail[tailbytes - 5] = (uint8_t)(databits >> 32 & 0xFF);
datatail[tailbytes - 4] = (uint8_t)(databits >> 24 & 0xFF);
datatail[tailbytes - 3] = (uint8_t)(databits >> 16 & 0xFF);
datatail[tailbytes - 2] = (uint8_t)(databits >> 8 & 0xFF);
datatail[tailbytes - 1] = (uint8_t)(databits >> 0 & 0xFF);
for (lidx = 0; lidx < loopcount; lidx++) {
memset(W, 0, 80 * sizeof(uint32_t));
for (widx = 0; widx <= 15; widx++) {
wcount = 24;
while (didx < databytes && wcount >= 0) {
W[widx] += (((uint32_t)data[didx]) << wcount);
didx++;
wcount -= 8;
}
while (wcount >= 0) {
W[widx] += (((uint32_t)datatail[didx - databytes]) << wcount);
didx++;
wcount -= 8;
}
}
for (widx = 16; widx <= 31; widx++) {
W[widx] = SHA1ROTATELEFT((W[widx - 3] ^ W[widx - 8] ^ W[widx - 14] ^ W[widx - 16]), 1);
}
for (widx = 32; widx <= 79; widx++) {
W[widx] = SHA1ROTATELEFT((W[widx - 6] ^ W[widx - 16] ^ W[widx - 28] ^ W[widx - 32]), 2);
}
a = H[0];
b = H[1];
c = H[2];
d = H[3];
e = H[4];
for (idx = 0; idx <= 79; idx++) {
if (idx <= 19) {
f = (b & c) | ((~b) & d);
k = 0x5A827999;
} else if (idx >= 20 && idx <= 39) {
f = b ^ c ^ d;
k = 0x6ED9EBA1;
} else if (idx >= 40 && idx <= 59) {
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
} else if (idx >= 60 && idx <= 79) {
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
temp = SHA1ROTATELEFT(a, 5) + f + e + k + W[idx];
e = d;
d = c;
c = SHA1ROTATELEFT(b, 30);
b = a;
a = temp;
}
H[0] += a;
H[1] += b;
H[2] += c;
H[3] += d;
H[4] += e;
}
if (digest) {
for (idx = 0; idx < 5; idx++) {
digest[idx * 4 + 0] = (uint8_t)(H[idx] >> 24);
digest[idx * 4 + 1] = (uint8_t)(H[idx] >> 16);
digest[idx * 4 + 2] = (uint8_t)(H[idx] >> 8);
digest[idx * 4 + 3] = (uint8_t)(H[idx]);
}
}
if (hexdigest) {
snprintf(hexdigest, 41, "%08x%08x%08x%08x%08x",
H[0], H[1], H[2], H[3], H[4]);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment