9#include <botan/internal/iso9796.h>
11#include <botan/exceptn.h>
12#include <botan/hash.h>
14#include <botan/internal/buffer_stuffer.h>
15#include <botan/internal/ct_utils.h>
16#include <botan/internal/fmt.h>
17#include <botan/internal/hash_id.h>
18#include <botan/internal/mgf1.h>
25 std::span<const uint8_t> msg1,
26 std::span<const uint8_t> hmsg2,
27 std::span<const uint8_t> salt) {
29 hash.update_be(
static_cast<uint64_t
>(msg1.size()) * 8);
33 return hash.final_stdvec();
36std::vector<uint8_t> iso9796_encoding(std::span<const uint8_t> msg,
38 std::unique_ptr<HashFunction>& hash,
42 const size_t output_length = (output_bits + 7) / 8;
45 const size_t trailer_len = (implicit) ? 1 : 2;
47 const size_t hash_len = hash->output_length();
49 if(output_length <= hash_len + salt_len + trailer_len) {
50 throw Encoding_Error(
"ISO9796-2::encoding_of: Output length is too small");
54 const size_t capacity = output_length - hash_len - salt_len - trailer_len - 1;
57 const size_t msg1_len = std::min(capacity, msg.size());
58 const auto msg1 = msg.first(msg1_len);
59 const auto msg2 = msg.subspan(msg1_len);
61 const auto hmsg2 = hash->process<std::vector<uint8_t>>(msg2);
62 const auto salt = rng.random_vec<std::vector<uint8_t>>(salt_len);
64 const auto H = iso9796_hash(*hash, msg1, hmsg2, salt);
66 std::vector<uint8_t> EM(output_length);
69 stuffer.append(0x00, stuffer.remaining_capacity() - (hash_len + salt_len + trailer_len + msg1_len + 1));
75 const size_t mgf1_bytes = EM.size() - hash_len - trailer_len;
76 mgf1_mask(*hash, H, std::span{EM}.first(mgf1_bytes));
79 EM[0] &= 0xFF >> (8 * output_length - output_bits);
90 throw Encoding_Error(
"ISO-9796: no hash identifier for " + hash->name());
92 stuffer.append(hash_id);
101bool iso9796_verification(std::span<const uint8_t> repr,
102 std::span<const uint8_t> raw,
104 std::unique_ptr<HashFunction>& hash,
109 if(repr.size() > key_bytes) {
115 std::vector<uint8_t> coded(key_bytes);
118 stuffer.append(0x00, key_bytes - repr.size());
119 stuffer.append(repr);
129 const size_t trailer_len = implicit ? 1 : 2;
131 const size_t hash_len = hash->output_length();
136 if(coded.size() <= hash_len + trailer_len + salt_len) {
141 if(coded[coded.size() - 1] != 0xBC) {
147 throw Decoding_Error(
"ISO-9796: no hash identifier for " + hash->name());
150 const uint8_t trailer_0 = coded[coded.size() - 2];
151 const uint8_t trailer_1 = coded[coded.size() - 1];
153 if(trailer_0 != hash_id || trailer_1 != 0xCC) {
160 const size_t top_bits = 8 * key_bytes - key_bits;
161 if(top_bits > 8 -
high_bit(coded[0])) {
167 uint8_t* DB = coded.data();
168 const size_t DB_size = coded.size() - hash_len - trailer_len;
170 const uint8_t* H = &coded[DB_size];
172 mgf1_mask(*hash, {H, hash_len}, {DB, DB_size});
174 DB[0] &= 0xFF >> top_bits;
177 size_t msg1_offset = 1;
182 for(
size_t j = 0; j < DB_size; ++j) {
186 const auto add_m = waiting_for_delim & is_zero;
188 bad_input |= waiting_for_delim & ~(is_zero | is_one);
189 msg1_offset += add_m.if_set_return(1);
191 waiting_for_delim &= is_zero;
195 bad_input |= waiting_for_delim;
197 const auto bad_offset =
CT::Mask<size_t>::is_lt(coded.size(), trailer_len + hash_len + msg1_offset + salt_len);
206 const size_t msg1_len = coded.size() - (trailer_len + hash_len + msg1_offset + salt_len);
208 const auto msg1 = std::span(coded).subspan(msg1_offset, msg1_len);
209 const auto salt = std::span(coded).subspan(msg1_offset + msg1.size(), salt_len);
214 const size_t capacity = key_bytes - hash_len - salt_len - trailer_len - 1;
216 std::span<const uint8_t> msg1raw = raw;
217 if(msg1raw.size() > capacity) {
218 hash->update(msg1raw.subspan(capacity));
219 msg1raw = msg1raw.first(capacity);
222 const auto hmsg2 = hash->final_stdvec();
225 const auto H2 = iso9796_hash(*hash, msg1, hmsg2, salt);
232 bad_input |=
~CT::is_equal(msg1.data(), msg1raw.data(), std::min(msg1.size(), msg1raw.size()));
235 return (bad_input.as_bool() ==
false);
244void ISO_9796_DS2::update(
const uint8_t input[],
size_t length) {
247 m_msg_buffer.insert(m_msg_buffer.end(), input, input + length);
255 std::vector<uint8_t> retbuffer = m_msg_buffer;
256 m_msg_buffer.clear();
263std::vector<uint8_t> ISO_9796_DS2::encoding_of(std::span<const uint8_t> msg,
266 return iso9796_encoding(msg, output_bits, m_hash, m_salt_len, m_implicit, rng);
272bool ISO_9796_DS2::verify(std::span<const uint8_t> repr, std::span<const uint8_t> raw,
size_t key_bits) {
273 return iso9796_verification(repr, raw, key_bits, m_hash, m_salt_len, m_implicit);
277 return m_hash->name();
284 return fmt(
"ISO_9796_DS2({},{},{})", m_hash->name(), (m_implicit ?
"imp" :
"exp"), m_salt_len);
291void ISO_9796_DS3::update(
const uint8_t input[],
size_t length) {
294 m_msg_buffer.insert(m_msg_buffer.end(), input, input + length);
302 std::vector<uint8_t> retbuffer = m_msg_buffer;
303 m_msg_buffer.clear();
310std::vector<uint8_t> ISO_9796_DS3::encoding_of(std::span<const uint8_t> msg,
313 return iso9796_encoding(msg, output_bits, m_hash, 0, m_implicit, rng);
319bool ISO_9796_DS3::verify(std::span<const uint8_t> repr, std::span<const uint8_t> raw,
size_t key_bits) {
320 return iso9796_verification(repr, raw, key_bits, m_hash, 0, m_implicit);
324 return m_hash->name();
331 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)
BOTAN_FORCE_INLINE constexpr T ceil_tobytes(T bits)
uint8_t ieee1363_hash_id(std::string_view name)
BOTAN_FORCE_INLINE constexpr size_t high_bit(T n)