Botan
1.11.15
|
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 }