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_decode.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 decode
14 @param msg The encoded data to decode
15 @param msglen The length of the encoded data (octets)
16 @param lparam The session or system data (can be NULL)
17 @param lparamlen The length of the lparam
18 @param modulus_bitlen The bit length of the RSA modulus
19 @param hash_idx The index of the hash desired
20 @param out [out] Destination of decoding
21 @param outlen [in/out] The max size and resulting size of the decoding
22 @param res [out] Result of decoding, 1==valid, 0==invalid
23 @return CRYPT_OK if successful
24 */
pkcs_1_oaep_decode(const unsigned char * msg,unsigned long msglen,const unsigned char * lparam,unsigned long lparamlen,unsigned long modulus_bitlen,int hash_idx,unsigned char * out,unsigned long * outlen,int * res)25 int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen,
26 const unsigned char *lparam, unsigned long lparamlen,
27 unsigned long modulus_bitlen, int hash_idx,
28 unsigned char *out, unsigned long *outlen,
29 int *res)
30 {
31 unsigned char *DB, *seed, *mask;
32 unsigned long hLen, x, y, modulus_len;
33 int err, ret;
34
35 LTC_ARGCHK(msg != NULL);
36 LTC_ARGCHK(out != NULL);
37 LTC_ARGCHK(outlen != NULL);
38 LTC_ARGCHK(res != NULL);
39
40 /* default to invalid packet */
41 *res = 0;
42
43 /* test valid hash */
44 if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
45 return err;
46 }
47 hLen = hash_descriptor[hash_idx]->hashsize;
48 modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
49
50 /* test hash/message size */
51 if ((2*hLen >= (modulus_len - 2)) || (msglen != modulus_len)) {
52 return CRYPT_PK_INVALID_SIZE;
53 }
54
55 /* allocate ram for DB/mask/salt of size modulus_len */
56 DB = XMALLOC(modulus_len);
57 mask = XMALLOC(modulus_len);
58 seed = XMALLOC(hLen);
59 if (DB == NULL || mask == NULL || seed == NULL) {
60 if (DB != NULL) {
61 XFREE(DB);
62 }
63 if (mask != NULL) {
64 XFREE(mask);
65 }
66 if (seed != NULL) {
67 XFREE(seed);
68 }
69 return CRYPT_MEM;
70 }
71
72 /* ok so it's now in the form
73
74 0x00 || maskedseed || maskedDB
75
76 1 || hLen || modulus_len - hLen - 1
77
78 */
79
80 ret = CRYPT_OK;
81
82 /* must have leading 0x00 byte */
83 if (msg[0] != 0x00) {
84 ret = CRYPT_INVALID_PACKET;
85 }
86
87 /* now read the masked seed */
88 x = 1;
89 XMEMCPY(seed, msg + x, hLen);
90 x += hLen;
91
92 /* now read the masked DB */
93 XMEMCPY(DB, msg + x, modulus_len - hLen - 1);
94 x += modulus_len - hLen - 1;
95
96 /* compute MGF1 of maskedDB (hLen) */
97 if ((err = pkcs_1_mgf1(hash_idx, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) {
98 goto LBL_ERR;
99 }
100
101 /* XOR against seed */
102 for (y = 0; y < hLen; y++) {
103 seed[y] ^= mask[y];
104 }
105
106 /* compute MGF1 of seed (k - hlen - 1) */
107 if ((err = pkcs_1_mgf1(hash_idx, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
108 goto LBL_ERR;
109 }
110
111 /* xor against DB */
112 for (y = 0; y < (modulus_len - hLen - 1); y++) {
113 DB[y] ^= mask[y];
114 }
115
116 /* now DB == lhash || PS || 0x01 || M, PS == k - mlen - 2hlen - 2 zeroes */
117
118 /* compute lhash and store it in seed [reuse temps!] */
119 x = modulus_len;
120 if (lparam != NULL) {
121 if ((err = hash_memory(hash_idx, lparam, lparamlen, seed, &x)) != CRYPT_OK) {
122 goto LBL_ERR;
123 }
124 } else {
125 /* can't pass hash_memory a NULL so use DB with zero length */
126 if ((err = hash_memory(hash_idx, DB, 0, seed, &x)) != CRYPT_OK) {
127 goto LBL_ERR;
128 }
129 }
130
131 /* compare the lhash'es */
132 if (XMEM_NEQ(seed, DB, hLen) != 0) {
133 ret = CRYPT_INVALID_PACKET;
134 }
135
136 /* now zeroes before a 0x01 */
137 for (x = hLen; x < (modulus_len - hLen - 1) && DB[x] == 0x00; x++) {
138 /* step... */
139 }
140
141 /* error if wasn't 0x01 */
142 if (x == (modulus_len - hLen - 1) || DB[x] != 0x01) {
143 ret = CRYPT_INVALID_PACKET;
144 }
145
146 /* rest is the message (and skip 0x01) */
147 if ((modulus_len - hLen - 1 - ++x) > *outlen) {
148 ret = CRYPT_INVALID_PACKET;
149 }
150
151 if (ret == CRYPT_OK) {
152 /* copy message */
153 *outlen = modulus_len - hLen - 1 - x;
154 XMEMCPY(out, DB + x, modulus_len - hLen - 1 - x);
155
156 /* valid packet */
157 *res = 1;
158 }
159 err = ret;
160
161 LBL_ERR:
162 #ifdef LTC_CLEAN_STACK
163 zeromem(DB, modulus_len);
164 zeromem(seed, hLen);
165 zeromem(mask, modulus_len);
166 #endif
167
168 XFREE(seed);
169 XFREE(mask);
170 XFREE(DB);
171
172 return err;
173 }
174
175 #endif /* LTC_PKCS_1 */
176