1 /** 2 * ANSI X9.19 MAC 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.mac.x919_mac; 12 13 import botan.constants; 14 static if (BOTAN_HAS_ANSI_X919_MAC): 15 16 import botan.mac.mac; 17 import botan.block.block_cipher; 18 import botan.utils.xor_buf; 19 import std.algorithm; 20 import botan.utils.mem_ops; 21 22 /** 23 * DES/3DES-based MAC from ANSI X9.19 24 */ 25 final class ANSIX919MAC : MessageAuthenticationCode, SymmetricAlgorithm 26 { 27 public: 28 /* 29 * Clear memory of sensitive data 30 */ 31 void clear() 32 { 33 m_des1.clear(); 34 m_des2.clear(); 35 zeroise(m_state); 36 m_position = 0; 37 } 38 39 40 override @property string name() const 41 { 42 return "X9.19-MAC"; 43 } 44 45 override @property size_t outputLength() const { return 8; } 46 47 override MessageAuthenticationCode clone() const 48 { 49 return new ANSIX919MAC(m_des1.clone()); 50 } 51 52 KeyLengthSpecification keySpec() const 53 { 54 return KeyLengthSpecification(8, 16, 8); 55 } 56 57 /** 58 * Params: 59 * cipher = the underlying block cipher to use 60 */ 61 this(BlockCipher cipher) 62 { 63 m_des1 = cipher; 64 m_des2 = m_des1.clone(); 65 m_state = 8; 66 m_position = 0; 67 if (m_des1.name != "DES") 68 throw new InvalidArgument("ANSI X9.19 MAC only supports DES"); 69 } 70 71 protected: 72 /* 73 * Update an ANSI X9.19 MAC Calculation 74 */ 75 override void addData(const(ubyte)* input, size_t length) 76 { 77 size_t xored = std.algorithm.min(8 - m_position, length); 78 xorBuf(&m_state[m_position], input, xored); 79 m_position += xored; 80 81 if (m_position < 8) return; 82 83 m_des1.encrypt(m_state); 84 input += xored; 85 length -= xored; 86 while (length >= 8) 87 { 88 xorBuf(m_state, input, 8); 89 m_des1.encrypt(m_state); 90 input += 8; 91 length -= 8; 92 } 93 94 xorBuf(m_state, input, length); 95 m_position = length; 96 } 97 98 /* 99 * Finalize an ANSI X9.19 MAC Calculation 100 */ 101 override void finalResult(ubyte* mac) 102 { 103 if (m_position) 104 m_des1.encrypt(m_state); 105 m_des2.decrypt(m_state.ptr, mac); 106 m_des1.encrypt(mac); 107 zeroise(m_state); 108 m_position = 0; 109 } 110 111 112 /* 113 * ANSI X9.19 MAC Key Schedule 114 */ 115 override void keySchedule(const(ubyte)* key, size_t length) 116 { 117 m_des1.setKey(key, 8); 118 119 if (length == 16) 120 key += 8; 121 122 m_des2.setKey(key, 8); 123 } 124 125 126 Unique!BlockCipher m_des1, m_des2; 127 SecureVector!ubyte m_state; 128 size_t m_position; 129 }