Botan 3.0.0-alpha0
Crypto and TLS for C&
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/internal/oaep.h>
9#include <botan/internal/mgf1.h>
10#include <botan/exceptn.h>
11#include <botan/rng.h>
12#include <botan/internal/ct_utils.h>
13
14namespace Botan {
15
16/*
17* OAEP Pad Operation
18*/
19secure_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*/
52secure_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 (RFC 3447 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 should always be zero.
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
94secure_vector<uint8_t>
95oaep_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 auto 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*/
144size_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
152OAEP::OAEP(std::unique_ptr<HashFunction> hash,
153 const std::string& P) :
154 m_mgf1_hash(std::move(hash))
155 {
156 m_Phash = m_mgf1_hash->process(P);
157 }
158
159OAEP::OAEP(std::unique_ptr<HashFunction> hash,
160 std::unique_ptr<HashFunction> mgf1_hash,
161 const std::string& P) :
162 m_mgf1_hash(std::move(mgf1_hash))
163 {
164 auto phash = std::move(hash);
165 m_Phash = phash->process(P);
166 }
167
168}
static Mask< T > is_equal(T x, T y)
Definition: ct_utils.h:147
static Mask< T > is_zero(T x)
Definition: ct_utils.h:139
T if_set_return(T x) const
Definition: ct_utils.h:270
static Mask< T > set()
Definition: ct_utils.h:105
static Mask< T > cleared()
Definition: ct_utils.h:113
size_t maximum_input_size(size_t) const override
Definition: oaep.cpp:144
OAEP(std::unique_ptr< HashFunction > hash, const std::string &P="")
Definition: oaep.cpp:152
void poison(const T *p, size_t n)
Definition: ct_utils.h:48
secure_vector< uint8_t > copy_output(CT::Mask< uint8_t > bad_input_u8, const uint8_t input[], size_t input_length, size_t offset)
Definition: ct_utils.cpp:11
void unpoison(const T *p, size_t n)
Definition: ct_utils.h:58
Definition: alg_id.cpp:13
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 buffer_insert(std::vector< T, Alloc > &buf, size_t buf_offset, const T input[], size_t input_length)
Definition: mem_ops.h:221
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
uint8_t ct_compare_u8(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.cpp:65
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:65
Definition: bigint.h:1077
MechanismType hash