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));
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,
106 if(repr.size() != (key_bits + 7) / 8) {
111 const uint8_t last = repr[repr.size() - 1];
113 if(last != 0xBC && last != 0xCC) {
117 const size_t trailer_len = last == 0xBC ? 1 : 2;
119 if(trailer_len == 2) {
122 throw Decoding_Error(
"ISO-9796: no hash identifier for " + hash->name());
125 const uint8_t trailer_0 = repr[repr.size() - 2];
126 const uint8_t trailer_1 = repr[repr.size() - 1];
128 if(trailer_0 != hash_id || trailer_1 != 0xCC) {
133 const size_t hash_len = hash->output_length();
135 if(repr.size() < hash_len + trailer_len + salt_len) {
139 std::vector<uint8_t> coded(repr.begin(), repr.end());
143 uint8_t* DB = coded.data();
144 const size_t DB_size = coded.size() - hash_len - trailer_len;
146 const uint8_t* H = &coded[DB_size];
148 mgf1_mask(*hash, {H, hash_len}, {DB, DB_size});
153 size_t msg1_offset = 1;
158 for(
size_t j = 0; j < DB_size; ++j) {
162 const auto add_m = waiting_for_delim & is_zero;
164 bad_input |= waiting_for_delim & ~(is_zero | is_one);
165 msg1_offset += add_m.if_set_return(1);
167 waiting_for_delim &= is_zero;
171 bad_input |= waiting_for_delim;
173 const auto bad_offset =
CT::Mask<size_t>::is_lt(coded.size(), trailer_len + hash_len + msg1_offset + salt_len);
182 const size_t msg1_len = coded.size() - (trailer_len + hash_len + msg1_offset + salt_len);
184 const auto msg1 = std::span(coded).subspan(msg1_offset, msg1_len);
185 const auto salt = std::span(coded).subspan(msg1_offset + msg1.size(), salt_len);
188 const size_t capacity = (key_bits - 2 + 7) / 8 - hash_len - salt_len - trailer_len - 1;
190 std::span<const uint8_t> msg1raw = raw;
191 if(msg1raw.size() > capacity) {
192 hash->update(msg1raw.subspan(capacity));
193 msg1raw = msg1raw.first(capacity);
196 const auto hmsg2 = hash->final_stdvec();
199 const auto H2 = iso9796_hash(*hash, msg1, hmsg2, salt);
206 bad_input |=
~CT::is_equal(msg1.data(), msg1raw.data(), std::min(msg1.size(), msg1raw.size()));
209 return (bad_input.as_bool() ==
false);
218void ISO_9796_DS2::update(
const uint8_t input[],
size_t length) {
220 m_msg_buffer.insert(m_msg_buffer.end(), input, input + length);
227 std::vector<uint8_t> retbuffer = m_msg_buffer;
228 m_msg_buffer.clear();
235std::vector<uint8_t> ISO_9796_DS2::encoding_of(std::span<const uint8_t> msg,
238 return iso9796_encoding(msg, output_bits, m_hash, m_salt_len, m_implicit, rng);
244bool ISO_9796_DS2::verify(std::span<const uint8_t> repr, std::span<const uint8_t> raw,
size_t key_bits) {
245 return iso9796_verification(repr, raw, key_bits, m_hash, m_salt_len);
249 return m_hash->name();
256 return fmt(
"ISO_9796_DS2({},{},{})", m_hash->name(), (m_implicit ?
"imp" :
"exp"), m_salt_len);
263void ISO_9796_DS3::update(
const uint8_t input[],
size_t length) {
265 m_msg_buffer.insert(m_msg_buffer.end(), input, input + length);
272 std::vector<uint8_t> retbuffer = m_msg_buffer;
273 m_msg_buffer.clear();
280std::vector<uint8_t> ISO_9796_DS3::encoding_of(std::span<const uint8_t> msg,
283 return iso9796_encoding(msg, output_bits, m_hash, 0, m_implicit, rng);
289bool ISO_9796_DS3::verify(std::span<const uint8_t> repr, std::span<const uint8_t> raw,
size_t key_bits) {
290 return iso9796_verification(repr, raw, key_bits, m_hash, 0);
294 return m_hash->name();
301 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)