Botan  2.19.1
Crypto and TLS for C++11
oaep.cpp
Go to the documentation of this file.
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 */
19 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 */
52 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>
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();
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 */
144 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 */
155 OAEP::OAEP(HashFunction* hash, const std::string& P) : m_mgf1_hash(hash)
156  {
157  m_Phash = m_mgf1_hash->process(P);
158  }
159 
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 }
static Mask< T > cleared()
Definition: ct_utils.h:115
void poison(const T *p, size_t n)
Definition: ct_utils.h:48
T if_set_return(T x) const
Definition: ct_utils.h:272
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:65
uint8_t ct_compare_u8(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.cpp:56
secure_vector< uint8_t > copy_output(CT::Mask< uint8_t > bad_input, const uint8_t input[], size_t input_length, size_t offset)
Definition: ct_utils.cpp:13
Definition: alg_id.cpp:13
size_t buffer_insert(std::vector< T, Alloc > &buf, size_t buf_offset, const T input[], size_t input_length)
Definition: mem_ops.h:228
OAEP(HashFunction *hash, const std::string &P="")
Definition: oaep.cpp:155
void unpoison(const T *p, size_t n)
Definition: ct_utils.h:59
static Mask< T > set()
Definition: ct_utils.h:107
void mgf1_mask(HashFunction &hash, const uint8_t in[], size_t in_len, uint8_t out[], size_t out_len)
Definition: mgf1.cpp:14
size_t maximum_input_size(size_t) const override
Definition: oaep.cpp:144
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)
Definition: oaep.cpp:95
static Mask< T > is_zero(T x)
Definition: ct_utils.h:141
static Mask< T > is_equal(T x, T y)
Definition: ct_utils.h:149
MechanismType hash