Replaced system SQLite with SQLCipher to support encrypted database

This commit is contained in:
Oleksii Zghurskyi
2025-06-07 18:11:17 +03:00
parent f4198d62a7
commit 177d74700f
534 changed files with 362771 additions and 21 deletions

View File

@@ -0,0 +1,129 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file dsa_decrypt_key.c
DSA Crypto, Tom St Denis
*/
#ifdef LTC_MDSA
/**
Decrypt an DSA encrypted key
@param in The ciphertext
@param inlen The length of the ciphertext (octets)
@param out [out] The plaintext
@param outlen [in/out] The max size and resulting size of the plaintext
@param key The corresponding private DSA key
@return CRYPT_OK if successful
*/
int dsa_decrypt_key(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
const dsa_key *key)
{
unsigned char *skey, *expt;
void *g_pub;
unsigned long x, y;
unsigned long hashOID[32] = { 0 };
int hash, err;
ltc_asn1_list decode[3];
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;
}
/* decode to find out hash */
LTC_SET_ASN1(decode, 0, LTC_ASN1_OBJECT_IDENTIFIER, hashOID, sizeof(hashOID)/sizeof(hashOID[0]));
err = der_decode_sequence(in, inlen, decode, 1);
if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) {
return err;
}
hash = find_hash_oid(hashOID, decode[0].size);
if (hash_is_valid(hash) != CRYPT_OK) {
return CRYPT_INVALID_PACKET;
}
/* we now have the hash! */
if ((err = ltc_mp_init(&g_pub)) != CRYPT_OK) {
return err;
}
/* allocate memory */
expt = XMALLOC(ltc_mp_unsigned_bin_size(key->p) + 1);
skey = XMALLOC(MAXBLOCKSIZE);
if (expt == NULL || skey == NULL) {
if (expt != NULL) {
XFREE(expt);
}
if (skey != NULL) {
XFREE(skey);
}
ltc_mp_clear(g_pub);
return CRYPT_MEM;
}
LTC_SET_ASN1(decode, 1, LTC_ASN1_INTEGER, g_pub, 1UL);
LTC_SET_ASN1(decode, 2, LTC_ASN1_OCTET_STRING, skey, MAXBLOCKSIZE);
/* read the structure in now */
if ((err = der_decode_sequence(in, inlen, decode, 3)) != CRYPT_OK) {
goto LBL_ERR;
}
/* make shared key */
x = ltc_mp_unsigned_bin_size(key->p) + 1;
if ((err = dsa_shared_secret(key->x, g_pub, key, expt, &x)) != CRYPT_OK) {
goto LBL_ERR;
}
y = ltc_mp_unsigned_bin_size(key->p) + 1;
y = MIN(y, MAXBLOCKSIZE);
if ((err = hash_memory(hash, expt, x, expt, &y)) != CRYPT_OK) {
goto LBL_ERR;
}
/* ensure the hash of the shared secret is at least as big as the encrypt itself */
if (decode[2].size > y) {
err = CRYPT_INVALID_PACKET;
goto LBL_ERR;
}
/* avoid buffer overflow */
if (*outlen < decode[2].size) {
*outlen = decode[2].size;
err = CRYPT_BUFFER_OVERFLOW;
goto LBL_ERR;
}
/* Decrypt the key */
for (x = 0; x < decode[2].size; x++) {
out[x] = expt[x] ^ skey[x];
}
*outlen = x;
err = CRYPT_OK;
LBL_ERR:
#ifdef LTC_CLEAN_STACK
zeromem(expt, ltc_mp_unsigned_bin_size(key->p) + 1);
zeromem(skey, MAXBLOCKSIZE);
#endif
XFREE(expt);
XFREE(skey);
ltc_mp_clear(g_pub);
return err;
}
#endif

View File

@@ -0,0 +1,118 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file dsa_encrypt_key.c
DSA Crypto, Tom St Denis
*/
#ifdef LTC_MDSA
/**
Encrypt a symmetric key with DSA
@param in The symmetric key you want to encrypt
@param inlen The length of the key to encrypt (octets)
@param out [out] The destination for 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 you wish to use
@param hash The index of the hash you want to use
@param key The DSA key you want to encrypt to
@return CRYPT_OK if successful
*/
int dsa_encrypt_key(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, int hash,
const dsa_key *key)
{
unsigned char *expt, *skey;
void *g_pub, *g_priv;
unsigned long x, y;
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(key != NULL);
/* check that wprng/cipher/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;
}
/* make a random key and export the public copy */
if ((err = ltc_mp_init_multi(&g_pub, &g_priv, LTC_NULL)) != CRYPT_OK) {
return err;
}
expt = XMALLOC(ltc_mp_unsigned_bin_size(key->p) + 1);
skey = XMALLOC(MAXBLOCKSIZE);
if (expt == NULL || skey == NULL) {
if (expt != NULL) {
XFREE(expt);
}
if (skey != NULL) {
XFREE(skey);
}
ltc_mp_deinit_multi(g_pub, g_priv, LTC_NULL);
return CRYPT_MEM;
}
/* make a random g_priv, g_pub = g^x pair
private key x should be in range: 1 <= x <= q-1 (see FIPS 186-4 B.1.2)
*/
if ((err = rand_bn_upto(g_priv, key->q, prng, wprng)) != CRYPT_OK) {
goto LBL_ERR;
}
/* compute y */
if ((err = ltc_mp_exptmod(key->g, g_priv, key->p, g_pub)) != CRYPT_OK) {
goto LBL_ERR;
}
/* make random key */
x = ltc_mp_unsigned_bin_size(key->p) + 1;
if ((err = dsa_shared_secret(g_priv, key->y, key, expt, &x)) != CRYPT_OK) {
goto LBL_ERR;
}
y = MAXBLOCKSIZE;
if ((err = hash_memory(hash, expt, x, skey, &y)) != CRYPT_OK) {
goto LBL_ERR;
}
/* Encrypt key */
for (x = 0; x < inlen; x++) {
skey[x] ^= in[x];
}
err = der_encode_sequence_multi(out, outlen,
LTC_ASN1_OBJECT_IDENTIFIER, hash_descriptor[hash].OIDlen, hash_descriptor[hash].OID,
LTC_ASN1_INTEGER, 1UL, g_pub,
LTC_ASN1_OCTET_STRING, inlen, skey,
LTC_ASN1_EOL, 0UL, NULL);
LBL_ERR:
#ifdef LTC_CLEAN_STACK
/* clean up */
zeromem(expt, ltc_mp_unsigned_bin_size(key->p) + 1);
zeromem(skey, MAXBLOCKSIZE);
#endif
XFREE(skey);
XFREE(expt);
ltc_mp_deinit_multi(g_pub, g_priv, LTC_NULL);
return err;
}
#endif

View File

@@ -0,0 +1,100 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file dsa_export.c
DSA implementation, export key, Tom St Denis
*/
#ifdef LTC_MDSA
/**
Export a DSA key to a binary packet
@param out [out] Where to store the packet
@param outlen [in/out] The max size and resulting size of the packet
@param type The type of key to export (PK_PRIVATE or PK_PUBLIC)
@param key The key to export
@return CRYPT_OK if successful
*/
int dsa_export(unsigned char *out, unsigned long *outlen, int type, const dsa_key *key)
{
unsigned long zero=0;
unsigned char flags[1];
int err, std;
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(key != NULL);
std = type & PK_STD;
type &= ~PK_STD;
if (type == PK_PRIVATE && key->type != PK_PRIVATE) {
return CRYPT_PK_TYPE_MISMATCH;
}
if (type == PK_PRIVATE) {
if (std) {
return der_encode_sequence_multi(out, outlen,
LTC_ASN1_SHORT_INTEGER, 1UL, &zero,
LTC_ASN1_INTEGER, 1UL, key->p,
LTC_ASN1_INTEGER, 1UL, key->q,
LTC_ASN1_INTEGER, 1UL, key->g,
LTC_ASN1_INTEGER, 1UL, key->y,
LTC_ASN1_INTEGER, 1UL, key->x,
LTC_ASN1_EOL, 0UL, NULL);
}
flags[0] = 1;
return der_encode_sequence_multi(out, outlen,
LTC_ASN1_BIT_STRING, 1UL, flags,
LTC_ASN1_INTEGER, 1UL, key->g,
LTC_ASN1_INTEGER, 1UL, key->p,
LTC_ASN1_INTEGER, 1UL, key->q,
LTC_ASN1_INTEGER, 1UL, key->y,
LTC_ASN1_INTEGER, 1UL, key->x,
LTC_ASN1_EOL, 0UL, NULL);
}
if (type == PK_PUBLIC) {
if (std) {
unsigned long tmplen = (unsigned long)(ltc_mp_count_bits(key->y) / 8) + 8;
unsigned char* tmp = XMALLOC(tmplen);
ltc_asn1_list int_list[3];
if (tmp == NULL) {
return CRYPT_MEM;
}
err = der_encode_integer(key->y, tmp, &tmplen);
if (err != CRYPT_OK) {
goto error;
}
LTC_SET_ASN1(int_list, 0, LTC_ASN1_INTEGER, key->p, 1UL);
LTC_SET_ASN1(int_list, 1, LTC_ASN1_INTEGER, key->q, 1UL);
LTC_SET_ASN1(int_list, 2, LTC_ASN1_INTEGER, key->g, 1UL);
err = x509_encode_subject_public_key_info(out, outlen, LTC_OID_DSA, tmp,
tmplen, LTC_ASN1_SEQUENCE, int_list,
sizeof(int_list) / sizeof(int_list[0]));
error:
XFREE(tmp);
return err;
}
flags[0] = 0;
return der_encode_sequence_multi(out, outlen,
LTC_ASN1_BIT_STRING, 1UL, flags,
LTC_ASN1_INTEGER, 1UL, key->g,
LTC_ASN1_INTEGER, 1UL, key->p,
LTC_ASN1_INTEGER, 1UL, key->q,
LTC_ASN1_INTEGER, 1UL, key->y,
LTC_ASN1_EOL, 0UL, NULL);
}
return CRYPT_INVALID_ARG;
}
#endif

View File

@@ -0,0 +1,23 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file dsa_free.c
DSA implementation, free a DSA key, Tom St Denis
*/
#ifdef LTC_MDSA
/**
Free a DSA key
@param key The key to free from memory
*/
void dsa_free(dsa_key *key)
{
LTC_ARGCHKVD(key != NULL);
ltc_mp_cleanup_multi(&key->y, &key->x, &key->q, &key->g, &key->p, LTC_NULL);
key->type = key->qord = 0;
}
#endif

View File

@@ -0,0 +1,37 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file dsa_make_key.c
DSA implementation, generate a DSA key
*/
#ifdef LTC_MDSA
/**
Create a DSA key
@param prng An active PRNG state
@param wprng The index of the PRNG desired
@param key [in/out] Where to store the created key
@return CRYPT_OK if successful.
*/
int dsa_generate_key(prng_state *prng, int wprng, dsa_key *key)
{
int err;
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(ltc_mp.name != NULL);
/* so now we have our DH structure, generator g, order q, modulus p
Now we need a random exponent [mod q] and it's power g^x mod p
*/
/* private key x should be from range: 1 <= x <= q-1 (see FIPS 186-4 B.1.2) */
if ((err = rand_bn_upto(key->x, key->q, prng, wprng)) != CRYPT_OK) { return err; }
if ((err = ltc_mp_exptmod(key->g, key->x, key->p, key->y)) != CRYPT_OK) { return err; }
key->type = PK_PRIVATE;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,235 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
/**
@file dsa_generate_pqg.c
DSA implementation - generate DSA parameters p, q & g
*/
#ifdef LTC_MDSA
/**
Create DSA parameters (INTERNAL ONLY, not part of public API)
@param prng An active PRNG state
@param wprng The index of the PRNG desired
@param group_size Size of the multiplicative group (octets)
@param modulus_size Size of the modulus (octets)
@param p [out] bignum where generated 'p' is stored (must be initialized by caller)
@param q [out] bignum where generated 'q' is stored (must be initialized by caller)
@param g [out] bignum where generated 'g' is stored (must be initialized by caller)
@return CRYPT_OK if successful, upon error this function will free all allocated memory
*/
static int s_dsa_make_params(prng_state *prng, int wprng, int group_size, int modulus_size, void *p, void *q, void *g)
{
unsigned long L, N, n, outbytes, seedbytes, counter, j, i;
int err, res, mr_tests_q, mr_tests_p, found_p, found_q, hash;
unsigned char *wbuf, *sbuf, digest[MAXBLOCKSIZE];
void *t2L1, *t2N1, *t2q, *t2seedlen, *U, *W, *X, *c, *h, *e, *seedinc;
const char *accepted_hashes[] = { "sha3-512", "sha512", "sha3-384", "sha384", "sha3-256", "sha256" };
/* check size */
if (group_size > LTC_MDSA_MAX_GROUP || group_size < 1 || group_size >= modulus_size || modulus_size > LTC_MDSA_MAX_MODULUS) {
return CRYPT_INVALID_ARG;
}
/* FIPS-186-4 A.1.1.2 Generation of the Probable Primes p and q Using an Approved Hash Function
*
* L = The desired length of the prime p (in bits e.g. L = 1024)
* N = The desired length of the prime q (in bits e.g. N = 160)
* seedlen = The desired bit length of the domain parameter seed; seedlen shallbe equal to or greater than N
* outlen = The bit length of Hash function
*
* 1. Check that the (L, N)
* 2. If (seedlen <N), then return INVALID.
* 3. n = ceil(L / outlen) - 1
* 4. b = L- 1 - (n * outlen)
* 5. domain_parameter_seed = an arbitrary sequence of seedlen bits
* 6. U = Hash (domain_parameter_seed) mod 2^(N-1)
* 7. q = 2^(N-1) + U + 1 - (U mod 2)
* 8. Test whether or not q is prime as specified in Appendix C.3
* 9. If qis not a prime, then go to step 5.
* 10. offset = 1
* 11. For counter = 0 to (4L- 1) do {
* For j=0 to n do {
* Vj = Hash ((domain_parameter_seed+ offset + j) mod 2^seedlen
* }
* W = V0 + (V1 *2^outlen) + ... + (Vn-1 * 2^((n-1) * outlen)) + ((Vn mod 2^b) * 2^(n * outlen))
* X = W + 2^(L-1) Comment: 0 <= W < 2^(L-1); hence 2^(L-1) <= X < 2^L
* c = X mod 2*q
* p = X - (c - 1) Comment: p ~ 1 (mod 2*q)
* If (p >= 2^(L-1)) {
* Test whether or not p is prime as specified in Appendix C.3.
* If p is determined to be prime, then return VALID and the values of p, qand (optionally) the values of domain_parameter_seed and counter
* }
* offset = offset + n + 1 Comment: Increment offset
* }
*/
seedbytes = group_size;
L = (unsigned long)modulus_size * 8;
N = (unsigned long)group_size * 8;
/* XXX-TODO no Lucas test */
#ifdef LTC_MPI_HAS_LUCAS_TEST
/* M-R tests (when followed by one Lucas test) according FIPS-186-4 - Appendix C.3 - table C.1 */
mr_tests_p = (L <= 2048) ? 3 : 2;
if (N <= 160) { mr_tests_q = 19; }
else if (N <= 224) { mr_tests_q = 24; }
else { mr_tests_q = 27; }
#else
/* M-R tests (without Lucas test) according FIPS-186-4 - Appendix C.3 - table C.1 */
if (L <= 1024) { mr_tests_p = 40; }
else if (L <= 2048) { mr_tests_p = 56; }
else { mr_tests_p = 64; }
if (N <= 160) { mr_tests_q = 40; }
else if (N <= 224) { mr_tests_q = 56; }
else { mr_tests_q = 64; }
#endif
hash = -1;
for (i = 0; i < sizeof(accepted_hashes)/sizeof(accepted_hashes[0]); ++i) {
hash = find_hash(accepted_hashes[i]);
if (hash != -1) break;
}
if (hash == -1) {
return CRYPT_INVALID_ARG; /* no appropriate hash function found */
}
if (N > hash_descriptor[hash].hashsize * 8) {
return CRYPT_INVALID_ARG; /* group_size too big */
}
if ((err = hash_is_valid(hash)) != CRYPT_OK) { return err; }
outbytes = hash_descriptor[hash].hashsize;
n = ((L + outbytes*8 - 1) / (outbytes*8)) - 1;
if ((wbuf = XMALLOC((n+1)*outbytes)) == NULL) { err = CRYPT_MEM; goto cleanup3; }
if ((sbuf = XMALLOC(seedbytes)) == NULL) { err = CRYPT_MEM; goto cleanup2; }
err = ltc_mp_init_multi(&t2L1, &t2N1, &t2q, &t2seedlen, &U, &W, &X, &c, &h, &e, &seedinc, LTC_NULL);
if (err != CRYPT_OK) { goto cleanup1; }
if ((err = ltc_mp_2expt(t2L1, L-1)) != CRYPT_OK) { goto cleanup; }
/* t2L1 = 2^(L-1) */
if ((err = ltc_mp_2expt(t2N1, N-1)) != CRYPT_OK) { goto cleanup; }
/* t2N1 = 2^(N-1) */
if ((err = ltc_mp_2expt(t2seedlen, seedbytes*8)) != CRYPT_OK) { goto cleanup; }
/* t2seedlen = 2^seedlen */
for(found_p=0; !found_p;) {
/* q */
for(found_q=0; !found_q;) {
if (prng_descriptor[wprng].read(sbuf, seedbytes, prng) != seedbytes) { err = CRYPT_ERROR_READPRNG; goto cleanup; }
i = outbytes;
if ((err = hash_memory(hash, sbuf, seedbytes, digest, &i)) != CRYPT_OK) { goto cleanup; }
if ((err = ltc_mp_read_unsigned_bin(U, digest, outbytes)) != CRYPT_OK) { goto cleanup; }
if ((err = ltc_mp_mod(U, t2N1, U)) != CRYPT_OK) { goto cleanup; }
if ((err = ltc_mp_add(t2N1, U, q)) != CRYPT_OK) { goto cleanup; }
if (!ltc_mp_isodd(q)) ltc_mp_add_d(q, 1, q);
if ((err = ltc_mp_prime_is_prime(q, mr_tests_q, &res)) != CRYPT_OK) { goto cleanup; }
if (res == LTC_MP_YES) found_q = 1;
}
/* p */
if ((err = ltc_mp_read_unsigned_bin(seedinc, sbuf, seedbytes)) != CRYPT_OK) { goto cleanup; }
if ((err = ltc_mp_add(q, q, t2q)) != CRYPT_OK) { goto cleanup; }
for(counter=0; counter < 4*L && !found_p; counter++) {
for(j=0; j<=n; j++) {
if ((err = ltc_mp_add_d(seedinc, 1, seedinc)) != CRYPT_OK) { goto cleanup; }
if ((err = ltc_mp_mod(seedinc, t2seedlen, seedinc)) != CRYPT_OK) { goto cleanup; }
/* seedinc = (seedinc+1) % 2^seed_bitlen */
if ((i = ltc_mp_unsigned_bin_size(seedinc)) > seedbytes) { err = CRYPT_INVALID_ARG; goto cleanup; }
zeromem(sbuf, seedbytes);
if ((err = ltc_mp_to_unsigned_bin(seedinc, sbuf + seedbytes-i)) != CRYPT_OK) { goto cleanup; }
i = outbytes;
err = hash_memory(hash, sbuf, seedbytes, wbuf+(n-j)*outbytes, &i);
if (err != CRYPT_OK) { goto cleanup; }
}
if ((err = ltc_mp_read_unsigned_bin(W, wbuf, (n+1)*outbytes)) != CRYPT_OK) { goto cleanup; }
if ((err = ltc_mp_mod(W, t2L1, W)) != CRYPT_OK) { goto cleanup; }
if ((err = ltc_mp_add(W, t2L1, X)) != CRYPT_OK) { goto cleanup; }
if ((err = ltc_mp_mod(X, t2q, c)) != CRYPT_OK) { goto cleanup; }
if ((err = ltc_mp_sub_d(c, 1, p)) != CRYPT_OK) { goto cleanup; }
if ((err = ltc_mp_sub(X, p, p)) != CRYPT_OK) { goto cleanup; }
if (ltc_mp_cmp(p, t2L1) != LTC_MP_LT) {
/* p >= 2^(L-1) */
if ((err = ltc_mp_prime_is_prime(p, mr_tests_p, &res)) != CRYPT_OK) { goto cleanup; }
if (res == LTC_MP_YES) {
found_p = 1;
}
}
}
}
/* FIPS-186-4 A.2.1 Unverifiable Generation of the Generator g
* 1. e = (p - 1)/q
* 2. h = any integer satisfying: 1 < h < (p - 1)
* h could be obtained from a random number generator or from a counter that changes after each use
* 3. g = h^e mod p
* 4. if (g == 1), then go to step 2.
*
*/
if ((err = ltc_mp_sub_d(p, 1, e)) != CRYPT_OK) { goto cleanup; }
if ((err = ltc_mp_div(e, q, e, c)) != CRYPT_OK) { goto cleanup; }
/* e = (p - 1)/q */
i = ltc_mp_count_bits(p);
do {
do {
if ((err = rand_bn_bits(h, i, prng, wprng)) != CRYPT_OK) { goto cleanup; }
} while (ltc_mp_cmp(h, p) != LTC_MP_LT || ltc_mp_cmp_d(h, 2) != LTC_MP_GT);
if ((err = ltc_mp_sub_d(h, 1, h)) != CRYPT_OK) { goto cleanup; }
/* h is randon and 1 < h < (p-1) */
if ((err = ltc_mp_exptmod(h, e, p, g)) != CRYPT_OK) { goto cleanup; }
} while (ltc_mp_cmp_d(g, 1) == LTC_MP_EQ);
err = CRYPT_OK;
cleanup:
ltc_mp_deinit_multi(t2L1, t2N1, t2q, t2seedlen, U, W, X, c, h, e, seedinc, LTC_NULL);
cleanup1:
XFREE(sbuf);
cleanup2:
XFREE(wbuf);
cleanup3:
return err;
}
/**
Generate DSA parameters p, q & g
@param prng An active PRNG state
@param wprng The index of the PRNG desired
@param group_size Size of the multiplicative group (octets)
@param modulus_size Size of the modulus (octets)
@param key [out] Where to store the created key
@return CRYPT_OK if successful.
*/
int dsa_generate_pqg(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key)
{
int err;
/* init key */
if ((err = dsa_int_init(key)) != CRYPT_OK) return err;
/* generate params */
err = s_dsa_make_params(prng, wprng, group_size, modulus_size, key->p, key->q, key->g);
if (err != CRYPT_OK) {
goto cleanup;
}
key->qord = group_size;
return CRYPT_OK;
cleanup:
dsa_free(key);
return err;
}
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,145 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
/**
@file dsa_import.c
DSA implementation, import a DSA key, Tom St Denis
*/
#ifdef LTC_MDSA
int dsa_import_pkcs1(const unsigned char *in, unsigned long inlen, dsa_key *key)
{
int err;
unsigned long zero = 0;
/* get key type */
if ((err = der_decode_sequence_multi(in, inlen,
LTC_ASN1_SHORT_INTEGER, 1UL, &zero,
LTC_ASN1_INTEGER, 1UL, key->p,
LTC_ASN1_INTEGER, 1UL, key->q,
LTC_ASN1_INTEGER, 1UL, key->g,
LTC_ASN1_INTEGER, 1UL, key->y,
LTC_ASN1_INTEGER, 1UL, key->x,
LTC_ASN1_EOL, 0UL, NULL)) == CRYPT_OK) {
key->type = PK_PRIVATE;
}
return err;
}
/**
Import a DSA key
@param in The binary packet to import from
@param inlen The length of the binary packet
@param key [out] Where to store the imported key
@return CRYPT_OK if successful, upon error this function will free all allocated memory
*/
int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key)
{
int err, stat;
unsigned char* tmpbuf = NULL;
unsigned char flags[1];
LTC_ARGCHK(in != NULL);
/* init key */
if ((err = dsa_int_init(key)) != CRYPT_OK) return err;
/* try to match the old libtomcrypt format */
err = der_decode_sequence_multi(in, inlen, LTC_ASN1_BIT_STRING, 1UL, flags,
LTC_ASN1_EOL, 0UL, NULL);
if (err == CRYPT_OK || err == CRYPT_INPUT_TOO_LONG) {
/* private key */
if (flags[0] == 1) {
if ((err = der_decode_sequence_multi(in, inlen,
LTC_ASN1_BIT_STRING, 1UL, flags,
LTC_ASN1_INTEGER, 1UL, key->g,
LTC_ASN1_INTEGER, 1UL, key->p,
LTC_ASN1_INTEGER, 1UL, key->q,
LTC_ASN1_INTEGER, 1UL, key->y,
LTC_ASN1_INTEGER, 1UL, key->x,
LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) {
goto LBL_ERR;
}
key->type = PK_PRIVATE;
goto LBL_OK;
}
/* public key */
else if (flags[0] == 0) {
if ((err = der_decode_sequence_multi(in, inlen,
LTC_ASN1_BIT_STRING, 1UL, flags,
LTC_ASN1_INTEGER, 1UL, key->g,
LTC_ASN1_INTEGER, 1UL, key->p,
LTC_ASN1_INTEGER, 1UL, key->q,
LTC_ASN1_INTEGER, 1UL, key->y,
LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) {
goto LBL_ERR;
}
key->type = PK_PUBLIC;
goto LBL_OK;
}
else {
err = CRYPT_INVALID_PACKET;
goto LBL_ERR;
}
}
if (dsa_import_pkcs1(in, inlen, key) != CRYPT_OK) {
ltc_asn1_list params[3];
unsigned long tmpbuf_len = inlen, len;
LTC_SET_ASN1(params, 0, LTC_ASN1_INTEGER, key->p, 1UL);
LTC_SET_ASN1(params, 1, LTC_ASN1_INTEGER, key->q, 1UL);
LTC_SET_ASN1(params, 2, LTC_ASN1_INTEGER, key->g, 1UL);
len = 3;
tmpbuf = XCALLOC(1, tmpbuf_len);
if (tmpbuf == NULL) {
return CRYPT_MEM;
}
err = x509_decode_subject_public_key_info(in, inlen,
LTC_OID_DSA, tmpbuf, &tmpbuf_len,
LTC_ASN1_SEQUENCE, params, &len);
if (err != CRYPT_OK) {
XFREE(tmpbuf);
goto LBL_ERR;
}
if ((err = der_decode_integer(tmpbuf, tmpbuf_len, key->y)) != CRYPT_OK) {
XFREE(tmpbuf);
goto LBL_ERR;
}
key->type = PK_PUBLIC;
XFREE(tmpbuf);
}
LBL_OK:
key->qord = ltc_mp_unsigned_bin_size(key->q);
/* quick p, q, g validation, without primality testing
* + x, y validation */
if ((err = dsa_int_validate(key, &stat)) != CRYPT_OK) {
goto LBL_ERR;
}
if (stat == 0) {
err = CRYPT_INVALID_PACKET;
goto LBL_ERR;
}
return CRYPT_OK;
LBL_ERR:
dsa_free(key);
return err;
}
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,94 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
/**
@file dsa_import_pkcs8.c
Import a PKCS DSA key
*/
#ifdef LTC_MDSA
int dsa_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, dsa_key *key)
{
int err, stat;
LTC_UNUSED_PARAM(alg_id);
if (!alg_id->child
|| !LTC_ASN1_IS_TYPE(alg_id->child->next, LTC_ASN1_SEQUENCE)
|| !LTC_ASN1_IS_TYPE(priv_key, LTC_ASN1_OCTET_STRING)) {
return CRYPT_INVALID_PACKET;
}
if ((err = dsa_set_pqg_dsaparam(alg_id->child->next->data, alg_id->child->next->size, key)) != CRYPT_OK) {
return err;
}
if ((err = der_decode_integer(priv_key->data, priv_key->size, key->x)) != CRYPT_OK) {
goto LBL_ERR;
}
if ((err = ltc_mp_exptmod(key->g, key->x, key->p, key->y)) != CRYPT_OK) {
goto LBL_ERR;
}
/* quick p, q, g validation, without primality testing
* + x, y validation */
if ((err = dsa_int_validate(key, &stat)) != CRYPT_OK) {
goto LBL_ERR;
}
if (stat == 0) {
err = CRYPT_INVALID_PACKET;
goto LBL_ERR;
}
key->qord = ltc_mp_unsigned_bin_size(key->q);
key->type = PK_PRIVATE;
return err;
LBL_ERR:
dsa_free(key);
return err;
}
/**
Import an RSAPrivateKey in PKCS#8 format
@param in The packet to import from
@param inlen It's length (octets)
@param pw_ctx The password context when decrypting the private key
@param key [out] Destination for newly imported key
@return CRYPT_OK if successful, upon error allocated memory is freed
*/
int dsa_import_pkcs8(const unsigned char *in, unsigned long inlen,
const password_ctx *pw_ctx,
dsa_key *key)
{
int err;
ltc_asn1_list *l = NULL;
ltc_asn1_list *alg_id, *priv_key;
enum ltc_oid_id pka;
LTC_ARGCHK(in != NULL);
if ((err = pkcs8_decode_flexi(in, inlen, pw_ctx, &l)) != CRYPT_OK) {
return err;
}
if ((err = pkcs8_get_children(l, &pka, &alg_id, &priv_key)) != CRYPT_OK) {
goto LBL_DER_FREE;
}
if (pka != LTC_OID_DSA) {
err = CRYPT_INVALID_PACKET;
goto LBL_DER_FREE;
}
err = dsa_import_pkcs8_asn1(alg_id, priv_key, key);
LBL_DER_FREE:
der_free_sequence_flexi(l);
return err;
}
#endif /* LTC_MRSA */
#pragma clang diagnostic pop

View File

@@ -0,0 +1,22 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_MDSA
/**
Init DSA key
@param key [out] the key to init
@return CRYPT_OK if successful.
*/
int dsa_int_init(dsa_key *key)
{
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(ltc_mp.name != NULL);
/* init key */
return ltc_mp_init_multi(&key->p, &key->g, &key->q, &key->x, &key->y, LTC_NULL);
}
#endif

View File

@@ -0,0 +1,31 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file dsa_make_key.c
DSA implementation, generate a DSA key
*/
#ifdef LTC_MDSA
/**
Old-style creation of a DSA key
@param prng An active PRNG state
@param wprng The index of the PRNG desired
@param group_size Size of the multiplicative group (octets)
@param modulus_size Size of the modulus (octets)
@param key [out] Where to store the created key
@return CRYPT_OK if successful.
*/
int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key)
{
int err;
if ((err = dsa_generate_pqg(prng, wprng, group_size, modulus_size, key)) != CRYPT_OK) { return err; }
if ((err = dsa_generate_key(prng, wprng, key)) != CRYPT_OK) { return err; }
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,104 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
#ifdef LTC_MDSA
/**
Import DSA's p, q & g from raw numbers
@param p DSA's p in binary representation
@param plen The length of p
@param q DSA's q in binary representation
@param qlen The length of q
@param g DSA's g in binary representation
@param glen The length of g
@param key [out] the destination for the imported key
@return CRYPT_OK if successful.
*/
int dsa_set_pqg(const unsigned char *p, unsigned long plen,
const unsigned char *q, unsigned long qlen,
const unsigned char *g, unsigned long glen,
dsa_key *key)
{
int err, stat;
LTC_ARGCHK(p != NULL);
LTC_ARGCHK(q != NULL);
LTC_ARGCHK(g != NULL);
/* init key */
if ((err = dsa_int_init(key)) != CRYPT_OK) return err;
if ((err = ltc_mp_read_unsigned_bin(key->p, p , plen)) != CRYPT_OK) { goto LBL_ERR; }
if ((err = ltc_mp_read_unsigned_bin(key->g, g , glen)) != CRYPT_OK) { goto LBL_ERR; }
if ((err = ltc_mp_read_unsigned_bin(key->q, q , qlen)) != CRYPT_OK) { goto LBL_ERR; }
key->qord = ltc_mp_unsigned_bin_size(key->q);
/* do only a quick validation, without primality testing */
if ((err = dsa_int_validate_pqg(key, &stat)) != CRYPT_OK) { goto LBL_ERR; }
if (stat == 0) {
err = CRYPT_INVALID_PACKET;
goto LBL_ERR;
}
return CRYPT_OK;
LBL_ERR:
dsa_free(key);
return err;
}
/**
Import DSA public or private key-part from raw numbers
NB: The p, q & g parts must be set beforehand
@param in The key-part to import, either public or private.
@param inlen The key-part's length
@param type Which type of key (PK_PRIVATE or PK_PUBLIC)
@param key [out] the destination for the imported key
@return CRYPT_OK if successful.
*/
int dsa_set_key(const unsigned char *in, unsigned long inlen, int type, dsa_key *key)
{
int err, stat = 0;
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(key->x != NULL);
LTC_ARGCHK(key->y != NULL);
LTC_ARGCHK(key->p != NULL);
LTC_ARGCHK(key->g != NULL);
LTC_ARGCHK(key->q != NULL);
LTC_ARGCHK(ltc_mp.name != NULL);
if (type == PK_PRIVATE) {
key->type = PK_PRIVATE;
if ((err = ltc_mp_read_unsigned_bin(key->x, in, inlen)) != CRYPT_OK) { goto LBL_ERR; }
if ((err = ltc_mp_exptmod(key->g, key->x, key->p, key->y)) != CRYPT_OK) { goto LBL_ERR; }
}
else {
key->type = PK_PUBLIC;
if ((err = ltc_mp_read_unsigned_bin(key->y, in, inlen)) != CRYPT_OK) { goto LBL_ERR; }
}
if ((err = dsa_int_validate_xy(key, &stat)) != CRYPT_OK) { goto LBL_ERR; }
if (stat == 0) {
err = CRYPT_INVALID_PACKET;
goto LBL_ERR;
}
return CRYPT_OK;
LBL_ERR:
dsa_free(key);
return err;
}
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,61 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
#ifdef LTC_MDSA
/**
Import DSA's p, q & g from dsaparam
dsaparam data: openssl dsaparam -outform DER -out dsaparam.der 2048
@param dsaparam The DSA param DER encoded data
@param dsaparamlen The length of dhparam data
@param key [out] the destination for the imported key
@return CRYPT_OK if successful.
*/
int dsa_set_pqg_dsaparam(const unsigned char *dsaparam, unsigned long dsaparamlen,
dsa_key *key)
{
int err, stat;
LTC_ARGCHK(dsaparam != NULL);
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(ltc_mp.name != NULL);
/* init key */
if ((err = dsa_int_init(key)) != CRYPT_OK) return err;
if ((err = der_decode_sequence_multi(dsaparam, dsaparamlen,
LTC_ASN1_INTEGER, 1UL, key->p,
LTC_ASN1_INTEGER, 1UL, key->q,
LTC_ASN1_INTEGER, 1UL, key->g,
LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) {
goto LBL_ERR;
}
key->qord = ltc_mp_unsigned_bin_size(key->q);
/* quick p, q, g validation, without primality testing */
if ((err = dsa_int_validate_pqg(key, &stat)) != CRYPT_OK) {
goto LBL_ERR;
}
if (stat == 0) {
err = CRYPT_INVALID_PACKET;
goto LBL_ERR;
}
return CRYPT_OK;
LBL_ERR:
dsa_free(key);
return err;
}
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,60 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file dsa_shared_secret.c
DSA Crypto, Tom St Denis
*/
#ifdef LTC_MDSA
/**
Create a DSA shared secret between two keys
@param private_key The private DSA key (the exponent)
@param base The base of the exponentiation (allows this to be used for both encrypt and decrypt)
@param public_key The public key
@param out [out] Destination of the shared secret
@param outlen [in/out] The max size and resulting size of the shared secret
@return CRYPT_OK if successful
*/
int dsa_shared_secret(void *private_key, void *base,
const dsa_key *public_key,
unsigned char *out, unsigned long *outlen)
{
unsigned long x;
void *res;
int err;
LTC_ARGCHK(private_key != NULL);
LTC_ARGCHK(public_key != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* make new point */
if ((err = ltc_mp_init(&res)) != CRYPT_OK) {
return err;
}
if ((err = ltc_mp_exptmod(base, private_key, public_key->p, res)) != CRYPT_OK) {
ltc_mp_clear(res);
return err;
}
x = (unsigned long)ltc_mp_unsigned_bin_size(res);
if (*outlen < x) {
*outlen = x;
err = CRYPT_BUFFER_OVERFLOW;
goto done;
}
zeromem(out, x);
if ((err = ltc_mp_to_unsigned_bin(res, out + (x - ltc_mp_unsigned_bin_size(res)))) != CRYPT_OK) { goto done; }
err = CRYPT_OK;
*outlen = x;
done:
ltc_mp_clear(res);
return err;
}
#endif

View File

@@ -0,0 +1,142 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file dsa_sign_hash.c
DSA implementation, sign a hash, Tom St Denis
*/
#ifdef LTC_MDSA
/**
Sign a hash with DSA
@param in The hash to sign
@param inlen The length of the hash to sign
@param r The "r" integer of the signature (caller must initialize with ltc_mp_init() first)
@param s The "s" integer of the signature (caller must initialize with ltc_mp_init() first)
@param prng An active PRNG state
@param wprng The index of the PRNG desired
@param key A private DSA key
@return CRYPT_OK if successful
*/
int dsa_sign_hash_raw(const unsigned char *in, unsigned long inlen,
void *r, void *s,
prng_state *prng, int wprng, const dsa_key *key)
{
void *k, *kinv, *tmp;
unsigned char *buf;
int err, qbits;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(r != NULL);
LTC_ARGCHK(s != NULL);
LTC_ARGCHK(key != NULL);
if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
return err;
}
if (key->type != PK_PRIVATE) {
return CRYPT_PK_NOT_PRIVATE;
}
/* check group order size */
if (key->qord >= LTC_MDSA_MAX_GROUP) {
return CRYPT_INVALID_ARG;
}
buf = XMALLOC(LTC_MDSA_MAX_GROUP);
if (buf == NULL) {
return CRYPT_MEM;
}
/* Init our temps */
if ((err = ltc_mp_init_multi(&k, &kinv, &tmp, LTC_NULL)) != CRYPT_OK) { goto ERRBUF; }
qbits = ltc_mp_count_bits(key->q);
retry:
do {
/* gen random k */
if ((err = rand_bn_bits(k, qbits, prng, wprng)) != CRYPT_OK) { goto error; }
/* k should be from range: 1 <= k <= q-1 (see FIPS 186-4 B.2.2) */
if (ltc_mp_cmp_d(k, 0) != LTC_MP_GT || ltc_mp_cmp(k, key->q) != LTC_MP_LT) { goto retry; }
/* test gcd */
if ((err = ltc_mp_gcd(k, key->q, tmp)) != CRYPT_OK) { goto error; }
} while (ltc_mp_cmp_d(tmp, 1) != LTC_MP_EQ);
/* now find 1/k mod q */
if ((err = ltc_mp_invmod(k, key->q, kinv)) != CRYPT_OK) { goto error; }
/* now find r = g^k mod p mod q */
if ((err = ltc_mp_exptmod(key->g, k, key->p, r)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_mod(r, key->q, r)) != CRYPT_OK) { goto error; }
if (ltc_mp_iszero(r) == LTC_MP_YES) { goto retry; }
/* FIPS 186-4 4.6: use leftmost min(bitlen(q), bitlen(hash)) bits of 'hash'*/
inlen = MIN(inlen, (unsigned long)(key->qord));
/* now find s = (in + xr)/k mod q */
if ((err = ltc_mp_read_unsigned_bin(tmp, in, inlen)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_mul(key->x, r, s)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_add(s, tmp, s)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_mulmod(s, kinv, key->q, s)) != CRYPT_OK) { goto error; }
if (ltc_mp_iszero(s) == LTC_MP_YES) { goto retry; }
err = CRYPT_OK;
error:
ltc_mp_deinit_multi(k, kinv, tmp, LTC_NULL);
ERRBUF:
#ifdef LTC_CLEAN_STACK
zeromem(buf, LTC_MDSA_MAX_GROUP);
#endif
XFREE(buf);
return err;
}
/**
Sign a hash with DSA
@param in The hash to sign
@param inlen The length of the hash to sign
@param out [out] Where to store the signature
@param outlen [in/out] The max size and resulting size of the signature
@param prng An active PRNG state
@param wprng The index of the PRNG desired
@param key A private DSA key
@return CRYPT_OK if successful
*/
int dsa_sign_hash(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, const dsa_key *key)
{
void *r, *s;
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(key != NULL);
if (ltc_mp_init_multi(&r, &s, LTC_NULL) != CRYPT_OK) {
return CRYPT_MEM;
}
if ((err = dsa_sign_hash_raw(in, inlen, r, s, prng, wprng, key)) != CRYPT_OK) {
goto error;
}
err = der_encode_sequence_multi(out, outlen,
LTC_ASN1_INTEGER, 1UL, r,
LTC_ASN1_INTEGER, 1UL, s,
LTC_ASN1_EOL, 0UL, NULL);
error:
ltc_mp_deinit_multi(r, s, LTC_NULL);
return err;
}
#endif

View File

@@ -0,0 +1,127 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file dsa_verify_hash.c
DSA implementation, verify a signature, Tom St Denis
*/
#ifdef LTC_MDSA
/**
Verify a DSA signature
@param r DSA "r" parameter
@param s DSA "s" parameter
@param hash The hash that was signed
@param hashlen The length of the hash that was signed
@param stat [out] The result of the signature verification, 1==valid, 0==invalid
@param key The corresponding public DSA key
@return CRYPT_OK if successful (even if the signature is invalid)
*/
int dsa_verify_hash_raw( void *r, void *s,
const unsigned char *hash, unsigned long hashlen,
int *stat, const dsa_key *key)
{
void *w, *v, *u1, *u2;
int err;
LTC_ARGCHK(r != NULL);
LTC_ARGCHK(s != NULL);
LTC_ARGCHK(stat != NULL);
LTC_ARGCHK(key != NULL);
/* default to invalid signature */
*stat = 0;
/* init our variables */
if ((err = ltc_mp_init_multi(&w, &v, &u1, &u2, LTC_NULL)) != CRYPT_OK) {
return err;
}
/* neither r or s can be null or >q*/
if (ltc_mp_cmp_d(r, 0) != LTC_MP_GT || ltc_mp_cmp_d(s, 0) != LTC_MP_GT || ltc_mp_cmp(r, key->q) != LTC_MP_LT || ltc_mp_cmp(s, key->q) != LTC_MP_LT) {
err = CRYPT_INVALID_PACKET;
goto error;
}
/* FIPS 186-4 4.7: use leftmost min(bitlen(q), bitlen(hash)) bits of 'hash' */
hashlen = MIN(hashlen, (unsigned long)(key->qord));
/* w = 1/s mod q */
if ((err = ltc_mp_invmod(s, key->q, w)) != CRYPT_OK) { goto error; }
/* u1 = m * w mod q */
if ((err = ltc_mp_read_unsigned_bin(u1, hash, hashlen)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_mulmod(u1, w, key->q, u1)) != CRYPT_OK) { goto error; }
/* u2 = r*w mod q */
if ((err = ltc_mp_mulmod(r, w, key->q, u2)) != CRYPT_OK) { goto error; }
/* v = g^u1 * y^u2 mod p mod q */
if ((err = ltc_mp_exptmod(key->g, u1, key->p, u1)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_exptmod(key->y, u2, key->p, u2)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_mulmod(u1, u2, key->p, v)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_mod(v, key->q, v)) != CRYPT_OK) { goto error; }
/* if r = v then we're set */
if (ltc_mp_cmp(r, v) == LTC_MP_EQ) {
*stat = 1;
}
err = CRYPT_OK;
error:
ltc_mp_deinit_multi(w, v, u1, u2, LTC_NULL);
return err;
}
/**
Verify a DSA signature
@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 that was signed
@param stat [out] The result of the signature verification, 1==valid, 0==invalid
@param key The corresponding public DSA key
@return CRYPT_OK if successful (even if the signature is invalid)
*/
int dsa_verify_hash(const unsigned char *sig, unsigned long siglen,
const unsigned char *hash, unsigned long hashlen,
int *stat, const dsa_key *key)
{
int err;
void *r, *s;
ltc_asn1_list sig_seq[2];
unsigned long reallen = 0;
LTC_ARGCHK(stat != NULL);
*stat = 0; /* must be set before the first return */
if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) {
return err;
}
LTC_SET_ASN1(sig_seq, 0, LTC_ASN1_INTEGER, r, 1UL);
LTC_SET_ASN1(sig_seq, 1, LTC_ASN1_INTEGER, s, 1UL);
err = der_decode_sequence_strict(sig, siglen, sig_seq, 2);
if (err != CRYPT_OK) {
goto LBL_ERR;
}
err = der_length_sequence(sig_seq, 2, &reallen);
if (err != CRYPT_OK || reallen != siglen) {
goto LBL_ERR;
}
/* do the op */
err = dsa_verify_hash_raw(r, s, hash, hashlen, stat, key);
LBL_ERR:
ltc_mp_deinit_multi(r, s, LTC_NULL);
return err;
}
#endif

View File

@@ -0,0 +1,204 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file dsa_verify_key.c
DSA implementation, verify a key, Tom St Denis
*/
#ifdef LTC_MDSA
/**
Validate a DSA key
Yeah, this function should've been called dsa_validate_key()
in the first place and for compat-reasons we keep it
as it was (for now).
@param key The key to validate
@param stat [out] Result of test, 1==valid, 0==invalid
@return CRYPT_OK if successful
*/
int dsa_verify_key(const dsa_key *key, int *stat)
{
int err;
err = dsa_int_validate_primes(key, stat);
if (err != CRYPT_OK || *stat == 0) return err;
return dsa_int_validate(key, stat);
}
/**
Non-complex part (no primality testing) of the validation
of DSA params (p, q, g)
@param key The key to validate
@param stat [out] Result of test, 1==valid, 0==invalid
@return CRYPT_OK if successful
*/
int dsa_int_validate_pqg(const dsa_key *key, int *stat)
{
void *tmp1, *tmp2;
int err;
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(stat != NULL);
*stat = 0;
/* check q-order */
if ( key->qord >= LTC_MDSA_MAX_GROUP || key->qord <= 15 ||
(unsigned long)key->qord >= ltc_mp_unsigned_bin_size(key->p) ||
(ltc_mp_unsigned_bin_size(key->p) - key->qord) >= LTC_MDSA_DELTA ) {
return CRYPT_OK;
}
/* FIPS 186-4 chapter 4.1: 1 < g < p */
if (ltc_mp_cmp_d(key->g, 1) != LTC_MP_GT || ltc_mp_cmp(key->g, key->p) != LTC_MP_LT) {
return CRYPT_OK;
}
if ((err = ltc_mp_init_multi(&tmp1, &tmp2, LTC_NULL)) != CRYPT_OK) { return err; }
/* FIPS 186-4 chapter 4.1: q is a divisor of (p - 1) */
if ((err = ltc_mp_sub_d(key->p, 1, tmp1)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_div(tmp1, key->q, tmp1, tmp2)) != CRYPT_OK) { goto error; }
if (ltc_mp_iszero(tmp2) != LTC_MP_YES) {
err = CRYPT_OK;
goto error;
}
/* FIPS 186-4 chapter 4.1: g is a generator of a subgroup of order q in
* the multiplicative group of GF(p) - so we make sure that g^q mod p = 1
*/
if ((err = ltc_mp_exptmod(key->g, key->q, key->p, tmp1)) != CRYPT_OK) { goto error; }
if (ltc_mp_cmp_d(tmp1, 1) != LTC_MP_EQ) {
err = CRYPT_OK;
goto error;
}
err = CRYPT_OK;
*stat = 1;
error:
ltc_mp_deinit_multi(tmp2, tmp1, LTC_NULL);
return err;
}
/**
Primality testing of DSA params p and q
@param key The key to validate
@param stat [out] Result of test, 1==valid, 0==invalid
@return CRYPT_OK if successful
*/
int dsa_int_validate_primes(const dsa_key *key, int *stat)
{
int err, res;
*stat = 0;
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(stat != NULL);
/* key->q prime? */
if ((err = ltc_mp_prime_is_prime(key->q, LTC_MILLER_RABIN_REPS, &res)) != CRYPT_OK) {
return err;
}
if (res == LTC_MP_NO) {
return CRYPT_OK;
}
/* key->p prime? */
if ((err = ltc_mp_prime_is_prime(key->p, LTC_MILLER_RABIN_REPS, &res)) != CRYPT_OK) {
return err;
}
if (res == LTC_MP_NO) {
return CRYPT_OK;
}
*stat = 1;
return CRYPT_OK;
}
/**
Validation of a DSA key (x and y values)
@param key The key to validate
@param stat [out] Result of test, 1==valid, 0==invalid
@return CRYPT_OK if successful
*/
int dsa_int_validate_xy(const dsa_key *key, int *stat)
{
void *tmp;
int err;
*stat = 0;
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(stat != NULL);
/* 1 < y < p-1 */
if ((err = ltc_mp_init(&tmp)) != CRYPT_OK) {
return err;
}
if ((err = ltc_mp_sub_d(key->p, 1, tmp)) != CRYPT_OK) {
goto error;
}
if (ltc_mp_cmp_d(key->y, 1) != LTC_MP_GT || ltc_mp_cmp(key->y, tmp) != LTC_MP_LT) {
err = CRYPT_OK;
goto error;
}
if (key->type == PK_PRIVATE) {
/* FIPS 186-4 chapter 4.1: 0 < x < q */
if (ltc_mp_cmp_d(key->x, 0) != LTC_MP_GT || ltc_mp_cmp(key->x, key->q) != LTC_MP_LT) {
err = CRYPT_OK;
goto error;
}
/* FIPS 186-4 chapter 4.1: y = g^x mod p */
if ((err = ltc_mp_exptmod(key->g, key->x, key->p, tmp)) != CRYPT_OK) {
goto error;
}
if (ltc_mp_cmp(tmp, key->y) != LTC_MP_EQ) {
err = CRYPT_OK;
goto error;
}
}
else {
/* with just a public key we cannot test y = g^x mod p therefore we
* only test that y^q mod p = 1, which makes sure y is in g^x mod p
*/
if ((err = ltc_mp_exptmod(key->y, key->q, key->p, tmp)) != CRYPT_OK) {
goto error;
}
if (ltc_mp_cmp_d(tmp, 1) != LTC_MP_EQ) {
err = CRYPT_OK;
goto error;
}
}
err = CRYPT_OK;
*stat = 1;
error:
ltc_mp_clear(tmp);
return err;
}
/**
Validation of DSA params (p, q, g) and DSA key (x and y)
@param key The key to validate
@param stat [out] Result of test, 1==valid, 0==invalid
@return CRYPT_OK if successful
*/
int dsa_int_validate(const dsa_key *key, int *stat)
{
int err;
err = dsa_int_validate_pqg(key, stat);
if (err != CRYPT_OK || *stat == 0) return err;
return dsa_int_validate_xy(key, stat);
}
#endif