commit 452884f6a66f51ad48d04b8c7a2e94a57643651b
parent 419e41293a37b19d53da3dd4fd7a37bdce5566cb
Author: Jack Sangdahl <jack@pngu.org>
Date: Wed, 8 Oct 2025 10:48:59 -0600
challenge 11: an ecb/cbc detection oracle
Diffstat:
5 files changed, 97 insertions(+), 0 deletions(-)
diff --git a/lib/aes.c b/lib/aes.c
@@ -227,3 +227,10 @@ struct bytes aes_decrypt_cbc(unsigned char *data, size_t data_len,
free(plaintext);
return res;
}
+
+char *aes_oracle(unsigned char *encoded, size_t block_size) {
+ if (!memcmp(encoded + block_size, encoded + block_size * 2, block_size))
+ return "ECB";
+ else
+ return "CBC";
+}
diff --git a/lib/aes.h b/lib/aes.h
@@ -29,3 +29,4 @@ struct bytes aes_encrypt_cbc(char *data, const size_t data_len,
struct bytes aes_decrypt_cbc(unsigned char *data, size_t data_len,
const unsigned char *key, size_t key_len,
unsigned char *iv);
+char *aes_oracle(unsigned char *encoded, size_t block_size);
diff --git a/lib/random.c b/lib/random.c
@@ -0,0 +1,20 @@
+#include "random.h"
+
+unsigned char *random_bytes(size_t num_bytes) {
+ unsigned char *bytes =
+ (unsigned char *)malloc(num_bytes * sizeof(unsigned char));
+ for (size_t i = 0; i < num_bytes; i++)
+ bytes[i] = rand();
+ return bytes;
+}
+
+int random_int_inclusive(int min, int max) {
+ if (min >= max)
+ return min;
+ int range = max - min + 1, result;
+ int cutoff = (RAND_MAX / range) * range;
+ do
+ result = rand();
+ while (result >= cutoff);
+ return result % range + min;
+}
diff --git a/lib/random.h b/lib/random.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#include <stdlib.h>
+
+unsigned char *random_bytes(size_t num_bytes);
+int random_int_inclusive(int min, int max);
diff --git a/src/11_ecb_cbc_detection_oracle.c b/src/11_ecb_cbc_detection_oracle.c
@@ -0,0 +1,63 @@
+// An ECB/CBC detection oracle
+#include "aes.h"
+#include "random.h"
+#include <assert.h>
+
+/*
+ * now that you have ecb and cbc working: write a function to generate a random
+ * aes key; that's just 16 random bytes. write a function that encrypts that
+ * data under an unknown key -- that is, a function that generates a random key
+ * and encrypts under it. the function looks like: encryption_oracle(your_input)
+ * => [meaningless jibber jabber]
+ * under the hood, have the function append 5-10 bytes (count chosen randomly)
+ * before the plaintext and 5-10 bytes after the plaintext. now, have the
+ * function choose to encrypt under ecb 1/2 of the time, and under cbc the other
+ * half (just use random iv's each time for cbc). use rand(2) to decide which to
+ * use. detect the block cipher mode the function is using each time. you should
+ * end up with a piece of code that, pointed at a block box that might be
+ * encrypting ecb or cbc, tells you which is happening.
+ */
+
+struct bytes random_prefix_suffix(char *data, size_t data_len) {
+ size_t prefix_len = random_int_inclusive(5, 10);
+ size_t suffix_len = random_int_inclusive(5, 10);
+ unsigned char *prefix = random_bytes(prefix_len);
+ unsigned char *suffix = random_bytes(suffix_len);
+ size_t total_len = prefix_len + data_len + suffix_len;
+ unsigned char *str =
+ (unsigned char *)malloc(total_len * sizeof(unsigned char));
+ memcpy(str, prefix, prefix_len);
+ memcpy(str + prefix_len, data, data_len);
+ memcpy(str + prefix_len + data_len, suffix, suffix_len);
+ free(prefix);
+ free(suffix);
+ return (struct bytes){str, total_len};
+}
+
+int main(void) {
+ srand(time(NULL));
+ struct bytes data, encoded;
+ char *mode, ones[64] = {1};
+ unsigned char iv[16] = {0};
+ unsigned char *key;
+ for (int i = 1; i <= 100; i++) {
+ data = random_prefix_suffix(ones, 64);
+ key = random_bytes(16);
+ if (rand() % 2) {
+ mode = "ECB";
+ encoded = aes_encrypt_ecb((char *)data.data, data.len, key, 16);
+ } else {
+ mode = "CBC";
+ encoded = aes_encrypt_cbc((char *)data.data, data.len, key, 16, iv);
+ }
+ char *detected_mode = aes_oracle(encoded.data, 16);
+ printf("round %d:\n", i);
+ printf("mode: %s\n", mode);
+ printf("detected: %s\n\n", detected_mode);
+ assert(!strcmp(mode, detected_mode));
+ free(data.data);
+ free(encoded.data);
+ free(key);
+ }
+ return 0;
+}