Botan 2.1.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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 }
Botan::same_mem
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:98
Botan::CT::is_less
T is_less(T x, T y)
Definition: ct_utils.h:122
Botan::CT::poison
void poison(const T *p, size_t n)
Definition: ct_utils.h:46
Botan::ieee1363_hash_id
uint8_t ieee1363_hash_id(const std::string &name)
Definition: hash_id.cpp:104
Botan
Definition: alg_id.cpp:13
Botan::CT::is_zero
T is_zero(T x)
Definition: ct_utils.h:110
Botan::mgf1_mask
void mgf1_mask(HashFunction &hash, const uint8_t in[], size_t in_len, uint8_t out[], size_t out_len)
Definition: mgf1.cpp:14
Botan::buffer_insert
size_t buffer_insert(std::vector< T, Alloc > &buf, size_t buf_offset, const T input[], size_t input_length)
Definition: secmem.h:133
Botan::CT::unpoison
void unpoison(const T *p, size_t n)
Definition: ct_utils.h:57
hash
MechanismType hash
Definition: p11_mechanism.cpp:63