Botan 3.13.0
Crypto and TLS for C&
xmd.cpp
Go to the documentation of this file.
1/*
2* (C) 2019,2020,2021,2024 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#include <botan/internal/xmd.h>
8
9#include <botan/exceptn.h>
10#include <botan/hash.h>
11#include <botan/mem_ops.h>
12#include <botan/internal/fmt.h>
13#include <vector>
14
15namespace Botan {
16
18 std::span<uint8_t> output,
19 std::span<const uint8_t> input,
20 std::span<const uint8_t> domain_sep) {
21 if(domain_sep.size() > 0xFF) {
22 // RFC 9380 has a specification for handling this
23 throw Not_Implemented("XMD does not currently implement oversize DST handling");
24 }
25
26 if(domain_sep.empty()) {
27 // RFC 9380 Section 3.1: "Tags MUST have nonzero length."
28 throw Invalid_Argument("expand_message_xmd requires a non-empty domain separation tag");
29 }
30
31 const uint8_t domain_sep_len = static_cast<uint8_t>(domain_sep.size());
32
33 const size_t block_size = hash.hash_block_size();
34 if(block_size == 0) {
35 throw Invalid_Argument(fmt("expand_message_xmd cannot be used with {}", hash.name()));
36 }
37
38 const size_t hash_output_size = hash.output_length();
39
40 // RFC 9380 Section 5.3.1: "For correctness, H requires b <= s."
41 if(hash_output_size > block_size) {
42 throw Invalid_Argument(fmt("expand_message_xmd cannot be used with {}", hash.name()));
43 }
44
45 if(output.size() > 255 * hash_output_size || output.size() > 0xFFFF) {
46 throw Invalid_Argument("expand_message_xmd requested output length too long");
47 }
48
49 // Compute b_0 = H(msg_prime) = H(Z_pad || msg || l_i_b_str || 0x00 || DST_prime)
50
51 hash.update(std::vector<uint8_t>(block_size));
52 hash.update(input);
53 hash.update_be(static_cast<uint16_t>(output.size()));
54 hash.update(0x00);
55 hash.update(domain_sep);
56 hash.update(domain_sep_len);
57
58 const secure_vector<uint8_t> b_0 = hash.final();
59
60 // Compute b_1 = H(b_0 || 0x01 || DST_prime)
61
62 hash.update(b_0);
63 hash.update(0x01);
64 hash.update(domain_sep);
65 hash.update(domain_sep_len);
66
67 secure_vector<uint8_t> b_i = hash.final();
68
69 uint8_t cnt = 2;
70 for(;;) {
71 const size_t produced = std::min(output.size(), hash_output_size);
72
73 copy_mem(output.data(), b_i.data(), produced);
74 output = output.subspan(produced);
75
76 if(output.empty()) {
77 break;
78 }
79
80 // Now compute the next b_i if needed
81
82 b_i ^= b_0;
83 hash.update(b_i);
84 hash.update(cnt);
85 hash.update(domain_sep);
86 hash.update(domain_sep_len);
87 hash.final(b_i);
88 cnt += 1;
89 }
90}
91
92} // namespace Botan
void update(const uint8_t in[], size_t length)
Definition buf_comp.h:35
virtual size_t output_length() const =0
void update_be(uint16_t val)
Definition buf_comp.cpp:18
void final(uint8_t out[])
Definition buf_comp.h:97
virtual size_t hash_block_size() const
Definition hash.h:68
virtual std::string name() const =0
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144
void expand_message_xmd(HashFunction &hash, std::span< uint8_t > output, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep)
Definition xmd.cpp:17
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:128