Botan 3.0.0
Crypto and TLS for C&
pssr.cpp
Go to the documentation of this file.
1/*
2* PSSR
3* (C) 1999-2007,2017,2023 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/internal/pssr.h>
9#include <botan/internal/mgf1.h>
10#include <botan/internal/bit_ops.h>
11#include <botan/exceptn.h>
12#include <botan/rng.h>
13
14namespace Botan {
15
16namespace {
17
18/*
19* PSSR Encode Operation
20*/
21std::vector<uint8_t> pss_encode(HashFunction& hash,
22 const std::vector<uint8_t>& msg,
23 const std::vector<uint8_t>& salt,
24 size_t output_bits)
25 {
26 const size_t HASH_SIZE = hash.output_length();
27 const size_t SALT_SIZE = salt.size();
28
29 if(msg.size() != HASH_SIZE)
30 throw Encoding_Error("Cannot encode PSS string, input length invalid for hash");
31 if(output_bits < 8*HASH_SIZE + 8*SALT_SIZE + 9)
32 throw Encoding_Error("Cannot encode PSS string, output length too small");
33
34 const size_t output_length = (output_bits + 7) / 8;
35
36 for(size_t i = 0; i != 8; ++i)
37 hash.update(0);
38 hash.update(msg);
39 hash.update(salt);
40 std::vector<uint8_t> H = hash.final_stdvec();
41
42 std::vector<uint8_t> EM(output_length);
43
44 EM[output_length - HASH_SIZE - SALT_SIZE - 2] = 0x01;
45 buffer_insert(EM, output_length - 1 - HASH_SIZE - SALT_SIZE, salt);
46 mgf1_mask(hash, H.data(), HASH_SIZE, EM.data(), output_length - HASH_SIZE - 1);
47 EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits);
48 buffer_insert(EM, output_length - 1 - HASH_SIZE, H);
49 EM[output_length-1] = 0xBC;
50 return EM;
51 }
52
53bool pss_verify(HashFunction& hash,
54 const std::vector<uint8_t>& pss_repr,
55 const std::vector<uint8_t>& message_hash,
56 size_t key_bits,
57 size_t* out_salt_size)
58 {
59 const size_t HASH_SIZE = hash.output_length();
60 const size_t KEY_BYTES = (key_bits + 7) / 8;
61
62 if(key_bits < 8*HASH_SIZE + 9)
63 return false;
64
65 if(message_hash.size() != HASH_SIZE)
66 return false;
67
68 if(pss_repr.size() > KEY_BYTES || pss_repr.size() <= 1)
69 return false;
70
71 if(pss_repr[pss_repr.size()-1] != 0xBC)
72 return false;
73
74 std::vector<uint8_t> coded = pss_repr;
75 if(coded.size() < KEY_BYTES)
76 {
77 std::vector<uint8_t> temp(KEY_BYTES);
78 buffer_insert(temp, KEY_BYTES - coded.size(), coded);
79 coded = temp;
80 }
81
82 const size_t TOP_BITS = 8 * ((key_bits + 7) / 8) - key_bits;
83 if(TOP_BITS > 8 - high_bit(coded[0]))
84 return false;
85
86 uint8_t* DB = coded.data();
87 const size_t DB_size = coded.size() - HASH_SIZE - 1;
88
89 const uint8_t* H = &coded[DB_size];
90 const size_t H_size = HASH_SIZE;
91
92 mgf1_mask(hash, H, H_size, DB, DB_size);
93 DB[0] &= 0xFF >> TOP_BITS;
94
95 size_t salt_offset = 0;
96 for(size_t j = 0; j != DB_size; ++j)
97 {
98 if(DB[j] == 0x01)
99 { salt_offset = j + 1; break; }
100 if(DB[j])
101 return false;
102 }
103 if(salt_offset == 0)
104 return false;
105
106 const size_t salt_size = DB_size - salt_offset;
107
108 for(size_t j = 0; j != 8; ++j)
109 hash.update(0);
110 hash.update(message_hash);
111 hash.update(&DB[salt_offset], salt_size);
112
113 const std::vector<uint8_t> H2 = hash.final_stdvec();
114
115 const bool ok = constant_time_compare(H, H2.data(), HASH_SIZE);
116
117 if(out_salt_size && ok)
118 *out_salt_size = salt_size;
119
120 return ok;
121 }
122
123}
124
125PSSR::PSSR(std::unique_ptr<HashFunction> hash) :
126 m_hash(std::move(hash)),
127 m_salt_size(m_hash->output_length()),
128 m_required_salt_len(false)
129 {
130 }
131
132PSSR::PSSR(std::unique_ptr<HashFunction> hash, size_t salt_size) :
133 m_hash(std::move(hash)),
134 m_salt_size(salt_size),
135 m_required_salt_len(true)
136 {
137 }
138
139/*
140* PSSR Update Operation
141*/
142void PSSR::update(const uint8_t input[], size_t length)
143 {
144 m_hash->update(input, length);
145 }
146
147/*
148* Return the raw (unencoded) data
149*/
150std::vector<uint8_t> PSSR::raw_data()
151 {
152 return m_hash->final_stdvec();
153 }
154
155std::vector<uint8_t> PSSR::encoding_of(const std::vector<uint8_t>& msg,
156 size_t output_bits,
157 RandomNumberGenerator& rng)
158 {
159 const auto salt = rng.random_vec<std::vector<uint8_t>>(m_salt_size);
160 return pss_encode(*m_hash, msg, salt, output_bits);
161 }
162
163/*
164* PSSR Decode/Verify Operation
165*/
166bool PSSR::verify(const std::vector<uint8_t>& coded,
167 const std::vector<uint8_t>& raw,
168 size_t key_bits)
169 {
170 size_t salt_size = 0;
171 const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size);
172
173 if(m_required_salt_len && salt_size != m_salt_size)
174 return false;
175
176 return ok;
177 }
178
179std::string PSSR::name() const
180 {
181 return "EMSA4(" + m_hash->name() + ",MGF1," + std::to_string(m_salt_size) + ")";
182 }
183
184PSSR_Raw::PSSR_Raw(std::unique_ptr<HashFunction> hash) :
185 m_hash(std::move(hash)),
186 m_salt_size(m_hash->output_length()),
187 m_required_salt_len(false)
188 {
189 }
190
191PSSR_Raw::PSSR_Raw(std::unique_ptr<HashFunction> hash, size_t salt_size) :
192 m_hash(std::move(hash)),
193 m_salt_size(salt_size),
194 m_required_salt_len(true)
195 {
196 }
197
198/*
199* PSSR_Raw Update Operation
200*/
201void PSSR_Raw::update(const uint8_t input[], size_t length)
202 {
203 m_msg.insert(m_msg.end(), input, input + length);
204 }
205
206/*
207* Return the raw (unencoded) data
208*/
209std::vector<uint8_t> PSSR_Raw::raw_data()
210 {
211 std::vector<uint8_t> ret;
212 std::swap(ret, m_msg);
213
214 if(ret.size() != m_hash->output_length())
215 throw Encoding_Error("PSSR_Raw Bad input length, did not match hash");
216
217 return ret;
218 }
219
220std::vector<uint8_t> PSSR_Raw::encoding_of(const std::vector<uint8_t>& msg,
221 size_t output_bits,
222 RandomNumberGenerator& rng)
223 {
224 const auto salt = rng.random_vec<std::vector<uint8_t>>(m_salt_size);
225 return pss_encode(*m_hash, msg, salt, output_bits);
226 }
227
228/*
229* PSSR_Raw Decode/Verify Operation
230*/
231bool PSSR_Raw::verify(const std::vector<uint8_t>& coded,
232 const std::vector<uint8_t>& raw,
233 size_t key_bits)
234 {
235 size_t salt_size = 0;
236 const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size);
237
238 if(m_required_salt_len && salt_size != m_salt_size)
239 return false;
240
241 return ok;
242 }
243
244std::string PSSR_Raw::name() const
245 {
246 return "PSSR_Raw(" + m_hash->name() + ",MGF1," + std::to_string(m_salt_size) + ")";
247 }
248
249}
PSSR_Raw(std::unique_ptr< HashFunction > hash)
Definition: pssr.cpp:184
std::string name() const override
Definition: pssr.cpp:244
std::string name() const override
Definition: pssr.cpp:179
PSSR(std::unique_ptr< HashFunction > hash)
Definition: pssr.cpp:125
Definition: alg_id.cpp:12
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:221
constexpr size_t high_bit(T n)
Definition: bit_ops.h:58
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.h:82
Definition: bigint.h:1092