1 /**
2 * PKCS #1 v1.5 signature padding
3 * 
4 * Copyright:
5 * (C) 1999-2008 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_pkcs1;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_EMSA_PKCS1):
15 
16 import botan.pk_pad.emsa;
17 import botan.hash.hash;
18 import botan.pk_pad.emsa_pkcs1;
19 import botan.pk_pad.hash_id;
20 import botan.utils.types;
21 import botan.utils.mem_ops;
22 import std.algorithm : swap;
23 
24 /**
25 * PKCS #1 v1.5 signature padding
26 * aka PKCS #1 block type 1
27 * aka EMSA3 from IEEE 1363
28 */
29 final class EMSAPKCS1v15 : EMSA
30 {
31 public:
32     /**
33     * Params:
34     *  hash = the hash object to use
35     */
36     this(HashFunction hash)
37     {
38         m_hash = hash;
39         m_hash_id = pkcsHashId(m_hash.name);
40     }
41 
42     override void update(const(ubyte)* input, size_t length)
43     {
44         m_hash.update(input, length);
45     }
46 
47     override SecureVector!ubyte rawData()
48     {
49         return m_hash.finished();
50     }
51 
52     override SecureVector!ubyte
53         encodingOf(const ref SecureVector!ubyte msg,
54                     size_t output_bits,
55                     RandomNumberGenerator)
56     {
57         if (msg.length != m_hash.outputLength)
58             throw new EncodingError("encodingOf: Bad input length");
59         
60         return emsa3Encoding(msg, output_bits,
61                               m_hash_id.ptr, m_hash_id.length);
62     }
63 
64     override bool verify(const ref SecureVector!ubyte coded,
65                          const ref SecureVector!ubyte raw,
66                          size_t key_bits)
67     {
68         if (raw.length != m_hash.outputLength)
69             return false;
70         
71         try
72         {
73             return (coded == emsa3Encoding(raw, key_bits,
74                                             m_hash_id.ptr, m_hash_id.length));
75         }
76         catch (Exception)
77         {
78             return false;
79         }
80     }
81 private:
82     Unique!HashFunction m_hash;
83     Vector!ubyte m_hash_id;
84 }
85 
86 /**
87 * EMSA_PKCS1v15_Raw which is EMSA_PKCS1v15 without a hash or digest id
88 * (which according to QCA docs is "identical to PKCS#11's CKM_RSA_PKCS
89 * mechanism", something I have not confirmed)
90 */
91 final class EMSAPKCS1v15Raw : EMSA
92 {
93 public:
94     override void update(const(ubyte)* input, size_t length)
95     {
96         m_message ~= input[0 .. length];
97     }
98 
99     override SecureVector!ubyte rawData()
100     {
101         return m_message.dup;
102     }
103 
104     override SecureVector!ubyte encodingOf(const ref SecureVector!ubyte msg,
105                                            size_t output_bits,
106                                            RandomNumberGenerator)
107     {
108         return emsa3Encoding(msg, output_bits, null, 0);
109     }
110 
111     override bool verify(const ref SecureVector!ubyte coded,
112                          const ref SecureVector!ubyte raw,
113                          size_t key_bits)
114     {
115         try
116         {
117             return (coded == emsa3Encoding(raw, key_bits, null, 0));
118         }
119         catch (Exception)
120         {
121             return false;
122         }
123     }
124 
125 private:
126     SecureVector!ubyte m_message;
127 }
128 
129 private:
130 
131 SecureVector!ubyte emsa3Encoding(const ref SecureVector!ubyte msg,
132                                 size_t output_bits,
133                                 const(ubyte)* hash_id,
134                                 size_t hash_id_length)
135 {
136     size_t output_length = output_bits / 8;
137     if (output_length < hash_id_length + msg.length + 10)
138         throw new EncodingError("emsa3Encoding: Output length is too small");
139     
140     SecureVector!ubyte T = SecureVector!ubyte(output_length);
141     const size_t P_LENGTH = output_length - msg.length - hash_id_length - 2;
142     
143     T[0] = 0x01;
144     setMem(&T[1], P_LENGTH, 0xFF);
145     T[P_LENGTH+1] = 0x00;
146     bufferInsert(T, P_LENGTH+2, hash_id, hash_id_length);
147     bufferInsert(T, output_length-msg.length, msg.ptr, msg.length);
148     return T;
149 }