Skip to content

Commit a5c4f9c

Browse files
authored
Merge pull request #4965 from randombit/jack/cleanup-iso9796
Cleanup ISO-9796 padding implementation
2 parents 8e84cba + 5f9aeb7 commit a5c4f9c

3 files changed

Lines changed: 60 additions & 45 deletions

File tree

src/lib/pk_pad/iso9796/iso9796.cpp

Lines changed: 46 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@ namespace Botan {
2121

2222
namespace {
2323

24+
std::vector<uint8_t> iso9796_hash(HashFunction& hash,
25+
std::span<const uint8_t> msg1,
26+
std::span<const uint8_t> hmsg2,
27+
std::span<const uint8_t> salt) {
28+
// Compute H(C || msg1 || H(msg2) || S) as described in the ISO text
29+
hash.update_be(static_cast<uint64_t>(msg1.size()) * 8);
30+
hash.update(msg1);
31+
hash.update(hmsg2);
32+
hash.update(salt);
33+
return hash.final_stdvec();
34+
}
35+
2436
std::vector<uint8_t> iso9796_encoding(std::span<const uint8_t> msg,
2537
size_t output_bits,
2638
std::unique_ptr<HashFunction>& hash,
@@ -41,22 +53,15 @@ std::vector<uint8_t> iso9796_encoding(std::span<const uint8_t> msg,
4153
//calculate message capacity
4254
const size_t capacity = output_length - hash_len - salt_len - trailer_len - 1;
4355

44-
//msg1 is the recoverable and hmsg2 is the hash of the unrecoverable message part.
45-
std::span<const uint8_t> msg1;
56+
// msg1 is the recoverable part and hmsg2 is the hash of the unrecoverable message part.
4657
const size_t msg1_len = std::min(capacity, msg.size());
47-
const size_t msg2_len = msg.size() - msg1_len; // possibly zero
48-
msg1 = msg.first(msg1_len);
49-
50-
hash->update(msg.subspan(msg1_len, msg2_len)); // possibly empty
51-
const std::vector<uint8_t> hmsg2 = hash->final_stdvec();
58+
const auto msg1 = msg.first(msg1_len); // the first capacity bytes
59+
const auto msg2 = msg.subspan(msg1_len); // the rest; possibly empty
5260

53-
//compute H(C||msg1 ||H(msg2)||S)
61+
const auto hmsg2 = hash->process<std::vector<uint8_t>>(msg2);
5462
const auto salt = rng.random_vec<std::vector<uint8_t>>(salt_len);
55-
hash->update_be(static_cast<uint64_t>(msg1_len) * 8);
56-
hash->update(msg1);
57-
hash->update(hmsg2);
58-
hash->update(salt);
59-
const std::vector<uint8_t> H = hash->final_stdvec();
63+
64+
const auto H = iso9796_hash(*hash, msg1, hmsg2, salt);
6065

6166
std::vector<uint8_t> EM(output_length);
6267

@@ -97,10 +102,7 @@ bool iso9796_verification(std::span<const uint8_t> repr,
97102
size_t key_bits,
98103
std::unique_ptr<HashFunction>& hash,
99104
size_t salt_len) {
100-
const size_t hash_len = hash->output_length();
101-
const size_t KEY_BYTES = (key_bits + 7) / 8;
102-
103-
if(repr.size() != KEY_BYTES) {
105+
if(repr.size() != (key_bits + 7) / 8) {
104106
return false;
105107
}
106108
//get trailer length
@@ -127,6 +129,12 @@ bool iso9796_verification(std::span<const uint8_t> repr,
127129
}
128130
}
129131

132+
const size_t hash_len = hash->output_length();
133+
134+
if(repr.size() < hash_len + trailer_len + salt_len) {
135+
return false;
136+
}
137+
130138
std::vector<uint8_t> coded(repr.begin(), repr.end());
131139

132140
CT::poison(coded.data(), coded.size());
@@ -170,37 +178,31 @@ bool iso9796_verification(std::span<const uint8_t> repr,
170178
CT::unpoison(coded.data(), coded.size());
171179
CT::unpoison(msg1_offset);
172180

173-
std::vector<uint8_t> msg1(coded.begin() + msg1_offset, coded.end() - trailer_len - hash_len - salt_len);
174-
std::vector<uint8_t> salt(coded.begin() + msg1_offset + msg1.size(), coded.end() - trailer_len - hash_len);
181+
const size_t msg1_len = coded.size() - (trailer_len + hash_len + msg1_offset + salt_len);
182+
183+
const auto msg1 = std::span(coded).subspan(msg1_offset, msg1_len);
184+
const auto salt = std::span(coded).subspan(msg1_offset + msg1.size(), salt_len);
175185

176186
//compute H2(C||msg1||H(msg2)||S*). * indicates a recovered value
177187
const size_t capacity = (key_bits - 2 + 7) / 8 - hash_len - salt_len - trailer_len - 1;
178-
std::vector<uint8_t> msg1raw;
179-
if(raw.size() > capacity) {
180-
msg1raw = std::vector<uint8_t>(raw.begin(), raw.begin() + capacity);
181-
hash->update(std::span(raw).subspan(capacity));
182-
} else {
183-
msg1raw.assign(raw.begin(), raw.end());
188+
189+
std::span<const uint8_t> msg1raw = raw;
190+
if(msg1raw.size() > capacity) {
191+
hash->update(msg1raw.subspan(capacity));
192+
msg1raw = msg1raw.first(capacity);
184193
}
185-
const std::vector<uint8_t> hmsg2 = hash->final_stdvec();
186-
187-
const uint64_t msg1rawLength = msg1raw.size();
188-
hash->update_be(msg1rawLength * 8);
189-
hash->update(msg1raw);
190-
hash->update(hmsg2);
191-
hash->update(salt);
192-
std::vector<uint8_t> H3 = hash->final_stdvec();
193-
194-
//compute H3(C*||msg1*||H(msg2)||S*) * indicates a recovered value
195-
const uint64_t msg1_len = msg1.size();
196-
hash->update_be(msg1_len * 8);
197-
hash->update(msg1);
198-
hash->update(hmsg2);
199-
hash->update(salt);
200-
std::vector<uint8_t> H2 = hash->final_stdvec();
201-
202-
//check if H3 == H2
203-
bad_input |= CT::is_not_equal(H3.data(), H2.data(), hash_len);
194+
195+
const auto hmsg2 = hash->final_stdvec();
196+
197+
// Compute H(C*||msg1*||H(msg2)||S*) where '*' indicates a recovered value
198+
const auto H2 = iso9796_hash(*hash, msg1, hmsg2, salt);
199+
200+
// Check if H == H2
201+
bad_input |= CT::is_not_equal(H, H2.data(), hash_len);
202+
203+
// Check that msg after MGF1 matches msg in the original
204+
bad_input |= ~CT::Mask<uint8_t>(CT::Mask<size_t>::is_equal(msg1.size(), msg1raw.size()));
205+
bad_input |= ~CT::is_equal(msg1.data(), msg1raw.data(), std::min(msg1.size(), msg1raw.size()));
204206

205207
CT::unpoison(bad_input);
206208
return (bad_input.as_bool() == false);

src/lib/prov/pkcs11/p11_mechanism.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ const std::map<std::string, RSA_SignMechanism> SignMechanisms = {
114114
{"PSS(SHA-512)", RSA_SignMechanism(MechanismType::Sha512RsaPkcsPss)},
115115
{"PSS(SHA-512,MGF1,64)", RSA_SignMechanism(MechanismType::Sha512RsaPkcsPss)},
116116

117-
// ISO 9796 (TODO is this DS1, DS2, or DS3?)
117+
// ISO 9796 - this is the obsolete and insecure DS1 scheme, not the PSS-based DS2/DS3
118+
// TODO(Botan4) remove this
118119
{"ISO9796", RSA_SignMechanism(MechanismType::Rsa9796)},
119120

120121
// Deprecated aliases

src/tests/data/pubkey/rsa_verify.vec

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,12 +569,24 @@ N = 1252422424673042269808180400296267714490893999696163333810499416229537186732
569569
Msg = 6162636462636465636465666465666765666768666768696768696A68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F70716F70717270717273
570570
Signature = 2486dd61e560e661511db92f41045a87cbbb78ce577d28da533bc15fdf9cbc2748311a5faa6501270b46414ba3549de34160c1ef18eff339eeeae2c53f7ed4a5fddc19c5b3f5c391e8efb5548555d478f0698ec351f6a4974c9c74f0a0eba9fc03db9253f41f02ffc5f03cb9d1973946993aa3f831aa1d9e73a783e67bf7695d
571571

572+
# From ISO 9697-2 Appendix D.1.2.3
573+
E = 3
574+
N = 0xFAA8ED34EEF1CE38D29814B6EEAA154DC060BB37EB1A51E8AB0398DDADDFD334CB9BE20C087B1DDF1F78A39762B5F20A7A73008630913CD2EE60183DE249DD169CA4EB3AE0420E5113D730504A73A926BEFBFF32C89858DE5E5B3899FEC5252104933163625F29635AB8FAA7AA14C4F3C0DD2470DEFCEB392429110A0149A771
575+
Msg =
576+
Signature = F9DD9F72FAB4AFFCED3B0538C5848B27756AC50CB2890F4CBC268D96C5E91EE88E3B058F2EF6585FEF5323CA4E2C308CC6140CF5F53579605B3BF0CC621082EB77F4A42D3567355EAA151FB4652BAFFE58A4B3107A064669FD4177C8D79F5DE5EEC562FFA2D0F5D9C409AEA0D5B9F8DF493AF2F18F91D828CE32C4CC35C13113
577+
572578
[ISO_9796_DS2(RIPEMD-160,exp)]
573579
E = 17
574580
N = 125242242467304226980818040029626771449089399969616333381049941622953718673240322529328207020354780888067722576207206966012991943446137640922660671107037754599453565985942582513009492907982173446675216454634592761000191710251638590123948630732326307922952494464857505415177402322499891218582307842351942219477
575581
Msg = FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA98
576582
Signature = 3d853e02ccea35ac803227458aaf5c964387e20390a476419e853ed415b3ad2ad750d19b4e4667597c1863ea2b0aa35fdbb4de589c4663583674e2c8d15d07daa54ff389ae96d78cceb2b5a50b649362357042b2c40d780361b7f6f089c7e27e92d21db1b3e3d368582e3dfdcf0312f727743c09c5c2cb3c0552b78db71be278
577583

584+
# From ISO 9697-2 Appendix D.1.2.2
585+
E = 3
586+
N = 0xFAA8ED34EEF1CE38D29814B6EEAA154DC060BB37EB1A51E8AB0398DDADDFD334CB9BE20C087B1DDF1F78A39762B5F20A7A73008630913CD2EE60183DE249DD169CA4EB3AE0420E5113D730504A73A926BEFBFF32C89858DE5E5B3899FEC5252104933163625F29635AB8FAA7AA14C4F3C0DD2470DEFCEB392429110A0149A771
587+
Msg = FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210
588+
Signature = A4958BADDA6AB0F5E7F544BB1313DB93BB7336053678459A31386D3A9F0A477F37B853DF6BBBA87BECAC7CD2B19FFACD98B40E820B638D5F7DDAAE56FF198EF6AB1002C376C1FFDE03041201FF8E6AF94AFDF05606E10E32F3F6909134864AEBD983AAA2BD725FCCA288DECE27810D34807956DC78F3CFC4EA45A8DFADA4226C
589+
578590
[ISO_9796_DS3(RIPEMD-160,imp)]
579591
E = 17
580592
N = 125242242467304226980818040029626771449089399969616333381049941622953718673240322529328207020354780888067722576207206966012991943446137640922660671107037754599453565985942582513009492907982173446675216454634592761000191710251638590123948630732326307922952494464857505415177402322499891218582307842351942219477

0 commit comments

Comments
 (0)