1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4 
5 /**
6   @file pkcs_1_oaep_encode.c
7   OAEP Padding for PKCS #1, Tom St Denis
8 */
9 
10 #ifdef LTC_PKCS_1
11 
12 /**
13   PKCS #1 v2.00 OAEP encode
14   @param msg             The data to encode
15   @param msglen          The length of the data to encode (octets)
16   @param lparam          A session or system parameter (can be NULL)
17   @param lparamlen       The length of the lparam data
18   @param modulus_bitlen  The bit length of the RSA modulus
19   @param prng            An active PRNG state
20   @param prng_idx        The index of the PRNG desired
21   @param hash_idx        The index of the hash desired
22   @param out             [out] The destination for the encoded data
23   @param outlen          [in/out] The max size and resulting size of the encoded data
24   @return CRYPT_OK if successful
25 */
pkcs_1_oaep_encode(const unsigned char * msg,unsigned long msglen,const unsigned char * lparam,unsigned long lparamlen,unsigned long modulus_bitlen,prng_state * prng,int prng_idx,int hash_idx,unsigned char * out,unsigned long * outlen)26 int pkcs_1_oaep_encode(const unsigned char *msg,    unsigned long msglen,
27                        const unsigned char *lparam, unsigned long lparamlen,
28                              unsigned long modulus_bitlen, prng_state *prng,
29                              int           prng_idx,         int  hash_idx,
30                              unsigned char *out,    unsigned long *outlen)
31 {
32    unsigned char *DB, *seed, *mask;
33    unsigned long hLen, x, y, modulus_len;
34    int           err;
35 
36    LTC_ARGCHK(msg    != NULL);
37    LTC_ARGCHK(out    != NULL);
38    LTC_ARGCHK(outlen != NULL);
39 
40    /* test valid hash */
41    if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
42       return err;
43    }
44 
45    /* valid prng */
46    if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
47       return err;
48    }
49 
50    hLen        = hash_descriptor[hash_idx]->hashsize;
51    modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
52 
53    /* test message size */
54    if ((2*hLen >= (modulus_len - 2)) || (msglen > (modulus_len - 2*hLen - 2))) {
55       return CRYPT_PK_INVALID_SIZE;
56    }
57 
58    /* allocate ram for DB/mask/salt of size modulus_len */
59    DB   = XMALLOC(modulus_len);
60    mask = XMALLOC(modulus_len);
61    seed = XMALLOC(hLen);
62    if (DB == NULL || mask == NULL || seed == NULL) {
63       if (DB != NULL) {
64          XFREE(DB);
65       }
66       if (mask != NULL) {
67          XFREE(mask);
68       }
69       if (seed != NULL) {
70          XFREE(seed);
71       }
72       return CRYPT_MEM;
73    }
74 
75    /* get lhash */
76    /* DB == lhash || PS || 0x01 || M, PS == k - mlen - 2hlen - 2 zeroes */
77    x = modulus_len;
78    if (lparam != NULL) {
79       if ((err = hash_memory(hash_idx, lparam, lparamlen, DB, &x)) != CRYPT_OK) {
80          goto LBL_ERR;
81       }
82    } else {
83       /* can't pass hash_memory a NULL so use DB with zero length */
84       if ((err = hash_memory(hash_idx, DB, 0, DB, &x)) != CRYPT_OK) {
85          goto LBL_ERR;
86       }
87    }
88 
89    /* append PS then 0x01 (to lhash)  */
90    x = hLen;
91    y = modulus_len - msglen - 2*hLen - 2;
92    XMEMSET(DB+x, 0, y);
93    x += y;
94 
95    /* 0x01 byte */
96    DB[x++] = 0x01;
97 
98    /* message (length = msglen) */
99    XMEMCPY(DB+x, msg, msglen);
100    x += msglen;
101 
102    /* now choose a random seed */
103    if (prng_descriptor[prng_idx]->read(seed, hLen, prng) != hLen) {
104       err = CRYPT_ERROR_READPRNG;
105       goto LBL_ERR;
106    }
107 
108    /* compute MGF1 of seed (k - hlen - 1) */
109    if ((err = pkcs_1_mgf1(hash_idx, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
110       goto LBL_ERR;
111    }
112 
113    /* xor against DB */
114    for (y = 0; y < (modulus_len - hLen - 1); y++) {
115        DB[y] ^= mask[y];
116    }
117 
118    /* compute MGF1 of maskedDB (hLen) */
119    if ((err = pkcs_1_mgf1(hash_idx, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) {
120       goto LBL_ERR;
121    }
122 
123    /* XOR against seed */
124    for (y = 0; y < hLen; y++) {
125       seed[y] ^= mask[y];
126    }
127 
128    /* create string of length modulus_len */
129    if (*outlen < modulus_len) {
130       *outlen = modulus_len;
131       err = CRYPT_BUFFER_OVERFLOW;
132       goto LBL_ERR;
133    }
134 
135    /* start output which is 0x00 || maskedSeed || maskedDB */
136    x = 0;
137    out[x++] = 0x00;
138    XMEMCPY(out+x, seed, hLen);
139    x += hLen;
140    XMEMCPY(out+x, DB, modulus_len - hLen - 1);
141    x += modulus_len - hLen - 1;
142 
143    *outlen = x;
144 
145    err = CRYPT_OK;
146 LBL_ERR:
147 #ifdef LTC_CLEAN_STACK
148    zeromem(DB,   modulus_len);
149    zeromem(seed, hLen);
150    zeromem(mask, modulus_len);
151 #endif
152 
153    XFREE(seed);
154    XFREE(mask);
155    XFREE(DB);
156 
157    return err;
158 }
159 
160 #endif /* LTC_PKCS_1 */
161 
162