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