xref: /optee_os/core/lib/libtomcrypt/src/pk/pkcs1/pkcs_1_oaep_encode.c (revision 2a65ecaf7d6f855e24ce1a117fe1931f7378f82c)
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 mgf_hash,int lparam_hash,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,
30                              int           mgf_hash, int lparam_hash,
31                              unsigned char *out,    unsigned long *outlen)
32 {
33    unsigned char *DB, *seed, *mask;
34    unsigned long hLen, x, y, modulus_len;
35    int           err, lparam_hash_used;
36 
37    LTC_ARGCHK((msglen == 0) || (msg != NULL));
38    LTC_ARGCHK(out    != NULL);
39    LTC_ARGCHK(outlen != NULL);
40 
41    /* test valid hash */
42    if ((err = hash_is_valid(mgf_hash)) != CRYPT_OK) {
43       return err;
44    }
45    if (lparam_hash != -1) {
46       if ((err = hash_is_valid(lparam_hash)) != CRYPT_OK) {
47          return err;
48       }
49       lparam_hash_used = lparam_hash;
50    } else {
51       lparam_hash_used = mgf_hash;
52    }
53 
54    /* valid prng */
55    if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
56       return err;
57    }
58 
59    hLen        = hash_descriptor[lparam_hash_used]->hashsize;
60    modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
61 
62    /* test message size */
63    if ((2*hLen >= (modulus_len - 2)) || (msglen > (modulus_len - 2*hLen - 2))) {
64       return CRYPT_PK_INVALID_SIZE;
65    }
66 
67    /* allocate ram for DB/mask/salt of size modulus_len */
68    DB   = XMALLOC(modulus_len);
69    mask = XMALLOC(modulus_len);
70    seed = XMALLOC(hLen);
71    if (DB == NULL || mask == NULL || seed == NULL) {
72       if (DB != NULL) {
73          XFREE(DB);
74       }
75       if (mask != NULL) {
76          XFREE(mask);
77       }
78       if (seed != NULL) {
79          XFREE(seed);
80       }
81       return CRYPT_MEM;
82    }
83 
84    /* get lhash */
85    /* DB == lhash || PS || 0x01 || M, PS == k - mlen - 2hlen - 2 zeroes */
86    x = modulus_len;
87    if (lparam != NULL) {
88       if ((err = hash_memory(lparam_hash_used, lparam, lparamlen, DB, &x)) != CRYPT_OK) {
89          goto LBL_ERR;
90       }
91    } else {
92       /* can't pass hash_memory a NULL so use DB with zero length */
93       if ((err = hash_memory(lparam_hash_used, DB, 0, DB, &x)) != CRYPT_OK) {
94          goto LBL_ERR;
95       }
96    }
97 
98    /* append PS then 0x01 (to lhash)  */
99    x = hLen;
100    y = modulus_len - msglen - 2*hLen - 2;
101    XMEMSET(DB+x, 0, y);
102    x += y;
103 
104    /* 0x01 byte */
105    DB[x++] = 0x01;
106 
107    if (msglen != 0) {
108       /* message (length = msglen) */
109       XMEMCPY(DB+x, msg, msglen);
110       x += msglen;
111    }
112 
113    /* now choose a random seed */
114    if (prng_descriptor[prng_idx]->read(seed, hLen, prng) != hLen) {
115       err = CRYPT_ERROR_READPRNG;
116       goto LBL_ERR;
117    }
118 
119    /* compute MGF1 of seed (k - hlen - 1) */
120    if ((err = pkcs_1_mgf1(mgf_hash, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
121       goto LBL_ERR;
122    }
123 
124    /* xor against DB */
125    for (y = 0; y < (modulus_len - hLen - 1); y++) {
126        DB[y] ^= mask[y];
127    }
128 
129    /* compute MGF1 of maskedDB (hLen) */
130    if ((err = pkcs_1_mgf1(mgf_hash, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) {
131       goto LBL_ERR;
132    }
133 
134    /* XOR against seed */
135    for (y = 0; y < hLen; y++) {
136       seed[y] ^= mask[y];
137    }
138 
139    /* create string of length modulus_len */
140    if (*outlen < modulus_len) {
141       *outlen = modulus_len;
142       err = CRYPT_BUFFER_OVERFLOW;
143       goto LBL_ERR;
144    }
145 
146    /* start output which is 0x00 || maskedSeed || maskedDB */
147    x = 0;
148    out[x++] = 0x00;
149    XMEMCPY(out+x, seed, hLen);
150    x += hLen;
151    XMEMCPY(out+x, DB, modulus_len - hLen - 1);
152    x += modulus_len - hLen - 1;
153 
154    *outlen = x;
155 
156    err = CRYPT_OK;
157 LBL_ERR:
158 #ifdef LTC_CLEAN_STACK
159    zeromem(DB,   modulus_len);
160    zeromem(seed, hLen);
161    zeromem(mask, modulus_len);
162 #endif
163 
164    XFREE(seed);
165    XFREE(mask);
166    XFREE(DB);
167 
168    return err;
169 }
170 
171 #endif /* LTC_PKCS_1 */
172 
173