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 }