1 /*
2 * OAEP
3 * (C) 1999-2010,2015,2018 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/oaep.h>
9 #include <botan/mgf1.h>
10 #include <botan/exceptn.h>
11 #include <botan/rng.h>
12 #include <botan/internal/ct_utils.h>
13 
14 namespace Botan {
15 
16 /*
17 * OAEP Pad Operation
18 */
pad(const uint8_t in[],size_t in_length,size_t key_length,RandomNumberGenerator & rng) const19 secure_vector<uint8_t> OAEP::pad(const uint8_t in[], size_t in_length,
20                              size_t key_length,
21                              RandomNumberGenerator& rng) const
22    {
23    key_length /= 8;
24 
25    if(in_length > maximum_input_size(key_length * 8))
26       {
27       throw Invalid_Argument("OAEP: Input is too large");
28       }
29 
30    secure_vector<uint8_t> out(key_length);
31 
32    rng.randomize(out.data(), m_Phash.size());
33 
34    buffer_insert(out, m_Phash.size(), m_Phash.data(), m_Phash.size());
35    out[out.size() - in_length - 1] = 0x01;
36    buffer_insert(out, out.size() - in_length, in, in_length);
37 
38    mgf1_mask(*m_mgf1_hash,
39              out.data(), m_Phash.size(),
40              &out[m_Phash.size()], out.size() - m_Phash.size());
41 
42    mgf1_mask(*m_mgf1_hash,
43              &out[m_Phash.size()], out.size() - m_Phash.size(),
44              out.data(), m_Phash.size());
45 
46    return out;
47    }
48 
49 /*
50 * OAEP Unpad Operation
51 */
unpad(uint8_t & valid_mask,const uint8_t in[],size_t in_length) const52 secure_vector<uint8_t> OAEP::unpad(uint8_t& valid_mask,
53                                    const uint8_t in[], size_t in_length) const
54    {
55    /*
56    Must be careful about error messages here; if an attacker can
57    distinguish them, it is easy to use the differences as an oracle to
58    find the secret key, as described in "A Chosen Ciphertext Attack on
59    RSA Optimal Asymmetric Encryption Padding (OAEP) as Standardized in
60    PKCS #1 v2.0", James Manger, Crypto 2001
61 
62    Also have to be careful about timing attacks! Pointed out by Falko
63    Strenzke.
64 
65    According to the standard (Section 7.1.1), the encryptor always
66    creates a message as follows:
67       i. Concatenate a single octet with hexadecimal value 0x00,
68          maskedSeed, and maskedDB to form an encoded message EM of
69          length k octets as
70             EM = 0x00 || maskedSeed || maskedDB.
71    where k is the length of the modulus N.
72    Therefore, the first byte can always be skipped safely.
73    */
74 
75    const auto leading_0 = CT::Mask<uint8_t>::is_zero(in[0]);
76 
77    secure_vector<uint8_t> input(in + 1, in + in_length);
78 
79    const size_t hlen = m_Phash.size();
80 
81    mgf1_mask(*m_mgf1_hash,
82              &input[hlen], input.size() - hlen,
83              input.data(), hlen);
84 
85    mgf1_mask(*m_mgf1_hash,
86              input.data(), hlen,
87              &input[hlen], input.size() - hlen);
88 
89    auto unpadded = oaep_find_delim(valid_mask, input.data(), input.size(), m_Phash);
90    valid_mask &= leading_0.unpoisoned_value();
91    return unpadded;
92    }
93 
94 secure_vector<uint8_t>
oaep_find_delim(uint8_t & valid_mask,const uint8_t input[],size_t input_len,const secure_vector<uint8_t> & Phash)95 oaep_find_delim(uint8_t& valid_mask,
96                 const uint8_t input[], size_t input_len,
97                 const secure_vector<uint8_t>& Phash)
98    {
99    const size_t hlen = Phash.size();
100 
101    // Too short to be valid, reject immediately
102    if(input_len < 1 + 2*hlen)
103       {
104       return secure_vector<uint8_t>();
105       }
106 
107    CT::poison(input, input_len);
108 
109    size_t delim_idx = 2 * hlen;
110    CT::Mask<uint8_t> waiting_for_delim = CT::Mask<uint8_t>::set();
111    CT::Mask<uint8_t> bad_input_m = CT::Mask<uint8_t>::cleared();
112 
113    for(size_t i = delim_idx; i < input_len; ++i)
114       {
115       const auto zero_m = CT::Mask<uint8_t>::is_zero(input[i]);
116       const auto one_m = CT::Mask<uint8_t>::is_equal(input[i], 1);
117 
118       const auto add_m = waiting_for_delim & zero_m;
119 
120       bad_input_m |= waiting_for_delim & ~(zero_m | one_m);
121 
122       delim_idx += add_m.if_set_return(1);
123 
124       waiting_for_delim &= zero_m;
125       }
126 
127    // If we never saw any non-zero byte, then it's not valid input
128    bad_input_m |= waiting_for_delim;
129    bad_input_m |= CT::Mask<uint8_t>::is_zero(ct_compare_u8(&input[hlen], Phash.data(), hlen));
130 
131    delim_idx += 1;
132 
133    valid_mask = (~bad_input_m).unpoisoned_value();
134    const secure_vector<uint8_t> output = CT::copy_output(bad_input_m, input, input_len, delim_idx);
135 
136    CT::unpoison(input, input_len);
137 
138    return output;
139    }
140 
141 /*
142 * Return the max input size for a given key size
143 */
maximum_input_size(size_t keybits) const144 size_t OAEP::maximum_input_size(size_t keybits) const
145    {
146    if(keybits / 8 > 2*m_Phash.size() + 1)
147       return ((keybits / 8) - 2*m_Phash.size() - 1);
148    else
149       return 0;
150    }
151 
152 /*
153 * OAEP Constructor
154 */
OAEP(HashFunction * hash,const std::string & P)155 OAEP::OAEP(HashFunction* hash, const std::string& P) : m_mgf1_hash(hash)
156    {
157    m_Phash = m_mgf1_hash->process(P);
158    }
159 
OAEP(HashFunction * hash,HashFunction * mgf1_hash,const std::string & P)160 OAEP::OAEP(HashFunction* hash,
161            HashFunction* mgf1_hash,
162            const std::string& P) : m_mgf1_hash(mgf1_hash)
163    {
164    std::unique_ptr<HashFunction> phash(hash); // takes ownership
165    m_Phash = phash->process(P);
166    }
167 
168 }
169