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