Ejemplo n.º 1
0
/*
* OAEP Pad Operation
*/
secure_vector<byte> OAEP::pad(const byte in[], size_t in_length,
                             size_t key_length,
                             RandomNumberGenerator& rng) const
   {
   key_length /= 8;

   if(key_length < in_length + 2*m_Phash.size() + 1)
      throw Invalid_Argument("OAEP: Input is too large");

   secure_vector<byte> 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);

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

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

   return out;
   }
Ejemplo n.º 2
0
/*
* PSSR Encode Operation
*/
secure_vector<byte> PSSR::encoding_of(const secure_vector<byte>& msg,
                                      size_t output_bits,
                                      RandomNumberGenerator& rng)
{
    const size_t HASH_SIZE = m_hash->output_length();

    if(msg.size() != HASH_SIZE)
        throw Encoding_Error("PSSR::encoding_of: Bad input length");
    if(output_bits < 8*HASH_SIZE + 8*m_SALT_SIZE + 9)
        throw Encoding_Error("PSSR::encoding_of: Output length is too small");

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

    secure_vector<byte> salt = rng.random_vec(m_SALT_SIZE);

    for(size_t j = 0; j != 8; ++j)
        m_hash->update(0);
    m_hash->update(msg);
    m_hash->update(salt);
    secure_vector<byte> H = m_hash->final();

    secure_vector<byte> EM(output_length);

    EM[output_length - HASH_SIZE - m_SALT_SIZE - 2] = 0x01;
    buffer_insert(EM, output_length - 1 - HASH_SIZE - m_SALT_SIZE, salt);
    mgf1_mask(*m_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;

    return EM;
}
Ejemplo n.º 3
0
/*
* PSSR Decode/Verify Operation
*/
bool PSSR::verify(const secure_vector<byte>& const_coded,
                   const secure_vector<byte>& raw, size_t key_bits)
   {
   const size_t HASH_SIZE = hash->output_length();
   const size_t KEY_BYTES = (key_bits + 7) / 8;

   if(key_bits < 8*HASH_SIZE + 9)
      return false;

   if(raw.size() != HASH_SIZE)
      return false;

   if(const_coded.size() > KEY_BYTES || const_coded.size() <= 1)
      return false;

   if(const_coded[const_coded.size()-1] != 0xBC)
      return false;

   secure_vector<byte> coded = const_coded;
   if(coded.size() < KEY_BYTES)
      {
      secure_vector<byte> temp(KEY_BYTES);
      buffer_insert(temp, KEY_BYTES - coded.size(), coded);
      coded = temp;
      }

   const size_t TOP_BITS = 8 * ((key_bits + 7) / 8) - key_bits;
   if(TOP_BITS > 8 - high_bit(coded[0]))
      return false;

   byte* DB = &coded[0];
   const size_t DB_size = coded.size() - HASH_SIZE - 1;

   const byte* H = &coded[DB_size];
   const size_t H_size = HASH_SIZE;

   mgf1_mask(*hash, &H[0], H_size, &DB[0], DB_size);
   DB[0] &= 0xFF >> TOP_BITS;

   size_t salt_offset = 0;
   for(size_t j = 0; j != DB_size; ++j)
      {
      if(DB[j] == 0x01)
         { salt_offset = j + 1; break; }
      if(DB[j])
         return false;
      }
   if(salt_offset == 0)
      return false;

   for(size_t j = 0; j != 8; ++j)
      hash->update(0);
   hash->update(raw);
   hash->update(&DB[salt_offset], DB_size - salt_offset);
   secure_vector<byte> H2 = hash->final();

   return same_mem(&H[0], &H2[0], HASH_SIZE);
   }
Ejemplo n.º 4
0
/*
* OAEP Unpad Operation
*/
secure_vector<byte> OAEP::unpad(const byte in[], size_t in_length,
                               size_t key_length) const
   {
   /*
   Must be careful about error messages here; if an attacker can
   distinguish them, it is easy to use the differences as an oracle to
   find the secret key, as described in "A Chosen Ciphertext Attack on
   RSA Optimal Asymmetric Encryption Padding (OAEP) as Standardized in
   PKCS #1 v2.0", James Manger, Crypto 2001

   Also have to be careful about timing attacks! Pointed out by Falko
   Strenzke.
   */

   key_length /= 8;

   // Invalid input: truncate to zero length input, causing later
   // checks to fail
   if(in_length > key_length)
      in_length = 0;

   secure_vector<byte> input(key_length);
   buffer_insert(input, key_length - in_length, in, in_length);

   mgf1_mask(*m_hash,
             &input[m_Phash.size()], input.size() - m_Phash.size(),
             input.data(), m_Phash.size());

   mgf1_mask(*m_hash,
             input.data(), m_Phash.size(),
             &input[m_Phash.size()], input.size() - m_Phash.size());

   bool waiting_for_delim = true;
   bool bad_input = false;
   size_t delim_idx = 2 * m_Phash.size();

   /*
   * GCC 4.5 on x86-64 compiles this in a way that is still vunerable
   * to timing analysis. Other compilers, or GCC on other platforms,
   * may or may not.
   */
   for(size_t i = delim_idx; i < input.size(); ++i)
      {
      const bool zero_p = !input[i];
      const bool one_p = input[i] == 0x01;

      const bool add_1 = waiting_for_delim && zero_p;

      bad_input |= waiting_for_delim && !(zero_p || one_p);

      delim_idx += add_1;

      waiting_for_delim &= zero_p;
      }

   // If we never saw any non-zero byte, then it's not valid input
   bad_input |= waiting_for_delim;

   bad_input |= !same_mem(&input[m_Phash.size()], m_Phash.data(), m_Phash.size());

   if(bad_input)
      throw Decoding_Error("Invalid OAEP encoding");

   return secure_vector<byte>(input.begin() + delim_idx + 1, input.end());
   }