1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4
5 /**
6 @file dsa_encrypt_key.c
7 DSA Crypto, Tom St Denis
8 */
9
10 #ifdef LTC_MDSA
11
12 /**
13 Encrypt a symmetric key with DSA
14 @param in The symmetric key you want to encrypt
15 @param inlen The length of the key to encrypt (octets)
16 @param out [out] The destination for the ciphertext
17 @param outlen [in/out] The max size and resulting size of the ciphertext
18 @param prng An active PRNG state
19 @param wprng The index of the PRNG you wish to use
20 @param hash The index of the hash you want to use
21 @param key The DSA key you want to encrypt to
22 @return CRYPT_OK if successful
23 */
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)24 int dsa_encrypt_key(const unsigned char *in, unsigned long inlen,
25 unsigned char *out, unsigned long *outlen,
26 prng_state *prng, int wprng, int hash,
27 const dsa_key *key)
28 {
29 unsigned char *expt, *skey;
30 void *g_pub, *g_priv;
31 unsigned long x, y;
32 int err;
33
34 LTC_ARGCHK(in != NULL);
35 LTC_ARGCHK(out != NULL);
36 LTC_ARGCHK(outlen != NULL);
37 LTC_ARGCHK(key != NULL);
38
39 /* check that wprng/cipher/hash are not invalid */
40 if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
41 return err;
42 }
43
44 if ((err = hash_is_valid(hash)) != CRYPT_OK) {
45 return err;
46 }
47
48 if (inlen > hash_descriptor[hash]->hashsize) {
49 return CRYPT_INVALID_HASH;
50 }
51
52 /* make a random key and export the public copy */
53 if ((err = mp_init_multi(&g_pub, &g_priv, LTC_NULL)) != CRYPT_OK) {
54 return err;
55 }
56
57 expt = XMALLOC(mp_unsigned_bin_size(key->p) + 1);
58 skey = XMALLOC(MAXBLOCKSIZE);
59 if (expt == NULL || skey == NULL) {
60 if (expt != NULL) {
61 XFREE(expt);
62 }
63 if (skey != NULL) {
64 XFREE(skey);
65 }
66 mp_clear_multi(g_pub, g_priv, LTC_NULL);
67 return CRYPT_MEM;
68 }
69
70 /* make a random g_priv, g_pub = g^x pair
71 private key x should be in range: 1 <= x <= q-1 (see FIPS 186-4 B.1.2)
72 */
73 if ((err = rand_bn_upto(g_priv, key->q, prng, wprng)) != CRYPT_OK) {
74 goto LBL_ERR;
75 }
76
77 /* compute y */
78 if ((err = mp_exptmod(key->g, g_priv, key->p, g_pub)) != CRYPT_OK) {
79 goto LBL_ERR;
80 }
81
82 /* make random key */
83 x = mp_unsigned_bin_size(key->p) + 1;
84 if ((err = dsa_shared_secret(g_priv, key->y, key, expt, &x)) != CRYPT_OK) {
85 goto LBL_ERR;
86 }
87
88 y = MAXBLOCKSIZE;
89 if ((err = hash_memory(hash, expt, x, skey, &y)) != CRYPT_OK) {
90 goto LBL_ERR;
91 }
92
93 /* Encrypt key */
94 for (x = 0; x < inlen; x++) {
95 skey[x] ^= in[x];
96 }
97
98 err = der_encode_sequence_multi(out, outlen,
99 LTC_ASN1_OBJECT_IDENTIFIER, hash_descriptor[hash]->OIDlen, hash_descriptor[hash]->OID,
100 LTC_ASN1_INTEGER, 1UL, g_pub,
101 LTC_ASN1_OCTET_STRING, inlen, skey,
102 LTC_ASN1_EOL, 0UL, NULL);
103
104 LBL_ERR:
105 #ifdef LTC_CLEAN_STACK
106 /* clean up */
107 zeromem(expt, mp_unsigned_bin_size(key->p) + 1);
108 zeromem(skey, MAXBLOCKSIZE);
109 #endif
110
111 XFREE(skey);
112 XFREE(expt);
113
114 mp_clear_multi(g_pub, g_priv, LTC_NULL);
115 return err;
116 }
117
118 #endif
119