8#include <botan/internal/pssr.h>
9#include <botan/internal/mgf1.h>
10#include <botan/internal/bit_ops.h>
11#include <botan/exceptn.h>
21std::vector<uint8_t> pss_encode(HashFunction& hash,
22 const std::vector<uint8_t>& msg,
23 const std::vector<uint8_t>& salt,
26 const size_t HASH_SIZE = hash.output_length();
27 const size_t SALT_SIZE = salt.size();
29 if(msg.size() != HASH_SIZE)
30 throw Encoding_Error(
"Cannot encode PSS string, input length invalid for hash");
31 if(output_bits < 8*HASH_SIZE + 8*SALT_SIZE + 9)
32 throw Encoding_Error(
"Cannot encode PSS string, output length too small");
34 const size_t output_length = (output_bits + 7) / 8;
36 for(
size_t i = 0; i != 8; ++i)
40 std::vector<uint8_t> H = hash.final_stdvec();
42 std::vector<uint8_t> EM(output_length);
44 EM[output_length - HASH_SIZE - SALT_SIZE - 2] = 0x01;
45 buffer_insert(EM, output_length - 1 - HASH_SIZE - SALT_SIZE, salt);
46 mgf1_mask(hash, H.data(), HASH_SIZE, EM.data(), output_length - HASH_SIZE - 1);
47 EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits);
49 EM[output_length-1] = 0xBC;
53bool pss_verify(HashFunction& hash,
54 const std::vector<uint8_t>& pss_repr,
55 const std::vector<uint8_t>& message_hash,
57 size_t* out_salt_size)
59 const size_t HASH_SIZE = hash.output_length();
60 const size_t KEY_BYTES = (key_bits + 7) / 8;
62 if(key_bits < 8*HASH_SIZE + 9)
65 if(message_hash.size() != HASH_SIZE)
68 if(pss_repr.size() > KEY_BYTES || pss_repr.size() <= 1)
71 if(pss_repr[pss_repr.size()-1] != 0xBC)
74 std::vector<uint8_t> coded = pss_repr;
75 if(coded.size() < KEY_BYTES)
77 std::vector<uint8_t> temp(KEY_BYTES);
82 const size_t TOP_BITS = 8 * ((key_bits + 7) / 8) - key_bits;
83 if(TOP_BITS > 8 -
high_bit(coded[0]))
86 uint8_t* DB = coded.data();
87 const size_t DB_size = coded.size() - HASH_SIZE - 1;
89 const uint8_t* H = &coded[DB_size];
90 const size_t H_size = HASH_SIZE;
93 DB[0] &= 0xFF >> TOP_BITS;
95 size_t salt_offset = 0;
96 for(
size_t j = 0; j != DB_size; ++j)
99 { salt_offset = j + 1;
break; }
106 const size_t salt_size = DB_size - salt_offset;
108 for(
size_t j = 0; j != 8; ++j)
110 hash.update(message_hash);
111 hash.update(&DB[salt_offset], salt_size);
113 const std::vector<uint8_t> H2 = hash.final_stdvec();
117 if(out_salt_size && ok)
118 *out_salt_size = salt_size;
126 m_hash(
std::move(hash)),
127 m_salt_size(m_hash->output_length()),
128 m_required_salt_len(false)
132PSSR::PSSR(std::unique_ptr<HashFunction> hash,
size_t salt_size) :
133 m_hash(
std::move(hash)),
134 m_salt_size(salt_size),
135 m_required_salt_len(true)
142void PSSR::update(
const uint8_t input[],
size_t length)
144 m_hash->update(input, length);
150std::vector<uint8_t> PSSR::raw_data()
152 return m_hash->final_stdvec();
155std::vector<uint8_t> PSSR::encoding_of(
const std::vector<uint8_t>& msg,
157 RandomNumberGenerator& rng)
159 const auto salt = rng.random_vec<std::vector<uint8_t>>(m_salt_size);
160 return pss_encode(*m_hash, msg, salt, output_bits);
166bool PSSR::verify(
const std::vector<uint8_t>& coded,
167 const std::vector<uint8_t>& raw,
170 size_t salt_size = 0;
171 const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size);
173 if(m_required_salt_len && salt_size != m_salt_size)
181 return "EMSA4(" + m_hash->name() +
",MGF1," + std::to_string(m_salt_size) +
")";
185 m_hash(
std::move(hash)),
186 m_salt_size(m_hash->output_length()),
187 m_required_salt_len(false)
192 m_hash(
std::move(hash)),
193 m_salt_size(salt_size),
194 m_required_salt_len(true)
201void PSSR_Raw::update(
const uint8_t input[],
size_t length)
203 m_msg.insert(m_msg.end(), input, input + length);
209std::vector<uint8_t> PSSR_Raw::raw_data()
211 std::vector<uint8_t> ret;
212 std::swap(ret, m_msg);
214 if(ret.size() != m_hash->output_length())
215 throw Encoding_Error(
"PSSR_Raw Bad input length, did not match hash");
220std::vector<uint8_t> PSSR_Raw::encoding_of(
const std::vector<uint8_t>& msg,
222 RandomNumberGenerator& rng)
224 const auto salt = rng.random_vec<std::vector<uint8_t>>(m_salt_size);
225 return pss_encode(*m_hash, msg, salt, output_bits);
231bool PSSR_Raw::verify(
const std::vector<uint8_t>& coded,
232 const std::vector<uint8_t>& raw,
235 size_t salt_size = 0;
236 const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size);
238 if(m_required_salt_len && salt_size != m_salt_size)
246 return "PSSR_Raw(" + m_hash->name() +
",MGF1," + std::to_string(m_salt_size) +
")";
PSSR_Raw(std::unique_ptr< HashFunction > hash)
std::string name() const override
std::string name() const override
PSSR(std::unique_ptr< HashFunction > hash)
void mgf1_mask(HashFunction &hash, const uint8_t in[], size_t in_len, uint8_t out[], size_t out_len)
size_t buffer_insert(std::vector< T, Alloc > &buf, size_t buf_offset, const T input[], size_t input_length)
constexpr size_t high_bit(T n)
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)