Botan 3.13.0
Crypto and TLS for C&
prf_x942.cpp
Go to the documentation of this file.
1/*
2* X9.42 PRF
3* (C) 1999-2007 Jack Lloyd
4* (C) 2024 René Meusel, Rohde & Schwarz Cybersecurity
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/internal/prf_x942.h>
10
11#include <botan/der_enc.h>
12#include <botan/hash.h>
13#include <botan/internal/bit_ops.h>
14#include <botan/internal/buffer_stuffer.h>
15#include <botan/internal/concat_util.h>
16#include <botan/internal/loadstor.h>
17
18namespace Botan {
19
20namespace {
21
22/*
23* Encode an integer as an OCTET STRING
24*/
25std::vector<uint8_t> encode_x942_int(uint32_t n) {
26 const auto n_buf = store_be(n);
27
28 std::vector<uint8_t> output;
29 DER_Encoder(output).encode(n_buf.data(), n_buf.size(), ASN1_Type::OctetString);
30 return output;
31}
32
33} // namespace
34
35void X942_PRF::perform_kdf(std::span<uint8_t> key,
36 std::span<const uint8_t> secret,
37 std::span<const uint8_t> salt,
38 std::span<const uint8_t> label) const {
39 if(key.empty()) {
40 return;
41 }
42
43 constexpr size_t sha1_output_bytes = 20; // Fixed to use SHA-1
44 const auto blocks_required = ceil_division<uint64_t /* for 32bit systems */>(key.size(), sha1_output_bytes);
45
46 // This KDF uses a 32-bit counter for the hash blocks, initialized at 1.
47 // It will wrap around after 2^32 - 1 iterations limiting the theoretically
48 // possible output to 2^32 - 1 blocks.
49 BOTAN_ARG_CHECK(blocks_required <= 0xFFFFFFFE, "X942_PRF maximum output length exceeded");
50
51 // The key length in bits is encoded as a uint32_t in the DER output
52 BOTAN_ARG_CHECK(key.size() <= 0x1FFFFFFF, "X942_PRF output length too large for DER encoding");
53
54 auto hash = HashFunction::create("SHA-1");
55
56 const auto label_and_salt = [&]() -> std::vector<uint8_t> {
57 if(label.empty() && salt.empty()) {
58 return {};
59 }
60
61 const auto combined = concat<std::vector<uint8_t>>(label, salt);
62 return DER_Encoder()
63 .start_explicit(0)
64 .encode(combined, ASN1_Type::OctetString)
65 .end_explicit()
66 .get_contents_unlocked();
67 }();
68
69 BufferStuffer k(key);
70 for(uint32_t counter = 1; !k.full(); ++counter) {
71 BOTAN_ASSERT_NOMSG(counter != 0); // overflow check
72
73 hash->update(secret);
74 hash->update(DER_Encoder()
75 .start_sequence()
76
77 .start_sequence()
78 .encode(m_key_wrap_oid)
79 .raw_bytes(encode_x942_int(counter))
80 .end_cons()
81
82 .raw_bytes(label_and_salt)
83
84 .start_explicit(2)
85 .raw_bytes(encode_x942_int(static_cast<uint32_t>(8 * key.size())))
86 .end_explicit()
87
88 .end_cons()
89 .get_contents());
90
91 // Write straight into the output buffer, except if the hash output needs
92 // a truncation in the final iteration.
93 if(k.remaining_capacity() >= sha1_output_bytes) {
94 hash->final(k.next(sha1_output_bytes));
95 } else {
96 std::array<uint8_t, sha1_output_bytes> h{};
97 hash->final(h);
98 k.append(std::span{h}.first(k.remaining_capacity()));
99 }
100 }
101}
102
103std::string X942_PRF::name() const {
104 return "X9.42-PRF(" + m_key_wrap_oid.to_formatted_string() + ")";
105}
106
107} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
DER_Encoder & encode(bool b)
Definition der_enc.cpp:313
static std::unique_ptr< HashFunction > create(std::string_view algo_spec, std::string_view provider="")
Definition hash.cpp:111
std::string name() const override
Definition prf_x942.cpp:103
std::string encode(const uint8_t der[], size_t length, std::string_view label, size_t width)
Definition pem.cpp:39
BOTAN_FORCE_INLINE constexpr T ceil_division(T a, T b)
Definition bit_ops.h:167
constexpr auto concat(Rs &&... ranges)
Definition concat_util.h:90
constexpr auto store_be(ParamTs &&... params)
Definition loadstor.h:745