9#include <botan/internal/iso9796.h>
11#include <botan/exceptn.h>
12#include <botan/hash.h>
14#include <botan/internal/ct_utils.h>
15#include <botan/internal/fmt.h>
16#include <botan/internal/hash_id.h>
17#include <botan/internal/mgf1.h>
24 std::span<const uint8_t> msg1,
25 std::span<const uint8_t> hmsg2,
26 std::span<const uint8_t> salt) {
28 hash.update_be(
static_cast<uint64_t
>(msg1.size()) * 8);
32 return hash.final_stdvec();
35std::vector<uint8_t> iso9796_encoding(std::span<const uint8_t> msg,
37 std::unique_ptr<HashFunction>& hash,
41 const size_t output_length = (output_bits + 7) / 8;
44 const size_t trailer_len = (implicit) ? 1 : 2;
46 const size_t hash_len = hash->output_length();
48 if(output_length <= hash_len + salt_len + trailer_len) {
49 throw Encoding_Error(
"ISO9796-2::encoding_of: Output length is too small");
53 const size_t capacity = output_length - hash_len - salt_len - trailer_len - 1;
56 const size_t msg1_len = std::min(capacity, msg.size());
57 const auto msg1 = msg.first(msg1_len);
58 const auto msg2 = msg.subspan(msg1_len);
60 const auto hmsg2 = hash->process<std::vector<uint8_t>>(msg2);
61 const auto salt = rng.random_vec<std::vector<uint8_t>>(salt_len);
63 const auto H = iso9796_hash(*hash, msg1, hmsg2, salt);
65 std::vector<uint8_t> EM(output_length);
68 stuffer.append(0x00, stuffer.remaining_capacity() - (hash_len + salt_len + trailer_len + msg1_len + 1));
74 const size_t mgf1_bytes = EM.size() - hash_len - trailer_len;
75 mgf1_mask(*hash, H, std::span{EM}.first(mgf1_bytes));
89 throw Encoding_Error(
"ISO-9796: no hash identifier for " + hash->name());
91 stuffer.append(hash_id);
100bool iso9796_verification(std::span<const uint8_t> repr,
101 std::span<const uint8_t> raw,
103 std::unique_ptr<HashFunction>& hash,
105 if(repr.size() != (key_bits + 7) / 8) {
110 const uint8_t last = repr[repr.size() - 1];
112 if(last != 0xBC && last != 0xCC) {
116 const size_t trailer_len = last == 0xBC ? 1 : 2;
118 if(trailer_len == 2) {
121 throw Decoding_Error(
"ISO-9796: no hash identifier for " + hash->name());
124 const uint8_t trailer_0 = repr[repr.size() - 2];
125 const uint8_t trailer_1 = repr[repr.size() - 1];
127 if(trailer_0 != hash_id || trailer_1 != 0xCC) {
132 const size_t hash_len = hash->output_length();
134 if(repr.size() < hash_len + trailer_len + salt_len) {
138 std::vector<uint8_t> coded(repr.begin(), repr.end());
142 uint8_t* DB = coded.data();
143 const size_t DB_size = coded.size() - hash_len - trailer_len;
145 const uint8_t* H = &coded[DB_size];
147 mgf1_mask(*hash, {H, hash_len}, {DB, DB_size});
152 size_t msg1_offset = 1;
157 for(
size_t j = 0; j < DB_size; ++j) {
161 const auto add_m = waiting_for_delim & is_zero;
163 bad_input |= waiting_for_delim & ~(is_zero | is_one);
164 msg1_offset += add_m.if_set_return(1);
166 waiting_for_delim &= is_zero;
170 bad_input |= waiting_for_delim;
172 const auto bad_offset =
CT::Mask<size_t>::is_lt(coded.size(), trailer_len + hash_len + msg1_offset + salt_len);
181 const size_t msg1_len = coded.size() - (trailer_len + hash_len + msg1_offset + salt_len);
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);
187 const size_t capacity = (key_bits - 2 + 7) / 8 - hash_len - salt_len - trailer_len - 1;
189 std::span<const uint8_t> msg1raw = raw;
190 if(msg1raw.size() > capacity) {
191 hash->update(msg1raw.subspan(capacity));
192 msg1raw = msg1raw.first(capacity);
195 const auto hmsg2 = hash->final_stdvec();
198 const auto H2 = iso9796_hash(*hash, msg1, hmsg2, salt);
205 bad_input |=
~CT::is_equal(msg1.data(), msg1raw.data(), std::min(msg1.size(), msg1raw.size()));
208 return (bad_input.as_bool() ==
false);
217void ISO_9796_DS2::update(
const uint8_t input[],
size_t length) {
219 m_msg_buffer.insert(m_msg_buffer.end(), input, input + length);
226 std::vector<uint8_t> retbuffer = m_msg_buffer;
227 m_msg_buffer.clear();
234std::vector<uint8_t> ISO_9796_DS2::encoding_of(std::span<const uint8_t> msg,
237 return iso9796_encoding(msg, output_bits, m_hash, m_salt_len, m_implicit, rng);
243bool ISO_9796_DS2::verify(std::span<const uint8_t> repr, std::span<const uint8_t> raw,
size_t key_bits) {
244 return iso9796_verification(repr, raw, key_bits, m_hash, m_salt_len);
248 return m_hash->name();
255 return fmt(
"ISO_9796_DS2({},{},{})", m_hash->name(), (m_implicit ?
"imp" :
"exp"), m_salt_len);
262void ISO_9796_DS3::update(
const uint8_t input[],
size_t length) {
264 m_msg_buffer.insert(m_msg_buffer.end(), input, input + length);
271 std::vector<uint8_t> retbuffer = m_msg_buffer;
272 m_msg_buffer.clear();
279std::vector<uint8_t> ISO_9796_DS3::encoding_of(std::span<const uint8_t> msg,
282 return iso9796_encoding(msg, output_bits, m_hash, 0, m_implicit, rng);
288bool ISO_9796_DS3::verify(std::span<const uint8_t> repr, std::span<const uint8_t> raw,
size_t key_bits) {
289 return iso9796_verification(repr, raw, key_bits, m_hash, 0);
293 return m_hash->name();
300 return fmt(
"ISO_9796_DS3({},{})", m_hash->name(), (m_implicit ?
"imp" :
"exp"));
#define BOTAN_ASSERT_NOMSG(expr)
Helper class to ease in-place marshalling of concatenated fixed-length values.
static constexpr Mask< T > set()
static constexpr Mask< T > expand(T v)
static constexpr Mask< T > is_equal(T x, T y)
static constexpr Mask< T > is_lt(T x, T y)
static constexpr Mask< T > is_zero(T x)
static constexpr Mask< T > cleared()
std::string name() const override
std::string hash_function() const override
std::string hash_function() const override
std::string name() const override
virtual std::vector< uint8_t > raw_data()=0
constexpr CT::Mask< T > is_not_equal(const T x[], const T y[], size_t len)
constexpr void unpoison(const T *p, size_t n)
constexpr void poison(const T *p, size_t n)
std::string fmt(std::string_view format, const T &... args)
void mgf1_mask(HashFunction &hash, std::span< const uint8_t > input, std::span< uint8_t > output)
uint8_t ieee1363_hash_id(std::string_view name)