PwnThyBytes 2019 CTF - avec
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdint.h> | |
#include <unistd.h> | |
#include <assert.h> | |
#include <openssl/aes.h> | |
/* | |
gcc -O3 solve.c -L. -lghash_clmul -lcrypto -o solve | |
LD_LIBRARY_PATH=. time ./solve | |
... | |
j 0000000074000000: eca170b9065f6fac | |
pwned nonce: cc08407e4f4d770acc08407e00000001 | |
key: dce3354f78b6b53ddce3354f78b6b53d | |
5054424354467b376163663362363062 | |
PTBCTF{7acf3b60b | |
3038313937363765613637623464347d | |
0819767ea67b4d4} | |
~ 1 hour | |
*/ | |
typedef unsigned char u8; | |
typedef unsigned int u32; | |
static void xor_block(u8 *dst, const u8 *src) { | |
u32 *d = (u32 *) dst; | |
u32 *s = (u32 *) src; | |
*d++ ^= *s++; | |
*d++ ^= *s++; | |
*d++ ^= *s++; | |
*d++ ^= *s++; | |
} | |
int ghash_expand_clmul(u8* hk, void** ctxptr); | |
int ghash_clmul(u8* out, u8*in, size_t ln, u8* prevout, void* ctx); | |
int ghash_destroy_clmul(void *ghash_tables); | |
int good(u8 *nonce) { | |
if (nonce[0] != nonce[8]) return 0; | |
if (nonce[1] != nonce[9]) return 0; | |
if (nonce[2] != nonce[10]) return 0; | |
if (nonce[3] != nonce[11]) return 0; | |
if (nonce[12] != 0) return 0; | |
if (nonce[13] != 0) return 0; | |
if (nonce[14] != 0) return 0; | |
if (nonce[15] != 1) return 0; | |
return 1; | |
} | |
uint64_t MOD = 0x247f43cb7ull; | |
uint64_t G = 0x3bc02a1eb0a80bc8ull; | |
uint64_t gmul(uint64_t a, uint64_t b) { | |
uint64_t p = 0; | |
while (a && b) { | |
if (b & 1) p ^= a; | |
if (a >> 63) a = (a << 1) ^ MOD; | |
else a <<= 1; | |
b >>= 1; | |
} | |
return p; | |
} | |
int main(int argc, char *argv[]) { | |
u8 ZERO[16] = {}; | |
u8 CT[32] = "\x75\x31\x82\x22\x0e\x54\xf7\xf7\x61\xab\xc2\x7f\x58\x2d\x66\x11\xba\x9a\xe9\x77\x52\x9e\xa7\x8c\xee\x34\xf9\x56\x29\xb6\x6d\xc8"; | |
u8 TAG[16] = "\x97\x45\x52\xaa\xee\x43\x38\x8d\x76\x86\xfa\xe8\x52\xd1\xc0\xae"; | |
u8 AD[16] = "PTB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; | |
u8 LENS[16] = "\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x00\x00\x00\x01\x00"; | |
AES_KEY enc_key, dec_key, dummykey; | |
AES_set_decrypt_key("assume_nothing!!", 128, &dummykey); | |
uint64_t K = G; | |
for (uint64_t j = 0; j < (1ull<<32)+1; j++) { | |
if ( (j & 0xffffff) == 0 )printf("j %016lx: %016lx\n", j, K); | |
u8 key[16] = {}; | |
u8 hkey[16] = {}; | |
u8 nonce[16] = {}; | |
memcpy(key, &K, 8); | |
memcpy(key+8, &K, 8); | |
AES_set_encrypt_key(key, 128, &enc_key); | |
AES_set_decrypt_key(key, 128, &dec_key); | |
AES_encrypt(ZERO, hkey, &enc_key); | |
void *ctx; | |
u8 buf[17] = {}; | |
ghash_expand_clmul(hkey, &ctx); | |
ghash_clmul(buf, AD, 16, buf, ctx); | |
ghash_clmul(buf, CT, 32, buf, ctx); | |
ghash_clmul(buf, LENS, 16, buf, ctx); | |
xor_block(buf, TAG); | |
ghash_destroy_clmul(ctx); | |
AES_decrypt(buf, nonce, &dec_key); | |
if (good(nonce)) { | |
printf("pwned nonce: "); | |
for(int i = 0; i < 16; i++) printf("%02x", nonce[i]); puts(""); | |
printf(" key: "); | |
for(int i = 0; i < 16; i++) printf("%02x", key[i]); puts(""); | |
u8 iv[16]; | |
nonce[15] = 2; | |
AES_encrypt(nonce, buf, &enc_key); | |
xor_block(buf, CT); | |
memcpy(iv, buf, 16); | |
AES_decrypt(buf, buf, &dummykey); | |
for(int i = 0; i < 16; i++) printf("%02x", buf[i]); puts(""); | |
printf("%s\n", buf); | |
nonce[15] = 3; | |
AES_encrypt(nonce, buf, &enc_key); | |
xor_block(buf, CT+16); | |
AES_decrypt(buf, buf, &dummykey); | |
xor_block(buf, iv); | |
for(int i = 0; i < 16; i++) printf("%02x", buf[i]); puts(""); | |
printf("%s\n", buf); | |
} | |
K = gmul(K, G); | |
} | |
return 0; | |
} | |
/* | |
pwned nonce: cc08407e4f4d770acc08407e00000001 | |
key: dce3354f78b6b53ddce3354f78b6b53d | |
5054424354467b376163663362363062 | |
PTBCTF{7acf3b60b | |
3038313937363765613637623464347d | |
0819767ea67b4d4} | |
*/ |
#!/usr/bin/sage | |
import os | |
from Crypto.Cipher import AES # Use `sage -sh` to install pycryptodome for AES.MODE.GCM | |
from Crypto.Util.number import bytes_to_long, long_to_bytes | |
def do_raise_entropy(input_msg): | |
cipher = AES.new("assume_nothing!!", AES.MODE_CBC, "\x00"*16) | |
return cipher.encrypt(input_msg) | |
def polish_key(key): | |
key = bytes_to_long(key[::-1]) | |
key = GF(2**64).fetch_int(key) | |
key = key ** 0xbcafffff435 | |
key = long_to_bytes( key.integer_representation() )[::-1] | |
assert len(key) == 8 | |
return key | |
def do_encrypt(data): | |
half = polish_key( os.urandom(8) ) | |
key = half + half | |
half2 = polish_key( os.urandom(8) ) | |
nonce = half2 + half2 | |
cipher = AES.new(key, AES.MODE_GCM, nonce = nonce[:12]) | |
cipher.update("PTB") | |
ciphertext, tag = cipher.encrypt_and_digest( do_raise_entropy(data) ) | |
open("flag.bin", "wb+").write(ciphertext + tag) | |
do_encrypt( open("flag.txt").read() ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment