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