int dh_tests (void) { unsigned char buf[3][4096]; unsigned long x, y, z; int stat, stat2; dh_key usera, userb; DO(dh_test()); /* make up two keys */ DO(dh_make_key (&test_yarrow, find_prng ("yarrow"), 96, &usera)); DO(dh_make_key (&test_yarrow, find_prng ("yarrow"), 96, &userb)); /* make the shared secret */ x = 4096; DO(dh_shared_secret (&usera, &userb, buf[0], &x)); y = 4096; DO(dh_shared_secret (&userb, &usera, buf[1], &y)); if (y != x) { printf ("DH Shared keys are not same size.\n"); return 1; } if (memcmp (buf[0], buf[1], x)) { printf ("DH Shared keys not same contents.\n"); return 1; } /* now export userb */ y = 4096; DO(dh_export (buf[1], &y, PK_PUBLIC, &userb)); dh_free (&userb); /* import and make the shared secret again */ DO(dh_import (buf[1], y, &userb)); z = 4096; DO(dh_shared_secret (&usera, &userb, buf[2], &z)); if (z != x) { printf ("failed. Size don't match?\n"); return 1; } if (memcmp (buf[0], buf[2], x)) { printf ("Failed. Content didn't match.\n"); return 1; } dh_free (&usera); dh_free (&userb); /* test encrypt_key */ dh_make_key (&test_yarrow, find_prng ("yarrow"), 128, &usera); for (x = 0; x < 16; x++) { buf[0][x] = x; } y = sizeof (buf[1]); DO(dh_encrypt_key (buf[0], 16, buf[1], &y, &test_yarrow, find_prng ("yarrow"), find_hash ("md5"), &usera)); zeromem (buf[0], sizeof (buf[0])); x = sizeof (buf[0]); DO(dh_decrypt_key (buf[1], y, buf[0], &x, &usera)); if (x != 16) { printf ("Failed (length)\n"); return 1; } for (x = 0; x < 16; x++) if (buf[0][x] != x) { printf ("Failed (contents)\n"); return 1; } /* test sign_hash */ for (x = 0; x < 16; x++) { buf[0][x] = x; } x = sizeof (buf[1]); DO(dh_sign_hash (buf[0], 16, buf[1], &x, &test_yarrow , find_prng ("yarrow"), &usera)); DO(dh_verify_hash (buf[1], x, buf[0], 16, &stat, &usera)); buf[0][0] ^= 1; DO(dh_verify_hash (buf[1], x, buf[0], 16, &stat2, &usera)); if (!(stat == 1 && stat2 == 0)) { printf("dh_sign/verify_hash %d %d", stat, stat2); return 1; } dh_free (&usera); return 0; }
/** Encrypt a short symmetric key with a public DH key @param in The symmetric key to encrypt @param inlen The length of the key (octets) @param out [out] The ciphertext @param outlen [in/out] The max size and resulting size of the ciphertext @param prng An active PRNG state @param wprng The index of the PRNG desired @param hash The index of the hash desired (must produce a digest of size >= the size of the plaintext) @param key The public key you wish to encrypt with. @return CRYPT_OK if successful */ int dh_encrypt_key(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, prng_state *prng, int wprng, int hash, dh_key *key) { unsigned char *pub_expt, *dh_shared, *skey; dh_key pubkey; unsigned long x, y, z, hashsize, pubkeysize; int err; LTC_ARGCHK(in != NULL); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); LTC_ARGCHK(key != NULL); /* check that wprng/hash are not invalid */ if ((err = prng_is_valid(wprng)) != CRYPT_OK) { return err; } if ((err = hash_is_valid(hash)) != CRYPT_OK) { return err; } if (inlen > hash_descriptor[hash].hashsize) { return CRYPT_INVALID_HASH; } /* allocate memory */ pub_expt = XMALLOC(DH_BUF_SIZE); dh_shared = XMALLOC(DH_BUF_SIZE); skey = XMALLOC(MAXBLOCKSIZE); if (pub_expt == NULL || dh_shared == NULL || skey == NULL) { if (pub_expt != NULL) { XFREE(pub_expt); } if (dh_shared != NULL) { XFREE(dh_shared); } if (skey != NULL) { XFREE(skey); } return CRYPT_MEM; } /* make a random key and export the public copy */ if ((err = dh_make_key(prng, wprng, dh_get_size(key), &pubkey)) != CRYPT_OK) { goto LBL_ERR; } pubkeysize = DH_BUF_SIZE; if ((err = dh_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) { dh_free(&pubkey); goto LBL_ERR; } /* now check if the out buffer is big enough */ if (*outlen < (1 + 4 + 4 + PACKET_SIZE + pubkeysize + inlen)) { dh_free(&pubkey); err = CRYPT_BUFFER_OVERFLOW; goto LBL_ERR; } /* make random key */ hashsize = hash_descriptor[hash].hashsize; x = DH_BUF_SIZE; if ((err = dh_shared_secret(&pubkey, key, dh_shared, &x)) != CRYPT_OK) { dh_free(&pubkey); goto LBL_ERR; } dh_free(&pubkey); z = MAXBLOCKSIZE; if ((err = hash_memory(hash, dh_shared, x, skey, &z)) != CRYPT_OK) { goto LBL_ERR; } /* store header */ packet_store_header(out, PACKET_SECT_DH, PACKET_SUB_ENC_KEY); /* output header */ y = PACKET_SIZE; /* size of hash name and the name itself */ out[y++] = hash_descriptor[hash].ID; /* length of DH pubkey and the key itself */ STORE32L(pubkeysize, out+y); y += 4; for (x = 0; x < pubkeysize; x++, y++) { out[y] = pub_expt[x]; } /* Store the encrypted key */ STORE32L(inlen, out+y); y += 4; for (x = 0; x < inlen; x++, y++) { out[y] = skey[x] ^ in[x]; } *outlen = y; err = CRYPT_OK; LBL_ERR: #ifdef LTC_CLEAN_STACK /* clean up */ zeromem(pub_expt, DH_BUF_SIZE); zeromem(dh_shared, DH_BUF_SIZE); zeromem(skey, MAXBLOCKSIZE); #endif XFREE(skey); XFREE(dh_shared); XFREE(pub_expt); return err; }