Botan  2.11.0
Crypto and TLS for C++11
pssr.cpp
Go to the documentation of this file.
1 /*
2 * PSSR
3 * (C) 1999-2007,2017 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/pssr.h>
9 #include <botan/exceptn.h>
10 #include <botan/rng.h>
11 #include <botan/mgf1.h>
12 #include <botan/internal/bit_ops.h>
13 #include <botan/oids.h>
14 #include <botan/der_enc.h>
15 #include <botan/pk_keys.h>
16 #include <botan/internal/padding.h>
17 
18 namespace Botan {
19 
20 namespace {
21 
22 /*
23 * PSSR Encode Operation
24 */
25 secure_vector<uint8_t> pss_encode(HashFunction& hash,
26  const secure_vector<uint8_t>& msg,
27  const secure_vector<uint8_t>& salt,
28  size_t output_bits)
29  {
30  const size_t HASH_SIZE = hash.output_length();
31  const size_t SALT_SIZE = salt.size();
32 
33  if(msg.size() != HASH_SIZE)
34  throw Encoding_Error("Cannot encode PSS string, input length invalid for hash");
35  if(output_bits < 8*HASH_SIZE + 8*SALT_SIZE + 9)
36  throw Encoding_Error("Cannot encode PSS string, output length too small");
37 
38  const size_t output_length = (output_bits + 7) / 8;
39 
40  for(size_t i = 0; i != 8; ++i)
41  hash.update(0);
42  hash.update(msg);
43  hash.update(salt);
44  secure_vector<uint8_t> H = hash.final();
45 
46  secure_vector<uint8_t> EM(output_length);
47 
48  EM[output_length - HASH_SIZE - SALT_SIZE - 2] = 0x01;
49  buffer_insert(EM, output_length - 1 - HASH_SIZE - SALT_SIZE, salt);
50  mgf1_mask(hash, H.data(), HASH_SIZE, EM.data(), output_length - HASH_SIZE - 1);
51  EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits);
52  buffer_insert(EM, output_length - 1 - HASH_SIZE, H);
53  EM[output_length-1] = 0xBC;
54  return EM;
55  }
56 
57 bool pss_verify(HashFunction& hash,
58  const secure_vector<uint8_t>& pss_repr,
59  const secure_vector<uint8_t>& message_hash,
60  size_t key_bits,
61  size_t* out_salt_size)
62  {
63  const size_t HASH_SIZE = hash.output_length();
64  const size_t KEY_BYTES = (key_bits + 7) / 8;
65 
66  if(key_bits < 8*HASH_SIZE + 9)
67  return false;
68 
69  if(message_hash.size() != HASH_SIZE)
70  return false;
71 
72  if(pss_repr.size() > KEY_BYTES || pss_repr.size() <= 1)
73  return false;
74 
75  if(pss_repr[pss_repr.size()-1] != 0xBC)
76  return false;
77 
78  secure_vector<uint8_t> coded = pss_repr;
79  if(coded.size() < KEY_BYTES)
80  {
81  secure_vector<uint8_t> temp(KEY_BYTES);
82  buffer_insert(temp, KEY_BYTES - coded.size(), coded);
83  coded = temp;
84  }
85 
86  const size_t TOP_BITS = 8 * ((key_bits + 7) / 8) - key_bits;
87  if(TOP_BITS > 8 - high_bit(coded[0]))
88  return false;
89 
90  uint8_t* DB = coded.data();
91  const size_t DB_size = coded.size() - HASH_SIZE - 1;
92 
93  const uint8_t* H = &coded[DB_size];
94  const size_t H_size = HASH_SIZE;
95 
96  mgf1_mask(hash, H, H_size, DB, DB_size);
97  DB[0] &= 0xFF >> TOP_BITS;
98 
99  size_t salt_offset = 0;
100  for(size_t j = 0; j != DB_size; ++j)
101  {
102  if(DB[j] == 0x01)
103  { salt_offset = j + 1; break; }
104  if(DB[j])
105  return false;
106  }
107  if(salt_offset == 0)
108  return false;
109 
110  const size_t salt_size = DB_size - salt_offset;
111 
112  for(size_t j = 0; j != 8; ++j)
113  hash.update(0);
114  hash.update(message_hash);
115  hash.update(&DB[salt_offset], salt_size);
116 
117  const secure_vector<uint8_t> H2 = hash.final();
118 
119  const bool ok = constant_time_compare(H, H2.data(), HASH_SIZE);
120 
121  if(out_salt_size && ok)
122  *out_salt_size = salt_size;
123 
124  return ok;
125  }
126 
127 }
128 
129 PSSR::PSSR(HashFunction* h) :
130  m_hash(h),
131  m_salt_size(m_hash->output_length()),
132  m_required_salt_len(false)
133  {
134  }
135 
136 PSSR::PSSR(HashFunction* h, size_t salt_size) :
137  m_hash(h),
138  m_salt_size(salt_size),
139  m_required_salt_len(true)
140  {
141  }
142 
143 /*
144 * PSSR Update Operation
145 */
146 void PSSR::update(const uint8_t input[], size_t length)
147  {
148  m_hash->update(input, length);
149  }
150 
151 /*
152 * Return the raw (unencoded) data
153 */
154 secure_vector<uint8_t> PSSR::raw_data()
155  {
156  return m_hash->final();
157  }
158 
159 secure_vector<uint8_t> PSSR::encoding_of(const secure_vector<uint8_t>& msg,
160  size_t output_bits,
161  RandomNumberGenerator& rng)
162  {
163  const secure_vector<uint8_t> salt = rng.random_vec(m_salt_size);
164  return pss_encode(*m_hash, msg, salt, output_bits);
165  }
166 
167 /*
168 * PSSR Decode/Verify Operation
169 */
170 bool PSSR::verify(const secure_vector<uint8_t>& coded,
171  const secure_vector<uint8_t>& raw,
172  size_t key_bits)
173  {
174  size_t salt_size = 0;
175  const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size);
176 
177  if(m_required_salt_len && salt_size != m_salt_size)
178  return false;
179 
180  return ok;
181  }
182 
183 EMSA* PSSR::clone()
184  {
185  return new PSSR(m_hash->clone(), m_salt_size);
186  }
187 
188 std::string PSSR::name() const
189  {
190  return "EMSA4(" + m_hash->name() + ",MGF1," + std::to_string(m_salt_size) + ")";
191  }
192 
193 AlgorithmIdentifier PSSR::config_for_x509(const Private_Key& key,
194  const std::string& cert_hash_name) const
195  {
196  if(cert_hash_name != m_hash->name())
197  throw Invalid_Argument("Hash function from opts and hash_fn argument"
198  " need to be identical");
199  // check that the signature algorithm and the padding scheme fit
200  if(!sig_algo_and_pad_ok(key.algo_name(), "EMSA4"))
201  {
202  throw Invalid_Argument("Encoding scheme with canonical name EMSA4"
203  " not supported for signature algorithm " + key.algo_name());
204  }
205 
206  AlgorithmIdentifier sig_algo;
207  // hardcoded as RSA is the only valid algorithm for EMSA4 at the moment
208  sig_algo.oid = OIDS::lookup( "RSA/EMSA4" );
209 
210  const AlgorithmIdentifier hash_id(cert_hash_name, AlgorithmIdentifier::USE_NULL_PARAM);
211  const AlgorithmIdentifier mgf_id("MGF1", hash_id.BER_encode());
212 
213  DER_Encoder(sig_algo.parameters)
214  .start_cons(SEQUENCE)
215  .start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC).encode(hash_id).end_cons()
216  .start_cons(ASN1_Tag(1), CONTEXT_SPECIFIC).encode(mgf_id).end_cons()
217  .start_cons(ASN1_Tag(2), CONTEXT_SPECIFIC).encode(m_salt_size).end_cons()
218  .start_cons(ASN1_Tag(3), CONTEXT_SPECIFIC).encode(size_t(1)).end_cons() // trailer field
219  .end_cons();
220 
221  return sig_algo;
222  }
223 
224 PSSR_Raw::PSSR_Raw(HashFunction* h) :
225  m_hash(h),
226  m_salt_size(m_hash->output_length()),
227  m_required_salt_len(false)
228  {
229  }
230 
231 PSSR_Raw::PSSR_Raw(HashFunction* h, size_t salt_size) :
232  m_hash(h),
233  m_salt_size(salt_size),
234  m_required_salt_len(true)
235  {
236  }
237 
238 /*
239 * PSSR_Raw Update Operation
240 */
241 void PSSR_Raw::update(const uint8_t input[], size_t length)
242  {
243  m_msg.insert(m_msg.end(), input, input + length);
244  }
245 
246 /*
247 * Return the raw (unencoded) data
248 */
249 secure_vector<uint8_t> PSSR_Raw::raw_data()
250  {
251  secure_vector<uint8_t> ret;
252  std::swap(ret, m_msg);
253 
254  if(ret.size() != m_hash->output_length())
255  throw Encoding_Error("PSSR_Raw Bad input length, did not match hash");
256 
257  return ret;
258  }
259 
260 secure_vector<uint8_t> PSSR_Raw::encoding_of(const secure_vector<uint8_t>& msg,
261  size_t output_bits,
262  RandomNumberGenerator& rng)
263  {
264  secure_vector<uint8_t> salt = rng.random_vec(m_salt_size);
265  return pss_encode(*m_hash, msg, salt, output_bits);
266  }
267 
268 /*
269 * PSSR_Raw Decode/Verify Operation
270 */
271 bool PSSR_Raw::verify(const secure_vector<uint8_t>& coded,
272  const secure_vector<uint8_t>& raw,
273  size_t key_bits)
274  {
275  size_t salt_size = 0;
276  const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size);
277 
278  if(m_required_salt_len && salt_size != m_salt_size)
279  return false;
280 
281  return ok;
282  }
283 
284 EMSA* PSSR_Raw::clone()
285  {
286  return new PSSR_Raw(m_hash->clone(), m_salt_size);
287  }
288 
289 std::string PSSR_Raw::name() const
290  {
291  return "PSSR_Raw(" + m_hash->name() + ",MGF1," + std::to_string(m_salt_size) + ")";
292  }
293 
294 }
botan_rng_t rng
Definition: ffi.h:864
size_t * output_length
Definition: ffi.h:280
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.h:81
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
size_t salt_size
ASN1_Tag
Definition: asn1_obj.h:23
char * name
Definition: ffi.h:330
bool sig_algo_and_pad_ok(const std::string algo, const std::string padding)
Definition: padding.cpp:37
BigInt const BigInt const BigInt & h
Definition: rfc6979.h:47
size_t high_bit(T n)
Definition: bit_ops.h:55
Definition: alg_id.cpp:13
const uint8_t * key
Definition: ffi.h:362
int(* update)(CTX *, const void *, CC_LONG len)
size_t const uint8_t input[]
Definition: base32.h:30
uint8_t size_t const char const uint8_t salt[]
Definition: ffi.h:543
class BOTAN_PUBLIC_API(2, 11) Argon2 final class BOTAN_PUBLIC_API(2, 11) Argon2_Family final void size_t const char size_t const uint8_t salt[]
Definition: argon2.h:87
size_t buffer_insert(std::vector< T, Alloc > &buf, size_t buf_offset, const T input[], size_t input_length)
Definition: secmem.h:80
void mgf1_mask(HashFunction &hash, const uint8_t in[], size_t in_len, uint8_t out[], size_t out_len)
Definition: mgf1.cpp:14
std::string lookup(const OID &oid)
Definition: oids.cpp:113
bool size_t const std::string & hash
Definition: argon2.h:105