Botan  1.11.15
src/lib/pk_pad/eme_oaep/oaep.cpp
Go to the documentation of this file.
00001 /*
00002 * OAEP
00003 * (C) 1999-2010 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/internal/pad_utils.h>
00009 #include <botan/oaep.h>
00010 #include <botan/mgf1.h>
00011 #include <botan/mem_ops.h>
00012 
00013 
00014 namespace Botan {
00015 
00016 OAEP* OAEP::make(const Spec& request)
00017    {
00018    if(request.algo_name() == "OAEP" && request.arg_count_between(1, 2))
00019       {
00020       auto& hashes = Algo_Registry<HashFunction>::global_registry();
00021 
00022       if(request.arg_count() == 1 ||
00023          (request.arg_count() == 2 && request.arg(1) == "MGF1"))
00024          {
00025          if(HashFunction* hash = hashes.make(request.arg(0)))
00026             return new OAEP(hash);
00027          }
00028       }
00029 
00030    return nullptr;
00031    }
00032 
00033 BOTAN_REGISTER_NAMED_T(EME, "OAEP", OAEP, OAEP::make);
00034 
00035 
00036 /*
00037 * OAEP Pad Operation
00038 */
00039 secure_vector<byte> OAEP::pad(const byte in[], size_t in_length,
00040                              size_t key_length,
00041                              RandomNumberGenerator& rng) const
00042    {
00043    key_length /= 8;
00044 
00045    if(key_length < in_length + 2*m_Phash.size() + 1)
00046       throw Invalid_Argument("OAEP: Input is too large");
00047 
00048    secure_vector<byte> out(key_length);
00049 
00050    rng.randomize(&out[0], m_Phash.size());
00051 
00052    buffer_insert(out, m_Phash.size(), &m_Phash[0], m_Phash.size());
00053    out[out.size() - in_length - 1] = 0x01;
00054    buffer_insert(out, out.size() - in_length, in, in_length);
00055 
00056    mgf1_mask(*m_hash,
00057              &out[0], m_Phash.size(),
00058              &out[m_Phash.size()], out.size() - m_Phash.size());
00059 
00060    mgf1_mask(*m_hash,
00061              &out[m_Phash.size()], out.size() - m_Phash.size(),
00062              &out[0], m_Phash.size());
00063 
00064    return out;
00065    }
00066 
00067 /*
00068 * OAEP Unpad Operation
00069 */
00070 secure_vector<byte> OAEP::unpad(const byte in[], size_t in_length,
00071                                size_t key_length) const
00072    {
00073    /*
00074    Must be careful about error messages here; if an attacker can
00075    distinguish them, it is easy to use the differences as an oracle to
00076    find the secret key, as described in "A Chosen Ciphertext Attack on
00077    RSA Optimal Asymmetric Encryption Padding (OAEP) as Standardized in
00078    PKCS #1 v2.0", James Manger, Crypto 2001
00079 
00080    Also have to be careful about timing attacks! Pointed out by Falko
00081    Strenzke.
00082    */
00083 
00084    key_length /= 8;
00085 
00086    // Invalid input: truncate to zero length input, causing later
00087    // checks to fail
00088    if(in_length > key_length)
00089       in_length = 0;
00090 
00091    secure_vector<byte> input(key_length);
00092    buffer_insert(input, key_length - in_length, in, in_length);
00093 
00094    mgf1_mask(*m_hash,
00095              &input[m_Phash.size()], input.size() - m_Phash.size(),
00096              &input[0], m_Phash.size());
00097 
00098    mgf1_mask(*m_hash,
00099              &input[0], m_Phash.size(),
00100              &input[m_Phash.size()], input.size() - m_Phash.size());
00101 
00102    bool waiting_for_delim = true;
00103    bool bad_input = false;
00104    size_t delim_idx = 2 * m_Phash.size();
00105 
00106    /*
00107    * GCC 4.5 on x86-64 compiles this in a way that is still vunerable
00108    * to timing analysis. Other compilers, or GCC on other platforms,
00109    * may or may not.
00110    */
00111    for(size_t i = delim_idx; i < input.size(); ++i)
00112       {
00113       const bool zero_p = !input[i];
00114       const bool one_p = input[i] == 0x01;
00115 
00116       const bool add_1 = waiting_for_delim && zero_p;
00117 
00118       bad_input |= waiting_for_delim && !(zero_p || one_p);
00119 
00120       delim_idx += add_1;
00121 
00122       waiting_for_delim &= zero_p;
00123       }
00124 
00125    // If we never saw any non-zero byte, then it's not valid input
00126    bad_input |= waiting_for_delim;
00127 
00128    bad_input |= !same_mem(&input[m_Phash.size()], &m_Phash[0], m_Phash.size());
00129 
00130    if(bad_input)
00131       throw Decoding_Error("Invalid OAEP encoding");
00132 
00133    return secure_vector<byte>(&input[delim_idx + 1], &input[input.size()]);
00134    }
00135 
00136 /*
00137 * Return the max input size for a given key size
00138 */
00139 size_t OAEP::maximum_input_size(size_t keybits) const
00140    {
00141    if(keybits / 8 > 2*m_Phash.size() + 1)
00142       return ((keybits / 8) - 2*m_Phash.size() - 1);
00143    else
00144       return 0;
00145    }
00146 
00147 /*
00148 * OAEP Constructor
00149 */
00150 OAEP::OAEP(HashFunction* hash, const std::string& P) : m_hash(hash)
00151    {
00152    m_Phash = m_hash->process(P);
00153    }
00154 
00155 }