emsa_pssr.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2020 Mikhail Komarov <nemo@nil.foundation>
3 //
4 // MIT License
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in all
14 // copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 // SOFTWARE.
23 //---------------------------------------------------------------------------//
24 
25 #ifndef CRYPTO3_PSSR_HPP
26 #define CRYPTO3_PSSR_HPP
27 
29 
30 #include <nil/crypto3/utilities/bit_ops.hpp>
31 
32 namespace nil {
33  namespace crypto3 {
34  namespace pubkey {
35  namespace padding {
36  namespace detail {
37  /*
38  * PSSR Encode Operation
39  */
40  secure_vector<uint8_t> pss_encode(HashFunction &hash, const secure_vector<uint8_t> &msg,
41  const secure_vector<uint8_t> &salt, size_t output_bits) {
42  const size_t HASH_SIZE = hash.output_length();
43  const size_t SALT_SIZE = salt.size();
44 
45  if (msg.size() != HASH_SIZE) {
46  throw encoding_error("Cannot encode PSS string, input length invalid for hash");
47  }
48  if (output_bits < 8 * HASH_SIZE + 8 * SALT_SIZE + 9) {
49  throw encoding_error("Cannot encode PSS string, output length too small");
50  }
51 
52  const size_t output_length = (output_bits + 7) / 8;
53 
54  for (size_t i = 0; i != 8; ++i) {
55  hash.update(0);
56  }
57  hash.update(msg);
58  hash.update(salt);
59  secure_vector<uint8_t> H = hash.final();
60 
61  secure_vector<uint8_t> EM(output_length);
62 
63  EM[output_length - HASH_SIZE - SALT_SIZE - 2] = 0x01;
64  buffer_insert(EM, output_length - 1 - HASH_SIZE - SALT_SIZE, salt);
65  mgf1_mask(hash, H.data(), HASH_SIZE, EM.data(), output_length - HASH_SIZE - 1);
66  EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits);
67  buffer_insert(EM, output_length - 1 - HASH_SIZE, H);
68  EM[output_length - 1] = 0xBC;
69  return EM;
70  }
71 
72  bool pss_verify(HashFunction &hash, const secure_vector<uint8_t> &pss_repr,
73  const secure_vector<uint8_t> &message_hash, size_t key_bits,
74  size_t *out_salt_size) {
75  const size_t HASH_SIZE = hash.output_length();
76  const size_t KEY_BYTES = (key_bits + 7) / 8;
77 
78  if (key_bits < 8 * HASH_SIZE + 9) {
79  return false;
80  }
81 
82  if (message_hash.size() != HASH_SIZE) {
83  return false;
84  }
85 
86  if (pss_repr.size() > KEY_BYTES || pss_repr.size() <= 1) {
87  return false;
88  }
89 
90  if (pss_repr[pss_repr.size() - 1] != 0xBC) {
91  return false;
92  }
93 
94  secure_vector<uint8_t> coded = pss_repr;
95  if (coded.size() < KEY_BYTES) {
96  secure_vector<uint8_t> temp(KEY_BYTES);
97  buffer_insert(temp, KEY_BYTES - coded.size(), coded);
98  coded = temp;
99  }
100 
101  const size_t TOP_BITS = 8 * ((key_bits + 7) / 8) - key_bits;
102  if (TOP_BITS > 8 - high_bit(coded[0])) {
103  return false;
104  }
105 
106  uint8_t *DB = coded.data();
107  const size_t DB_size = coded.size() - HASH_SIZE - 1;
108 
109  const uint8_t *H = &coded[DB_size];
110  const size_t H_size = HASH_SIZE;
111 
112  mgf1_mask(hash, H, H_size, DB, DB_size);
113  DB[0] &= 0xFF >> TOP_BITS;
114 
115  size_t salt_offset = 0;
116  for (size_t j = 0; j != DB_size; ++j) {
117  if (DB[j] == 0x01) {
118  salt_offset = j + 1;
119  break;
120  }
121  if (DB[j]) {
122  return false;
123  }
124  }
125  if (salt_offset == 0) {
126  return false;
127  }
128 
129  const size_t salt_size = DB_size - salt_offset;
130 
131  for (size_t j = 0; j != 8; ++j) {
132  hash.update(0);
133  }
134  hash.update(message_hash);
135  hash.update(&DB[salt_offset], salt_size);
136 
137  const secure_vector<uint8_t> H2 = hash.final();
138 
139  const bool ok = constant_time_compare(H, H2.data(), HASH_SIZE);
140 
141  if (out_salt_size && ok) {
142  *out_salt_size = salt_size;
143  }
144 
145  return ok;
146  }
147  } // namespace detail
148 
153  template<typename Scheme, typename Hash>
154  struct emsa_pssr : public emsa<Scheme, Hash> {
155  template<typename InputIterator1, typename InputIterator2>
156  bool verify(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2,
157  InputIterator2 last2, std::size_t key_bits) const {
158  size_t salt_size = 0;
159  const bool ok = pss_verify(this->hash, first1, last1, first2, last2, key_bits, &salt_size);
160 
161  if (required_salt_len && salt_size != m_salt_size) {
162  return false;
163  }
164 
165  return ok;
166  }
167 
168  template<typename SinglePassRange1, typename SinglePassRange2>
169  bool verify(const SinglePassRange1 &range1, const SinglePassRange2 &range2,
170  std::size_t key_bits) const {
171  return verify(boost::begin(range1), boost::end(range1), boost::begin(range2),
172  boost::end(range2), 0);
173  }
174 
175  protected:
176  std::size_t required_salt_length;
177  std::size_t salt_size;
178 
179  template<typename InputMessageIterator, typename InputSaltIterator, typename OutputIterator>
180  OutputIterator pss_encode(Hash &hash, InputMessageIterator firstm, InputMessageIterator lastm,
181  InputSaltIterator firsts, InputSaltIterator lasts, size_t output_bits) {
182  std::ptrdiff_t message_size = std::distance(firstm, lastm);
183  std::ptrdiff_t salt_size = std::distance(firsts, lasts);
184 
185  if (message_size != Hash::policy_type::digest_bits / 8) {
186  throw encoding_error("Cannot encode PSS string, input length invalid for hash");
187  }
188  if (output_bits < Hash::policy_type::digest_bits + 8 * salt_size + 9) {
189  throw encoding_error("Cannot encode PSS string, output length too small");
190  }
191 
192  const size_t output_length = (output_bits + 7) / 8;
193 
194  for (size_t i = 0; i != 8; ++i) {
195  hash.update(0);
196  }
197  hash.update(msg);
198  hash.update(salt);
199  secure_vector<uint8_t> H = hash.final();
200 
201  secure_vector<uint8_t> EM(output_length);
202 
203  EM[output_length - Hash::policy_type::digest_bits / 8 - salt_size - 2] = 0x01;
204  buffer_insert(EM, output_length - 1 - Hash::policy_type::digest_bits / 8 - salt_size, salt);
205  mgf1_mask(hash, H.data(), Hash::policy_type::digest_bits / 8, EM.data(),
206  output_length - Hash::policy_type::digest_bits / 8 - 1);
207  EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits);
208  buffer_insert(EM, output_length - 1 - Hash::policy_type::digest_bits / 8, H);
209  EM[output_length - 1] = 0xBC;
210  return EM;
211  }
212 
213  template<typename InputIterator1, typename InputMessageIterator>
214  bool pss_verify(HashFunction &hash, const secure_vector<uint8_t> &pss_repr,
215  const secure_vector<uint8_t> &message_hash, size_t key_bits,
216  size_t *out_salt_size) {
217  const size_t KEY_BYTES = (key_bits + 7) / 8;
218 
219  if (key_bits < Hash::policy_type::digest_bits + 9) {
220  return false;
221  }
222 
223  if (message_hash.size() != Hash::policy_type::digest_bits / 8) {
224  return false;
225  }
226 
227  if (pss_repr.size() > KEY_BYTES || pss_repr.size() <= 1) {
228  return false;
229  }
230 
231  if (pss_repr[pss_repr.size() - 1] != 0xBC) {
232  return false;
233  }
234 
235  secure_vector<uint8_t> coded = pss_repr;
236  if (coded.size() < KEY_BYTES) {
237  secure_vector<uint8_t> temp(KEY_BYTES);
238  buffer_insert(temp, KEY_BYTES - coded.size(), coded);
239  coded = temp;
240  }
241 
242  const size_t TOP_BITS = 8 * ((key_bits + 7) / 8) - key_bits;
243  if (TOP_BITS > 8 - high_bit(coded[0])) {
244  return false;
245  }
246 
247  uint8_t *DB = coded.data();
248  const size_t DB_size = coded.size() - Hash::policy_type::digest_bits / 8 - 1;
249 
250  const uint8_t *H = &coded[DB_size];
251 
252  mgf1_mask(hash, H, Hash::policy_type::digest_bits / 8, DB, DB_size);
253  DB[0] &= 0xFF >> TOP_BITS;
254 
255  size_t salt_offset = 0;
256  for (size_t j = 0; j != DB_size; ++j) {
257  if (DB[j] == 0x01) {
258  salt_offset = j + 1;
259  break;
260  }
261  if (DB[j]) {
262  return false;
263  }
264  }
265  if (salt_offset == 0) {
266  return false;
267  }
268 
269  const size_t salt_size = DB_size - salt_offset;
270 
271  for (size_t j = 0; j != 8; ++j) {
272  hash.update(0);
273  }
274  hash.update(message_hash);
275  hash.update(&DB[salt_offset], salt_size);
276 
277  const secure_vector<uint8_t> H2 = hash.final();
278 
279  const bool ok = constant_time_compare(H, H2.data(), Hash::policy_type::digest_bits / 8);
280 
281  if (out_salt_size && ok) {
282  *out_salt_size = salt_size;
283  }
284 
285  return ok;
286  }
287  };
288  } // namespace padding
289  } // namespace pubkey
290  } // namespace crypto3
291 } // namespace nil
292 
293 #endif
std::enable_if<!boost::accumulators::detail::is_accumulator_set< OutputIterator >::value, OutputIterator >::type hash(InputIterator first, InputIterator last, OutputIterator out)
Definition: algorithm/hash.hpp:78
boost::mpl::apply< AccumulatorSet, tag::pubkey< ProcessingMode > >::type::result_type pubkey(const AccumulatorSet &acc)
Definition: accumulators/pubkey.hpp:106
secure_vector< uint8_t > pss_encode(HashFunction &hash, const secure_vector< uint8_t > &msg, const secure_vector< uint8_t > &salt, size_t output_bits)
Definition: emsa_pssr.hpp:40
bool pss_verify(HashFunction &hash, const secure_vector< uint8_t > &pss_repr, const secure_vector< uint8_t > &message_hash, size_t key_bits, size_t *out_salt_size)
Definition: emsa_pssr.hpp:72
OutputIterator mgf1_mask(InputIterator first, InputIterator last, OutputIterator out, StreamHash sh=StreamHash())
MGF1 from PKCS #1 v2.0.
Definition: mgf1.hpp:48
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: memory_operations.hpp:143
Definition: pair.hpp:31
EMSA, from IEEE 1363s Encoding Method for Signatures, Appendix.
Definition: emsa.hpp:48
PSSR aka EMSA4 in IEEE 1363.
Definition: emsa_pssr.hpp:154
bool verify(const SinglePassRange1 &range1, const SinglePassRange2 &range2, std::size_t key_bits) const
Definition: emsa_pssr.hpp:169
bool verify(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, std::size_t key_bits) const
Definition: emsa_pssr.hpp:156
OutputIterator pss_encode(Hash &hash, InputMessageIterator firstm, InputMessageIterator lastm, InputSaltIterator firsts, InputSaltIterator lasts, size_t output_bits)
Definition: emsa_pssr.hpp:180
bool pss_verify(HashFunction &hash, const secure_vector< uint8_t > &pss_repr, const secure_vector< uint8_t > &message_hash, size_t key_bits, size_t *out_salt_size)
Definition: emsa_pssr.hpp:214
std::size_t salt_size
Definition: emsa_pssr.hpp:177
std::size_t required_salt_length
Definition: emsa_pssr.hpp:176