1 /** 2 * OAEP 3 * 4 * Copyright: 5 * (C) 1999-2007 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.pk_pad.oaep; 12 13 import botan.constants; 14 static if (BOTAN_HAS_EME_OAEP): 15 16 import botan.pk_pad.eme; 17 import botan.kdf.kdf; 18 import botan.hash.hash; 19 import botan.rng.rng; 20 import botan.pk_pad.mgf1; 21 import botan.utils.mem_ops; 22 import botan.utils.types; 23 24 /** 25 * OAEP (called EME1 in IEEE 1363 and in earlier versions of the library) 26 */ 27 final class OAEP : EME 28 { 29 public: 30 /* 31 * Return the max input size for a given key size 32 */ 33 override size_t maximumInputSize(size_t keybits) const 34 { 35 if (keybits / 8 > 2*m_Phash.length + 1) 36 return ((keybits / 8) - 2*m_Phash.length - 1); 37 else 38 return 0; 39 } 40 41 /** 42 * Params: 43 * hash = object to use for hashing (takes ownership) 44 * P = an optional label. Normally empty. 45 */ 46 this(HashFunction hash, in string P = "") 47 { 48 m_hash = hash; 49 m_Phash = m_hash.process(P); 50 } 51 52 /* 53 * OAEP Pad Operation 54 */ 55 override SecureVector!ubyte pad(const(ubyte)* input, size_t in_length, size_t key_length, 56 RandomNumberGenerator rng) const 57 { 58 key_length /= 8; 59 60 if (key_length < in_length + 2*m_Phash.length + 1) 61 throw new InvalidArgument("OAEP: Input is too large"); 62 63 SecureVector!ubyte output = SecureVector!ubyte(key_length); 64 rng.randomize(output.ptr, m_Phash.length); 65 66 bufferInsert(output, m_Phash.length, m_Phash.ptr, m_Phash.length); 67 output[output.length - in_length - 1] = 0x01; 68 bufferInsert(output, output.length - in_length, input, in_length); 69 70 mgf1Mask(cast() *m_hash, output.ptr, m_Phash.length, &output[m_Phash.length], output.length - m_Phash.length); 71 72 mgf1Mask(cast() *m_hash, &output[m_Phash.length], output.length - m_Phash.length, 73 output.ptr, m_Phash.length); 74 75 return output; 76 } 77 78 /* 79 * OAEP Unpad Operation 80 */ 81 override SecureVector!ubyte unpad(const(ubyte)* input_, size_t in_length, size_t key_length) const 82 { 83 /* 84 Must be careful about error messages here; if an attacker can 85 distinguish them, it is easy to use the differences as an oracle to 86 find the secret key, as described in "A Chosen Ciphertext Attack on 87 RSA Optimal Asymmetric Encryption Padding (OAEP) as Standardized in 88 PKCS #1 v2.0", James Manger, Crypto 2001 89 90 Also have to be careful about timing attacks! Pointed out by Falko 91 Strenzke. 92 */ 93 94 key_length /= 8; 95 96 // Invalid input: truncate to zero length input, causing later 97 // checks to fail 98 if (in_length > key_length) 99 in_length = 0; 100 101 SecureVector!ubyte input = SecureVector!ubyte(key_length); 102 bufferInsert(input, key_length - in_length, input_, in_length); 103 104 mgf1Mask(cast() *m_hash, &input[m_Phash.length], input.length - m_Phash.length, input.ptr, m_Phash.length); 105 mgf1Mask(cast() *m_hash, input.ptr, m_Phash.length, &input[m_Phash.length], input.length - m_Phash.length); 106 107 bool waiting_for_delim = true; 108 bool bad_input = false; 109 size_t delim_idx = 2 * m_Phash.length; 110 111 /* 112 * GCC 4.5 on x86-64 compiles this in a way that is still vunerable 113 * to timing analysis. Other compilers, or GCC on other platforms, 114 * may or may not. 115 */ 116 for (size_t i = delim_idx; i < input.length; ++i) 117 { 118 const bool zero_p = !input[i]; 119 const bool one_p = input[i] == 0x01; 120 121 const bool add_1 = waiting_for_delim && zero_p; 122 123 bad_input |= waiting_for_delim && !(zero_p || one_p); 124 125 delim_idx += add_1; 126 127 waiting_for_delim &= zero_p; 128 } 129 130 // If we never saw any non-zero ubyte, then it's not valid input 131 bad_input |= waiting_for_delim; 132 133 bad_input |= !sameMem(&input[m_Phash.length], m_Phash.ptr, m_Phash.length); 134 135 if (bad_input) 136 throw new DecodingError("Invalid OAEP encoding"); 137 138 return SecureVector!ubyte(input.ptr[delim_idx + 1 .. input.length]); 139 } 140 141 SecureVector!ubyte m_Phash; 142 Unique!HashFunction m_hash; 143 }