Skip to content

Commit

Permalink
Use BufferStuffer in pk_pad
Browse files Browse the repository at this point in the history
Adds a BufferStuffer API to repeat a single byte many times,
since this is a common need at least in this code.

Co-authored-by: René Meusel <github@renemeusel.de>
  • Loading branch information
randombit and reneme committed Oct 13, 2023
1 parent 2423e91 commit fb2f9c2
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 82 deletions.
15 changes: 9 additions & 6 deletions src/lib/pk_pad/eme_oaep/oaep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <botan/rng.h>
#include <botan/internal/ct_utils.h>
#include <botan/internal/mgf1.h>
#include <botan/internal/stl_util.h>

namespace Botan {

Expand All @@ -28,12 +29,14 @@ secure_vector<uint8_t> OAEP::pad(const uint8_t in[],
}

secure_vector<uint8_t> out(key_length);

rng.randomize(out.data(), m_Phash.size());

buffer_insert(out, m_Phash.size(), m_Phash.data(), m_Phash.size());
out[out.size() - in_length - 1] = 0x01;
buffer_insert(out, out.size() - in_length, in, in_length);
BufferStuffer stuffer(out);

// We always use a seed len equal to the underlying hash
rng.randomize(stuffer.next(m_Phash.size()));
stuffer.append(m_Phash);
stuffer.append(0x00, stuffer.remaining_capacity() - (1 + in_length));
stuffer.append(0x01);
stuffer.append({in, in_length});

mgf1_mask(*m_mgf1_hash, out.data(), m_Phash.size(), &out[m_Phash.size()], out.size() - m_Phash.size());

Expand Down
16 changes: 8 additions & 8 deletions src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <botan/exceptn.h>
#include <botan/rng.h>
#include <botan/internal/ct_utils.h>
#include <botan/internal/stl_util.h>

namespace Botan {

Expand All @@ -27,17 +28,16 @@ secure_vector<uint8_t> EME_PKCS1v15::pad(const uint8_t in[],
}

secure_vector<uint8_t> out(key_length);
BufferStuffer stuffer(out);

out[0] = 0x02;
rng.randomize(out.data() + 1, (key_length - inlen - 2));
const size_t padding_bytes = key_length - inlen - 2;

for(size_t j = 1; j != key_length - inlen - 1; ++j) {
if(out[j] == 0) {
out[j] = rng.next_nonzero_byte();
}
stuffer.append(0x02);
for(size_t i = 0; i != padding_bytes; ++i) {
stuffer.append(rng.next_nonzero_byte());
}

buffer_insert(out, key_length - inlen, in, inlen);
stuffer.append(0x00);
stuffer.append({in, inlen});

return out;
}
Expand Down
37 changes: 17 additions & 20 deletions src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,31 @@

#include <botan/exceptn.h>
#include <botan/internal/hash_id.h>
#include <botan/internal/stl_util.h>

namespace Botan {

namespace {

std::vector<uint8_t> emsa3_encoding(const std::vector<uint8_t>& msg,
size_t output_bits,
const uint8_t hash_id[],
size_t hash_id_length) {
size_t output_length = output_bits / 8;
if(output_length < hash_id_length + msg.size() + 10) {
std::span<const uint8_t> hash_id) {
const size_t output_length = output_bits / 8;

if(output_length < hash_id.size() + msg.size() + 2 + 8) {
throw Encoding_Error("emsa3_encoding: Output length is too small");
}

std::vector<uint8_t> T(output_length);
const size_t P_LENGTH = output_length - msg.size() - hash_id_length - 2;

T[0] = 0x01;
set_mem(&T[1], P_LENGTH, 0xFF);
T[P_LENGTH + 1] = 0x00;
std::vector<uint8_t> padded(output_length);
BufferStuffer stuffer(padded);

if(hash_id_length > 0) {
BOTAN_ASSERT_NONNULL(hash_id);
buffer_insert(T, P_LENGTH + 2, hash_id, hash_id_length);
}
stuffer.append(0x01);
stuffer.append(0xFF, stuffer.remaining_capacity() - (1 + hash_id.size() + msg.size()));
stuffer.append(0x00);
stuffer.append(hash_id);
stuffer.append(msg);

buffer_insert(T, output_length - msg.size(), msg.data(), msg.size());
return T;
return padded;
}

} // namespace
Expand All @@ -56,7 +53,7 @@ std::vector<uint8_t> EMSA_PKCS1v15::encoding_of(const std::vector<uint8_t>& msg,
throw Encoding_Error("EMSA_PKCS1v15::encoding_of: Bad input length");
}

return emsa3_encoding(msg, output_bits, m_hash_id.data(), m_hash_id.size());
return emsa3_encoding(msg, output_bits, m_hash_id);
}

bool EMSA_PKCS1v15::verify(const std::vector<uint8_t>& coded, const std::vector<uint8_t>& raw, size_t key_bits) {
Expand All @@ -65,7 +62,7 @@ bool EMSA_PKCS1v15::verify(const std::vector<uint8_t>& coded, const std::vector<
}

try {
return (coded == emsa3_encoding(raw, key_bits, m_hash_id.data(), m_hash_id.size()));
return coded == emsa3_encoding(raw, key_bits, m_hash_id);
} catch(...) {
return false;
}
Expand Down Expand Up @@ -105,7 +102,7 @@ std::vector<uint8_t> EMSA_PKCS1v15_Raw::raw_data() {
std::vector<uint8_t> EMSA_PKCS1v15_Raw::encoding_of(const std::vector<uint8_t>& msg,
size_t output_bits,
RandomNumberGenerator& /*rng*/) {
return emsa3_encoding(msg, output_bits, m_hash_id.data(), m_hash_id.size());
return emsa3_encoding(msg, output_bits, m_hash_id);
}

bool EMSA_PKCS1v15_Raw::verify(const std::vector<uint8_t>& coded, const std::vector<uint8_t>& raw, size_t key_bits) {
Expand All @@ -114,7 +111,7 @@ bool EMSA_PKCS1v15_Raw::verify(const std::vector<uint8_t>& coded, const std::vec
}

try {
return (coded == emsa3_encoding(raw, key_bits, m_hash_id.data(), m_hash_id.size()));
return coded == emsa3_encoding(raw, key_bits, m_hash_id);
} catch(...) {
return false;
}
Expand Down
37 changes: 23 additions & 14 deletions src/lib/pk_pad/emsa_pssr/pssr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
#include <botan/internal/pssr.h>

#include <botan/exceptn.h>
#include <botan/mem_ops.h>
#include <botan/rng.h>
#include <botan/internal/bit_ops.h>
#include <botan/internal/mgf1.h>
#include <botan/internal/stl_util.h>

namespace Botan {

Expand All @@ -24,16 +26,16 @@ std::vector<uint8_t> pss_encode(HashFunction& hash,
const std::vector<uint8_t>& salt,
size_t output_bits) {
const size_t HASH_SIZE = hash.output_length();
const size_t SALT_SIZE = salt.size();

if(msg.size() != HASH_SIZE) {
throw Encoding_Error("Cannot encode PSS string, input length invalid for hash");
}
if(output_bits < 8 * HASH_SIZE + 8 * SALT_SIZE + 9) {
if(output_bits < 8 * HASH_SIZE + 8 * salt.size() + 9) {
throw Encoding_Error("Cannot encode PSS string, output length too small");
}

const size_t output_length = (output_bits + 7) / 8;
const size_t output_length = ceil_tobytes(output_bits);
const uint8_t db0_mask = 0xFF >> (8 * output_length - output_bits);

for(size_t i = 0; i != 8; ++i) {
hash.update(0);
Expand All @@ -42,14 +44,19 @@ std::vector<uint8_t> pss_encode(HashFunction& hash,
hash.update(salt);
std::vector<uint8_t> H = hash.final_stdvec();

const size_t db_len = output_length - HASH_SIZE - 1;
std::vector<uint8_t> EM(output_length);

EM[output_length - HASH_SIZE - SALT_SIZE - 2] = 0x01;
buffer_insert(EM, output_length - 1 - HASH_SIZE - SALT_SIZE, salt);
mgf1_mask(hash, H.data(), HASH_SIZE, EM.data(), output_length - HASH_SIZE - 1);
EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits);
buffer_insert(EM, output_length - 1 - HASH_SIZE, H);
EM[output_length - 1] = 0xBC;
BufferStuffer stuffer(EM);
stuffer.append(0x00, stuffer.remaining_capacity() - (1 + salt.size() + H.size() + 1));
stuffer.append(0x01);
stuffer.append(salt);

mgf1_mask(hash, H.data(), H.size(), EM.data(), db_len);
EM[0] &= db0_mask;

stuffer.append(H);
stuffer.append(0xBC);
return EM;
}

Expand All @@ -59,7 +66,7 @@ bool pss_verify(HashFunction& hash,
size_t key_bits,
size_t* out_salt_size) {
const size_t HASH_SIZE = hash.output_length();
const size_t KEY_BYTES = (key_bits + 7) / 8;
const size_t key_bytes = ceil_tobytes(key_bits);

if(key_bits < 8 * HASH_SIZE + 9) {
return false;
Expand All @@ -69,7 +76,7 @@ bool pss_verify(HashFunction& hash,
return false;
}

if(pss_repr.size() > KEY_BYTES || pss_repr.size() <= 1) {
if(pss_repr.size() > key_bytes || pss_repr.size() <= 1) {
return false;
}

Expand All @@ -78,9 +85,11 @@ bool pss_verify(HashFunction& hash,
}

std::vector<uint8_t> coded = pss_repr;
if(coded.size() < KEY_BYTES) {
std::vector<uint8_t> temp(KEY_BYTES);
buffer_insert(temp, KEY_BYTES - coded.size(), coded);
if(coded.size() < key_bytes) {
std::vector<uint8_t> temp(key_bytes);
BufferStuffer stuffer(temp);
stuffer.append(0x00, stuffer.remaining_capacity() - coded.size());
stuffer.append(coded);
coded = temp;
}

Expand Down
18 changes: 10 additions & 8 deletions src/lib/pk_pad/emsa_x931/emsa_x931.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <botan/exceptn.h>
#include <botan/internal/hash_id.h>
#include <botan/internal/stl_util.h>

namespace Botan {

Expand All @@ -20,7 +21,7 @@ std::vector<uint8_t> emsa2_encoding(const std::vector<uint8_t>& msg,
uint8_t hash_id) {
const size_t HASH_SIZE = empty_hash.size();

size_t output_length = (output_bits + 1) / 8;
const size_t output_length = (output_bits + 1) / 8;

if(msg.size() != HASH_SIZE) {
throw Encoding_Error("EMSA_X931::encoding_of: Bad input length");
Expand All @@ -32,13 +33,14 @@ std::vector<uint8_t> emsa2_encoding(const std::vector<uint8_t>& msg,
const bool empty_input = (msg == empty_hash);

std::vector<uint8_t> output(output_length);

output[0] = (empty_input ? 0x4B : 0x6B);
output[output_length - 3 - HASH_SIZE] = 0xBA;
set_mem(&output[1], output_length - 4 - HASH_SIZE, 0xBB);
buffer_insert(output, output_length - (HASH_SIZE + 2), msg.data(), msg.size());
output[output_length - 2] = hash_id;
output[output_length - 1] = 0xCC;
BufferStuffer stuffer(output);

stuffer.append(empty_input ? 0x4B : 0x6B);
stuffer.append(0xBB, stuffer.remaining_capacity() - (1 + msg.size() + 2));
stuffer.append(0xBA);
stuffer.append(msg);
stuffer.append(hash_id);
stuffer.append(0xCC);

return output;
}
Expand Down
47 changes: 23 additions & 24 deletions src/lib/pk_pad/iso9796/iso9796.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <botan/internal/ct_utils.h>
#include <botan/internal/hash_id.h>
#include <botan/internal/mgf1.h>
#include <botan/internal/stl_util.h>

namespace Botan {

Expand All @@ -27,10 +28,8 @@ std::vector<uint8_t> iso9796_encoding(const std::vector<uint8_t>& msg,
const size_t output_length = (output_bits + 7) / 8;

//set trailer length
size_t tLength = 1;
if(!implicit) {
tLength = 2;
}
const size_t tLength = (implicit) ? 1 : 2;

const size_t HASH_SIZE = hash->output_length();

if(output_length <= HASH_SIZE + SALT_SIZE + tLength) {
Expand All @@ -45,8 +44,7 @@ std::vector<uint8_t> iso9796_encoding(const std::vector<uint8_t>& msg,
std::vector<uint8_t> msg2;
if(msg.size() > capacity) {
msg1 = std::vector<uint8_t>(msg.begin(), msg.begin() + capacity);
msg2 = std::vector<uint8_t>(msg.begin() + capacity, msg.end());
hash->update(msg2);
hash->update(std::span(msg).subspan(capacity));
} else {
msg1 = msg;
}
Expand All @@ -63,31 +61,32 @@ std::vector<uint8_t> iso9796_encoding(const std::vector<uint8_t>& msg,

std::vector<uint8_t> EM(output_length);

//compute message offset.
const size_t offset = output_length - HASH_SIZE - SALT_SIZE - tLength - msgLength - 1;

//insert message border (0x01), msg1 and salt into the output buffer
EM[offset] = 0x01;
buffer_insert(EM, offset + 1, msg1);
buffer_insert(EM, offset + 1 + msgLength, salt);
BufferStuffer stuffer(EM);
stuffer.append(0x00, stuffer.remaining_capacity() - (HASH_SIZE + SALT_SIZE + tLength + msgLength + 1));
stuffer.append(0x01);
stuffer.append(msg1);
stuffer.append(salt);

//apply mask
mgf1_mask(*hash, H.data(), HASH_SIZE, EM.data(), output_length - HASH_SIZE - tLength);
buffer_insert(EM, output_length - HASH_SIZE - tLength, H);
//set implicit/ISO trailer
if(!implicit) {
uint8_t hash_id = ieee1363_hash_id(hash->name());

//clear the leftmost bit (confer bouncy castle)
EM[0] &= 0x7F;

stuffer.append(H);

// set implicit/ISO trailer

if(implicit) {
stuffer.append(0xBC);
} else {
const uint8_t hash_id = ieee1363_hash_id(hash->name());
if(!hash_id) {
throw Encoding_Error("ISO9796-2::encoding_of: no hash identifier for " + hash->name());
}
EM[output_length - 1] = 0xCC;
EM[output_length - 2] = hash_id;

} else {
EM[output_length - 1] = 0xBC;
stuffer.append(hash_id);
stuffer.append(0xCC);
}
//clear the leftmost bit (confer bouncy castle)
EM[0] &= 0x7F;

return EM;
}
Expand Down
4 changes: 4 additions & 0 deletions src/lib/utils/mem_ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,17 +162,21 @@ inline constexpr To typecast_copy(const FromT* src) noexcept
return dst;
}

#if !defined(BOTAN_IS_BEGIN_BUILT)
/**
* Set memory to a fixed value
* @param ptr a pointer to an array of bytes
* @param n the number of Ts pointed to by ptr
* @param val the value to set each byte to
*/
BOTAN_DEPRECATED("This function is deprecated")

inline constexpr void set_mem(uint8_t* ptr, size_t n, uint8_t val) {
if(n > 0) {
std::memset(ptr, val, n);
}
}
#endif

inline const uint8_t* cast_char_ptr_to_uint8(const char* s) {
return reinterpret_cast<const uint8_t*>(s);
Expand Down
6 changes: 6 additions & 0 deletions src/lib/utils/stl_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef BOTAN_STL_UTIL_H_
#define BOTAN_STL_UTIL_H_

#include <algorithm>
#include <functional>
#include <map>
#include <set>
Expand Down Expand Up @@ -218,6 +219,11 @@ class BufferStuffer {
std::copy(buffer.begin(), buffer.end(), sink.begin());
}

void append(uint8_t b, size_t repeat = 1) {
auto sink = next(repeat);
std::fill(sink.begin(), sink.end(), b);
}

bool full() const { return m_buffer.empty(); }

size_t remaining_capacity() const { return m_buffer.size(); }
Expand Down
Loading

0 comments on commit fb2f9c2

Please sign in to comment.