Botan  2.7.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>& const_coded,
59  const secure_vector<uint8_t>& raw,
60  size_t key_bits)
61  {
62  const size_t HASH_SIZE = hash.output_length();
63  const size_t KEY_BYTES = (key_bits + 7) / 8;
64 
65  if(key_bits < 8*HASH_SIZE + 9)
66  return false;
67 
68  if(raw.size() != HASH_SIZE)
69  return false;
70 
71  if(const_coded.size() > KEY_BYTES || const_coded.size() <= 1)
72  return false;
73 
74  if(const_coded[const_coded.size()-1] != 0xBC)
75  return false;
76 
77  secure_vector<uint8_t> coded = const_coded;
78  if(coded.size() < KEY_BYTES)
79  {
80  secure_vector<uint8_t> temp(KEY_BYTES);
81  buffer_insert(temp, KEY_BYTES - coded.size(), coded);
82  coded = temp;
83  }
84 
85  const size_t TOP_BITS = 8 * ((key_bits + 7) / 8) - key_bits;
86  if(TOP_BITS > 8 - high_bit(coded[0]))
87  return false;
88 
89  uint8_t* DB = coded.data();
90  const size_t DB_size = coded.size() - HASH_SIZE - 1;
91 
92  const uint8_t* H = &coded[DB_size];
93  const size_t H_size = HASH_SIZE;
94 
95  mgf1_mask(hash, H, H_size, DB, DB_size);
96  DB[0] &= 0xFF >> TOP_BITS;
97 
98  size_t salt_offset = 0;
99  for(size_t j = 0; j != DB_size; ++j)
100  {
101  if(DB[j] == 0x01)
102  { salt_offset = j + 1; break; }
103  if(DB[j])
104  return false;
105  }
106  if(salt_offset == 0)
107  return false;
108 
109  const size_t salt_size = DB_size - salt_offset;
110 
111  for(size_t j = 0; j != 8; ++j)
112  hash.update(0);
113  hash.update(raw);
114  hash.update(&DB[salt_offset], salt_size);
115 
116  secure_vector<uint8_t> H2 = hash.final();
117 
118  return constant_time_compare(H, H2.data(), HASH_SIZE);
119  }
120 
121 }
122 
124  m_hash(h), m_SALT_SIZE(m_hash->output_length())
125  {
126  }
127 
129  m_hash(h), m_SALT_SIZE(salt_size)
130  {
131  }
132 
133 /*
134 * PSSR Update Operation
135 */
136 void PSSR::update(const uint8_t input[], size_t length)
137  {
138  m_hash->update(input, length);
139  }
140 
141 /*
142 * Return the raw (unencoded) data
143 */
144 secure_vector<uint8_t> PSSR::raw_data()
145  {
146  return m_hash->final();
147  }
148 
149 secure_vector<uint8_t> PSSR::encoding_of(const secure_vector<uint8_t>& msg,
150  size_t output_bits,
151  RandomNumberGenerator& rng)
152  {
153  secure_vector<uint8_t> salt = rng.random_vec(m_SALT_SIZE);
154  return pss_encode(*m_hash, msg, salt, output_bits);
155  }
156 
157 /*
158 * PSSR Decode/Verify Operation
159 */
160 bool PSSR::verify(const secure_vector<uint8_t>& coded,
161  const secure_vector<uint8_t>& raw,
162  size_t key_bits)
163  {
164  return pss_verify(*m_hash, coded, raw, key_bits);
165  }
166 
167 std::string PSSR::name() const
168  {
169  return "EMSA4(" + m_hash->name() + ",MGF1," + std::to_string(m_SALT_SIZE) + ")";
170  }
171 
173  const std::string& cert_hash_name) const
174  {
175  if(cert_hash_name != m_hash->name())
176  throw Invalid_Argument("Hash function from opts and hash_fn argument"
177  " need to be identical");
178  // check that the signature algorithm and the padding scheme fit
179  if(!sig_algo_and_pad_ok(key.algo_name(), "EMSA4"))
180  {
181  throw Invalid_Argument("Encoding scheme with canonical name EMSA4"
182  " not supported for signature algorithm " + key.algo_name());
183  }
184 
185  AlgorithmIdentifier sig_algo;
186  // hardcoded as RSA is the only valid algorithm for EMSA4 at the moment
187  sig_algo.oid = OIDS::lookup( "RSA/EMSA4" );
188 
189  const AlgorithmIdentifier hash_id(cert_hash_name, AlgorithmIdentifier::USE_NULL_PARAM);
190  const AlgorithmIdentifier mgf_id("MGF1", hash_id.BER_encode());
191 
192  DER_Encoder(sig_algo.parameters)
196  .start_cons(ASN1_Tag(2), CONTEXT_SPECIFIC).encode(m_SALT_SIZE).end_cons()
197  .start_cons(ASN1_Tag(3), CONTEXT_SPECIFIC).encode(size_t(1)).end_cons() // trailer field
198  .end_cons();
199 
200  return sig_algo;
201  }
202 
204  m_hash(h), m_SALT_SIZE(m_hash->output_length())
205  {
206  }
207 
209  m_hash(h), m_SALT_SIZE(salt_size)
210  {
211  }
212 
213 /*
214 * PSSR_Raw Update Operation
215 */
216 void PSSR_Raw::update(const uint8_t input[], size_t length)
217  {
218  m_msg.insert(m_msg.end(), input, input + length);
219  }
220 
221 /*
222 * Return the raw (unencoded) data
223 */
224 secure_vector<uint8_t> PSSR_Raw::raw_data()
225  {
226  secure_vector<uint8_t> ret;
227  std::swap(ret, m_msg);
228 
229  if(ret.size() != m_hash->output_length())
230  throw Encoding_Error("PSSR_Raw Bad input length, did not match hash");
231 
232  return ret;
233  }
234 
235 secure_vector<uint8_t> PSSR_Raw::encoding_of(const secure_vector<uint8_t>& msg,
236  size_t output_bits,
237  RandomNumberGenerator& rng)
238  {
239  secure_vector<uint8_t> salt = rng.random_vec(m_SALT_SIZE);
240  return pss_encode(*m_hash, msg, salt, output_bits);
241  }
242 
243 /*
244 * PSSR_Raw Decode/Verify Operation
245 */
246 bool PSSR_Raw::verify(const secure_vector<uint8_t>& coded,
247  const secure_vector<uint8_t>& raw,
248  size_t key_bits)
249  {
250  return pss_verify(*m_hash, coded, raw, key_bits);
251  }
252 
253 std::string PSSR_Raw::name() const
254  {
255  return "PSSR_Raw(" + m_hash->name() + ",MGF1," + std::to_string(m_SALT_SIZE) + ")";
256  }
257 
258 }
std::string name() const override
Definition: pssr.cpp:253
std::vector< uint8_t > parameters
Definition: alg_id.h:46
std::vector< uint8_t > BER_encode() const
Definition: asn1_obj.cpp:16
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.cpp:51
virtual std::string algo_name() const =0
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:210
size_t salt_size
ASN1_Tag
Definition: asn1_obj.h:22
DER_Encoder & end_cons()
Definition: der_enc.cpp:191
std::string name() const override
Definition: pssr.cpp:167
bool sig_algo_and_pad_ok(const std::string algo, const std::string padding)
Definition: padding.cpp:37
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:285
PSSR_Raw(HashFunction *hash)
Definition: pssr.cpp:203
size_t high_bit(T n)
Definition: bit_ops.h:37
Definition: alg_id.cpp:13
size_t buffer_insert(std::vector< T, Alloc > &buf, size_t buf_offset, const T input[], size_t input_length)
Definition: secmem.h:103
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: der_enc.cpp:181
PSSR(HashFunction *hash)
Definition: pssr.cpp:123
void mgf1_mask(HashFunction &hash, const uint8_t in[], size_t in_len, uint8_t out[], size_t out_len)
Definition: mgf1.cpp:14
AlgorithmIdentifier config_for_x509(const Private_Key &key, const std::string &cert_hash_name) const override
Definition: pssr.cpp:172
std::string lookup(const OID &oid)
Definition: oids.cpp:113
MechanismType hash