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