Beispiel #1
0
bool EMSA1::verify(const secure_vector<uint8_t>& input,
                   const secure_vector<uint8_t>& raw,
                   size_t key_bits)
   {
   try {
      if(raw.size() != m_hash->output_length())
         throw Encoding_Error("EMSA1::encoding_of: Invalid size for input");

      // Call emsa1_encoding to handle any required bit shifting
      const secure_vector<uint8_t> our_coding = emsa1_encoding(raw, key_bits);

      if(our_coding.size() < input.size())
         return false;

      const size_t offset = our_coding.size() - input.size(); // must be >= 0 per check above

      // If our encoding is longer, all the bytes in it must be zero
      for(size_t i = 0; i != offset; ++i)
         if(our_coding[i] != 0)
            return false;

      return same_mem(input.data(), &our_coding[offset], input.size());
      }
   catch(Invalid_Argument)
      {
      return false;
      }
   }
Beispiel #2
0
Ed25519_PrivateKey::Ed25519_PrivateKey(RandomNumberGenerator& rng)
   {
   const secure_vector<uint8_t> seed = rng.random_vec(32);
   m_public.resize(32);
   m_private.resize(64);
   ed25519_gen_keypair(m_public.data(), m_private.data(), seed.data());
   }
Beispiel #3
0
void mceliece_decrypt(secure_vector<byte>& plaintext_out,
                      secure_vector<byte>& error_mask_out,
                      const secure_vector<byte>& ciphertext,
                      const McEliece_PrivateKey& key)
   {
   mceliece_decrypt(plaintext_out, error_mask_out, ciphertext.data(), ciphertext.size(), key);
   }
Beispiel #4
0
void Montgomery_Params::mul_by(BigInt& x,
                               const secure_vector<word>& y,
                               secure_vector<word>& ws) const
   {
   const size_t output_size = 2*m_p_words + 2;

   if(ws.size() < 2*output_size)
      ws.resize(2*output_size);

   word* z_data = &ws[0];
   word* ws_data = &ws[output_size];

   BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words);

   bigint_mul(z_data, output_size,
              x.data(), x.size(), std::min(m_p_words, x.size()),
              y.data(), y.size(), std::min(m_p_words, y.size()),
              ws_data, output_size);

   bigint_monty_redc(z_data,
                     m_p.data(), m_p_words, m_p_dash,
                     ws_data, output_size);

   if(x.size() < output_size)
      x.grow_to(output_size);
   copy_mem(x.mutable_data(), z_data, output_size);
   }
Beispiel #5
0
//static
void SHA_3::expand(size_t bitrate,
                   secure_vector<uint64_t>& S,
                   uint8_t output[], size_t output_length)
   {
   BOTAN_ARG_CHECK(bitrate % 8 == 0);

   size_t Si = 0;

   for(size_t i = 0; i != output_length; ++i)
      {
      if(i > 0)
         {
         if(i % (bitrate / 8) == 0)
            {
            SHA_3::permute(S.data());
            Si = 0;
            }
         else if(i % 8 == 0)
            {
            Si += 1;
            }
         }

      output[i] = get_byte(7 - (i % 8), S[Si]);
      }
   }
Beispiel #6
0
void EAX_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
{
    BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
    const size_t sz = buffer.size() - offset;
    byte* buf = buffer.data() + offset;

    BOTAN_ASSERT(sz >= tag_size(), "Have the tag as part of final input");

    const size_t remaining = sz - tag_size();

    if(remaining)
    {
        m_cmac->update(buf, remaining);
        m_ctr->cipher(buf, buf, remaining);
    }

    const byte* included_tag = &buf[remaining];

    secure_vector<byte> mac = m_cmac->final();
    mac ^= m_nonce_mac;
    mac ^= m_ad_mac;

    if(!same_mem(mac.data(), included_tag, tag_size()))
        throw Integrity_Failure("EAX tag check failed");

    buffer.resize(offset + remaining);
}
Beispiel #7
0
void Stream_Decompression::process(secure_vector<byte>& buf, size_t offset, u32bit flags)
   {
   BOTAN_ASSERT(m_stream, "Initialized");
   BOTAN_ASSERT(buf.size() >= offset, "Offset is sane");

   if(m_buffer.size() < buf.size() + offset)
      m_buffer.resize(buf.size() + offset);

   m_stream->next_in(buf.data() + offset, buf.size() - offset);
   m_stream->next_out(m_buffer.data() + offset, m_buffer.size() - offset);

   while(true)
      {
      const bool stream_end = m_stream->run(flags);

      if(stream_end)
         {
         if(m_stream->avail_in() == 0) // all data consumed?
            {
            m_buffer.resize(m_buffer.size() - m_stream->avail_out());
            clear();
            break;
            }

         // More data follows: try to process as a following stream
         const size_t read = (buf.size() - offset) - m_stream->avail_in();
         start();
         m_stream->next_in(buf.data() + offset + read, buf.size() - offset - read);
         }

      if(m_stream->avail_out() == 0)
         {
         const size_t added = 8 + m_buffer.size();
         m_buffer.resize(m_buffer.size() + added);
         m_stream->next_out(m_buffer.data() + m_buffer.size() - added, added);
         }
      else if(m_stream->avail_in() == 0)
         {
         m_buffer.resize(m_buffer.size() - m_stream->avail_out());
         break;
         }
      }

   copy_mem(m_buffer.data(), buf.data(), offset);
   buf.swap(m_buffer);
   }
Beispiel #8
0
void EAX_Decryption::update(secure_vector<byte>& buffer, size_t offset)
{
    BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
    const size_t sz = buffer.size() - offset;
    byte* buf = buffer.data() + offset;

    m_cmac->update(buf, sz);
    m_ctr->cipher(buf, buf, sz);
}
Beispiel #9
0
uint32_t HOTP::generate_hotp(uint64_t counter)
   {
   m_mac->update_be(counter);
   const secure_vector<uint8_t> mac = m_mac->final();

   const size_t offset = mac[mac.size()-1] & 0x0F;
   const uint32_t code = load_be<uint32_t>(mac.data() + offset, 0) & 0x7FFFFFFF;
   return code % m_digit_mod;
   }
Beispiel #10
0
void CCM_Mode::update(secure_vector<byte>& buffer, size_t offset)
   {
   BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
   const size_t sz = buffer.size() - offset;
   byte* buf = buffer.data() + offset;

   m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz);
   buffer.resize(offset); // truncate msg
   }
Beispiel #11
0
void CCM_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
   {
   BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");

   buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());

   const size_t sz = buffer.size() - offset;
   byte* buf = buffer.data() + offset;

   BOTAN_ASSERT(sz >= tag_size(), "We have the tag");

   const secure_vector<byte>& ad = ad_buf();
   BOTAN_ASSERT(ad.size() % BS == 0, "AD is block size multiple");

   const BlockCipher& E = cipher();

   secure_vector<byte> T(BS);
   E.encrypt(format_b0(sz - tag_size()), T);

   for(size_t i = 0; i != ad.size(); i += BS)
      {
      xor_buf(T.data(), &ad[i], BS);
      E.encrypt(T);
      }

   secure_vector<byte> C = format_c0();

   secure_vector<byte> S0(BS);
   E.encrypt(C, S0);
   inc(C);

   secure_vector<byte> X(BS);

   const byte* buf_end = &buf[sz - tag_size()];

   while(buf != buf_end)
      {
      const size_t to_proc = std::min<size_t>(BS, buf_end - buf);

      E.encrypt(C, X);
      xor_buf(buf, X.data(), to_proc);
      inc(C);

      xor_buf(T.data(), buf, to_proc);
      E.encrypt(T);

      buf += to_proc;
      }

   T ^= S0;

   if(!same_mem(T.data(), buf_end, tag_size()))
      throw Integrity_Failure("CCM tag check failed");

   buffer.resize(buffer.size() - tag_size());
   }
Beispiel #12
0
//static
void SHA_3::finish(size_t bitrate,
                   secure_vector<uint64_t>& S, size_t S_pos,
                   uint8_t init_pad, uint8_t fini_pad)
   {
   BOTAN_ARG_CHECK(bitrate % 64 == 0, "SHA-3 bitrate must be multiple of 64");

   S[S_pos / 8] ^= static_cast<uint64_t>(init_pad) << (8 * (S_pos % 8));
   S[(bitrate / 64) - 1] ^= static_cast<uint64_t>(fini_pad) << 56;
   SHA_3::permute(S.data());
   }
Beispiel #13
0
BigInt Montgomery_Params::sqr(const BigInt& x, secure_vector<word>& ws) const
   {
   const size_t output_size = 2*m_p_words + 2;

   if(ws.size() < output_size)
      ws.resize(output_size);

   BigInt z(BigInt::Positive, output_size);

   BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words);

   bigint_sqr(z.mutable_data(), z.size(),
              x.data(), x.size(), std::min(m_p_words, x.size()),
              ws.data(), ws.size());

   bigint_monty_redc(z.mutable_data(),
                     m_p.data(), m_p_words, m_p_dash,
                     ws.data(), ws.size());

   return z;
   }
Beispiel #14
0
secure_vector<byte>
PK_Decryptor::decrypt_or_random(const byte in[],
                                size_t length,
                                size_t expected_pt_len,
                                RandomNumberGenerator& rng,
                                const byte required_content_bytes[],
                                const byte required_content_offsets[],
                                size_t required_contents_length) const
   {
   const secure_vector<byte> fake_pms = rng.random_vec(expected_pt_len);

   //CT::poison(in, length);

   byte valid_mask = 0;
   secure_vector<byte> decoded = do_decrypt(valid_mask, in, length);

   valid_mask &= CT::is_equal(decoded.size(), expected_pt_len);

   decoded.resize(expected_pt_len);

   for(size_t i = 0; i != required_contents_length; ++i)
      {
      /*
      These values are chosen by the application and for TLS are constants,
      so this early failure via assert is fine since we know 0,1 < 48

      If there is a protocol that has content checks on the key where
      the expected offsets are controllable by the attacker this could
      still leak.

      Alternately could always reduce the offset modulo the length?
      */

      const byte exp = required_content_bytes[i];
      const byte off = required_content_offsets[i];

      BOTAN_ASSERT(off < expected_pt_len, "Offset in range of plaintext");

      valid_mask &= CT::is_equal(decoded[off], exp);
      }

   CT::conditional_copy_mem(valid_mask,
                            /*output*/decoded.data(),
                            /*from0*/decoded.data(),
                            /*from1*/fake_pms.data(),
                            expected_pt_len);

   //CT::unpoison(in, length);
   //CT::unpoison(decoded.data(), decoded.size());

   return decoded;
   }
Beispiel #15
0
secure_vector<uint8_t> rfc3394_keywrap(const secure_vector<uint8_t>& key,
                                       const SymmetricKey& kek)
   {
   BOTAN_ARG_CHECK(kek.size() == 16 || kek.size() == 24 || kek.size() == 32,
                   "Invalid KEK length for NIST key wrap");

   const std::string cipher_name = "AES-" + std::to_string(8*kek.size());
   std::unique_ptr<BlockCipher> aes(BlockCipher::create_or_throw(cipher_name));
   aes->set_key(kek);

   std::vector<uint8_t> wrapped = nist_key_wrap(key.data(), key.size(), *aes);
   return secure_vector<uint8_t>(wrapped.begin(), wrapped.end());
   }
Beispiel #16
0
void Stream_Compression::process(secure_vector<byte>& buf, size_t offset, u32bit flags)
   {
   BOTAN_ASSERT(m_stream, "Initialized");
   BOTAN_ASSERT(buf.size() >= offset, "Offset is sane");

   if(m_buffer.size() < buf.size() + offset)
      m_buffer.resize(buf.size() + offset);

   // If the output buffer has zero length, .data() might return nullptr. This would
   // make some compression algorithms (notably those provided by zlib) fail.
   // Any small positive value works fine, but we choose 32 as it is the smallest power
   // of two that is large enough to hold all the headers and trailers of the common
   // formats, preventing further resizings to make room for output data.
   if(m_buffer.size() == 0)
      m_buffer.resize(32);

   m_stream->next_in(buf.data() + offset, buf.size() - offset);
   m_stream->next_out(m_buffer.data() + offset, m_buffer.size() - offset);

   while(true)
      {
      m_stream->run(flags);

      if(m_stream->avail_out() == 0)
         {
         const size_t added = 8 + m_buffer.size();
         m_buffer.resize(m_buffer.size() + added);
         m_stream->next_out(m_buffer.data() + m_buffer.size() - added, added);
         }
      else if(m_stream->avail_in() == 0)
         {
         m_buffer.resize(m_buffer.size() - m_stream->avail_out());
         break;
         }
      }

   copy_mem(m_buffer.data(), buf.data(), offset);
   buf.swap(m_buffer);
   }
Beispiel #17
0
void ECB_Encryption::update(secure_vector<byte>& buffer, size_t offset)
   {
   BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
   const size_t sz = buffer.size() - offset;
   byte* buf = buffer.data() + offset;

   const size_t BS = cipher().block_size();

   BOTAN_ASSERT(sz % BS == 0, "ECB input is full blocks");
   const size_t blocks = sz / BS;

   cipher().encrypt_n(buf, buf, blocks);
   }
Beispiel #18
0
void CCM_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
   {
   BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");

   buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());

   const size_t sz = buffer.size() - offset;
   byte* buf = buffer.data() + offset;

   const secure_vector<byte>& ad = ad_buf();
   BOTAN_ASSERT(ad.size() % BS == 0, "AD is block size multiple");

   const BlockCipher& E = cipher();

   secure_vector<byte> T(BS);
   E.encrypt(format_b0(sz), T);

   for(size_t i = 0; i != ad.size(); i += BS)
      {
      xor_buf(T.data(), &ad[i], BS);
      E.encrypt(T);
      }

   secure_vector<byte> C = format_c0();
   secure_vector<byte> S0(BS);
   E.encrypt(C, S0);
   inc(C);

   secure_vector<byte> X(BS);

   const byte* buf_end = &buf[sz];

   while(buf != buf_end)
      {
      const size_t to_proc = std::min<size_t>(BS, buf_end - buf);

      xor_buf(T.data(), buf, to_proc);
      E.encrypt(T);

      E.encrypt(C, X);
      xor_buf(buf, X.data(), to_proc);
      inc(C);

      buf += to_proc;
      }

   T ^= S0;

   buffer += std::make_pair(T.data(), tag_size());
   }
Beispiel #19
0
/*
* EMSA-Raw Verify Operation
*/
bool EMSA_Raw::verify(const secure_vector<byte>& coded,
                      const secure_vector<byte>& raw,
                      size_t)
   {
   if(coded.size() == raw.size())
      return (coded == raw);

   if(coded.size() > raw.size())
      return false;

   // handle zero padding differences
   const size_t leading_zeros_expected = raw.size() - coded.size();

   bool same_modulo_leading_zeros = true;

   for(size_t i = 0; i != leading_zeros_expected; ++i)
      if(raw[i])
         same_modulo_leading_zeros = false;

   if(!same_mem(coded.data(), raw.data() + leading_zeros_expected, coded.size()))
      same_modulo_leading_zeros = false;

   return same_modulo_leading_zeros;
   }
Beispiel #20
0
std::set<std::string> Encrypted_PSK_Database::list_names() const
   {
   const std::set<std::string> encrypted_names = kv_get_all();

   std::set<std::string> names;

   for(std::string enc_name : encrypted_names)
      {
      try
         {
         const secure_vector<uint8_t> raw_name = base64_decode(enc_name);
         const secure_vector<uint8_t> name_bits =
            nist_key_unwrap_padded(raw_name.data(), raw_name.size(), *m_cipher);

         std::string pt_name(cast_uint8_ptr_to_char(name_bits.data()), name_bits.size());
         names.insert(pt_name);
         }
      catch(Integrity_Failure&)
         {
         }
      }

   return names;
   }
Beispiel #21
0
secure_vector<uint8_t> rfc3394_keyunwrap(const secure_vector<uint8_t>& key,
                                         const SymmetricKey& kek)
   {
   BOTAN_ARG_CHECK(kek.size() == 16 || kek.size() == 24 || kek.size() == 32,
                   "Invalid KEK length for NIST key wrap");

   BOTAN_ARG_CHECK(key.size() >= 16 && key.size() % 8 == 0,
                   "Bad input key size for NIST key unwrap");

   const std::string cipher_name = "AES-" + std::to_string(8*kek.size());
   std::unique_ptr<BlockCipher> aes(BlockCipher::create_or_throw(cipher_name));
   aes->set_key(kek);

   return nist_key_unwrap(key.data(), key.size(), *aes);
   }
Beispiel #22
0
Ed25519_PrivateKey::Ed25519_PrivateKey(const secure_vector<uint8_t>& secret_key)
   {
   if(secret_key.size() == 64)
      {
      m_private = secret_key;
      m_public.assign(&m_private[32], &m_private[64]);
      }
   else if(secret_key.size() == 32)
      {
      m_public.resize(32);
      m_private.resize(64);
      ed25519_gen_keypair(m_public.data(), m_private.data(), secret_key.data());
      }
   else
      throw Decoding_Error("Invalid size for Ed25519 private key");
   }
Beispiel #23
0
BigInt Montgomery_Params::redc(const BigInt& x, secure_vector<word>& ws) const
   {
   const size_t output_size = 2*m_p_words + 2;

   if(ws.size() < output_size)
      ws.resize(output_size);

   BigInt z = x;
   z.grow_to(output_size);

   bigint_monty_redc(z.mutable_data(),
                     m_p.data(), m_p_words, m_p_dash,
                     ws.data(), ws.size());

   return z;
   }
Beispiel #24
0
//static
size_t SHA_3::absorb(size_t bitrate,
                     secure_vector<uint64_t>& S, size_t S_pos,
                     const uint8_t input[], size_t length)
   {
   while(length > 0)
      {
      size_t to_take = std::min(length, bitrate / 8 - S_pos);

      length -= to_take;

      while(to_take && S_pos % 8)
         {
         S[S_pos / 8] ^= static_cast<uint64_t>(input[0]) << (8 * (S_pos % 8));

         ++S_pos;
         ++input;
         --to_take;
         }

      while(to_take && to_take % 8 == 0)
         {
         S[S_pos / 8] ^= load_le<uint64_t>(input, 0);
         S_pos += 8;
         input += 8;
         to_take -= 8;
         }

      while(to_take)
         {
         S[S_pos / 8] ^= static_cast<uint64_t>(input[0]) << (8 * (S_pos % 8));

         ++S_pos;
         ++input;
         --to_take;
         }

      if(S_pos == bitrate / 8)
         {
         SHA_3::permute(S.data());
         S_pos = 0;
         }
      }

   return S_pos;
   }
Beispiel #25
0
secure_vector<uint8_t> rfc3394_keywrap(const secure_vector<uint8_t>& key,
                                    const SymmetricKey& kek)
   {
   if(key.size() % 8 != 0)
      throw Invalid_Argument("Bad input key size for NIST key wrap");

   if(kek.size() != 16 && kek.size() != 24 && kek.size() != 32)
      throw Invalid_Argument("Bad KEK length " + std::to_string(kek.size()) + " for NIST key wrap");

   const std::string cipher_name = "AES-" + std::to_string(8*kek.size());
   std::unique_ptr<BlockCipher> aes(BlockCipher::create_or_throw(cipher_name));
   aes->set_key(kek);

   const size_t n = key.size() / 8;

   secure_vector<uint8_t> R((n + 1) * 8);
   secure_vector<uint8_t> A(16);

   for(size_t i = 0; i != 8; ++i)
      A[i] = 0xA6;

   copy_mem(&R[8], key.data(), key.size());

   for(size_t j = 0; j <= 5; ++j)
      {
      for(size_t i = 1; i <= n; ++i)
         {
         const uint32_t t = static_cast<uint32_t>((n * j) + i);

         copy_mem(&A[8], &R[8*i], 8);

         aes->encrypt(A.data());
         copy_mem(&R[8*i], &A[8], 8);

         uint8_t t_buf[4] = { 0 };
         store_be(t, t_buf);
         xor_buf(&A[4], t_buf, 4);
         }
      }

   copy_mem(R.data(), A.data(), 8);

   return R;
   }
Beispiel #26
0
void XTS_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
   {
   BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
   const size_t sz = buffer.size() - offset;
   uint8_t* buf = buffer.data() + offset;

   BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input in XTS decrypt");

   const size_t BS = cipher().block_size();

   if(sz % BS == 0)
      {
      update(buffer, offset);
      }
   else
      {
      // steal ciphertext
      const size_t full_blocks = ((sz / BS) - 1) * BS;
      const size_t final_bytes = sz - full_blocks;
      BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range");

      secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes);
      buffer.resize(full_blocks + offset);
      update(buffer, offset);

      xor_buf(last, tweak() + BS, BS);
      cipher().decrypt(last);
      xor_buf(last, tweak() + BS, BS);

      for(size_t i = 0; i != final_bytes - BS; ++i)
         {
         last[i] ^= last[i + BS];
         last[i + BS] ^= last[i];
         last[i] ^= last[i + BS];
         }

      xor_buf(last, tweak(), BS);
      cipher().decrypt(last);
      xor_buf(last, tweak(), BS);

      buffer += last;
      }
   }
Beispiel #27
0
void CTS_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
   {
   BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
   const size_t sz = buffer.size() - offset;
   uint8_t* buf = buffer.data() + offset;

   const size_t BS = cipher().block_size();

   if(sz < BS + 1)
      throw Encoding_Error(name() + ": insufficient data to decrypt");

   if(sz % BS == 0)
      {
      // swap last two blocks

      for(size_t i = 0; i != BS; ++i)
         std::swap(buffer[buffer.size()-BS+i], buffer[buffer.size()-2*BS+i]);

      update(buffer, offset);
      }
   else
      {
      const size_t full_blocks = ((sz / BS) - 1) * BS;
      const size_t final_bytes = sz - full_blocks;
      BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range");

      secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes);
      buffer.resize(full_blocks + offset);
      update(buffer, offset);

      cipher().decrypt(last.data());

      xor_buf(last.data(), &last[BS], final_bytes - BS);

      for(size_t i = 0; i != final_bytes - BS; ++i)
         std::swap(last[i], last[i + BS]);

      cipher().decrypt(last.data());
      xor_buf(last.data(), state_ptr(), BS);

      buffer += last;
      }
   }
Beispiel #28
0
secure_vector<uint8_t> Encrypted_PSK_Database::get(const std::string& name) const
   {
   const std::vector<uint8_t> wrapped_name =
      nist_key_wrap_padded(cast_char_ptr_to_uint8(name.data()),
                           name.size(),
                           *m_cipher);

   const std::string val_base64 = kv_get(base64_encode(wrapped_name));

   if(val_base64.empty())
      throw Invalid_Argument("Named PSK not located");

   const secure_vector<uint8_t> val = base64_decode(val_base64);

   std::unique_ptr<BlockCipher> wrap_cipher(m_cipher->clone());
   wrap_cipher->set_key(m_hmac->process(wrapped_name));

   return nist_key_unwrap_padded(val.data(), val.size(), *wrap_cipher);
   }
Beispiel #29
0
//static
void SHA_3::expand(size_t bitrate,
                   secure_vector<uint64_t>& S,
                   uint8_t output[], size_t output_length)
   {
   BOTAN_ARG_CHECK(bitrate % 64 == 0, "SHA-3 bitrate must be multiple of 64");

   const size_t byterate = bitrate / 8;

   while(output_length > 0)
      {
      const size_t copying = std::min(byterate, output_length);

      copy_out_vec_le(output, copying, S);

      output += copying;
      output_length -= copying;

      if(output_length > 0)
         {
         SHA_3::permute(S.data());
         }
      }
   }
Beispiel #30
0
secure_vector<byte>
mceies_encrypt(const McEliece_PublicKey& pubkey,
               const byte pt[], size_t pt_len,
               const byte ad[], size_t ad_len,
               RandomNumberGenerator& rng,
               const std::string& algo)
   {
   McEliece_KEM_Encryptor kem_op(pubkey);

   const std::pair<secure_vector<byte>,secure_vector<byte>> mce_ciphertext__key = kem_op.encrypt(rng);
   const secure_vector<byte>& mce_ciphertext = mce_ciphertext__key.first;
   const secure_vector<byte>& mce_key = mce_ciphertext__key.second;

   const size_t mce_code_bytes = (pubkey.get_code_length() + 7) / 8;

   BOTAN_ASSERT(mce_ciphertext.size() == mce_code_bytes, "Unexpected size");

   std::unique_ptr<AEAD_Mode> aead(get_aead(algo, ENCRYPTION));
   if(!aead)
      throw std::runtime_error("mce_encrypt unable to create AEAD instance '" + algo + "'");

   const size_t nonce_len = aead->default_nonce_length();

   aead->set_key(aead_key(mce_key, *aead));
   aead->set_associated_data(ad, ad_len);

   const secure_vector<byte> nonce = rng.random_vec(nonce_len);

   secure_vector<byte> msg(mce_ciphertext.size() + nonce.size() + pt_len);
   copy_mem(msg.data(), mce_ciphertext.data(), mce_ciphertext.size());
   copy_mem(msg.data() + mce_ciphertext.size(), nonce.data(), nonce.size());
   copy_mem(msg.data() + mce_ciphertext.size() + nonce.size(), pt, pt_len);

   aead->start(nonce);
   aead->finish(msg, mce_ciphertext.size() + nonce.size());
   return msg;
   }