1 /**
2 * TLS Handshake Hash
3 * 
4 * Copyright:
5 * (C) 2004-2006,2011,2012 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.tls.handshake_hash;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_TLS):
15 package:
16 
17 import memutils.vector;
18 import botan.tls.version_;
19 import botan.tls.magic;
20 import botan.tls.exceptn;
21 import botan.hash.hash;
22 import botan.libstate.libstate;
23 import botan.tls.exceptn;
24 import botan.libstate.libstate;
25 import botan.hash.hash;
26 import botan.utils.types;
27 
28 /**
29 * TLS Handshake Hash
30 */
31 struct HandshakeHash
32 {
33 public:
34     void update(const(ubyte)* input, size_t length)
35     { m_data ~= input[0 .. length]; }
36 
37     void update(ALLOC)(auto const ref Vector!(ubyte, ALLOC) input)
38     { m_data ~= input[]; }
39 
40     /**
41     * Return a TLS Handshake Hash
42     */
43     SecureVector!ubyte flushInto(TLSProtocolVersion _version, in string mac_algo) const
44     {
45         AlgorithmFactory af = globalState().algorithmFactory();
46         
47         Unique!HashFunction hash;
48         
49         if (_version.supportsCiphersuiteSpecificPrf())
50         {
51             if (mac_algo == "MD5" || mac_algo == "SHA-1")
52                 hash = af.makeHashFunction("SHA-256");
53             else
54                 hash = af.makeHashFunction(mac_algo);
55         }
56         else
57             hash = af.makeHashFunction("Parallel(MD5,SHA-160)");
58         
59         hash.update(m_data);
60         return hash.finished();
61     }
62 
63     /**
64     * Return a SSLv3 Handshake Hash
65     */
66     SecureVector!ubyte finalSSL3()(auto const ref SecureVector!ubyte secret) const
67     {
68         const ubyte PAD_INNER = 0x36, PAD_OUTER = 0x5C;
69         
70         AlgorithmFactory af = globalState().algorithmFactory();
71         
72         Unique!HashFunction md5 = af.makeHashFunction("MD5");
73         Unique!HashFunction sha1 = af.makeHashFunction("SHA-1");
74         
75         md5.update(m_data);
76         sha1.update(m_data);
77         
78         md5.update(secret);
79         sha1.update(secret);
80         
81         foreach (size_t i; 0 .. 48)
82             md5.update(PAD_INNER);
83         foreach (size_t i; 0 .. 40)
84             sha1.update(PAD_INNER);
85         
86         SecureVector!ubyte inner_md5 = md5.finished(), inner_sha1 = sha1.finished();
87         
88         md5.update(secret);
89         sha1.update(secret);
90         
91         foreach (size_t i; 0 .. 48)
92             md5.update(PAD_OUTER);
93         foreach (size_t i; 0 .. 40)
94             sha1.update(PAD_OUTER);
95         
96         md5.update(inner_md5);
97         sha1.update(inner_sha1);
98         
99         SecureVector!ubyte output;
100         output ~= md5.finished();
101         output ~= sha1.finished();
102         return output;
103     }
104 
105     ref const(Vector!ubyte) getContents() const
106     { return m_data; }
107 
108     void reset() { m_data.clear(); }
109 
110     @property HandshakeHash dup() const 
111     { 
112         HandshakeHash ret;
113         ret.m_data = m_data.dup;
114         return ret;
115     }
116 private:
117     Vector!ubyte m_data;
118 }