Botan  2.7.0
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  uint8_t skip_first = CT::is_zero<uint8_t>(in[0]) & 0x01;
76 
77  secure_vector<uint8_t> input(in + skip_first, in + in_length);
78 
79  CT::poison(input.data(), input.size());
80 
81  const size_t hlen = m_Phash.size();
82 
83  mgf1_mask(*m_mgf1_hash,
84  &input[hlen], input.size() - hlen,
85  input.data(), hlen);
86 
87  mgf1_mask(*m_mgf1_hash,
88  input.data(), hlen,
89  &input[hlen], input.size() - hlen);
90 
91  size_t delim_idx = 2 * hlen;
92  uint8_t waiting_for_delim = 0xFF;
93  uint8_t bad_input = 0;
94 
95  for(size_t i = delim_idx; i < input.size(); ++i)
96  {
97  const uint8_t zero_m = CT::is_zero<uint8_t>(input[i]);
98  const uint8_t one_m = CT::is_equal<uint8_t>(input[i], 1);
99 
100  const uint8_t add_m = waiting_for_delim & zero_m;
101 
102  bad_input |= waiting_for_delim & ~(zero_m | one_m);
103 
104  delim_idx += CT::select<uint8_t>(add_m, 1, 0);
105 
106  waiting_for_delim &= zero_m;
107  }
108 
109  // If we never saw any non-zero byte, then it's not valid input
110  bad_input |= waiting_for_delim;
111  bad_input |= CT::is_equal<uint8_t>(constant_time_compare(&input[hlen], m_Phash.data(), hlen), false);
112 
113  CT::unpoison(input.data(), input.size());
114  CT::unpoison(&bad_input, 1);
115  CT::unpoison(&delim_idx, 1);
116 
117  valid_mask = ~bad_input;
118 
119  secure_vector<uint8_t> output(input.begin() + delim_idx + 1, input.end());
120  CT::cond_zero_mem(bad_input, output.data(), output.size());
121 
122  return output;
123  }
124 
125 /*
126 * Return the max input size for a given key size
127 */
128 size_t OAEP::maximum_input_size(size_t keybits) const
129  {
130  if(keybits / 8 > 2*m_Phash.size() + 1)
131  return ((keybits / 8) - 2*m_Phash.size() - 1);
132  else
133  return 0;
134  }
135 
136 /*
137 * OAEP Constructor
138 */
139 OAEP::OAEP(HashFunction* hash, const std::string& P) : m_mgf1_hash(hash)
140  {
141  m_Phash = m_mgf1_hash->process(P);
142  }
143 
145  HashFunction* mgf1_hash,
146  const std::string& P) : m_mgf1_hash(mgf1_hash)
147  {
148  std::unique_ptr<HashFunction> phash(hash); // takes ownership
149  m_Phash = phash->process(P);
150  }
151 
152 }
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.cpp:51
void poison(const T *p, size_t n)
Definition: ct_utils.h:46
void cond_zero_mem(T cond, T *array, size_t elems)
Definition: ct_utils.h:171
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: secmem.h:103
OAEP(HashFunction *hash, const std::string &P="")
Definition: oaep.cpp:139
void unpoison(const T *p, size_t n)
Definition: ct_utils.h:57
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:128
MechanismType hash