diff options
author | SoniEx2 <endermoneymod@gmail.com> | 2021-04-09 07:19:03 -0300 |
---|---|---|
committer | SoniEx2 <endermoneymod@gmail.com> | 2021-04-09 07:19:03 -0300 |
commit | 0e752a6e215aee21dc73da097c3225495d54a5b6 (patch) | |
tree | b81be02cbf2f06aebf322ac4a5d014b44176bba5 /libotr/libotr-4.1.1/tests/unit/test_dh.c | |
parent | 7754076c715285173311a1b6811ce377950e18a6 (diff) |
Add libotr/etc sources
Diffstat (limited to 'libotr/libotr-4.1.1/tests/unit/test_dh.c')
-rw-r--r-- | libotr/libotr-4.1.1/tests/unit/test_dh.c | 515 |
1 files changed, 515 insertions, 0 deletions
diff --git a/libotr/libotr-4.1.1/tests/unit/test_dh.c b/libotr/libotr-4.1.1/tests/unit/test_dh.c new file mode 100644 index 0000000..c27c09b --- /dev/null +++ b/libotr/libotr-4.1.1/tests/unit/test_dh.c @@ -0,0 +1,515 @@ +/* + * Copyright (C) 2014 - Julien Voisin <julien.voisin@dustri.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <gcrypt.h> +#include <pthread.h> + +#include <dh.h> +#include <proto.h> + +#include <tap/tap.h> +#include <utils.h> + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +#define NUM_TESTS 38 + +/* + * The re-implementation/inclusion of crypto stuff is necessary because libotr + * doesn't expose them. + */ + +static const char* DH1536_MODULUS_S = "0x" + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"; +static const char *DH1536_GENERATOR_S = "0x02"; +static const int DH1536_MOD_LEN_BITS = 1536; + +static gcry_mpi_t DH1536_MODULUS = NULL; +static gcry_mpi_t DH1536_MODULUS_MINUS_2 = NULL; +static gcry_mpi_t DH1536_GENERATOR = NULL; + +static void test_otrl_dh_keypair_init(void) +{ + DH_keypair kp; + + otrl_dh_keypair_init(&kp); + + ok(kp.groupid == 0 && + kp.priv == NULL && + kp.pub == NULL, + "Keypair initialized"); +} + +static void test_otrl_dh_keypair_copy(void) +{ + DH_keypair k1, k2; + unsigned char *buf; + + k1.groupid = rand(); + + buf = gcry_random_bytes(32, GCRY_WEAK_RANDOM); + gcry_mpi_scan(&(k1.priv), GCRYMPI_FMT_USG, buf, 32, NULL); + gcry_free(buf); + + buf = gcry_random_bytes(32, GCRY_WEAK_RANDOM); + gcry_mpi_scan(&(k1.pub), GCRYMPI_FMT_USG, buf, 32, NULL); + gcry_free(buf); + + otrl_dh_keypair_copy(&k2, &k1); + + ok(k1.groupid == k2.groupid && + gcry_mpi_cmp(k1.priv, k2.priv) == 0 && + gcry_mpi_cmp(k1.pub, k2.pub) == 0, + "Keypair copied"); + + gcry_mpi_release(k1.priv); + gcry_mpi_release(k1.pub); + gcry_mpi_release(k2.priv); + gcry_mpi_release(k2.pub); +} + +static void test_otrl_dh_session_free() +{ + DH_sesskeys sess; + DH_keypair kp1, kp2; + otrl_dh_gen_keypair(DH1536_GROUP_ID, &(kp1)); + otrl_dh_gen_keypair(DH1536_GROUP_ID, &(kp2)); + otrl_dh_session(&sess, &kp1, kp2.pub); + + otrl_dh_session_free(&sess); + + ok(sess.sendenc == NULL && + sess.sendmac == NULL && + sess.rcvenc == NULL && + sess.rcvmac == NULL && + utils_is_zeroed(sess.sendctr, 16) && + utils_is_zeroed(sess.rcvctr, 16) && + utils_is_zeroed(sess.sendmackey, 16) && + utils_is_zeroed(sess.rcvmackey, 16) && + sess.sendmacused == 0 && + sess.rcvmacused == 0 && + utils_is_zeroed(sess.extrakey, OTRL_EXTRAKEY_BYTES), + "Session freed"); +} + + +static void test_otrl_dh_session_blank() +{ + DH_sesskeys sess; + DH_keypair kp1, kp2; + otrl_dh_gen_keypair(DH1536_GROUP_ID, &(kp1)); + otrl_dh_gen_keypair(DH1536_GROUP_ID, &(kp2)); + otrl_dh_session(&sess, &kp1, kp2.pub); + + otrl_dh_session_blank(&sess); + + ok(sess.sendenc == NULL && + sess.sendmac == NULL && + sess.rcvenc == NULL && + sess.rcvmac == NULL && + utils_is_zeroed(sess.sendctr, 16) && + utils_is_zeroed(sess.rcvctr, 16) && + utils_is_zeroed(sess.sendmackey, 16) && + utils_is_zeroed(sess.rcvmackey, 16) && + sess.sendmacused == 0 && + sess.rcvmacused == 0 && + utils_is_zeroed(sess.extrakey, OTRL_EXTRAKEY_BYTES), + "Session blanked"); +} + +static void test_otrl_dh_gen_keypair(void) +{ + DH_keypair kp; + gcry_mpi_t pubkey = NULL; + + otrl_dh_keypair_init(&kp); + + ok(otrl_dh_gen_keypair(DH1536_GROUP_ID+1, &kp) == + gcry_error(GPG_ERR_INV_VALUE), + "Invalid group detected"); + + ok(otrl_dh_gen_keypair(DH1536_GROUP_ID, &kp) == + gcry_error(GPG_ERR_NO_ERROR), + "Valid group set"); + ok(kp.groupid == DH1536_GROUP_ID, "Group set"); + + pubkey = gcry_mpi_new(DH1536_MOD_LEN_BITS); + gcry_mpi_powm(pubkey, DH1536_GENERATOR, kp.priv, DH1536_MODULUS); + ok(gcry_mpi_cmp(pubkey, kp.pub) == 0, "Matching pubkey"); + otrl_dh_keypair_free(&kp); +} + +static void test_otrl_dh_keypair_free(void) +{ + DH_keypair kp; + otrl_dh_gen_keypair(DH1536_GROUP_ID, &kp); + otrl_dh_keypair_free(&kp); + ok(kp.pub == NULL && kp.priv == NULL && kp.groupid == DH1536_GROUP_ID, + "DH_keypair free'd with success"); + +} + +static void invert_DH_keypair(DH_keypair* kp1, DH_keypair* kp2) +{ + DH_keypair tmp; + otrl_dh_keypair_copy(&tmp, kp1); + otrl_dh_keypair_copy(kp1, kp2); + otrl_dh_keypair_copy(kp2, &tmp); + otrl_dh_keypair_free(&tmp); +} + +/* + * This is an helper function. See the next one. + */ +static void _test_ortl_dh_session(const DH_keypair *kp, gcry_mpi_t y) +{ + unsigned char *gabdata; + unsigned char *hashdata; + unsigned char encrypt[32] = {0}; + unsigned char expected_encrypt[32] = {0}; + unsigned char sendbyte, rcvbyte; + const char test_vector[] = "This is a test vector"; + DH_sesskeys sess; + DH_sesskeys sess_expected; + gcry_mpi_t gab; + size_t gablen; + otrl_dh_session_blank(&sess); + otrl_dh_session(&sess, kp, y); + + gab = gcry_mpi_snew(DH1536_MOD_LEN_BITS); + gcry_mpi_powm(gab, y, kp->priv, DH1536_MODULUS); + + gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &gablen, gab); + gabdata = gcry_malloc_secure(gablen + 5); + gabdata[1] = (gablen >> 24) & 0xff; + gabdata[2] = (gablen >> 16) & 0xff; + gabdata[3] = (gablen >> 8) & 0xff; + gabdata[4] = gablen & 0xff; + gcry_mpi_print(GCRYMPI_FMT_USG, gabdata + 5, gablen, NULL, gab); + gcry_mpi_release(gab); + + hashdata = gcry_malloc_secure(20); + + if (gcry_mpi_cmp(kp->pub, y) > 0 ) { + sendbyte = 0x01; + rcvbyte = 0x02; + } else { + sendbyte = 0x02; + rcvbyte = 0x01; + } + + gabdata[0] = sendbyte; + gcry_md_hash_buffer(GCRY_MD_SHA1, hashdata, gabdata, gablen + 5); + + gcry_cipher_open(&(sess_expected.sendenc), GCRY_CIPHER_AES, + GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE); + gcry_cipher_setkey(sess_expected.sendenc, hashdata, 16); + gcry_cipher_encrypt(sess_expected.sendenc, expected_encrypt, + sizeof(expected_encrypt), test_vector, strlen(test_vector)); + gcry_cipher_encrypt(sess.sendenc, encrypt, sizeof(encrypt), test_vector, + strlen(test_vector)); + ok(memcmp(encrypt, expected_encrypt, sizeof(encrypt)) == 0, "sendenc ok"); + + gcry_md_hash_buffer(GCRY_MD_SHA1, sess_expected.sendmackey, hashdata, 16); + gcry_md_open(&(sess_expected.sendmac), GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC); + gcry_md_setkey(sess_expected.sendmac, sess_expected.sendmackey, 20); + gcry_md_write(sess_expected.sendmac, test_vector, sizeof(test_vector)); + gcry_md_write(sess.sendmac, test_vector, sizeof(test_vector)); + + ok(memcmp(gcry_md_read(sess_expected.sendmac, 0), + gcry_md_read(sess.sendmac, 0), 32) == 0, + "Sendmac ok"); + + gabdata[0] = rcvbyte; + gcry_md_hash_buffer(GCRY_MD_SHA1, hashdata, gabdata, gablen + 5); + gcry_cipher_open(&(sess_expected.rcvenc), GCRY_CIPHER_AES, + GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE); + gcry_cipher_setkey(sess_expected.rcvenc, hashdata, 16); + gcry_cipher_encrypt(sess_expected.rcvenc, expected_encrypt, + sizeof(expected_encrypt), test_vector, strlen(test_vector)); + gcry_cipher_encrypt(sess.rcvenc, encrypt, sizeof(encrypt), test_vector, + strlen(test_vector)); + ok(memcmp(encrypt, expected_encrypt, sizeof(encrypt)) == 0, "Sendenc ok"); + + gcry_md_hash_buffer(GCRY_MD_SHA1, sess_expected.rcvmackey, hashdata, 16); + gcry_md_open(&(sess_expected.rcvmac), GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC); + gcry_md_setkey(sess_expected.rcvmac, sess_expected.rcvmackey, 20); + gcry_md_write(sess_expected.rcvmac, test_vector, sizeof(test_vector)); + gcry_md_write(sess.rcvmac, test_vector, sizeof(test_vector)); + ok(memcmp(gcry_md_read(sess_expected.sendmac, 0), + gcry_md_read(sess.sendmac, 0), 32) == 0, + "rcvmac ok"); + + gabdata[0] = 0xff; + + gcry_md_hash_buffer(GCRY_MD_SHA256, sess_expected.extrakey, gabdata, + gablen + 5); + ok(memcmp(sess_expected.extrakey, sess.extrakey, 32) == 0, "extrakey set"); + + gcry_free(gabdata); + gcry_free(hashdata); +} + +/* + * This function is a little bit tricky, since it uses an array of 3 + * DH_keypair. The first one has a smaller pubkey than the second, which has a + * smaller pubkey than the third one. + * + * The second key is used as "main" key. The two other ones are used to test + * the otrl_dh_session, with a biggest and a smallest key than the "main" one. + */ +static void test_otrl_dh_session(void) +{ + int i; + DH_keypair kp[3]; /* kp[0] < kp[1] < kp[2] */ + DH_sesskeys sess; + + for (i = 0; i < 3; i++) { + otrl_dh_gen_keypair(DH1536_GROUP_ID, &(kp[i])); + } + + /* Sort the array. */ + for (i = 0; i < 2; i++) { + if (gcry_mpi_cmp(kp[i].pub, kp[i + 1].pub) > 0) { + invert_DH_keypair(kp + i, kp + i + 1); + } + } + + if (gcry_mpi_cmp(kp[0].pub, kp[1].pub) > 0) { + invert_DH_keypair(kp, kp + 1); + } + + kp[1].groupid++; + + ok(otrl_dh_session(&sess, &(kp[1]), kp[0].pub) == + gcry_error(GPG_ERR_INV_VALUE), + "Invalid group detected"); + kp[1].groupid--; + + _test_ortl_dh_session(&(kp[1]), kp[0].pub); + _test_ortl_dh_session(&(kp[1]), kp[2].pub); +} + +static void test_otrl_dh_compute_v2_auth_keys(void) +{ + const char test_vector[] = "This is a test vector"; + size_t slen = 0; + size_t sessionidlenp = 0; + unsigned char *sdata = NULL; + unsigned char *hashdata = NULL; + gcry_mpi_t s = NULL; + unsigned char ctr[16] = {0}; + + DH_keypair our_dh, their_dh; + gcry_mpi_t public_key = NULL; + + unsigned char sessionid[8]; + gcry_md_hd_t mac_m1 = NULL, mac_m1p = NULL, mac_m2 = NULL, mac_m2p = NULL; + gcry_cipher_hd_t enc_c = NULL, enc_cp = NULL; + unsigned char encrypt[32] = {0}; + + unsigned char sessionid_expected[8]; + + gcry_md_hd_t mac_m1_expected = NULL, mac_m1p_expected = NULL; + gcry_md_hd_t mac_m2_expected = NULL, mac_m2p_expected = NULL; + gcry_cipher_hd_t enc_c_expected = NULL, enc_cp_expected = NULL; + unsigned char expected_encrypt[32] = {0}; + + otrl_dh_gen_keypair(DH1536_GROUP_ID, &our_dh); + otrl_dh_gen_keypair(DH1536_GROUP_ID, &their_dh); + + our_dh.groupid++; + ok(otrl_dh_compute_v2_auth_keys(&our_dh, their_dh.pub, + sessionid, &sessionidlenp, &enc_c, &enc_cp, + &mac_m1, &mac_m1p, &mac_m2, &mac_m2p) + == gcry_error(GPG_ERR_INV_VALUE), + "Invalid group detected"); + our_dh.groupid--; + + gcry_mpi_scan(&public_key, GCRYMPI_FMT_USG, "1", 0, NULL); + + ok(otrl_dh_compute_v2_auth_keys(&our_dh, public_key, + sessionid, &sessionidlenp, &enc_c, &enc_cp, + &mac_m1, &mac_m1p, &mac_m2, &mac_m2p) + == gcry_error(GPG_ERR_INV_VALUE), + "Public key too small"); + + gcry_mpi_scan(&public_key, GCRYMPI_FMT_HEX, + (const unsigned char *) DH1536_MODULUS_S, 0, NULL); + gcry_mpi_add_ui(public_key, DH1536_MODULUS, 1); + + ok(otrl_dh_compute_v2_auth_keys(&our_dh, DH1536_MODULUS, + sessionid, &sessionidlenp, &enc_c, &enc_cp, + &mac_m1, &mac_m1p, &mac_m2, &mac_m2p) + == gcry_error(GPG_ERR_INV_VALUE), + "Public key too big"); + + ok(otrl_dh_compute_v2_auth_keys(&our_dh, their_dh.pub, sessionid, + &sessionidlenp, &enc_c, &enc_cp, &mac_m1, &mac_m1p, &mac_m2, + &mac_m2p) == gcry_error(GPG_ERR_NO_ERROR), + "Auth keys generated"); + + ok(sessionidlenp == 8, "Session id len p set to correct value"); + + s = gcry_mpi_snew(DH1536_MOD_LEN_BITS); + gcry_mpi_powm(s, their_dh.pub, our_dh.priv, DH1536_MODULUS); + + gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &slen, s); + sdata = gcry_malloc_secure(slen + 5); + sdata[1] = (slen >> 24) & 0xff; + sdata[2] = (slen >> 16) & 0xff; + sdata[3] = (slen >> 8) & 0xff; + sdata[4] = slen & 0xff; + gcry_mpi_print(GCRYMPI_FMT_USG, sdata+5, slen, NULL, s); + gcry_mpi_release(s); + + hashdata = gcry_malloc_secure(32); + sdata[0] = 0x00; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + memmove(sessionid_expected, hashdata, 8); + ok(memcmp(sessionid_expected, sessionid, 8) == 0, "Session id is correct"); + + sdata[0] = 0x01; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + + gcry_cipher_open(&enc_c_expected, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR, + GCRY_CIPHER_SECURE); + gcry_cipher_setkey(enc_c_expected, hashdata, 16); + gcry_cipher_setctr(enc_c_expected, ctr, 16); + + gcry_cipher_encrypt(enc_c_expected, expected_encrypt, + sizeof(expected_encrypt), test_vector, strlen(test_vector)); + gcry_cipher_encrypt(enc_c, encrypt, sizeof(encrypt), test_vector, + strlen(test_vector)); + ok(memcmp(encrypt, expected_encrypt, sizeof(encrypt)) == 0, "Enc ok"); + + gcry_cipher_open(&(enc_cp_expected), GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR, + GCRY_CIPHER_SECURE); + gcry_cipher_setkey(enc_cp_expected, hashdata+16, 16); + gcry_cipher_setctr(enc_cp_expected, ctr, 16); + gcry_cipher_encrypt(enc_cp_expected, expected_encrypt, + sizeof(expected_encrypt), test_vector, strlen(test_vector)); + gcry_cipher_encrypt(enc_cp, encrypt, sizeof(encrypt), test_vector, + strlen(test_vector)); + ok(memcmp(encrypt, expected_encrypt, sizeof(encrypt)) == 0, "Encp ok"); + + sdata[0] = 0x02; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + gcry_md_open(&mac_m1_expected, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); + gcry_md_setkey(mac_m1_expected, hashdata, 32); + gcry_md_write(mac_m1_expected, test_vector, sizeof(test_vector)); + gcry_md_write(mac_m1, test_vector, sizeof(test_vector)); + ok(memcmp(gcry_md_read(mac_m1_expected, 0), + gcry_md_read(mac_m1, 0), 32) == 0, + "mac_m1 set"); + + sdata[0] = 0x03; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + gcry_md_open(&mac_m2_expected, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); + gcry_md_setkey(mac_m2_expected, hashdata, 32); + gcry_md_write(mac_m2_expected, test_vector, sizeof(test_vector)); + gcry_md_write(mac_m2, test_vector, sizeof(test_vector)); + ok(memcmp(gcry_md_read(mac_m2_expected, 0), + gcry_md_read(mac_m2, 0), 32) == 0, + "mac_m2 set"); + + sdata[0] = 0x04; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + gcry_md_open(&mac_m1p_expected, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); + gcry_md_setkey(mac_m1p_expected, hashdata, 32); + gcry_md_write(mac_m1p_expected, test_vector, sizeof(test_vector)); + gcry_md_write(mac_m1p, test_vector, sizeof(test_vector)); + + ok(memcmp(gcry_md_read(mac_m1p_expected, 0), + gcry_md_read(mac_m1p, 0), 32) == 0, + "mac_m1p set"); + + sdata[0] = 0x05; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + gcry_md_open(&mac_m2p_expected, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); + gcry_md_setkey(mac_m2p_expected, hashdata, 32); + gcry_md_write(mac_m2p_expected, test_vector, sizeof(test_vector)); + gcry_md_write(mac_m2p, test_vector, sizeof(test_vector)); + + ok(memcmp(gcry_md_read(mac_m2p_expected, 0), + gcry_md_read(mac_m2p, 0), 32) == 0, + "mac_m2p set"); + + gcry_free(sdata); + gcry_free(hashdata); +} + +static void test_otrl_dh_incctr() +{ + unsigned char ctr[8] = {0}; + otrl_dh_incctr(ctr); + ok(ctr[7] == 1 && utils_is_zeroed(ctr, 7), "Counter set"); + ctr[7] = 255; + otrl_dh_incctr(ctr); + ok(ctr[7] == 0 && ctr[6] == 1 && utils_is_zeroed(ctr, 5), + "Counter set"); + memset(ctr, 255, sizeof(ctr)); + otrl_dh_incctr(ctr); + ok(utils_is_zeroed(ctr, sizeof(ctr)), "Counter set"); +} + +static void test_otrl_dh_cmpctr() +{ + unsigned char ctr1[8] = {0}, ctr2[8] = {0}; + ok(otrl_dh_cmpctr(ctr1, ctr2) == 0, "Null counters are equals"); + ctr1[1]++; + ok(otrl_dh_cmpctr(ctr1, ctr2) > 0, "Ctr1 is bigger than ctr2"); + ctr2[0]++; + ok(otrl_dh_cmpctr(ctr1, ctr2) < 0, "Ctr2 is bigger than ctr1"); +} + +int main(int argc, char **argv) +{ + plan_tests(NUM_TESTS); + + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + OTRL_INIT; + + otrl_dh_init(); + + gcry_mpi_scan(&DH1536_MODULUS, GCRYMPI_FMT_HEX, + (const unsigned char *)DH1536_MODULUS_S, 0, NULL); + gcry_mpi_scan(&DH1536_GENERATOR, GCRYMPI_FMT_HEX, + (const unsigned char *)DH1536_GENERATOR_S, 0, NULL); + DH1536_MODULUS_MINUS_2 = gcry_mpi_new(DH1536_MOD_LEN_BITS); + gcry_mpi_sub_ui(DH1536_MODULUS_MINUS_2, DH1536_MODULUS, 2); + + test_otrl_dh_gen_keypair(); + test_otrl_dh_keypair_free(); + test_otrl_dh_keypair_init(); + test_otrl_dh_compute_v2_auth_keys(); + test_otrl_dh_session(); + test_otrl_dh_keypair_copy(); + test_otrl_dh_session_blank(); + test_otrl_dh_session_free(); + test_otrl_dh_incctr(); + test_otrl_dh_cmpctr(); + + return 0; +} |