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 mgf1_mask(*hash, H.data(), hash_len, EM.data(), output_length - hash_len - trailer_len);
88 throw Encoding_Error(
"ISO-9796: no hash identifier for " + hash->name());
90 stuffer.append(hash_id);
99bool iso9796_verification(std::span<const uint8_t> repr,
100 std::span<const uint8_t> raw,
102 std::unique_ptr<HashFunction>& hash,
104 if(repr.size() != (key_bits + 7) / 8) {
109 const uint8_t last = repr[repr.size() - 1];
111 if(last != 0xBC && last != 0xCC) {
115 const size_t trailer_len = last == 0xBC ? 1 : 2;
117 if(trailer_len == 2) {
120 throw Decoding_Error(
"ISO-9796: no hash identifier for " + hash->name());
123 const uint8_t trailer_0 = repr[repr.size() - 2];
124 const uint8_t trailer_1 = repr[repr.size() - 1];
126 if(trailer_0 != hash_id || trailer_1 != 0xCC) {
131 const size_t hash_len = hash->output_length();
133 if(repr.size() < hash_len + trailer_len + salt_len) {
137 std::vector<uint8_t> coded(repr.begin(), repr.end());
141 uint8_t* DB = coded.data();
142 const size_t DB_size = coded.size() - hash_len - trailer_len;
144 const uint8_t* H = &coded[DB_size];
146 mgf1_mask(*hash, H, hash_len, DB, DB_size);
151 size_t msg1_offset = 1;
156 for(
size_t j = 0; j < DB_size; ++j) {
160 const auto add_m = waiting_for_delim & is_zero;
162 bad_input |= waiting_for_delim & ~(is_zero | is_one);
163 msg1_offset += add_m.if_set_return(1);
165 waiting_for_delim &= is_zero;
169 bad_input |= waiting_for_delim;
171 const auto bad_offset =
CT::Mask<size_t>::is_lt(coded.size(), trailer_len + hash_len + msg1_offset + salt_len);
180 const size_t msg1_len = coded.size() - (trailer_len + hash_len + msg1_offset + salt_len);
182 const auto msg1 = std::span(coded).subspan(msg1_offset, msg1_len);
183 const auto salt = std::span(coded).subspan(msg1_offset + msg1.size(), salt_len);
186 const size_t capacity = (key_bits - 2 + 7) / 8 - hash_len - salt_len - trailer_len - 1;
188 std::span<const uint8_t> msg1raw = raw;
189 if(msg1raw.size() > capacity) {
190 hash->update(msg1raw.subspan(capacity));
191 msg1raw = msg1raw.first(capacity);
194 const auto hmsg2 = hash->final_stdvec();
197 const auto H2 = iso9796_hash(*hash, msg1, hmsg2, salt);
204 bad_input |=
~CT::is_equal(msg1.data(), msg1raw.data(), std::min(msg1.size(), msg1raw.size()));
207 return (bad_input.as_bool() ==
false);
216void ISO_9796_DS2::update(
const uint8_t input[],
size_t length) {
218 m_msg_buffer.insert(m_msg_buffer.end(), input, input + length);
225 std::vector<uint8_t> retbuffer = m_msg_buffer;
226 m_msg_buffer.clear();
233std::vector<uint8_t> ISO_9796_DS2::encoding_of(std::span<const uint8_t> msg,
236 return iso9796_encoding(msg, output_bits, m_hash, m_salt_len, m_implicit, rng);
242bool ISO_9796_DS2::verify(std::span<const uint8_t> repr, std::span<const uint8_t> raw,
size_t key_bits) {
243 return iso9796_verification(repr, raw, key_bits, m_hash, m_salt_len);
247 return m_hash->name();
254 return fmt(
"ISO_9796_DS2({},{},{})", m_hash->name(), (m_implicit ?
"imp" :
"exp"), m_salt_len);
261void ISO_9796_DS3::update(
const uint8_t input[],
size_t length) {
263 m_msg_buffer.insert(m_msg_buffer.end(), input, input + length);
270 std::vector<uint8_t> retbuffer = m_msg_buffer;
271 m_msg_buffer.clear();
278std::vector<uint8_t> ISO_9796_DS3::encoding_of(std::span<const uint8_t> msg,
281 return iso9796_encoding(msg, output_bits, m_hash, 0, m_implicit, rng);
287bool ISO_9796_DS3::verify(std::span<const uint8_t> repr, std::span<const uint8_t> raw,
size_t key_bits) {
288 return iso9796_verification(repr, raw, key_bits, m_hash, 0);
292 return m_hash->name();
299 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)
void mgf1_mask(HashFunction &hash, const uint8_t in[], size_t in_len, uint8_t out[], size_t out_len)
std::string fmt(std::string_view format, const T &... args)
uint8_t ieee1363_hash_id(std::string_view name)