Last active
March 29, 2023 15:34
-
-
Save warm-ice0x00/9e504e0cc22f0babbe630f6a47c6a932 to your computer and use it in GitHub Desktop.
Known plaintext attack XOR cipher.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
const size_t kMaxKeyLen = 8; | |
unsigned char *hex_to_bytes(const char *hex, const size_t len) { | |
size_t final_len = len / 2 + (len % 2 != 0); | |
unsigned char *const result = (unsigned char *)malloc(final_len), *p = result; | |
if (result == NULL) { | |
perror("malloc"); | |
exit(EXIT_FAILURE); | |
} | |
if (len % 2 == 1) { | |
if (sscanf(hex++, "%1hhx", p++) != 1) { | |
perror("sscanf"); | |
exit(EXIT_FAILURE); | |
} | |
final_len--; | |
} | |
for (; final_len--; hex += 2, p++) { | |
if (sscanf(hex, "%2hhx", p) != 1) { | |
perror("sscanf"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
return result; | |
} | |
int search(const unsigned char *const pat, const size_t pat_len, | |
const unsigned char *const arr, const size_t arr_len) { | |
if (pat_len > arr_len) { | |
return 0; | |
} | |
const unsigned char *p, | |
*q, *const arr_end = arr + arr_len, *const pat_end = pat + pat_len; | |
for (p = arr, q = pat; p < arr_end && q < pat_end; p++) { | |
if (*p == *q) { | |
q++; | |
} else { | |
p -= q - pat, q = pat; | |
} | |
} | |
return q == pat_end; | |
} | |
int increment(unsigned char *const arr, const size_t len) { | |
unsigned char *p; | |
for (p = arr + len - 1; p >= arr; p--) { | |
if (*p == 0xFF) { | |
*p = 0; | |
} else { | |
(*p)++; | |
break; | |
} | |
} | |
return p < arr; | |
} | |
void exclusive_or(unsigned char *arr, const size_t arr_len, | |
const unsigned char *const key, const size_t key_len) { | |
size_t i; | |
for (i = 0; i < arr_len; i++, arr++) { | |
*arr ^= *(key + (i % key_len)); | |
} | |
} | |
void print_bytes(const unsigned char *arr, size_t len) { | |
const unsigned char *const end = arr + len - 1; | |
for (; arr < end; arr++) { | |
printf("%02hhx ", *arr); | |
} | |
printf("%02hhx\n", *arr); | |
} | |
int main(int argc, char **argv) { | |
if (argc != 3) { | |
printf("Usage: %s filename known_plaintext\n", argv[0]); | |
return 1; | |
} | |
const unsigned char *known; | |
size_t known_len = strlen(argv[2]); | |
known = hex_to_bytes(argv[2], known_len); | |
known_len = known_len / 2 + (known_len % 2 != 0); | |
FILE *const fp = fopen(argv[1], "rb"); | |
if (fp == NULL) { | |
perror("fopen"); | |
return 1; | |
} | |
if (fseek(fp, 0, SEEK_END) != 0) { | |
perror("fseek"); | |
fclose(fp); | |
return 1; | |
} | |
const size_t file_size = ftello64(fp); | |
if (file_size == -1) { | |
perror("ftello64"); | |
fclose(fp); | |
return 1; | |
} | |
if (fseek(fp, 0, SEEK_SET) != 0) { | |
perror("fseek"); | |
fclose(fp); | |
return 1; | |
} | |
unsigned char *const ciphertext = (unsigned char *)malloc(file_size); | |
if (ciphertext == NULL) { | |
perror("malloc"); | |
fclose(fp); | |
exit(EXIT_FAILURE); | |
} | |
if (fread(ciphertext, 1, file_size, fp) != file_size) { | |
perror("fread"); | |
fclose(fp); | |
free(ciphertext); | |
exit(EXIT_FAILURE); | |
} | |
fclose(fp); | |
printf("Filesize: %zu\n", file_size); | |
unsigned char *const temp = (unsigned char *)malloc(file_size); | |
if (temp == NULL) { | |
perror("malloc"); | |
exit(EXIT_FAILURE); | |
} | |
size_t key_len; | |
for (key_len = 1; key_len <= kMaxKeyLen; key_len++) { | |
printf("Trying key length %zu...\n", key_len); | |
unsigned char *const key = (unsigned char *)calloc(key_len, 1); | |
if (key == NULL) { | |
perror("calloc"); | |
exit(EXIT_FAILURE); | |
} | |
do { | |
memcpy(temp, ciphertext, file_size); | |
exclusive_or(temp, file_size, key, key_len); | |
if (search(known, known_len, temp, file_size)) { | |
printf("Key found: "); | |
print_bytes(key, key_len); | |
} | |
} while (!increment(key, key_len)); | |
free(key); | |
} | |
free(ciphertext); | |
free(temp); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment