diff --git a/meson.build b/meson.build index 4384063..73914ef 100644 --- a/meson.build +++ b/meson.build @@ -9,19 +9,25 @@ cmake = import('cmake') mbedtls_proj = cmake.subproject('mbedtls') mbedtls_dep = mbedtls_proj.dependency('mbedcrypto') -executable('ex01', ['src/ex01/main.c', 'src/utils.c'], dependencies: m_dep, include_directories: incdir) -executable('ex02', ['src/ex02/main.c', 'src/utils.c'], dependencies: m_dep, include_directories: incdir) -executable('ex03', ['src/ex03/main.c', 'src/utils.c'], dependencies: m_dep, include_directories: incdir) -executable('ex04', ['src/ex04/main.c', 'src/utils.c'], dependencies: m_dep, include_directories: incdir) -executable('ex05', ['src/ex05/main.c', 'src/utils.c'], dependencies: m_dep, include_directories: incdir) -executable('ex06', ['src/ex06/main.c', 'src/utils.c'], dependencies: m_dep, include_directories: incdir) -executable('ex07', ['src/ex07/main.c', 'src/utils.c'], +executable('ex01', ['src/ex01/main.c', 'src/io.c'], + dependencies: m_dep, include_directories: incdir) +executable('ex02', ['src/ex02/main.c', 'src/io.c'], + dependencies: m_dep, include_directories: incdir) +executable('ex03', ['src/ex03/main.c', 'src/io.c', 'src/frequency.c'], + dependencies: m_dep, include_directories: incdir) +executable('ex04', ['src/ex04/main.c', 'src/io.c', 'src/frequency.c'], + dependencies: m_dep, include_directories: incdir) +executable('ex05', ['src/ex05/main.c', 'src/io.c'], + dependencies: m_dep, include_directories: incdir) +executable('ex06', ['src/ex06/main.c', 'src/io.c', 'src/distance.c', 'src/frequency.c'], + dependencies: m_dep, include_directories: incdir) +executable('ex07', ['src/ex07/main.c', 'src/io.c'], dependencies: [m_dep, mbedtls_dep], include_directories: incdir) -executable('ex08', ['src/ex08/main.c', 'src/utils.c'], +executable('ex08', ['src/ex08/main.c', 'src/io.c'], dependencies: [m_dep, mbedtls_dep], include_directories: incdir) munit_dep = dependency('munit', fallback: ['munit', 'munit_dep']) -tests = executable('tests', ['tests/main.c', 'src/utils.c'], include_directories: incdir, - dependencies: [m_dep, munit_dep]) +tests = executable('tests', ['tests/main.c', 'src/io.c', 'src/distance.c', 'src/frequency.c'], + include_directories: incdir, dependencies: [m_dep, munit_dep]) test('tests', tests) diff --git a/src/distance.c b/src/distance.c new file mode 100644 index 0000000..fca6cd3 --- /dev/null +++ b/src/distance.c @@ -0,0 +1,14 @@ +#include + +unsigned int hamming(size_t len, const unsigned char s1[static len], + const unsigned char s2[static len]) { + unsigned int res = 0; + for (size_t i = 0; i < len; ++i) { + unsigned int n = s1[i] ^ s2[i]; + while (n) { + res += n & 1; + n >>= 1; + } + } + return res; +} diff --git a/src/distance.h b/src/distance.h new file mode 100644 index 0000000..a2231e1 --- /dev/null +++ b/src/distance.h @@ -0,0 +1,9 @@ +#ifndef DISTANCE_H +#define DISTANCE_H + +#include + +unsigned int hamming(size_t len, const unsigned char s1[static len], + const unsigned char s2[static len]); + +#endif /* DISTANCE_H */ diff --git a/src/ex01/main.c b/src/ex01/main.c index 849bb30..ad02346 100644 --- a/src/ex01/main.c +++ b/src/ex01/main.c @@ -1,4 +1,4 @@ -#include "utils.h" +#include "io.h" #include #include diff --git a/src/ex02/main.c b/src/ex02/main.c index 9bffe7e..1fcd6fc 100644 --- a/src/ex02/main.c +++ b/src/ex02/main.c @@ -1,9 +1,8 @@ -#include "utils.h" +#include "io.h" #include #include -int main(int argc, char *argv[]) -{ +int main(int argc, char *argv[]) { if (argc < 3) { printf("Usage: %s \n", argv[0]); return EXIT_FAILURE; diff --git a/src/ex03/main.c b/src/ex03/main.c index c82d202..14b8580 100644 --- a/src/ex03/main.c +++ b/src/ex03/main.c @@ -1,9 +1,10 @@ -#include "utils.h" +#include "frequency.h" +#include "io.h" #include +#include #include #include #include -#include int main(int argc, char *argv[]) { if (argc < 2) { diff --git a/src/ex04/main.c b/src/ex04/main.c index aea2137..aac1631 100644 --- a/src/ex04/main.c +++ b/src/ex04/main.c @@ -1,4 +1,5 @@ -#include "utils.h" +#include "frequency.h" +#include "io.h" #include #include @@ -37,16 +38,15 @@ int main(int argc, char *argv[]) { } double score = frequency_score(len, cur); if (score < 40.0) { - printf("%4u | %c | %5.1f | ", line_count, c, - score); + printf("%4u | %c | %5.1f | ", line_count, c, score); for (size_t i = 0; i < len; ++i) { - if (isprint(cur[i])) { - putchar(cur[i]); - } else if (cur[i] == '\n') { - printf("\\n"); - } + if (isprint(cur[i])) { + putchar(cur[i]); + } else if (cur[i] == '\n') { + printf("\\n"); + } } - printf("\n"); + printf("\n"); } } } diff --git a/src/ex05/main.c b/src/ex05/main.c index c89215d..b19bab9 100644 --- a/src/ex05/main.c +++ b/src/ex05/main.c @@ -1,4 +1,4 @@ -#include "utils.h" +#include "io.h" #include #include #include diff --git a/src/ex06/main.c b/src/ex06/main.c index 339b883..46c63d3 100644 --- a/src/ex06/main.c +++ b/src/ex06/main.c @@ -1,4 +1,6 @@ -#include "utils.h" +#include "distance.h" +#include "frequency.h" +#include "io.h" #include #include #include diff --git a/src/ex07/main.c b/src/ex07/main.c index ffec533..849ee8b 100644 --- a/src/ex07/main.c +++ b/src/ex07/main.c @@ -1,5 +1,5 @@ +#include "io.h" #include "mbedtls/aes.h" -#include "utils.h" #include #include #include diff --git a/src/ex08/main.c b/src/ex08/main.c index 286b45c..6281a74 100644 --- a/src/ex08/main.c +++ b/src/ex08/main.c @@ -1,4 +1,4 @@ -#include "utils.h" +#include "io.h" #include #define BUF_SIZE 1024 diff --git a/src/frequency.c b/src/frequency.c new file mode 100644 index 0000000..388299c --- /dev/null +++ b/src/frequency.c @@ -0,0 +1,65 @@ +#include "frequency.h" +#include +#include +#include + +double frequency_score(size_t len, const char buf[static len]) { + static const double english_freqs[27] = { + // A-Z + 0.0855, 0.0160, 0.0316, 0.0387, 0.01210, 0.0218, 0.0209, 0.0496, 0.0733, + 0.0022, 0.0081, 0.0421, 0.0253, 0.0717, 0.0747, 0.0207, 0.0010, 0.0633, + 0.0673, 0.0894, 0.0268, 0.0106, 0.0183, 0.0019, 0.0172, 0.0011, + // space + 0.19182}; + + // static const double english_freqs[27] = { + // // A-Z + // 0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015, 0.06094, + // 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749, 0.07507, 0.01929, + // 0.00095, 0.05987, 0.06327, 0.09056, 0.02758, 0.00978, 0.02360, 0.00150, + // 0.01974, 0.00074, + // // space + // 0.19182}; + + unsigned int counts[27] = {0}; + for (size_t i = 0; i < len; ++i) { + if (!isprint(buf[i]) && buf[i] != '\n') { + // If character is not printable, it's definitely not English. + return INFINITY; + } + if (buf[i] == ' ') { + counts[26]++; + continue; + } + unsigned char c = tolower(buf[i]) - 'a'; + if (c < 26) { + counts[c]++; + } + } + + double chi2 = 0; + for (size_t i = 0; i < 27; ++i) { + double expected = len * english_freqs[i]; + chi2 += pow(counts[i] - expected, 2) / expected; + } + return chi2; +} + +char best_single_char_xor_key(size_t len, unsigned char buf[static len]) { + char cur[len]; + double min_score = INFINITY; + char key = 'X'; + + for (char c = 32; c < 127; ++c) { + for (size_t i = 0; i < len; ++i) { + cur[i] = buf[i] ^ c; + } + double score = frequency_score(len, cur); + if (score < min_score) { + min_score = score; + key = c; + } + } + + return key; +} diff --git a/src/frequency.h b/src/frequency.h new file mode 100644 index 0000000..770477d --- /dev/null +++ b/src/frequency.h @@ -0,0 +1,9 @@ +#ifndef FREQUENCY_H +#define FREQUENCY_H + +#include + +double frequency_score(size_t len, const char buf[static len]); +char best_single_char_xor_key(size_t len, unsigned char buf[static len]); + +#endif /* FREQUENCY_H */ diff --git a/src/io.c b/src/io.c new file mode 100644 index 0000000..f970ca9 --- /dev/null +++ b/src/io.c @@ -0,0 +1,73 @@ +#include "io.h" +#include +#include + +unsigned char hex_to_byte(const char c) { + if (isdigit(c)) { + return c - '0'; + } + return 10 + c - 'a'; +} + +size_t hex_to_bytes(unsigned char out[static 1], const char hex[static 1]) { + for (size_t i = 0; i < strlen(hex); ++i) { + char c = tolower(hex[i]); + unsigned char value = hex_to_byte(c); + if (i % 2 == 0) { + value <<= 4; + } + out[i / 2] += value; + } + return strlen(hex) / 2 + strlen(hex) % 2; +} + +static const char base64_table[65] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +char *bytes_to_base64(char out[static 4], const unsigned char in[static 3], + size_t len) { + for (size_t i = 0; i < len - 2; i += 3) { + size_t j = i / 3 * 4; + out[j] = base64_table[in[i] >> 2]; + out[j + 1] = base64_table[((in[i] & 0x03) << 4) | (in[i + 1] >> 4)]; + out[j + 2] = base64_table[((in[i + 1] & 0x0f) << 2) | (in[i + 2] >> 6)]; + out[j + 3] = base64_table[in[i + 2] & 0x3f]; + } + return out; +} + +size_t base64_to_bytes(unsigned char out[static 3], const char in[static 4]) { + char decoding_table[256] = {0}; + for (size_t i = 0; i < 64; ++i) { + decoding_table[(unsigned char)base64_table[i]] = i; + } + + size_t in_length = strlen(in); + if (in_length % 4 != 0) { + return 0; + } + + size_t i = 0; + for (size_t j = 0; j < in_length - 3;) { + unsigned char sextet1 = + in[j] == '=' ? 0 : decoding_table[(unsigned char)in[j]]; + unsigned char sextet2 = + in[j + 1] == '=' ? 0 : decoding_table[(unsigned char)in[j + 1]]; + unsigned char sextet3 = + in[j + 2] == '=' ? 0 : decoding_table[(unsigned char)in[j + 2]]; + unsigned char sextet4 = + in[j + 3] == '=' ? 0 : decoding_table[(unsigned char)in[j + 3]]; + + out[i] = sextet1 << 2; + out[i] += sextet2 >> 4; + out[i + 1] = sextet2 << 4; + out[i + 1] += sextet3 >> 2; + out[i + 2] = sextet3 << 6; + out[i + 2] += sextet4; + + j += 4; + i += 3; + } + + return i; +} diff --git a/src/io.h b/src/io.h new file mode 100644 index 0000000..9414fa9 --- /dev/null +++ b/src/io.h @@ -0,0 +1,12 @@ +#ifndef IO_H +#define IO_H + +#include + +unsigned char hex_to_byte(const char c); +size_t hex_to_bytes(unsigned char out[static 1], const char hex[static 1]); +char *bytes_to_base64(char out[static 4], const unsigned char in[static 3], + size_t len); +size_t base64_to_bytes(unsigned char out[static 3], const char in[static 4]); + +#endif /* IO_H */ diff --git a/src/utils.c b/src/utils.c deleted file mode 100644 index a3f80ff..0000000 --- a/src/utils.c +++ /dev/null @@ -1,148 +0,0 @@ -#include "utils.h" -#include -#include -#include - -unsigned char hex_to_byte(const char c) { - if (isdigit(c)) { - return c - '0'; - } - return 10 + c - 'a'; -} - -size_t hex_to_bytes(unsigned char out[static 1], const char hex[static 1]) { - for (size_t i = 0; i < strlen(hex); ++i) { - char c = tolower(hex[i]); - unsigned char value = hex_to_byte(c); - if (i % 2 == 0) { - value <<= 4; - } - out[i / 2] += value; - } - return strlen(hex) / 2 + strlen(hex) % 2; -} - -static const char base64_table[65] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -char *bytes_to_base64(char out[static 4], const unsigned char in[static 3], - size_t len) { - for (size_t i = 0; i < len - 2; i += 3) { - size_t j = i / 3 * 4; - out[j] = base64_table[in[i] >> 2]; - out[j + 1] = base64_table[((in[i] & 0x03) << 4) | (in[i + 1] >> 4)]; - out[j + 2] = base64_table[((in[i + 1] & 0x0f) << 2) | (in[i + 2] >> 6)]; - out[j + 3] = base64_table[in[i + 2] & 0x3f]; - } - return out; -} - -size_t base64_to_bytes(unsigned char out[static 3], const char in[static 4]) { - char decoding_table[256] = {0}; - for (size_t i = 0; i < 64; ++i) { - decoding_table[(unsigned char)base64_table[i]] = i; - } - - size_t in_length = strlen(in); - if (in_length % 4 != 0) { - return 0; - } - - size_t i = 0; - for (size_t j = 0; j < in_length - 3;) { - unsigned char sextet1 = - in[j] == '=' ? 0 : decoding_table[(unsigned char)in[j]]; - unsigned char sextet2 = - in[j + 1] == '=' ? 0 : decoding_table[(unsigned char)in[j + 1]]; - unsigned char sextet3 = - in[j + 2] == '=' ? 0 : decoding_table[(unsigned char)in[j + 2]]; - unsigned char sextet4 = - in[j + 3] == '=' ? 0 : decoding_table[(unsigned char)in[j + 3]]; - - out[i] = sextet1 << 2; - out[i] += sextet2 >> 4; - out[i + 1] = sextet2 << 4; - out[i + 1] += sextet3 >> 2; - out[i + 2] = sextet3 << 6; - out[i + 2] += sextet4; - - j += 4; - i += 3; - } - - return i; -} - -double frequency_score(size_t len, const char buf[static len]) { - static const double english_freqs[27] = { - // A-Z - 0.0855, 0.0160, 0.0316, 0.0387, 0.01210, 0.0218, 0.0209, 0.0496, 0.0733, - 0.0022, 0.0081, 0.0421, 0.0253, 0.0717, 0.0747, 0.0207, 0.0010, 0.0633, - 0.0673, 0.0894, 0.0268, 0.0106, 0.0183, 0.0019, 0.0172, 0.0011, - // space - 0.19182}; - - // static const double english_freqs[27] = { - // // A-Z - // 0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015, 0.06094, - // 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749, 0.07507, 0.01929, - // 0.00095, 0.05987, 0.06327, 0.09056, 0.02758, 0.00978, 0.02360, 0.00150, - // 0.01974, 0.00074, - // // space - // 0.19182}; - - unsigned int counts[27] = {0}; - for (size_t i = 0; i < len; ++i) { - if (!isprint(buf[i]) && buf[i] != '\n') { - // If character is not printable, it's definitely not English. - return INFINITY; - } - if (buf[i] == ' ') { - counts[26]++; - continue; - } - unsigned char c = tolower(buf[i]) - 'a'; - if (c < 26) { - counts[c]++; - } - } - - double chi2 = 0; - for (size_t i = 0; i < 27; ++i) { - double expected = len * english_freqs[i]; - chi2 += pow(counts[i] - expected, 2) / expected; - } - return chi2; -} - -unsigned int hamming(size_t len, const unsigned char s1[static len], - const unsigned char s2[static len]) { - unsigned int res = 0; - for (size_t i = 0; i < len; ++i) { - unsigned int n = s1[i] ^ s2[i]; - while (n) { - res += n & 1; - n >>= 1; - } - } - return res; -} - -char best_single_char_xor_key(size_t len, unsigned char buf[static len]) { - char cur[len]; - double min_score = INFINITY; - char key = 'X'; - - for (char c = 32; c < 127; ++c) { - for (size_t i = 0; i < len; ++i) { - cur[i] = buf[i] ^ c; - } - double score = frequency_score(len, cur); - if (score < min_score) { - min_score = score; - key = c; - } - } - - return key; -} diff --git a/src/utils.h b/src/utils.h deleted file mode 100644 index 6e900bf..0000000 --- a/src/utils.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef UTILS_H -#define UTILS_H - -#include - -unsigned char hex_to_byte(const char c); -size_t hex_to_bytes(unsigned char out[static 1], const char hex[static 1]); -char *bytes_to_base64(char out[static 4], const unsigned char in[static 3], size_t len); -size_t base64_to_bytes(unsigned char out[static 3], const char in[static 4]); -double frequency_score(size_t len, const char buf[static len]); -unsigned int hamming(size_t len, const unsigned char s1[static len], const unsigned char s2[static len]); -char best_single_char_xor_key(size_t len, unsigned char buf[static len]); - -#endif /* UTILS_H */ diff --git a/tests/main.c b/tests/main.c index 28b170a..84900b0 100644 --- a/tests/main.c +++ b/tests/main.c @@ -1,6 +1,8 @@ #define MUNIT_ENABLE_ASSERT_ALIASES +#include "distance.h" +#include "frequency.h" +#include "io.h" #include "munit.h" -#include "utils.h" #include #include