akira-bruteforce/decrypt.c
2025-03-13 12:31:49 +07:00

370 lines
11 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include <assert.h>
#include <nettle/yarrow.h>
#include "chacha8.h"
#include "test-ts.h"
#include "kcipher2.h"
#include <sys/mman.h>
uint32_t swap32(uint32_t x)
{
return ((x & 0xff) << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | ((x & 0xff000000) >> 24);
}
void gen_key(uint64_t t, char *buffer, int size)
{
struct yarrow256_ctx ctx;
yarrow256_init(&ctx, 0, NULL);
char seed[32];
snprintf(seed, sizeof(seed), "%lld", t);
yarrow256_seed(&ctx, strlen(seed), seed);
yarrow256_random(&ctx, size, buffer);
}
void hexdump(const char *title, const void *data, size_t size)
{
printf("%s: ", title);
const uint8_t *p = data;
for (size_t i = 0; i < size; i++) {
printf("%02x ", p[i]);
}
printf("\n");
}
void compute_blocks(uint64_t filesize,
uint8_t percent,
uint64_t *enc_block_size,
uint64_t *part_size,
uint64_t *encrypted_parts)
{
int parts = 3;
if ( percent > 49u )
parts = 5;
uint64_t enc_size = filesize * (uint64_t)percent / 100;
*enc_block_size = enc_size / parts;
*encrypted_parts = parts - 1;
*part_size = (filesize - *enc_block_size * (*encrypted_parts)) / parts;
}
void test_compute()
{
uint64_t enc_block_size;
uint64_t part_size;
uint64_t encrypted_parts;
compute_blocks(330, 15, &enc_block_size, &part_size, &encrypted_parts);
printf("Enc block size: %lld\n", enc_block_size);
printf("Part size: %lld\n", part_size);
printf("Encrypted parts: %lld\n", encrypted_parts);
}
void decrypt_file_bykey(const char *filename,
uint8_t *chacha8_key,
uint8_t *cacha8_nonce,
uint8_t *kcipher2_key,
uint8_t *kcipher2_iv
)
{
//get file size
FILE *fp = fopen(filename, "rb");
if (!fp) {
perror("fopen");
return;
}
fseek(fp, 0, SEEK_END);
uint64_t filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
fclose(fp);
uint64_t enc_block_size;
uint64_t part_size;
uint64_t encrypted_parts;
#define PERCENT 15
compute_blocks(filesize - 512, PERCENT, &enc_block_size, &part_size, &encrypted_parts);
printf("Allocating: %zu bytes\n", enc_block_size);
uint8_t *enc_block = (uint8_t *)malloc(128*1024);
fp = fopen(filename, "r+b");
if (!fp) {
perror("fopen");
free(enc_block);
return;
}
struct chacha8_ctx chacha_ctx;
chacha8_keysetup(&chacha_ctx, chacha8_key, cacha8_nonce);
uint32_t *kcipher2_key_ptr = (uint32_t *)kcipher2_key;
//swap32
for (int i = 0; i < 4; i++) {
kcipher2_key_ptr[i] = swap32(kcipher2_key_ptr[i]);
}
uint32_t *kcipher2_iv_ptr = (uint32_t *)kcipher2_iv;
//swap32
for (int i = 0; i < 4; i++) {
kcipher2_iv_ptr[i] = swap32(kcipher2_iv_ptr[i]);
}
kcipher2_init(kcipher2_key_ptr, kcipher2_iv_ptr);
kcipher2_stream stream;
init_kcipher2_stream(&stream, &State);
size_t chacha_bytes = 0;
int current_chacha_block = 0;
for (int i = 0; encrypted_parts > i; ++i )
{
uint64_t offs = 0LL;
uint64_t block_pos = part_size * i;
while ( offs < enc_block_size )
{
size_t enc_size = 0xFFFFLL;
if ( enc_block_size - offs <= 0xFFFF )
enc_size = enc_block_size - offs;
assert(enc_size < 128*1024);
//seek to offs + block_pos
fseek(fp, offs + block_pos, SEEK_SET);
//read enc_size
size_t bytesread = fread(enc_block, 1, enc_size, fp);
if ( bytesread != enc_size )
{
perror("fread");
free(enc_block);
fclose(fp);
return;
}
int current_enc = 0;
if ( !offs || enc_block_size <= offs + bytesread )
current_enc = 1; // kcipher2
if ( current_enc ) {
//kcipher2
printf("Decrypting with kcipher2: %d at offs %zu\n", bytesread, offs + block_pos);
//hexdump("Encrypted kcipher2 block", enc_block, bytesread>32?32:bytesread);
// // block size must be multiple of 8
// int block_size = bytesread;
// if (block_size % 8 != 0) {
// block_size = (block_size / 8 + 1) * 8;
// }
// kcipher2_encrypt(enc_zero_block, block_size, enc_tmp_block);
// for (int i = 0; i < bytesread; i++) {
// enc_block[i] ^= enc_tmp_block[i];
// }
kcipher2_xor_data(&stream, bytesread, enc_block);
// //dump enc_tmp_block
// hexdump("stream", enc_tmp_block, bytesread>32?32:bytesread);
// //last 32 bytes
// hexdump("stream (last 32 bytes)", enc_tmp_block + bytesread - 32,bytesread>32?32:bytesread);
//hexdump("decrypted kchiper2", enc_block, bytesread>32?32:bytesread);
//last 32
//hexdump("decrypted kchiper2 (last 32 bytes)", enc_block + bytesread - 32, bytesread>32?32:bytesread);
} else {
//hexdump("Encrypted block", enc_block, bytesread>32?32:bytesread);
printf("Decrypting with chacha8 %zu offs=%zu\n", bytesread, offs);
//chacha8
int blocks = (bytesread + 63) / 64;
chacha8_xor_keystream(&chacha_ctx, current_chacha_block, blocks, enc_block);
current_chacha_block += blocks;
//chacha8_xor_data(&chacha_stream, bytesread, enc_block);
chacha_bytes += bytesread ;
//hexdump("decrypted chacha", enc_block, bytesread<32?bytesread:32);
//dump last 32 bytes
//hexdump("decrypted chacha (last 32 bytes)", enc_block + bytesread - 32, bytesread>32?32:bytesread);
}
//seek and write back
fseek(fp, offs + block_pos, SEEK_SET);
fwrite(enc_block, 1, bytesread, fp);
offs += bytesread;
}
}
//truncate last 512 bytes
ftruncate(fileno(fp), filesize - 512);
fclose(fp);
free(enc_block);
printf("Decryption done\n");
//rename, removing .akira from end of file
char newname[256];
snprintf(newname, sizeof(newname), "%s", filename);
if (strstr(newname, ".akira")) {
newname[strlen(newname) - 6] = 0;
rename(filename, newname);
}
#if 0
struct chacha8_ctx chacha_ctx;
chacha8_keysetup(&chacha_ctx, chacha8_key, cacha8_nonce);
//dump keystream hex
printf("Chacha 20 state: ");
uint8_t *state = (uint8_t *)chacha_ctx.input;
for (int i = 0; i < 64; i++) {
printf("%02x ", state[i]);
}
printf("\n");
uint8_t test_data[256];
uint8_t test_data_out[256];
memset(test_data, 0, sizeof(test_data));
memset(test_data_out, 0, sizeof(test_data_out));
chacha8_get_keystream(&chacha_ctx, 0, 5, test_data);
hexdump("Chacha8 Stream", test_data, sizeof(test_data));
uint32_t *kcipher2_key_ptr = (uint32_t *)kcipher2_key;
//swap32
for (int i = 0; i < 4; i++) {
kcipher2_key_ptr[i] = swap32(kcipher2_key_ptr[i]);
}
uint32_t *kcipher2_iv_ptr = (uint32_t *)kcipher2_iv;
//swap32
for (int i = 0; i < 4; i++) {
kcipher2_iv_ptr[i] = swap32(kcipher2_iv_ptr[i]);
}
//for testing zero vectors
// memset(kcipher2_key_ptr, 0, 16);
// memset(kcipher2_iv_ptr, 0, 16);
printf("KEY as int32: ");
for (int i = 0; i < 4; i++) {
printf("%08x ", kcipher2_key_ptr[i]);
}
printf("\n");
printf("IV as int32: ");
for (int i = 0; i < 4; i++) {
printf("%08x ", kcipher2_iv_ptr[i]);
}
printf("\n");
kcipher2_init(kcipher2_key_ptr, kcipher2_iv_ptr);
/*
*
typedef struct
{
unsigned int A[5];
unsigned int B[11];
unsigned int L1, R1, L2, R2;
} kcipher2_state;
*/
//DUMP all the state
// printf("kcipher2_state:\n");
// printf("A[5]:\n");
// for (int i = 0; i < 5; i++) {
// printf("%08x ", State.A[i]);
// }
// printf("\n");
// printf("B[11]:\n");
// for (int i = 0; i < 11; i++) {
// printf("%08x ", State.B[i]);
// }
// printf("\n");
// printf("L1: %08x\n", State.L1);
// printf("R1: %08x\n", State.R1);
// printf("L2: %08x\n", State.L2);
// printf("R2: %08x\n", State.R2);
// printf("\n");
memset(test_data, 0, sizeof(test_data));
memset(test_data_out, 0, sizeof(test_data_out));
kcipher2_encrypt(test_data, sizeof(test_data), test_data_out);
hexdump("Kcipher2 Stream", test_data_out, sizeof(test_data_out));
#endif
}
void decrypt_file(const char *filename, uint64_t t1, uint64_t t2, uint64_t t3, uint64_t t4)
{
uint8_t chacha8_key[32];
uint8_t cacha8_nonce[16];
uint8_t kcipher2_key[16];
uint8_t kcipher2_iv[16];
printf("T1 = %lld\n", t1);
gen_key(t1, chacha8_key, 32);
hexdump("chacha8_k8", chacha8_key, 32);
printf("T2 = %lld\n", t2);
gen_key(t2, cacha8_nonce, 16);
hexdump("chacha8_nonce", cacha8_nonce, 16);
printf("T3 = %lld\n", t3);
gen_key(t3, kcipher2_key, 16);
hexdump("kcipher2_key ", kcipher2_key, 16);
printf("T4 = %lld\n", t4);
gen_key(t4, kcipher2_iv, 16);
hexdump("kcipher2_iv ", kcipher2_iv, 16);
decrypt_file_bykey(filename, chacha8_key, cacha8_nonce, kcipher2_key, kcipher2_iv);
}
int main(int argc, char *argv[])
{
//test_compute();
// uint8_t chacha8_key[32];
// uint8_t cacha8_nonce[16];
// uint8_t kcipher2_key[16];
// uint8_t kcipher2_iv[16];
// memset(chacha8_key, 0, sizeof(chacha8_key));
// memset(cacha8_nonce, 0, sizeof(cacha8_nonce));
// memset(kcipher2_key, 0, sizeof(kcipher2_key));
// memset(kcipher2_iv, 0, sizeof(kcipher2_iv));
// printf("Test zero input: ");
// decrypt_file_bykey("test-zero/mytest.akira", chacha8_key, cacha8_nonce, kcipher2_key, kcipher2_iv);
if (argc > 5) {
uint64_t t1 = atoll(argv[2]);
uint64_t t2 = atoll(argv[3]);
uint64_t t3 = atoll(argv[4]);
uint64_t t4 = atoll(argv[5]);
decrypt_file(argv[1], t1, t2, t3, t4);
} else {
printf("Usage: %s <filename> <t1> <t2> <t3> <t4>\n", argv[0]);
}
// uint64_t time_start = TEST_TIMESTAMP;
// decrypt_file("test-zero/mytest.akira", time_start, time_start + 1000, time_start +2000 , time_start + 3000);
// decrypt_file("test-zero/mytest.akira", time_start, time_start + 1000, time_start +2000 , time_start + 3001);
// decrypt_file("test-zero/mytest.akira", time_start, time_start + 1000, time_start +2000 , time_start + 3999);
// decrypt_file("test-zero/mytest.akira", time_start, time_start + 1000, time_start +2001 , time_start + 3001);
return 0;
}