Botan 3.1.1
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
15namespace Botan {
16
17/*
18* OAEP Pad Operation
19*/
20secure_vector<uint8_t> OAEP::pad(const uint8_t in[],
21 size_t in_length,
22 size_t key_length,
23 RandomNumberGenerator& rng) const {
24 key_length /= 8;
25
26 if(in_length > maximum_input_size(key_length * 8)) {
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, out.data(), m_Phash.size(), &out[m_Phash.size()], out.size() - m_Phash.size());
39
40 mgf1_mask(*m_mgf1_hash, &out[m_Phash.size()], out.size() - m_Phash.size(), out.data(), m_Phash.size());
41
42 return out;
43}
44
45/*
46* OAEP Unpad Operation
47*/
48secure_vector<uint8_t> OAEP::unpad(uint8_t& valid_mask, const uint8_t in[], size_t in_length) const {
49 /*
50 Must be careful about error messages here; if an attacker can
51 distinguish them, it is easy to use the differences as an oracle to
52 find the secret key, as described in "A Chosen Ciphertext Attack on
53 RSA Optimal Asymmetric Encryption Padding (OAEP) as Standardized in
54 PKCS #1 v2.0", James Manger, Crypto 2001
55
56 Also have to be careful about timing attacks! Pointed out by Falko
57 Strenzke.
58
59 According to the standard (RFC 3447 Section 7.1.1), the encryptor always
60 creates a message as follows:
61 i. Concatenate a single octet with hexadecimal value 0x00,
62 maskedSeed, and maskedDB to form an encoded message EM of
63 length k octets as
64 EM = 0x00 || maskedSeed || maskedDB.
65 where k is the length of the modulus N.
66 Therefore, the first byte should always be zero.
67 */
68
69 const auto leading_0 = CT::Mask<uint8_t>::is_zero(in[0]);
70
71 secure_vector<uint8_t> input(in + 1, in + in_length);
72
73 const size_t hlen = m_Phash.size();
74
75 mgf1_mask(*m_mgf1_hash, &input[hlen], input.size() - hlen, input.data(), hlen);
76
77 mgf1_mask(*m_mgf1_hash, input.data(), hlen, &input[hlen], input.size() - hlen);
78
79 auto unpadded = oaep_find_delim(valid_mask, input.data(), input.size(), m_Phash);
80 valid_mask &= leading_0.unpoisoned_value();
81 return unpadded;
82}
83
85 const uint8_t input[],
86 size_t input_len,
87 const secure_vector<uint8_t>& Phash) {
88 const size_t hlen = Phash.size();
89
90 // Too short to be valid, reject immediately
91 if(input_len < 1 + 2 * hlen) {
93 }
94
95 CT::poison(input, input_len);
96
97 size_t delim_idx = 2 * hlen;
98 CT::Mask<uint8_t> waiting_for_delim = CT::Mask<uint8_t>::set();
100
101 for(size_t i = delim_idx; i < input_len; ++i) {
102 const auto zero_m = CT::Mask<uint8_t>::is_zero(input[i]);
103 const auto one_m = CT::Mask<uint8_t>::is_equal(input[i], 1);
104
105 const auto add_m = waiting_for_delim & zero_m;
106
107 bad_input_m |= waiting_for_delim & ~(zero_m | one_m);
108
109 delim_idx += add_m.if_set_return(1);
110
111 waiting_for_delim &= zero_m;
112 }
113
114 // If we never saw any non-zero byte, then it's not valid input
115 bad_input_m |= waiting_for_delim;
116 bad_input_m |= CT::Mask<uint8_t>::is_zero(ct_compare_u8(&input[hlen], Phash.data(), hlen));
117
118 delim_idx += 1;
119
120 valid_mask = (~bad_input_m).unpoisoned_value();
121 auto output = CT::copy_output(bad_input_m, input, input_len, delim_idx);
122
123 CT::unpoison(input, input_len);
124
125 return output;
126}
127
128/*
129* Return the max input size for a given key size
130*/
131size_t OAEP::maximum_input_size(size_t keybits) const {
132 if(keybits / 8 > 2 * m_Phash.size() + 1) {
133 return ((keybits / 8) - 2 * m_Phash.size() - 1);
134 } else {
135 return 0;
136 }
137}
138
139OAEP::OAEP(std::unique_ptr<HashFunction> hash, std::string_view P) : m_mgf1_hash(std::move(hash)) {
140 m_Phash = m_mgf1_hash->process(P);
141}
142
143OAEP::OAEP(std::unique_ptr<HashFunction> hash, std::unique_ptr<HashFunction> mgf1_hash, std::string_view P) :
144 m_mgf1_hash(std::move(mgf1_hash)) {
145 auto phash = std::move(hash);
146 m_Phash = phash->process(P);
147}
148
149} // namespace Botan
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
T if_set_return(T x) const
Definition: ct_utils.h:218
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:139
size_t maximum_input_size(size_t) const override
Definition: oaep.cpp:131
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:57
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:15
size_t buffer_insert(std::vector< T, Alloc > &buf, size_t buf_offset, const T input[], size_t input_length)
Definition: mem_ops.h:211
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:84
uint8_t ct_compare_u8(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.cpp:70
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:61
Definition: bigint.h:1030