summary refs log tree commit diff stats
path: root/plugins/fishlim/tests
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/fishlim/tests')
-rw-r--r--plugins/fishlim/tests/fake/keystore.c47
-rw-r--r--plugins/fishlim/tests/meson.build17
-rw-r--r--plugins/fishlim/tests/old_version/fish.c155
-rw-r--r--plugins/fishlim/tests/old_version/fish.h37
-rw-r--r--plugins/fishlim/tests/old_version/meson.build4
-rw-r--r--plugins/fishlim/tests/tests.c297
6 files changed, 557 insertions, 0 deletions
diff --git a/plugins/fishlim/tests/fake/keystore.c b/plugins/fishlim/tests/fake/keystore.c
new file mode 100644
index 00000000..854f38dc
--- /dev/null
+++ b/plugins/fishlim/tests/fake/keystore.c
@@ -0,0 +1,47 @@
+/*
+
+  Copyright (c) 2010 Samuel Lidén Borell <samuel@kodafritt.se>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+*/
+
+#include "../../fish.h"
+
+
+/**
+ * Extracts a key from the key store file.
+ */
+char *keystore_get_key(const char *nick, enum fish_mode *mode) {
+    return NULL;
+}
+
+/**
+ * Sets a key in the key store file.
+ */
+gboolean keystore_store_key(const char *nick, const char *key, enum fish_mode mode) {
+    return TRUE;
+}
+
+/**
+ * Deletes a nick from the key store.
+ */
+gboolean keystore_delete_nick(const char *nick) {
+    return TRUE;
+}
diff --git a/plugins/fishlim/tests/meson.build b/plugins/fishlim/tests/meson.build
new file mode 100644
index 00000000..3b75018e
--- /dev/null
+++ b/plugins/fishlim/tests/meson.build
@@ -0,0 +1,17 @@
+subdir('old_version')
+
+fishlim_test_sources = [
+  'tests.c',
+  'fake/keystore.c',
+  '../fish.c',
+  '../utils.c',
+]
+
+fishlim_tests = executable('fishlim_tests', fishlim_test_sources,
+  dependencies: [libgio_dep, libssl_dep],
+  link_with : fishlim_old_lib
+)
+
+test('Fishlim Tests', fishlim_tests,
+  timeout: 90
+)
diff --git a/plugins/fishlim/tests/old_version/fish.c b/plugins/fishlim/tests/old_version/fish.c
new file mode 100644
index 00000000..99601398
--- /dev/null
+++ b/plugins/fishlim/tests/old_version/fish.c
@@ -0,0 +1,155 @@
+/*
+
+  Copyright (c) 2010 Samuel Lidén Borell <samuel@kodafritt.se>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+*/
+
+#ifdef __APPLE__
+#define __AVAILABILITYMACROS__
+#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/blowfish.h>
+
+#include "fish.h"
+
+#define IB 64
+static const char fish_base64[64] = "./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+static const signed char fish_unbase64[256] = {
+    IB,IB,IB,IB,IB,IB,IB,IB,  IB,IB,IB,IB,IB,IB,IB,IB,
+    IB,IB,IB,IB,IB,IB,IB,IB,  IB,IB,IB,IB,IB,IB,IB,IB,
+/*      !  "  #  $  %  &  '  (    )  *  +  ,  -  .  / */
+    IB,IB,IB,IB,IB,IB,IB,IB,  IB,IB,IB,IB,IB,IB, 0, 1,
+/*   0  1  2  3  4  5  6  7    8  9  :  ;  <  =  >  ? */
+     2, 3, 4, 5, 6, 7, 8, 9,  10,11,IB,IB,IB,IB,IB,IB,
+/*   @  A  B  C  D  E  F  G    H  I  J  K  L  M  N  O */
+    IB,38,39,40,41,42,43,44,  45,46,47,48,49,50,51,52,
+/*   P  Q  R  S  T  U  V  W    X  Y  Z  [  \  ]  ^  _*/
+    53,54,55,56,57,58,59,60,  61,62,63,IB,IB,IB,IB,IB,
+/*   `  a  b  c  d  e  f  g    h  i  j  k  l  m  n  o */
+    IB,12,13,14,15,16,17,18,  19,20,21,22,23,24,25,26,
+/*   p  q  r  s  t  u  v  w    x  y  z  {  |  }  ~  <del> */
+    27,28,29,30,31,32,33,34,  35,36,37,IB,IB,IB,IB,IB,
+};
+
+#define GET_BYTES(dest, source) do { \
+    *((dest)++) = ((source) >> 24) & 0xFF; \
+    *((dest)++) = ((source) >> 16) & 0xFF; \
+    *((dest)++) = ((source) >> 8) & 0xFF; \
+    *((dest)++) = (source) & 0xFF; \
+} while (0);
+
+
+char *__old_fish_encrypt(const char *key, size_t keylen, const char *message) {
+    BF_KEY bfkey;
+    size_t messagelen;
+    size_t i;
+    int j;
+    char *encrypted;
+    char *end;
+    unsigned char bit;
+    unsigned char word;
+    unsigned char d;
+    BF_set_key(&bfkey, keylen, (const unsigned char*)key);
+    
+    messagelen = strlen(message);
+    if (messagelen == 0) return NULL;
+    encrypted = g_malloc(((messagelen - 1) / 8) * 12 + 12 + 1); /* each 8-byte block becomes 12 bytes */
+    end = encrypted;
+     
+    while (*message) {
+        /* Read 8 bytes (a Blowfish block) */
+        BF_LONG binary[2] = { 0, 0 };
+        unsigned char c;
+        for (i = 0; i < 8; i++) {
+            c = message[i];
+            binary[i >> 2] |= c << 8*(3 - (i&3));
+            if (c == '\0') break;
+        }
+        message += 8;
+        
+        /* Encrypt block */
+        BF_encrypt(binary, &bfkey);
+        
+        /* Emit FiSH-BASE64 */
+        bit = 0;
+        word = 1;
+        for (j = 0; j < 12; j++) {
+            d = fish_base64[(binary[word] >> bit) & 63];
+            *(end++) = d;
+            bit += 6;
+            if (j == 5) {
+                bit = 0;
+                word = 0;
+            }
+        }
+        
+        /* Stop if a null terminator was found */
+        if (c == '\0') break;
+    }
+    *end = '\0';
+    return encrypted;
+}
+
+
+char *__old_fish_decrypt(const char *key, size_t keylen, const char *data) {
+    BF_KEY bfkey;
+    size_t i;
+    char *decrypted;
+    char *end;
+    unsigned char bit;
+    unsigned char word;
+    unsigned char d;
+    BF_set_key(&bfkey, keylen, (const unsigned char*)key);
+    
+    decrypted = g_malloc(strlen(data) + 1);
+    end = decrypted;
+    
+    while (*data) {
+        /* Convert from FiSH-BASE64 */
+        BF_LONG binary[2] = { 0, 0 };
+        bit = 0;
+        word = 1;
+        for (i = 0; i < 12; i++) {
+            d = fish_unbase64[(const unsigned char)*(data++)];
+            if (d == IB) goto decrypt_end;
+            binary[word] |= (unsigned long)d << bit;
+            bit += 6;
+            if (i == 5) {
+                bit = 0;
+                word = 0;
+            }
+        }
+        
+        /* Decrypt block */
+        BF_decrypt(binary, &bfkey);
+        
+        /* Copy to buffer */
+        GET_BYTES(end, binary[0]);
+        GET_BYTES(end, binary[1]);
+    }
+    
+  decrypt_end:
+    *end = '\0';
+    return decrypted;
+}
\ No newline at end of file
diff --git a/plugins/fishlim/tests/old_version/fish.h b/plugins/fishlim/tests/old_version/fish.h
new file mode 100644
index 00000000..7037782b
--- /dev/null
+++ b/plugins/fishlim/tests/old_version/fish.h
@@ -0,0 +1,37 @@
+/*
+
+  Copyright (c) 2010 Samuel Lidén Borell <samuel@kodafritt.se>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+*/
+
+#ifndef FISH_OLD_H
+#define FISH_OLD_H
+
+#include <stddef.h>
+
+#include <glib.h>
+
+char *__old_fish_encrypt(const char *key, size_t keylen, const char *message);
+char *__old_fish_decrypt(const char *key, size_t keylen, const char *data);
+
+#endif
+
+
diff --git a/plugins/fishlim/tests/old_version/meson.build b/plugins/fishlim/tests/old_version/meson.build
new file mode 100644
index 00000000..54647d71
--- /dev/null
+++ b/plugins/fishlim/tests/old_version/meson.build
@@ -0,0 +1,4 @@
+fishlim_old_lib = shared_library('fishlim_old_lib',
+  ['fish.c'],
+  dependencies: [libgio_dep, libssl_dep],
+)
diff --git a/plugins/fishlim/tests/tests.c b/plugins/fishlim/tests/tests.c
new file mode 100644
index 00000000..bb841c5e
--- /dev/null
+++ b/plugins/fishlim/tests/tests.c
@@ -0,0 +1,297 @@
+/*
+
+  Copyright (c) 2020 <bakasura@protonmail.ch>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+*/
+
+#ifndef PLUGIN_HEXCHAT_FISHLIM_TEST_H
+#define PLUGIN_HEXCHAT_FISHLIM_TEST_H
+
+// Libs
+#include <glib.h>
+// Project Libs
+#include "../fish.h"
+#include "../utils.h"
+#include "old_version/fish.h"
+
+/**
+ * Auxiliary function: Generate a random string
+ * @param out Preallocated string to fill
+ * @param len Size of bytes to fill
+ */
+void random_string(char *out, size_t len) {
+    GRand *rand = NULL;
+    int i = 0;
+
+    rand = g_rand_new();
+    for (i = 0; i < len; ++i) {
+        out[i] = g_rand_int_range(rand, 1, 256);
+    }
+
+    out[len] = 0;
+
+    g_rand_free(rand);
+}
+
+
+/**
+ * Check encrypt and decrypt in ECB mode and compare with old implementation
+ */
+void __ecb(void) {
+    char *bo64 = NULL, *b64 = NULL;
+    char *deo = NULL, *de = NULL;
+    int key_len, message_len = 0;
+    char key[57];
+    char message[1000];
+
+    /* Generate key 32–448 bits (Yes, I start with 8 bits) */
+    for (key_len = 1; key_len < 57; ++key_len) {
+
+        random_string(key, key_len);
+
+        for (message_len = 1; message_len < 1000; ++message_len) {
+            random_string(message, message_len);
+
+            /* Encrypt */
+            bo64 = __old_fish_encrypt(key, key_len, message);
+            g_assert_nonnull(bo64);
+            b64 = fish_encrypt(key, key_len, message, message_len, FISH_ECB_MODE);
+            g_assert_nonnull(b64);
+            g_assert_cmpuint(g_strcmp0(b64, bo64), == , 0);
+
+            /* Decrypt */
+            /* Linear */
+            deo = __old_fish_decrypt(key, key_len, bo64);
+            de = fish_decrypt_str(key, key_len, b64, FISH_ECB_MODE);
+            g_assert_nonnull(deo);
+            g_assert_nonnull(de);
+            g_assert_cmpuint(g_strcmp0(de, message), == , 0);
+            g_assert_cmpuint(g_strcmp0(deo, message), == , 0);
+            g_assert_cmpuint(g_strcmp0(de, deo), == , 0);
+            g_free(deo);
+            g_free(de);
+            /* Mixed */
+            deo = __old_fish_decrypt(key, key_len, b64);
+            de = fish_decrypt_str(key, key_len, bo64, FISH_ECB_MODE);
+            g_assert_nonnull(deo);
+            g_assert_nonnull(de);
+            g_assert_cmpuint(g_strcmp0(de, message), == , 0);
+            g_assert_cmpuint(g_strcmp0(deo, message), == , 0);
+            g_assert_cmpuint(g_strcmp0(de, deo), == , 0);
+            g_free(deo);
+            g_free(de);
+
+            /* Free */
+            g_free(bo64);
+            g_free(b64);
+        }
+    }
+}
+
+/**
+ * Check encrypt and decrypt in CBC mode
+ */
+void __cbc(void) {
+    char *b64 = NULL;
+    char *de = NULL;
+    int key_len, message_len = 0;
+    char key[57];
+    char message[1000];
+
+    /* Generate key 32–448 bits (Yes, I start with 8 bits) */
+    for (key_len = 1; key_len < 57; ++key_len) {
+
+        random_string(key, key_len);
+
+        for (message_len = 1; message_len < 1000; ++message_len) {
+            random_string(message, message_len);
+
+            /* Encrypt */
+            b64 = fish_encrypt(key, key_len, message, message_len, FISH_CBC_MODE);
+            g_assert_nonnull(b64);
+
+            /* Decrypt */
+            /* Linear */
+            de = fish_decrypt_str(key, key_len, b64, FISH_CBC_MODE);
+            g_assert_nonnull(de);
+            g_assert_cmpuint(g_strcmp0(de, message), == , 0);
+            g_free(de);
+
+            /* Free */
+            g_free(b64);
+        }
+    }
+}
+
+/**
+ * Check the calculation of final length from an encoded string in Base64
+ */
+void __base64_len(void) {
+    char *b64 = NULL;
+    int i, message_len = 0;
+    char message[1000];
+
+    for (i = 0; i < 10; ++i) {
+
+        for (message_len = 1; message_len < 1000; ++message_len) {
+            random_string(message, message_len);
+            b64 = g_base64_encode((const unsigned char *) message, message_len);
+            g_assert_nonnull(b64);
+            g_assert_cmpuint(strlen(b64), == , base64_len(message_len));
+            g_free(b64);
+        }
+    }
+}
+
+/**
+ * Check the calculation of final length from an encoded string in BlowcryptBase64
+ */
+void __base64_fish_len(void) {
+    char *b64 = NULL;
+    int i, message_len = 0;
+    char message[1000];
+
+    for (i = 0; i < 10; ++i) {
+
+        for (message_len = 1; message_len < 1000; ++message_len) {
+            random_string(message, message_len);
+            b64 = fish_base64_encode(message, message_len);
+            g_assert_nonnull(b64);
+            g_assert_cmpuint(strlen(b64), == , base64_fish_len(message_len));
+            g_free(b64);
+        }
+    }
+}
+
+
+/**
+ * Check the calculation of final length from an encrypted string in ECB mode
+ */
+void __base64_ecb_len(void) {
+    char *b64 = NULL;
+    int key_len, message_len = 0;
+    char key[57];
+    char message[1000];
+
+    /* Generate key 32–448 bits (Yes, I start with 8 bits) */
+    for (key_len = 1; key_len < 57; ++key_len) {
+
+        random_string(key, key_len);
+
+        for (message_len = 1; message_len < 1000; ++message_len) {
+            random_string(message, message_len);
+            b64 = fish_encrypt(key, key_len, message, message_len, FISH_ECB_MODE);
+            g_assert_nonnull(b64);
+            g_assert_cmpuint(strlen(b64), == , ecb_len(message_len));
+            g_free(b64);
+        }
+    }
+}
+
+/**
+ * Check the calculation of final length from an encrypted string in CBC mode
+ */
+void __base64_cbc_len(void) {
+    char *b64 = NULL;
+    int key_len, message_len = 0;
+    char key[57];
+    char message[1000];
+
+    /* Generate key 32–448 bits (Yes, I start with 8 bits) */
+    for (key_len = 1; key_len < 57; ++key_len) {
+
+        random_string(key, key_len);
+
+        for (message_len = 1; message_len < 1000; ++message_len) {
+            random_string(message, message_len);
+            b64 = fish_encrypt(key, key_len, message, message_len, FISH_CBC_MODE);
+            g_assert_nonnull(b64);
+            g_assert_cmpuint(strlen(b64), == , cbc_len(message_len));
+            g_free(b64);
+        }
+    }
+}
+
+/**
+ * Check the calculation of length limit for a plaintext in each encryption mode
+ */
+void __max_text_command_len(void) {
+    int max_encoded_len, plaintext_len;
+    enum fish_mode mode;
+
+    for (max_encoded_len = 0; max_encoded_len < 10000; ++max_encoded_len) {
+        for (mode = FISH_ECB_MODE; mode <= FISH_CBC_MODE; ++mode) {
+            plaintext_len = max_text_command_len(max_encoded_len, mode);
+            g_assert_cmpuint(encoded_len(plaintext_len, mode), <= , max_encoded_len);
+        }
+    }
+}
+
+/**
+ * Check the calculation of length limit for a plaintext in each encryption mode
+ */
+void __foreach_utf8_data_chunks(void) {
+    GRand *rand = NULL;
+    GString *chunks = NULL;
+    int tests, max_chunks_len, chunks_len;
+    char ascii_message[1001];
+    char *data_chunk = NULL;
+
+    rand = g_rand_new();
+
+    for (tests = 0; tests < 1000; ++tests) {
+
+        max_chunks_len = g_rand_int_range(rand, 2, 301);
+        random_string(ascii_message, 1000);
+
+        data_chunk = ascii_message;
+
+        chunks = g_string_new(NULL);
+
+        while (foreach_utf8_data_chunks(data_chunk, max_chunks_len, &chunks_len)) {
+            g_string_append(chunks, g_strndup(data_chunk, chunks_len));
+            /* Next chunk */
+            data_chunk += chunks_len;
+        }
+        /* Check data loss */
+        g_assert_cmpstr(chunks->str, == , ascii_message);
+        g_string_free(chunks, TRUE);
+    }
+}
+
+
+int main(int argc, char *argv[]) {
+
+    g_test_init(&argc, &argv, NULL);
+
+    g_test_add_func("/fishlim/__ecb", __ecb);
+    g_test_add_func("/fishlim/__cbc", __ecb);
+    g_test_add_func("/fishlim/__base64_len", __base64_len);
+    g_test_add_func("/fishlim/__base64_fish_len", __base64_fish_len);
+    g_test_add_func("/fishlim/__base64_ecb_len", __base64_ecb_len);
+    g_test_add_func("/fishlim/__base64_cbc_len", __base64_cbc_len);
+    g_test_add_func("/fishlim/__max_text_command_len", __max_text_command_len);
+    g_test_add_func("/fishlim/__foreach_utf8_data_chunks", __foreach_utf8_data_chunks);
+
+    return g_test_run();
+}
+
+#endif //PLUGIN_HEXCHAT_FISHLIM_TEST_H
\ No newline at end of file