8#include <botan/internal/pssr.h>
10#include <botan/exceptn.h>
11#include <botan/hash.h>
13#include <botan/internal/ct_utils.h>
14#include <botan/internal/fmt.h>
15#include <botan/internal/mgf1.h>
26 std::span<const uint8_t> msg,
27 std::span<const uint8_t> salt,
29 const size_t HASH_SIZE = hash.output_length();
31 if(msg.size() != HASH_SIZE) {
32 throw Encoding_Error(
"Cannot encode PSS string, input length invalid for hash");
34 if(output_bits < 8 * HASH_SIZE + 8 * salt.size() + 9) {
35 throw Encoding_Error(
"Cannot encode PSS string, output length too small");
39 const uint8_t db0_mask = 0xFF >> (8 * output_length - output_bits);
41 std::array<uint8_t, 8> padding = {0};
45 std::vector<uint8_t> H = hash.final_stdvec();
47 const size_t db_len = output_length - HASH_SIZE - 1;
48 std::vector<uint8_t> EM(output_length);
51 stuffer.append(0x00, stuffer.remaining_capacity() - (1 + salt.size() + H.size() + 1));
55 mgf1_mask(hash, H.data(), H.size(), EM.data(), db_len);
66 std::span<const uint8_t> pss_repr,
67 std::span<const uint8_t> message_hash,
69 size_t* out_salt_size) {
70 const size_t HASH_SIZE = hash.output_length();
73 if(key_bits < 8 * HASH_SIZE + 9) {
77 if(message_hash.size() != HASH_SIZE) {
81 if(pss_repr.size() > key_bytes || pss_repr.size() <= 1) {
85 if(pss_repr[pss_repr.size() - 1] != 0xBC) {
89 std::vector<uint8_t> coded;
90 if(pss_repr.size() < key_bytes) {
91 coded.resize(key_bytes);
93 stuffer.append(0x00, key_bytes - pss_repr.size());
94 stuffer.append(pss_repr);
96 coded.assign(pss_repr.begin(), pss_repr.end());
100 const size_t top_bits = 8 * ((key_bits + 7) / 8) - key_bits;
101 if(top_bits > 8 -
high_bit(coded[0])) {
105 uint8_t* DB = coded.data();
106 const size_t DB_size = coded.size() - HASH_SIZE - 1;
108 const uint8_t* H = &coded[DB_size];
109 const size_t H_size = HASH_SIZE;
112 DB[0] &= 0xFF >> top_bits;
114 size_t salt_offset = 0;
115 for(
size_t j = 0; j != DB_size; ++j) {
124 if(salt_offset == 0) {
128 const size_t salt_size = DB_size - salt_offset;
130 std::array<uint8_t, 8> padding = {0};
131 hash.update(padding);
132 hash.update(message_hash);
133 hash.update(&DB[salt_offset], salt_size);
135 const std::vector<uint8_t> H2 = hash.final_stdvec();
137 const bool ok =
CT::is_equal(H, H2.data(), HASH_SIZE).as_bool();
139 if(ok && out_salt_size !=
nullptr) {
140 *out_salt_size = salt_size;
149 m_hash(std::move(hash)), m_salt_size(m_hash->output_length()), m_required_salt_len(false) {}
151PSSR::PSSR(std::unique_ptr<HashFunction> hash,
size_t salt_size) :
152 m_hash(std::move(hash)), m_salt_size(salt_size), m_required_salt_len(true) {}
157void PSSR::update(
const uint8_t input[],
size_t length) {
158 m_hash->update(input, length);
165 return m_hash->final_stdvec();
168std::vector<uint8_t> PSSR::encoding_of(std::span<const uint8_t> msg,
size_t output_bits,
RandomNumberGenerator& rng) {
169 const auto salt = rng.random_vec<std::vector<uint8_t>>(m_salt_size);
170 return pss_encode(*m_hash, msg, salt, output_bits);
176bool PSSR::verify(std::span<const uint8_t> coded, std::span<const uint8_t> raw,
size_t key_bits) {
177 size_t salt_size = 0;
178 const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size);
180 if(m_required_salt_len && salt_size != m_salt_size) {
188 return m_hash->name();
192 return fmt(
"PSS({},MGF1,{})", m_hash->name(), m_salt_size);
196 m_hash(std::move(hash)), m_salt_size(m_hash->output_length()), m_required_salt_len(false) {}
199 m_hash(std::move(hash)), m_salt_size(salt_size), m_required_salt_len(true) {}
204void PSS_Raw::update(
const uint8_t input[],
size_t length) {
205 m_msg.insert(m_msg.end(), input, input + length);
212 std::vector<uint8_t> ret;
213 std::swap(ret, m_msg);
215 if(ret.size() != m_hash->output_length()) {
216 throw Encoding_Error(
"PSS_Raw Bad input length, did not match hash");
222std::vector<uint8_t> PSS_Raw::encoding_of(std::span<const uint8_t> msg,
225 const auto salt = rng.random_vec<std::vector<uint8_t>>(m_salt_size);
226 return pss_encode(*m_hash, msg, salt, output_bits);
232bool PSS_Raw::verify(std::span<const uint8_t> coded, std::span<const uint8_t> raw,
size_t key_bits) {
233 size_t salt_size = 0;
234 const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size);
236 if(m_required_salt_len && salt_size != m_salt_size) {
244 return m_hash->name();
248 return fmt(
"PSS_Raw({},MGF1,{})", m_hash->name(), m_salt_size);
#define BOTAN_ASSERT_NOMSG(expr)
Helper class to ease in-place marshalling of concatenated fixed-length values.
std::string name() const override
PSSR(std::unique_ptr< HashFunction > hash)
std::string hash_function() const override
std::string name() const override
PSS_Raw(std::unique_ptr< HashFunction > hash)
std::string hash_function() const override
virtual std::vector< uint8_t > raw_data()=0
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
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)
BOTAN_FORCE_INLINE constexpr T ceil_tobytes(T bits)
BOTAN_FORCE_INLINE constexpr size_t high_bit(T n)