summaryrefslogtreecommitdiff
path: root/single_byte_ecb_decryption_s2.c
diff options
context:
space:
mode:
authorJack Sangdahl <[email protected]>2024-06-15 22:27:25 -0600
committerJack Sangdahl <[email protected]>2024-06-15 22:27:25 -0600
commita59a5d144cc31cc8386e60dcc97be45a0dfd5256 (patch)
tree076d0adc9bc53538e7283e0248adef57ce2a9a51 /single_byte_ecb_decryption_s2.c
downloadcryptopals-master.tar.gz
cryptopals-master.zip
Diffstat (limited to 'single_byte_ecb_decryption_s2.c')
-rw-r--r--single_byte_ecb_decryption_s2.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/single_byte_ecb_decryption_s2.c b/single_byte_ecb_decryption_s2.c
new file mode 100644
index 0000000..f4b5def
--- /dev/null
+++ b/single_byte_ecb_decryption_s2.c
@@ -0,0 +1,150 @@
+// https://cryptopals.com/sets/2/challenges/12
+#include "util/aes.h"
+#include "util/base64.h"
+#include "util/random.h"
+#include <string.h>
+
+#define MAX_BLOCK_SIZE 128
+#define MAX_SECRET_SIZE 512
+
+static unsigned char key[16];
+
+static int oracle(unsigned char *in, size_t in_len, unsigned char *out) {
+ size_t secret_len;
+ char *secret_str =
+ "Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkg"
+ "aGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBq"
+ "dXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUg"
+ "YnKK";
+ uint8_t *secret = base64_decode(secret_str, &secret_len);
+ if (secret == NULL) {
+ fprintf(stderr, "base64_decode() failed\n");
+ exit(1);
+ }
+ // append 'secret' to end of input
+ size_t new_in_len = in_len + secret_len;
+ unsigned char *new_in = malloc(new_in_len);
+ if (new_in == NULL)
+ return -1;
+ memcpy(new_in, in, in_len);
+ memcpy(new_in + in_len, secret, secret_len);
+ // encrypt with ECB
+ EVP_CIPHER_CTX *ctx = evp_init();
+ int encrypted_len = evp_ecb_encrypt(ctx, new_in, new_in_len, key, out);
+ evp_cleanup(ctx);
+ free(new_in);
+ return encrypted_len;
+}
+
+static ssize_t detect_block_size() {
+ size_t first_increase = 0, second_increase = 0, prev_out_size, curr_out_size;
+ unsigned char *in, *out;
+ int res = -1;
+ in = calloc(MAX_BLOCK_SIZE, 1);
+ out = calloc(2 * MAX_BLOCK_SIZE + MAX_SECRET_SIZE, 1);
+ if (in == NULL || out == NULL)
+ goto error;
+ prev_out_size = oracle(in, 1, out);
+ if (prev_out_size < 0)
+ goto error;
+ for (size_t i = 2; i <= MAX_BLOCK_SIZE; i++) {
+ curr_out_size = oracle(in, i, out);
+ if (curr_out_size < 0)
+ goto error;
+ else {
+ if ((size_t)curr_out_size != prev_out_size) {
+ prev_out_size = curr_out_size;
+ if (first_increase == 0)
+ first_increase = i;
+ else {
+ second_increase = i;
+ break;
+ }
+ }
+ }
+ }
+ res = first_increase == 0 || second_increase == 0
+ ? -1
+ : second_increase - first_increase;
+error:
+ free(in);
+ free(out);
+ return res;
+}
+
+static int detect_ecb(size_t block_size) {
+ unsigned char *two_blocks = calloc(2 * block_size, 1);
+ unsigned char *encrypted = malloc(3 * block_size + MAX_SECRET_SIZE);
+ int res = -1;
+ if (oracle(two_blocks, 2 * block_size, encrypted) < 0)
+ goto error;
+ res = (0 == memcmp(encrypted, encrypted + block_size, block_size));
+error:
+ free(two_blocks);
+ free(encrypted);
+ return res;
+}
+
+static int decrypt_next_char(size_t block_size, unsigned char *known_chars,
+ size_t known_len) {
+ size_t blocks_needed = 1 + known_len / block_size;
+ size_t padding_needed = block_size - 1 - (known_len % block_size);
+ size_t total_size = block_size * blocks_needed;
+ int res = -1;
+ unsigned char *in = calloc(block_size, blocks_needed);
+ unsigned char *out =
+ malloc((blocks_needed + 1) * block_size + MAX_SECRET_SIZE);
+ if (oracle(in, padding_needed, out) < 0) {
+ free(in);
+ free(out);
+ return -1;
+ }
+ // save last relevant block of output for later comparison
+ unsigned char *last_relevant_block = out + (blocks_needed - 1) * block_size;
+ unsigned char *char_block = malloc(block_size);
+ memcpy(char_block, last_relevant_block, block_size);
+ // setup 'blocks_needed' of input for checking
+ memcpy(in + padding_needed, known_chars, known_len);
+ for (uint i = 0; i < 256; i++) {
+ in[total_size - 1] = (unsigned char)i;
+ if (oracle(in, total_size, out) < 0)
+ goto early_exit;
+ if (memcmp(last_relevant_block, char_block, block_size) == 0) {
+ res = i;
+ break;
+ }
+ }
+early_exit:
+ free(in);
+ free(out);
+ free(char_block);
+ return res;
+}
+
+int main() {
+ init_with_random_bytes(key, 16);
+ ssize_t s_block_size = detect_block_size();
+ if (s_block_size < 0) {
+ fprintf(stderr, "unable to detect block_size\n");
+ exit(1);
+ }
+ size_t block_size = (size_t)s_block_size;
+ int is_ecb = detect_ecb(block_size);
+ printf("detected block size: %zu, ecb: %d\n", block_size, is_ecb);
+ // decrypt message byte-by-byte using oracle
+ ssize_t i = 0;
+ unsigned char *decrypted = calloc(MAX_SECRET_SIZE, 1);
+ for (;;) {
+ int next_char = decrypt_next_char(block_size, decrypted, i);
+ if (next_char == -1)
+ break;
+ else {
+ decrypted[i] = (unsigned char)next_char;
+ i++;
+ }
+ }
+ // write message!
+ fwrite(decrypted, 1, i - 1, stdout);
+ free(decrypted);
+ return 0;
+}