1 /** 2 * X9.31 EMSA 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.emsa_x931; 12 13 import botan.constants; 14 static if (BOTAN_HAS_EMSA_X931): 15 import botan.pk_pad.emsa; 16 import botan.hash.hash; 17 import botan.pk_pad.hash_id; 18 import botan.utils.types; 19 import botan.utils.mem_ops; 20 21 /** 22 * EMSA from X9.31 (EMSA2 in IEEE 1363) 23 * Useful for Rabin-Williams, also sometimes used with RSA in 24 * odd protocols. 25 */ 26 final class EMSAX931 : EMSA 27 { 28 public: 29 /** 30 * Params: 31 * hash = the hash object to use 32 */ 33 this(HashFunction hash) 34 { 35 m_hash = hash; 36 m_empty_hash = m_hash.finished(); 37 38 m_hash_id = ieee1363HashId(m_hash.name); 39 40 if (!m_hash_id) 41 throw new EncodingError("EMSA_X931 no hash identifier for " ~ hash.name); 42 } 43 public: 44 override void update(const(ubyte)* input, size_t length) 45 { 46 m_hash.update(input, length); 47 } 48 49 override SecureVector!ubyte rawData() 50 { 51 return m_hash.finished(); 52 } 53 54 /* 55 * EMSA_X931 Encode Operation 56 */ 57 override SecureVector!ubyte encodingOf(const ref SecureVector!ubyte msg, 58 size_t output_bits, 59 RandomNumberGenerator) 60 { 61 return emsa2Encoding(msg, output_bits, m_empty_hash, m_hash_id); 62 } 63 64 /* 65 * EMSA_X931 Verify Operation 66 */ 67 bool verify(const ref SecureVector!ubyte coded, 68 const ref SecureVector!ubyte raw, 69 size_t key_bits) 70 { 71 try 72 { 73 return (coded == emsa2Encoding(raw, key_bits, 74 m_empty_hash, m_hash_id)); 75 } 76 catch (Exception) 77 { 78 return false; 79 } 80 } 81 82 private: 83 SecureVector!ubyte m_empty_hash; 84 Unique!HashFunction m_hash; 85 ubyte m_hash_id; 86 } 87 88 private: 89 90 SecureVector!ubyte emsa2Encoding(const ref SecureVector!ubyte msg, 91 size_t output_bits, 92 const ref SecureVector!ubyte empty_hash, 93 ubyte hash_id) 94 { 95 const size_t HASH_SIZE = empty_hash.length; 96 97 size_t output_length = (output_bits + 1) / 8; 98 99 if (msg.length != HASH_SIZE) 100 throw new EncodingError("encodingOf: Bad input length"); 101 if (output_length < HASH_SIZE + 4) 102 throw new EncodingError("encodingOf: Output length is too small"); 103 104 const bool empty_input = (msg == empty_hash); 105 106 SecureVector!ubyte output = SecureVector!ubyte(output_length); 107 108 output[0] = (empty_input ? 0x4B : 0x6B); 109 output[output_length - 3 - HASH_SIZE] = 0xBA; 110 setMem(&output[1], output_length - 4 - HASH_SIZE, 0xBB); 111 bufferInsert(output, output_length - (HASH_SIZE + 2), msg.ptr, msg.length); 112 output[output_length-2] = hash_id; 113 output[output_length-1] = 0xCC; 114 115 return output; 116 }