Botan  2.6.0
Crypto and TLS for C++11
iso9796.cpp
Go to the documentation of this file.
1 /*
2  * ISO-9796-2 - Digital signature schemes giving message recovery schemes 2 and 3
3  * (C) 2016 Tobias Niemann, Hackmanit GmbH
4  *
5  * Botan is released under the Simplified BSD License (see license.txt)
6  */
7 
8 #include <botan/iso9796.h>
9 #include <botan/rng.h>
10 #include <botan/exceptn.h>
11 #include <botan/mgf1.h>
12 #include <botan/hash_id.h>
13 #include <botan/internal/bit_ops.h>
14 #include <botan/internal/ct_utils.h>
15 
16 namespace Botan {
17 
18 namespace {
19 
20 secure_vector<uint8_t> iso9796_encoding(const secure_vector<uint8_t>& msg,
21  size_t output_bits, std::unique_ptr<HashFunction>& hash, size_t SALT_SIZE, bool implicit, RandomNumberGenerator& rng)
22  {
23  const size_t output_length = (output_bits + 7) / 8;
24 
25  //set trailer length
26  size_t tLength = 1;
27  if(!implicit)
28  {
29  tLength = 2;
30  }
31  const size_t HASH_SIZE = hash->output_length();
32 
33  if(output_length <= HASH_SIZE + SALT_SIZE + tLength)
34  {
35  throw Encoding_Error("ISO9796-2::encoding_of: Output length is too small");
36  }
37 
38  //calculate message capacity
39  const size_t capacity = output_length
40  - HASH_SIZE - SALT_SIZE - tLength - 1;
41 
42  //msg1 is the recoverable and msg2 the unrecoverable message part.
43  secure_vector<uint8_t> msg1;
44  secure_vector<uint8_t> msg2;
45  if(msg.size() > capacity)
46  {
47  msg1 = secure_vector<uint8_t> (msg.begin(), msg.begin() + capacity);
48  msg2 = secure_vector<uint8_t> (msg.begin() + capacity, msg.end());
49  hash->update(msg2);
50  }
51  else
52  {
53  msg1 = msg;
54  }
55  msg2 = hash->final();
56 
57  //compute H(C||msg1 ||H(msg2)||S)
58  uint64_t msgLength = msg1.size();
59  secure_vector<uint8_t> salt = rng.random_vec(SALT_SIZE);
60  hash->update_be(msgLength * 8);
61  hash->update(msg1);
62  hash->update(msg2);
63  hash->update(salt);
64  secure_vector<uint8_t> H = hash->final();
65 
66  secure_vector<uint8_t> EM(output_length);
67 
68  //compute message offset.
69  size_t offset = output_length - HASH_SIZE - SALT_SIZE - tLength
70  - msgLength - 1;
71 
72  //insert message border (0x01), msg1 and salt into the output buffer
73  EM[offset] = 0x01;
74  buffer_insert(EM, offset + 1, msg1);
75  buffer_insert(EM, offset + 1 + msgLength, salt);
76 
77  //apply mask
78  mgf1_mask(*hash, H.data(), HASH_SIZE, EM.data(),
79  output_length - HASH_SIZE - tLength);
80  buffer_insert(EM, output_length - HASH_SIZE - tLength, H);
81  //set implicit/ISO trailer
82  if(!implicit)
83  {
84  uint8_t hash_id = ieee1363_hash_id(hash->name());
85  if(!hash_id)
86  {
87  throw Encoding_Error("ISO9796-2::encoding_of: no hash identifier for " + hash->name());
88  }
89  EM[output_length - 1] = 0xCC;
90  EM[output_length - 2] = hash_id;
91 
92  }
93  else
94  {
95  EM[output_length - 1] = 0xBC;
96  }
97  //clear the leftmost bit (confer bouncy castle)
98  EM[0] &= 0x7F;
99 
100  return EM;
101  }
102 
103 bool iso9796_verification(const secure_vector<uint8_t>& const_coded,
104  const secure_vector<uint8_t>& raw, size_t key_bits, std::unique_ptr<HashFunction>& hash, size_t SALT_SIZE)
105  {
106  const size_t HASH_SIZE = hash->output_length();
107  const size_t KEY_BYTES = (key_bits + 7) / 8;
108 
109  if(const_coded.size() != KEY_BYTES)
110  {
111  return false;
112  }
113  //get trailer length
114  size_t tLength;
115  if(const_coded[const_coded.size() - 1] == 0xBC)
116  {
117  tLength = 1;
118  }
119  else
120  {
121  uint8_t hash_id = ieee1363_hash_id(hash->name());
122  if((!const_coded[const_coded.size() - 2]) || (const_coded[const_coded.size() - 2] != hash_id) ||
123  (const_coded[const_coded.size() - 1] != 0xCC))
124  {
125  return false; //in case of wrong ISO trailer.
126  }
127  tLength = 2;
128  }
129 
130  secure_vector<uint8_t> coded = const_coded;
131 
132  CT::poison(coded.data(), coded.size());
133  //remove mask
134  uint8_t* DB = coded.data();
135  const size_t DB_size = coded.size() - HASH_SIZE - tLength;
136 
137  const uint8_t* H = &coded[DB_size];
138 
139  mgf1_mask(*hash, H, HASH_SIZE, DB, DB_size);
140  //clear the leftmost bit (confer bouncy castle)
141  DB[0] &= 0x7F;
142 
143  //recover msg1 and salt
144  size_t msg1_offset = 1;
145  uint8_t waiting_for_delim = 0xFF;
146  uint8_t bad_input = 0;
147  for(size_t j = 0; j < DB_size; ++j)
148  {
149  const uint8_t one_m = CT::is_equal<uint8_t>(DB[j], 0x01);
150  const uint8_t zero_m = CT::is_zero(DB[j]);
151  const uint8_t add_m = waiting_for_delim & zero_m;
152 
153  bad_input |= waiting_for_delim & ~(zero_m | one_m);
154  msg1_offset += CT::select<uint8_t>(add_m, 1, 0);
155 
156  waiting_for_delim &= zero_m;
157  }
158 
159  //invalid, if delimiter 0x01 was not found or msg1_offset is too big
160  bad_input |= waiting_for_delim;
161  bad_input |= CT::is_less(coded.size(), tLength + HASH_SIZE + msg1_offset + SALT_SIZE);
162 
163  //in case that msg1_offset is too big, just continue with offset = 0.
164  msg1_offset = CT::select<size_t>(bad_input, 0, msg1_offset);
165 
166  CT::unpoison(coded.data(), coded.size());
167  CT::unpoison(msg1_offset);
168 
169  secure_vector<uint8_t> msg1(coded.begin() + msg1_offset,
170  coded.end() - tLength - HASH_SIZE - SALT_SIZE);
171  secure_vector<uint8_t> salt(coded.begin() + msg1_offset + msg1.size(),
172  coded.end() - tLength - HASH_SIZE);
173 
174  //compute H2(C||msg1||H(msg2)||S*). * indicates a recovered value
175  const size_t capacity = (key_bits - 2 + 7) / 8 - HASH_SIZE
176  - SALT_SIZE - tLength - 1;
177  secure_vector<uint8_t> msg1raw;
178  secure_vector<uint8_t> msg2;
179  if(raw.size() > capacity)
180  {
181  msg1raw = secure_vector<uint8_t> (raw.begin(), raw.begin() + capacity);
182  msg2 = secure_vector<uint8_t> (raw.begin() + capacity, raw.end());
183  hash->update(msg2);
184  }
185  else
186  {
187  msg1raw = raw;
188  }
189  msg2 = hash->final();
190 
191  uint64_t msg1rawLength = msg1raw.size();
192  hash->update_be(msg1rawLength * 8);
193  hash->update(msg1raw);
194  hash->update(msg2);
195  hash->update(salt);
196  secure_vector<uint8_t> H3 = hash->final();
197 
198  //compute H3(C*||msg1*||H(msg2)||S*) * indicates a recovered value
199  uint64_t msgLength = msg1.size();
200  hash->update_be(msgLength * 8);
201  hash->update(msg1);
202  hash->update(msg2);
203  hash->update(salt);
204  secure_vector<uint8_t> H2 = hash->final();
205 
206  //check if H3 == H2
207  bad_input |= CT::is_equal<uint8_t>(constant_time_compare(H3.data(), H2.data(), HASH_SIZE), false);
208 
209  CT::unpoison(bad_input);
210  return (bad_input == 0);
211  }
212 
213 }
214 
216  {
217  return new ISO_9796_DS2(m_hash->clone(), m_implicit, m_SALT_SIZE);
218  }
219 
220 /*
221  * ISO-9796-2 signature scheme 2
222  * DS 2 is probabilistic
223  */
224 void ISO_9796_DS2::update(const uint8_t input[], size_t length)
225  {
226  //need to buffer message completely, before digest
227  m_msg_buffer.insert(m_msg_buffer.end(), input, input+length);
228  }
229 
230 /*
231  * Return the raw (unencoded) data
232  */
233 secure_vector<uint8_t> ISO_9796_DS2::raw_data()
234  {
235  secure_vector<uint8_t> retbuffer = m_msg_buffer;
236  m_msg_buffer.clear();
237  return retbuffer;
238  }
239 
240 /*
241  * ISO-9796-2 scheme 2 encode operation
242  */
243 secure_vector<uint8_t> ISO_9796_DS2::encoding_of(const secure_vector<uint8_t>& msg,
244  size_t output_bits, RandomNumberGenerator& rng)
245  {
246  return iso9796_encoding(msg, output_bits, m_hash, m_SALT_SIZE, m_implicit, rng);
247  }
248 
249 /*
250  * ISO-9796-2 scheme 2 verify operation
251  */
252 bool ISO_9796_DS2::verify(const secure_vector<uint8_t>& const_coded,
253  const secure_vector<uint8_t>& raw, size_t key_bits)
254  {
255  return iso9796_verification(const_coded,raw,key_bits,m_hash,m_SALT_SIZE);
256  }
257 
258 /*
259  * Return the SCAN name
260  */
261 std::string ISO_9796_DS2::name() const
262  {
263  return "ISO_9796_DS2(" + m_hash->name() + ","
264  + (m_implicit ? "imp" : "exp") + "," + std::to_string(m_SALT_SIZE) + ")";
265  }
266 
268  {
269  return new ISO_9796_DS3(m_hash->clone(), m_implicit);
270  }
271 
272 /*
273  * ISO-9796-2 signature scheme 3
274  * DS 3 is deterministic and equals DS2 without salt
275  */
276 void ISO_9796_DS3::update(const uint8_t input[], size_t length)
277  {
278  //need to buffer message completely, before digest
279  m_msg_buffer.insert(m_msg_buffer.end(), input, input+length);
280  }
281 
282 /*
283  * Return the raw (unencoded) data
284  */
285 secure_vector<uint8_t> ISO_9796_DS3::raw_data()
286  {
287  secure_vector<uint8_t> retbuffer = m_msg_buffer;
288  m_msg_buffer.clear();
289  return retbuffer;
290  }
291 
292 /*
293  * ISO-9796-2 scheme 3 encode operation
294  */
295 secure_vector<uint8_t> ISO_9796_DS3::encoding_of(const secure_vector<uint8_t>& msg,
296  size_t output_bits, RandomNumberGenerator& rng)
297  {
298  return iso9796_encoding(msg, output_bits, m_hash, 0, m_implicit, rng);
299  }
300 
301 /*
302  * ISO-9796-2 scheme 3 verify operation
303  */
304 bool ISO_9796_DS3::verify(const secure_vector<uint8_t>& const_coded,
305  const secure_vector<uint8_t>& raw, size_t key_bits)
306  {
307  return iso9796_verification(const_coded, raw, key_bits, m_hash, 0);
308  }
309 /*
310  * Return the SCAN name
311  */
312 std::string ISO_9796_DS3::name() const
313  {
314  return "ISO_9796_DS3(" + m_hash->name() + "," +
315  (m_implicit ? "imp" : "exp") + ")";
316  }
317 }
EMSA * clone() override
Definition: iso9796.cpp:215
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.cpp:51
std::string name() const override
Definition: iso9796.cpp:312
void poison(const T *p, size_t n)
Definition: ct_utils.h:46
uint8_t ieee1363_hash_id(const std::string &name)
Definition: hash_id.cpp:146
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:145
T is_less(T a, T b)
Definition: ct_utils.h:130
ISO_9796_DS3(HashFunction *hash, bool implicit=false)
Definition: iso9796.h:69
Definition: alg_id.cpp:13
std::string name() const override
Definition: iso9796.cpp:261
T is_zero(T x)
Definition: ct_utils.h:118
size_t buffer_insert(std::vector< T, Alloc > &buf, size_t buf_offset, const T input[], size_t input_length)
Definition: secmem.h:103
void unpoison(const T *p, size_t n)
Definition: ct_utils.h:57
void mgf1_mask(HashFunction &hash, const uint8_t in[], size_t in_len, uint8_t out[], size_t out_len)
Definition: mgf1.cpp:14
ISO_9796_DS2(HashFunction *hash, bool implicit=false)
Definition: iso9796.h:26
MechanismType hash
EMSA * clone() override
Definition: iso9796.cpp:267