/** Verify the signature given @param sig The signature @param siglen The length of the signature (octets) @param hash The hash that was signed @param hashlen The length of the hash (octets) @param stat [out] Result of signature comparison, 1==valid, 0==invalid @param key The public DH key that signed the hash @return CRYPT_OK if succsessful (even if signature is invalid) */ int dh_verify_hash(const unsigned char *sig, unsigned long siglen, const unsigned char *hash, unsigned long hashlen, int *stat, dh_key *key) { mp_int a, b, p, g, m, tmp; unsigned long x, y; int err; LTC_ARGCHK(sig != NULL); LTC_ARGCHK(hash != NULL); LTC_ARGCHK(stat != NULL); LTC_ARGCHK(key != NULL); /* default to invalid */ *stat = 0; /* check initial input length */ if (siglen < PACKET_SIZE+4+4) { return CRYPT_INVALID_PACKET; } /* header ok? */ if ((err = packet_valid_header((unsigned char *)sig, PACKET_SECT_DH, PACKET_SUB_SIGNED)) != CRYPT_OK) { return err; } /* get hash out of packet */ y = PACKET_SIZE; /* init all bignums */ if ((err = mp_init_multi(&a, &p, &b, &g, &m, &tmp, NULL)) != MP_OKAY) { return mpi_to_ltc_error(err); } /* load a and b */ INPUT_BIGNUM(&a, sig, x, y, siglen); INPUT_BIGNUM(&b, sig, x, y, siglen); /* load p and g */ if ((err = mp_read_radix(&p, sets[key->idx].prime, 64)) != MP_OKAY) { goto error1; } if ((err = mp_read_radix(&g, sets[key->idx].base, 64)) != MP_OKAY) { goto error1; } /* load m */ if ((err = mp_read_unsigned_bin(&m, (unsigned char *)hash, hashlen)) != MP_OKAY) { goto error1; } /* find g^m mod p */ if ((err = mp_exptmod(&g, &m, &p, &m)) != MP_OKAY) { goto error1; } /* m = g^m mod p */ /* find y^a * a^b */ if ((err = mp_exptmod(&key->y, &a, &p, &tmp)) != MP_OKAY) { goto error1; } /* tmp = y^a mod p */ if ((err = mp_exptmod(&a, &b, &p, &a)) != MP_OKAY) { goto error1; } /* a = a^b mod p */ if ((err = mp_mulmod(&a, &tmp, &p, &a)) != MP_OKAY) { goto error1; } /* a = y^a * a^b mod p */ /* y^a * a^b == g^m ??? */ if (mp_cmp(&a, &m) == 0) { *stat = 1; } /* clean up */ err = CRYPT_OK; goto done; error1: err = mpi_to_ltc_error(err); error: done: mp_clear_multi(&tmp, &m, &g, &p, &b, &a, NULL); return err; }
int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) { unsigned long x, y; int err; _ARGCHK(in != NULL); _ARGCHK(key != NULL); /* check length */ if (inlen < 1+PACKET_SIZE) { return CRYPT_INVALID_PACKET; } /* test packet header */ if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_RSA, PACKET_SUB_KEY)) != CRYPT_OK) { return err; } /* init key */ if (mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->pQ, &key->p, &key->q, NULL) != MP_OKAY) { return CRYPT_MEM; } /* get key type */ y = PACKET_SIZE; key->type = (int)in[y++]; /* load the modulus */ INPUT_BIGNUM(&key->N, in, x, y); /* load public exponent */ INPUT_BIGNUM(&key->e, in, x, y); /* get private exponent */ if (key->type == PK_PRIVATE || key->type == PK_PRIVATE_OPTIMIZED) { INPUT_BIGNUM(&key->d, in, x, y); } /* get CRT private data if required */ if (key->type == PK_PRIVATE_OPTIMIZED) { INPUT_BIGNUM(&key->dQ, in, x, y); INPUT_BIGNUM(&key->dP, in, x, y); INPUT_BIGNUM(&key->pQ, in, x, y); INPUT_BIGNUM(&key->qP, in, x, y); INPUT_BIGNUM(&key->p, in, x, y); INPUT_BIGNUM(&key->q, in, x, y); } /* free up ram not required */ if (key->type != PK_PRIVATE_OPTIMIZED) { mp_clear_multi(&key->dQ, &key->dP, &key->pQ, &key->qP, &key->p, &key->q, NULL); } if (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED) { mp_clear(&key->d); } return CRYPT_OK; error2: mp_clear_multi(&key->d, &key->e, &key->N, &key->dQ, &key->dP, &key->pQ, &key->qP, &key->p, &key->q, NULL); return err; }
/** Decrypt a DH encrypted symmetric key @param in The DH encrypted packet @param inlen The length of the DH encrypted packet @param out The plaintext @param outlen [in/out] The max size and resulting size of the plaintext @param key The private DH key corresponding to the public key that encrypted the plaintext @return CRYPT_OK if successful */ int dh_decrypt_key(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, dh_key *key) { unsigned char *shared_secret, *skey; unsigned long x, y, z, hashsize, keysize; int hash, err; dh_key pubkey; LTC_ARGCHK(in != NULL); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); LTC_ARGCHK(key != NULL); /* right key type? */ if (key->type != PK_PRIVATE) { return CRYPT_PK_NOT_PRIVATE; } /* allocate ram */ shared_secret = XMALLOC(DH_BUF_SIZE); skey = XMALLOC(MAXBLOCKSIZE); if (shared_secret == NULL || skey == NULL) { if (shared_secret != NULL) { XFREE(shared_secret); } if (skey != NULL) { XFREE(skey); } return CRYPT_MEM; } /* check if initial header should fit */ if (inlen < PACKET_SIZE+1+4+4) { err = CRYPT_INVALID_PACKET; goto LBL_ERR; } else { inlen -= PACKET_SIZE+1+4+4; } /* is header correct? */ if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_DH, PACKET_SUB_ENC_KEY)) != CRYPT_OK) { goto LBL_ERR; } /* now lets get the hash name */ y = PACKET_SIZE; hash = find_hash_id(in[y++]); if (hash == -1) { err = CRYPT_INVALID_HASH; goto LBL_ERR; } /* common values */ hashsize = hash_descriptor[hash].hashsize; /* get public key */ LOAD32L(x, in+y); /* now check if the imported key will fit */ if (inlen < x) { err = CRYPT_INVALID_PACKET; goto LBL_ERR; } else { inlen -= x; } y += 4; if ((err = dh_import(in+y, x, &pubkey)) != CRYPT_OK) { goto LBL_ERR; } y += x; /* make shared key */ x = DH_BUF_SIZE; if ((err = dh_shared_secret(key, &pubkey, shared_secret, &x)) != CRYPT_OK) { dh_free(&pubkey); goto LBL_ERR; } dh_free(&pubkey); z = MAXBLOCKSIZE; if ((err = hash_memory(hash, shared_secret, x, skey, &z)) != CRYPT_OK) { goto LBL_ERR; } /* load in the encrypted key */ LOAD32L(keysize, in+y); /* will the out fit as part of the input */ if (inlen < keysize) { err = CRYPT_INVALID_PACKET; goto LBL_ERR; } else { inlen -= keysize; } if (keysize > *outlen) { err = CRYPT_BUFFER_OVERFLOW; goto LBL_ERR; } y += 4; *outlen = keysize; for (x = 0; x < keysize; x++, y++) { out[x] = skey[x] ^ in[y]; } err = CRYPT_OK; LBL_ERR: #ifdef LTC_CLEAN_STACK zeromem(shared_secret, DH_BUF_SIZE); zeromem(skey, MAXBLOCKSIZE); #endif XFREE(skey); XFREE(shared_secret); return err; }