Coverage Report

Created: 2020-10-17 06:46

/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
   /*
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
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
221
   {
97
221
   const size_t hlen = Phash.size();
98
221
99
   // Too short to be valid, reject immediately
100
221
   if(input_len < 1 + 2*hlen)
101
6
      {
102
6
      return secure_vector<uint8_t>();
103
6
      }
104
215
105
215
   CT::poison(input, input_len);
106
215
107
215
   size_t delim_idx = 2 * hlen;
108
215
   CT::Mask<uint8_t> waiting_for_delim = CT::Mask<uint8_t>::set();
109
215
   CT::Mask<uint8_t> bad_input_m = CT::Mask<uint8_t>::cleared();
110
215
111
202k
   for(size_t i = delim_idx; i < input_len; ++i)
112
202k
      {
113
202k
      const auto zero_m = CT::Mask<uint8_t>::is_zero(input[i]);
114
202k
      const auto one_m = CT::Mask<uint8_t>::is_equal(input[i], 1);
115
202k
116
202k
      const auto add_m = waiting_for_delim & zero_m;
117
202k
118
202k
      bad_input_m |= waiting_for_delim & ~(zero_m | one_m);
119
202k
120
202k
      delim_idx += add_m.if_set_return(1);
121
202k
122
202k
      waiting_for_delim &= zero_m;
123
202k
      }
124
215
125
   // If we never saw any non-zero byte, then it's not valid input
126
215
   bad_input_m |= waiting_for_delim;
127
215
   bad_input_m |= CT::Mask<uint8_t>::is_zero(ct_compare_u8(&input[hlen], Phash.data(), hlen));
128
215
129
215
   delim_idx += 1;
130
215
131
215
   valid_mask = (~bad_input_m).unpoisoned_value();
132
215
   const secure_vector<uint8_t> output = CT::copy_output(bad_input_m, input, input_len, delim_idx);
133
215
134
215
   CT::unpoison(input, input_len);
135
215
136
215
   return output;
137
215
   }
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
}