Botan 2.19.0
Crypto and TLS for C&
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/der_enc.h>
14#include <botan/pk_keys.h>
15#include <botan/internal/padding.h>
16
17namespace Botan {
18
19namespace {
20
21/*
22* PSSR Encode Operation
23*/
24secure_vector<uint8_t> pss_encode(HashFunction& hash,
25 const secure_vector<uint8_t>& msg,
26 const secure_vector<uint8_t>& salt,
27 size_t output_bits)
28 {
29 const size_t HASH_SIZE = hash.output_length();
30 const size_t SALT_SIZE = salt.size();
31
32 if(msg.size() != HASH_SIZE)
33 throw Encoding_Error("Cannot encode PSS string, input length invalid for hash");
34 if(output_bits < 8*HASH_SIZE + 8*SALT_SIZE + 9)
35 throw Encoding_Error("Cannot encode PSS string, output length too small");
36
37 const size_t output_length = (output_bits + 7) / 8;
38
39 for(size_t i = 0; i != 8; ++i)
40 hash.update(0);
41 hash.update(msg);
42 hash.update(salt);
43 secure_vector<uint8_t> H = hash.final();
44
45 secure_vector<uint8_t> EM(output_length);
46
47 EM[output_length - HASH_SIZE - SALT_SIZE - 2] = 0x01;
48 buffer_insert(EM, output_length - 1 - HASH_SIZE - SALT_SIZE, salt);
49 mgf1_mask(hash, H.data(), HASH_SIZE, EM.data(), output_length - HASH_SIZE - 1);
50 EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits);
51 buffer_insert(EM, output_length - 1 - HASH_SIZE, H);
52 EM[output_length-1] = 0xBC;
53 return EM;
54 }
55
56bool pss_verify(HashFunction& hash,
57 const secure_vector<uint8_t>& pss_repr,
58 const secure_vector<uint8_t>& message_hash,
59 size_t key_bits,
60 size_t* out_salt_size)
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(message_hash.size() != HASH_SIZE)
69 return false;
70
71 if(pss_repr.size() > KEY_BYTES || pss_repr.size() <= 1)
72 return false;
73
74 if(pss_repr[pss_repr.size()-1] != 0xBC)
75 return false;
76
77 secure_vector<uint8_t> coded = pss_repr;
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(message_hash);
114 hash.update(&DB[salt_offset], salt_size);
115
116 const secure_vector<uint8_t> H2 = hash.final();
117
118 const bool ok = constant_time_compare(H, H2.data(), HASH_SIZE);
119
120 if(out_salt_size && ok)
121 *out_salt_size = salt_size;
122
123 return ok;
124 }
125
126}
127
129 m_hash(h),
130 m_salt_size(m_hash->output_length()),
131 m_required_salt_len(false)
132 {
133 }
134
136 m_hash(h),
137 m_salt_size(salt_size),
138 m_required_salt_len(true)
139 {
140 }
141
142/*
143* PSSR Update Operation
144*/
145void PSSR::update(const uint8_t input[], size_t length)
146 {
147 m_hash->update(input, length);
148 }
149
150/*
151* Return the raw (unencoded) data
152*/
153secure_vector<uint8_t> PSSR::raw_data()
154 {
155 return m_hash->final();
156 }
157
158secure_vector<uint8_t> PSSR::encoding_of(const secure_vector<uint8_t>& msg,
159 size_t output_bits,
160 RandomNumberGenerator& rng)
161 {
162 const secure_vector<uint8_t> salt = rng.random_vec(m_salt_size);
163 return pss_encode(*m_hash, msg, salt, output_bits);
164 }
165
166/*
167* PSSR Decode/Verify Operation
168*/
169bool PSSR::verify(const secure_vector<uint8_t>& coded,
170 const secure_vector<uint8_t>& raw,
171 size_t key_bits)
172 {
173 size_t salt_size = 0;
174 const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size);
175
176 if(m_required_salt_len && salt_size != m_salt_size)
177 return false;
178
179 return ok;
180 }
181
183 {
184 return new PSSR(m_hash->clone(), m_salt_size);
185 }
186
187std::string PSSR::name() const
188 {
189 return "EMSA4(" + m_hash->name() + ",MGF1," + std::to_string(m_salt_size) + ")";
190 }
191
193 const std::string& cert_hash_name) const
194 {
195 if(cert_hash_name != m_hash->name())
196 throw Invalid_Argument("Hash function from opts and hash_fn argument"
197 " need to be identical");
198 // check that the signature algorithm and the padding scheme fit
199 if(!sig_algo_and_pad_ok(key.algo_name(), "EMSA4"))
200 {
201 throw Invalid_Argument("Encoding scheme with canonical name EMSA4"
202 " not supported for signature algorithm " + key.algo_name());
203 }
204
205 const AlgorithmIdentifier hash_id(cert_hash_name, AlgorithmIdentifier::USE_NULL_PARAM);
206 const AlgorithmIdentifier mgf_id("MGF1", hash_id.BER_encode());
207
208 std::vector<uint8_t> parameters;
209 DER_Encoder(parameters)
214 .start_cons(ASN1_Tag(3), CONTEXT_SPECIFIC).encode(size_t(1)).end_cons() // trailer field
215 .end_cons();
216
217 // hardcoded as RSA is the only valid algorithm for EMSA4 at the moment
218 return AlgorithmIdentifier("RSA/EMSA4", parameters);
219 }
220
222 m_hash(h),
223 m_salt_size(m_hash->output_length()),
224 m_required_salt_len(false)
225 {
226 }
227
229 m_hash(h),
230 m_salt_size(salt_size),
231 m_required_salt_len(true)
232 {
233 }
234
235/*
236* PSSR_Raw Update Operation
237*/
238void PSSR_Raw::update(const uint8_t input[], size_t length)
239 {
240 m_msg.insert(m_msg.end(), input, input + length);
241 }
242
243/*
244* Return the raw (unencoded) data
245*/
246secure_vector<uint8_t> PSSR_Raw::raw_data()
247 {
248 secure_vector<uint8_t> ret;
249 std::swap(ret, m_msg);
250
251 if(ret.size() != m_hash->output_length())
252 throw Encoding_Error("PSSR_Raw Bad input length, did not match hash");
253
254 return ret;
255 }
256
257secure_vector<uint8_t> PSSR_Raw::encoding_of(const secure_vector<uint8_t>& msg,
258 size_t output_bits,
259 RandomNumberGenerator& rng)
260 {
261 secure_vector<uint8_t> salt = rng.random_vec(m_salt_size);
262 return pss_encode(*m_hash, msg, salt, output_bits);
263 }
264
265/*
266* PSSR_Raw Decode/Verify Operation
267*/
268bool PSSR_Raw::verify(const secure_vector<uint8_t>& coded,
269 const secure_vector<uint8_t>& raw,
270 size_t key_bits)
271 {
272 size_t salt_size = 0;
273 const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size);
274
275 if(m_required_salt_len && salt_size != m_salt_size)
276 return false;
277
278 return ok;
279 }
280
282 {
283 return new PSSR_Raw(m_hash->clone(), m_salt_size);
284 }
285
286std::string PSSR_Raw::name() const
287 {
288 return "PSSR_Raw(" + m_hash->name() + ",MGF1," + std::to_string(m_salt_size) + ")";
289 }
290
291}
std::vector< uint8_t > BER_encode() const
Definition: asn1_obj.cpp:16
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: der_enc.cpp:181
DER_Encoder & end_cons()
Definition: der_enc.cpp:191
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:285
std::string name() const override
Definition: pssr.cpp:286
PSSR_Raw(HashFunction *hash)
Definition: pssr.cpp:221
EMSA * clone() override
Definition: pssr.cpp:281
std::string name() const override
Definition: pssr.cpp:187
PSSR(HashFunction *hash)
Definition: pssr.cpp:128
EMSA * clone() override
Definition: pssr.cpp:182
AlgorithmIdentifier config_for_x509(const Private_Key &key, const std::string &cert_hash_name) const override
Definition: pssr.cpp:192
virtual std::string algo_name() const =0
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
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:14
size_t buffer_insert(std::vector< T, Alloc > &buf, size_t buf_offset, const T input[], size_t input_length)
Definition: mem_ops.h:228
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.h:82
ASN1_Tag
Definition: asn1_obj.h:25
@ SEQUENCE
Definition: asn1_obj.h:42
@ CONTEXT_SPECIFIC
Definition: asn1_obj.h:28
size_t high_bit(T n)
Definition: bit_ops.h:55
bool sig_algo_and_pad_ok(const std::string algo, const std::string padding)
Definition: padding.cpp:39
MechanismType hash
size_t salt_size