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