Botan 3.3.0
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
10#include <botan/exceptn.h>
11#include <botan/rng.h>
12#include <botan/internal/ct_utils.h>
13#include <botan/internal/mgf1.h>
14#include <botan/internal/stl_util.h>
15
16namespace Botan {
17
18/*
19* OAEP Pad Operation
20*/
21secure_vector<uint8_t> OAEP::pad(const uint8_t in[],
22 size_t in_length,
23 size_t key_length,
24 RandomNumberGenerator& rng) const {
25 key_length /= 8;
26
27 if(in_length > maximum_input_size(key_length * 8)) {
28 throw Invalid_Argument("OAEP: Input is too large");
29 }
30
31 secure_vector<uint8_t> out(key_length);
32 BufferStuffer stuffer(out);
33
34 // We always use a seed len equal to the underlying hash
35 rng.randomize(stuffer.next(m_Phash.size()));
36 stuffer.append(m_Phash);
37 stuffer.append(0x00, stuffer.remaining_capacity() - (1 + in_length));
38 stuffer.append(0x01);
39 stuffer.append({in, in_length});
40 BOTAN_ASSERT_NOMSG(stuffer.full());
41
42 mgf1_mask(*m_mgf1_hash, out.data(), m_Phash.size(), &out[m_Phash.size()], out.size() - m_Phash.size());
43
44 mgf1_mask(*m_mgf1_hash, &out[m_Phash.size()], out.size() - m_Phash.size(), 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, const uint8_t in[], size_t in_length) const {
53 /*
54 Must be careful about error messages here; if an attacker can
55 distinguish them, it is easy to use the differences as an oracle to
56 find the secret key, as described in "A Chosen Ciphertext Attack on
57 RSA Optimal Asymmetric Encryption Padding (OAEP) as Standardized in
58 PKCS #1 v2.0", James Manger, Crypto 2001
59
60 Also have to be careful about timing attacks! Pointed out by Falko
61 Strenzke.
62
63 According to the standard (RFC 3447 Section 7.1.1), the encryptor always
64 creates a message as follows:
65 i. Concatenate a single octet with hexadecimal value 0x00,
66 maskedSeed, and maskedDB to form an encoded message EM of
67 length k octets as
68 EM = 0x00 || maskedSeed || maskedDB.
69 where k is the length of the modulus N.
70 Therefore, the first byte should always be zero.
71 */
72
73 const auto leading_0 = CT::Mask<uint8_t>::is_zero(in[0]);
74
75 secure_vector<uint8_t> input(in + 1, in + in_length);
76
77 const size_t hlen = m_Phash.size();
78
79 mgf1_mask(*m_mgf1_hash, &input[hlen], input.size() - hlen, input.data(), hlen);
80
81 mgf1_mask(*m_mgf1_hash, input.data(), hlen, &input[hlen], input.size() - hlen);
82
83 auto unpadded = oaep_find_delim(valid_mask, input.data(), input.size(), m_Phash);
84 valid_mask &= leading_0.unpoisoned_value();
85 return unpadded;
86}
87
89 const uint8_t input[],
90 size_t input_len,
91 const secure_vector<uint8_t>& Phash) {
92 const size_t hlen = Phash.size();
93
94 // Too short to be valid, reject immediately
95 if(input_len < 1 + 2 * hlen) {
97 }
98
99 CT::poison(input, input_len);
100
101 size_t delim_idx = 2 * hlen;
102 CT::Mask<uint8_t> waiting_for_delim = CT::Mask<uint8_t>::set();
104
105 for(size_t i = delim_idx; i < input_len; ++i) {
106 const auto zero_m = CT::Mask<uint8_t>::is_zero(input[i]);
107 const auto one_m = CT::Mask<uint8_t>::is_equal(input[i], 1);
108
109 const auto add_m = waiting_for_delim & zero_m;
110
111 bad_input_m |= waiting_for_delim & ~(zero_m | one_m);
112
113 delim_idx += add_m.if_set_return(1);
114
115 waiting_for_delim &= zero_m;
116 }
117
118 // If we never saw any non-zero byte, then it's not valid input
119 bad_input_m |= waiting_for_delim;
120
121 // If the P hash is wrong, then it's not valid
122 bad_input_m |= CT::is_not_equal(&input[hlen], Phash.data(), hlen);
123
124 delim_idx += 1;
125
126 valid_mask = (~bad_input_m).unpoisoned_value();
127 auto output = CT::copy_output(bad_input_m, input, input_len, delim_idx);
128
129 CT::unpoison(input, input_len);
130
131 return output;
132}
133
134/*
135* Return the max input size for a given key size
136*/
137size_t OAEP::maximum_input_size(size_t keybits) const {
138 if(keybits / 8 > 2 * m_Phash.size() + 1) {
139 return ((keybits / 8) - 2 * m_Phash.size() - 1);
140 } else {
141 return 0;
142 }
143}
144
145OAEP::OAEP(std::unique_ptr<HashFunction> hash, std::string_view P) : m_mgf1_hash(std::move(hash)) {
146 m_Phash = m_mgf1_hash->process(P);
147}
148
149OAEP::OAEP(std::unique_ptr<HashFunction> hash, std::unique_ptr<HashFunction> mgf1_hash, std::string_view P) :
150 m_mgf1_hash(std::move(mgf1_hash)) {
151 auto phash = std::move(hash);
152 m_Phash = phash->process(P);
153}
154
155} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
static Mask< T > is_equal(T x, T y)
Definition ct_utils.h:128
static Mask< T > is_zero(T x)
Definition ct_utils.h:123
static Mask< T > set()
Definition ct_utils.h:99
static Mask< T > cleared()
Definition ct_utils.h:104
OAEP(std::unique_ptr< HashFunction > hash, std::string_view P="")
Definition oaep.cpp:145
size_t maximum_input_size(size_t) const override
Definition oaep.cpp:137
void poison(const T *p, size_t n)
Definition ct_utils.h:46
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:55
CT::Mask< T > is_not_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:354
void mgf1_mask(HashFunction &hash, const uint8_t in[], size_t in_len, uint8_t out[], size_t out_len)
Definition mgf1.cpp:15
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:88
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61