commit c41dcb673c914e2d755cf53624926a9093477feb
parent 406aa4552a412082f67d3eb20a165c31fa4474d5
Author: Jack Sangdahl <jack@pngu.org>
Date: Mon, 6 Oct 2025 14:03:02 -0600
challenge 7: aes in ecb mode
Diffstat:
5 files changed, 184 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,7 +1,8 @@
DEBUG ?= 0
-CFLAGS = -Wall -Wextra -Werror -Wno-unused -pedantic -Ilib
-LDFLAGS =
+CFLAGS = -Wall -Wextra -Werror -Wno-unused -pedantic -Ilib \
+ $(shell pkgconf --cflags openssl)
+LDFLAGS = $(shell pkgconf --libs openssl)
ifeq ($(DEBUG),1)
CFLAGS += -g -fsanitize=address
diff --git a/data/07.txt b/data/07.txt
@@ -0,0 +1,64 @@
+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
diff --git a/lib/aes.c b/lib/aes.c
@@ -0,0 +1,66 @@
+#include "aes.h"
+
+int next_block(int length, size_t block_size) {
+ return (length + block_size) & ~(block_size - 1);
+}
+
+struct bytes pkcs7(const char *data, const size_t data_len, size_t block_size) {
+ size_t res_len = next_block(data_len, block_size);
+ unsigned char *res = (unsigned char *)malloc(res_len * sizeof(unsigned char));
+ unsigned char padding = res_len - data_len;
+ memcpy(res, data, data_len);
+ for (size_t i = data_len; i < res_len; i++)
+ res[i] = padding;
+ return (struct bytes){res, res_len};
+}
+
+struct bytes pkcs7_strip(unsigned char *data, size_t data_len) {
+ size_t padding = data[data_len - 1], res_len = data_len - padding;
+ unsigned char *res = (unsigned char *)malloc(res_len * sizeof(unsigned char));
+ memcpy(res, data, res_len);
+ return (struct bytes){res, res_len};
+}
+
+bool pkcs7_validate(unsigned char *data, size_t data_len) {
+ size_t padding = data[data_len - 1];
+ if (!padding || padding > data_len)
+ return false;
+ for (size_t i = 1; i < padding; i++)
+ if (padding != data[data_len - 1 - i])
+ return false;
+ return true;
+}
+
+struct bytes pkcs7_validate_strip(unsigned char *data, size_t data_len) {
+ struct bytes res = {NULL, 0};
+ if (pkcs7_validate(data, data_len))
+ res = pkcs7_strip(data, data_len);
+ return res;
+}
+
+struct bytes aes_encrypt_ecb(char *data, const size_t data_len,
+ const unsigned char *key, const size_t key_len) {
+ AES_KEY aes_key;
+ AES_set_encrypt_key(key, key_len * 8, &aes_key);
+ struct bytes padded = pkcs7(data, data_len, AES_BLOCK_SIZE);
+ unsigned char *res =
+ (unsigned char *)calloc(padded.len, sizeof(unsigned char));
+ for (size_t i = 0; i < padded.len; i += AES_BLOCK_SIZE)
+ AES_ecb_encrypt(padded.data + i, res + i, &aes_key, AES_ENCRYPT);
+ free(padded.data);
+ return (struct bytes){res, padded.len};
+}
+
+struct bytes aes_decrypt_ecb(const unsigned char *data, size_t data_len,
+ const unsigned char *key, size_t key_len) {
+ struct bytes res = {NULL, 0};
+ unsigned char *decrypted = calloc(data_len + 1, sizeof(unsigned char));
+ AES_KEY aes_key;
+ AES_set_decrypt_key(key, key_len * 8, &aes_key);
+ for (size_t i = 0; i < data_len; i += AES_BLOCK_SIZE)
+ AES_ecb_encrypt(data + i, decrypted + i, &aes_key, AES_DECRYPT);
+ if (data_len)
+ res = pkcs7_strip(decrypted, data_len);
+ free(decrypted);
+ return res;
+}
diff --git a/lib/aes.h b/lib/aes.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <openssl/aes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct bytes {
+ unsigned char *data;
+ size_t len;
+};
+
+int next_block(int length, size_t block_size);
+struct bytes pkcs7(const char *data, const size_t data_len, size_t block_size);
+struct bytes pkcs7_strip(unsigned char *data, size_t data_len);
+bool pkcs7_validate(unsigned char *data, size_t data_len);
+struct bytes pkcs7_validate_strip(unsigned char *data, size_t data_len);
+struct bytes aes_encrypt_ecb(char *data, const size_t data_len,
+ const unsigned char *key, const size_t key_len);
+struct bytes aes_decrypt_ecb(const unsigned char *data, size_t data_len,
+ const unsigned char *key, size_t key_len);
diff --git a/src/07_aes_ecb_mode.c b/src/07_aes_ecb_mode.c
@@ -0,0 +1,30 @@
+// AES in ECB mode
+#include "aes.h"
+#include "base64.h"
+#include "file.h"
+
+/*
+ * the base64 encoded content in [data/07.txt] has been encrypted via aes-128 in
+ * ecb mode under the key "YELLOW SUBMARINE" (case sensitive, without quotes,
+ * exactly 16 characters; i like "YELLOW SUBMARINE" because it's exactly 16
+ * bytes long, and now you do too). decrypt it. you know the key afterall.
+ * easiest way: use openssl cipher and give it aes-128 ecb as the cipher. you
+ * can obviously decrypt this using the openssl command line tool, but we're
+ * having you get ecb working in code for a reason. you'll need it a lot later
+ * on, and not just for attacking ecb.
+ */
+
+int main(void) {
+ static char *key = "YELLOW SUBMARINE";
+ char *input = NULL, *decoded = NULL;
+ int file_len = read_file("data/07.txt", &input);
+ int decoded_len = base64_decode(input, file_len, &decoded);
+ struct bytes res = aes_decrypt_ecb((unsigned char *)decoded, decoded_len,
+ (const unsigned char *)key, strlen(key));
+ if (res.data) {
+ printf("%s", res.data);
+ free(res.data);
+ }
+ free(decoded);
+ return 0;
+}