1 /** 2 * PSSR 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.pssr; 12 13 import botan.constants; 14 static if (BOTAN_HAS_EMSA_PSSR): 15 16 import botan.pk_pad.emsa; 17 import botan.hash.hash; 18 import botan.utils.types; 19 import botan.pk_pad.mgf1; 20 import botan.utils.bit_ops; 21 import botan.utils.xor_buf; 22 import botan.utils.mem_ops; 23 24 /** 25 * PSSR (called EMSA4 in IEEE 1363 and in old versions of the library) 26 */ 27 class PSSR : EMSA 28 { 29 public: 30 31 /** 32 * Params: 33 * hash = the hash object to use 34 */ 35 this(HashFunction hash) 36 { 37 m_SALT_SIZE = hash.outputLength; 38 m_hash = hash; 39 } 40 41 /** 42 * Params: 43 * hash = the hash object to use 44 * salt_size = the size of the salt to use in bytes 45 */ 46 this(HashFunction hash, size_t salt_size) 47 { 48 m_SALT_SIZE = salt_size; 49 m_hash = hash; 50 } 51 52 /* 53 * PSSR Update Operation 54 */ 55 override void update(const(ubyte)* input, size_t length) 56 { 57 m_hash.update(input, length); 58 } 59 60 /* 61 * Return the raw (unencoded) data 62 */ 63 override SecureVector!ubyte rawData() 64 { 65 return m_hash.finished(); 66 } 67 68 /* 69 * PSSR Encode Operation 70 */ 71 override SecureVector!ubyte encodingOf(const ref SecureVector!ubyte msg, 72 size_t output_bits, 73 RandomNumberGenerator rng) 74 { 75 const size_t HASH_SIZE = m_hash.outputLength; 76 77 if (msg.length != HASH_SIZE) 78 throw new EncodingError("encodingOf: Bad input length"); 79 if (output_bits < 8*HASH_SIZE + 8*m_SALT_SIZE + 9) 80 throw new EncodingError("encodingOf: Output length is too small"); 81 82 const size_t output_length = (output_bits + 7) / 8; 83 84 SecureVector!ubyte salt = rng.randomVec(m_SALT_SIZE); 85 86 foreach (size_t j; 0 .. 8) 87 m_hash.update(0); 88 m_hash.update(msg); 89 m_hash.update(salt); 90 SecureVector!ubyte H = m_hash.finished(); 91 92 SecureVector!ubyte EM = SecureVector!ubyte(output_length); 93 94 EM[output_length - HASH_SIZE - m_SALT_SIZE - 2] = 0x01; 95 bufferInsert(EM, output_length - 1 - HASH_SIZE - m_SALT_SIZE, salt); 96 mgf1Mask(*m_hash, H.ptr, HASH_SIZE, EM.ptr, output_length - HASH_SIZE - 1); 97 EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits); 98 bufferInsert(EM, output_length - 1 - HASH_SIZE, H); 99 EM[output_length-1] = 0xBC; 100 101 return EM; 102 } 103 104 /* 105 * PSSR Decode/Verify Operation 106 */ 107 override bool verify(const ref SecureVector!ubyte const_coded, 108 const ref SecureVector!ubyte raw, size_t key_bits) 109 { 110 const size_t HASH_SIZE = m_hash.outputLength; 111 const size_t KEY_BYTES = (key_bits + 7) / 8; 112 113 if (key_bits < 8*HASH_SIZE + 9) 114 return false; 115 116 if (raw.length != HASH_SIZE) 117 return false; 118 119 if (const_coded.length > KEY_BYTES || const_coded.length <= 1) 120 return false; 121 122 if (const_coded[const_coded.length-1] != 0xBC) 123 return false; 124 125 SecureVector!ubyte coded = const_coded.dup; 126 if (coded.length < KEY_BYTES) 127 { 128 SecureVector!ubyte temp = SecureVector!ubyte(KEY_BYTES); 129 bufferInsert(temp, KEY_BYTES - coded.length, coded); 130 coded = temp; 131 } 132 133 const size_t TOP_BITS = 8 * ((key_bits + 7) / 8) - key_bits; 134 if (TOP_BITS > 8 - highBit(coded[0])) 135 return false; 136 137 ubyte* DB = coded.ptr; 138 const size_t DB_size = coded.length - HASH_SIZE - 1; 139 140 const(ubyte)* H = &coded[DB_size]; 141 const size_t H_size = HASH_SIZE; 142 143 mgf1Mask(*m_hash, H, H_size, DB, DB_size); 144 DB[0] &= 0xFF >> TOP_BITS; 145 146 size_t salt_offset = 0; 147 foreach (size_t j; 0 .. DB_size) 148 { 149 if (DB[j] == 0x01) 150 { salt_offset = j + 1; break; } 151 if (DB[j]) 152 return false; 153 } 154 if (salt_offset == 0) 155 return false; 156 157 foreach (size_t j; 0 .. 8) 158 m_hash.update(0); 159 m_hash.update(raw); 160 m_hash.update(&DB[salt_offset], DB_size - salt_offset); 161 SecureVector!ubyte H2 = m_hash.finished(); 162 163 return sameMem(H, H2.ptr, HASH_SIZE); 164 } 165 166 private: 167 size_t m_SALT_SIZE; 168 Unique!HashFunction m_hash; 169 }