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 }