Coverage Report

Created: 2020-08-01 06:18

/src/botan/src/lib/pk_pad/eme_oaep/oaep.cpp
Line
Count
Source (jump to first uncovered line)
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
0
   {
23
0
   key_length /= 8;
24
0
25
0
   if(in_length > maximum_input_size(key_length * 8))
26
0
      {
27
0
      throw Invalid_Argument("OAEP: Input is too large");
28
0
      }
29
0
30
0
   secure_vector<uint8_t> out(key_length);
31
0
32
0
   rng.randomize(out.data(), m_Phash.size());
33
0
34
0
   buffer_insert(out, m_Phash.size(), m_Phash.data(), m_Phash.size());
35
0
   out[out.size() - in_length - 1] = 0x01;
36
0
   buffer_insert(out, out.size() - in_length, in, in_length);
37
0
38
0
   mgf1_mask(*m_mgf1_hash,
39
0
             out.data(), m_Phash.size(),
40
0
             &out[m_Phash.size()], out.size() - m_Phash.size());
41
0
42
0
   mgf1_mask(*m_mgf1_hash,
43
0
             &out[m_Phash.size()], out.size() - m_Phash.size(),
44
0
             out.data(), m_Phash.size());
45
0
46
0
   return out;
47
0
   }
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
0
   {
55
0
   /*
56
0
   Must be careful about error messages here; if an attacker can
57
0
   distinguish them, it is easy to use the differences as an oracle to
58
0
   find the secret key, as described in "A Chosen Ciphertext Attack on
59
0
   RSA Optimal Asymmetric Encryption Padding (OAEP) as Standardized in
60
0
   PKCS #1 v2.0", James Manger, Crypto 2001
61
0
62
0
   Also have to be careful about timing attacks! Pointed out by Falko
63
0
   Strenzke.
64
0
65
0
   According to the standard (Section 7.1.1), the encryptor always
66
0
   creates a message as follows:
67
0
      i. Concatenate a single octet with hexadecimal value 0x00,
68
0
         maskedSeed, and maskedDB to form an encoded message EM of
69
0
         length k octets as
70
0
            EM = 0x00 || maskedSeed || maskedDB.
71
0
   where k is the length of the modulus N.
72
0
   Therefore, the first byte can always be skipped safely.
73
0
   */
74
0
75
0
   const uint8_t skip_first = CT::Mask<uint8_t>::is_zero(in[0]).if_set_return(1);
76
0
77
0
   secure_vector<uint8_t> input(in + skip_first, in + in_length);
78
0
79
0
   const size_t hlen = m_Phash.size();
80
0
81
0
   mgf1_mask(*m_mgf1_hash,
82
0
             &input[hlen], input.size() - hlen,
83
0
             input.data(), hlen);
84
0
85
0
   mgf1_mask(*m_mgf1_hash,
86
0
             input.data(), hlen,
87
0
             &input[hlen], input.size() - hlen);
88
0
89
0
   return oaep_find_delim(valid_mask, input.data(), input.size(), m_Phash);
90
0
   }
91
92
secure_vector<uint8_t>
93
oaep_find_delim(uint8_t& valid_mask,
94
                const uint8_t input[], size_t input_len,
95
                const secure_vector<uint8_t>& Phash)
96
214
   {
97
214
   const size_t hlen = Phash.size();
98
214
99
214
   // Too short to be valid, reject immediately
100
214
   if(input_len < 1 + 2*hlen)
101
6
      {
102
6
      return secure_vector<uint8_t>();
103
6
      }
104
208
105
208
   CT::poison(input, input_len);
106
208
107
208
   size_t delim_idx = 2 * hlen;
108
208
   CT::Mask<uint8_t> waiting_for_delim = CT::Mask<uint8_t>::set();
109
208
   CT::Mask<uint8_t> bad_input_m = CT::Mask<uint8_t>::cleared();
110
208
111
194k
   for(size_t i = delim_idx; i < input_len; ++i)
112
194k
      {
113
194k
      const auto zero_m = CT::Mask<uint8_t>::is_zero(input[i]);
114
194k
      const auto one_m = CT::Mask<uint8_t>::is_equal(input[i], 1);
115
194k
116
194k
      const auto add_m = waiting_for_delim & zero_m;
117
194k
118
194k
      bad_input_m |= waiting_for_delim & ~(zero_m | one_m);
119
194k
120
194k
      delim_idx += add_m.if_set_return(1);
121
194k
122
194k
      waiting_for_delim &= zero_m;
123
194k
      }
124
208
125
208
   // If we never saw any non-zero byte, then it's not valid input
126
208
   bad_input_m |= waiting_for_delim;
127
208
   bad_input_m |= CT::Mask<uint8_t>::is_zero(ct_compare_u8(&input[hlen], Phash.data(), hlen));
128
208
129
208
   delim_idx += 1;
130
208
131
208
   valid_mask = (~bad_input_m).unpoisoned_value();
132
208
   const secure_vector<uint8_t> output = CT::copy_output(bad_input_m, input, input_len, delim_idx);
133
208
134
208
   CT::unpoison(input, input_len);
135
208
136
208
   return output;
137
208
   }
138
139
/*
140
* Return the max input size for a given key size
141
*/
142
size_t OAEP::maximum_input_size(size_t keybits) const
143
0
   {
144
0
   if(keybits / 8 > 2*m_Phash.size() + 1)
145
0
      return ((keybits / 8) - 2*m_Phash.size() - 1);
146
0
   else
147
0
      return 0;
148
0
   }
149
150
/*
151
* OAEP Constructor
152
*/
153
OAEP::OAEP(HashFunction* hash, const std::string& P) : m_mgf1_hash(hash)
154
0
   {
155
0
   m_Phash = m_mgf1_hash->process(P);
156
0
   }
157
158
OAEP::OAEP(HashFunction* hash,
159
           HashFunction* mgf1_hash,
160
           const std::string& P) : m_mgf1_hash(mgf1_hash)
161
0
   {
162
0
   std::unique_ptr<HashFunction> phash(hash); // takes ownership
163
0
   m_Phash = phash->process(P);
164
0
   }
165
166
}