Skip to content

Instantly share code, notes, and snippets.

@hellman
Last active October 4, 2019 08:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hellman/42bdd7a359b8ebaf2bc19cb9ca49ff33 to your computer and use it in GitHub Desktop.
Save hellman/42bdd7a359b8ebaf2bc19cb9ca49ff33 to your computer and use it in GitHub Desktop.
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