1 /**
2 * PSSR
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.pssr;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_EMSA_PSSR):
15 
16 import botan.pk_pad.emsa;
17 import botan.hash.hash;
18 import botan.utils.types;
19 import botan.pk_pad.mgf1;
20 import botan.utils.bit_ops;
21 import botan.utils.xor_buf;
22 import botan.utils.mem_ops;
23 
24 /**
25 * PSSR (called EMSA4 in IEEE 1363 and in old versions of the library)
26 */
27 class PSSR : EMSA
28 {
29 public:
30 
31     /**
32     * Params:
33     *  hash = the hash object to use
34     */
35     this(HashFunction hash)
36     {
37         m_SALT_SIZE = hash.outputLength;
38         m_hash = hash;
39     }
40 
41     /**
42     * Params:
43     *  hash = the hash object to use
44     *  salt_size = the size of the salt to use in bytes
45     */
46     this(HashFunction hash, size_t salt_size)
47     {
48         m_SALT_SIZE = salt_size;
49         m_hash = hash;
50     }
51 
52     /*
53     * PSSR Update Operation
54     */
55     override void update(const(ubyte)* input, size_t length)
56     {
57         m_hash.update(input, length);
58     }
59 
60     /*
61     * Return the raw (unencoded) data
62     */
63     override SecureVector!ubyte rawData()
64     {
65         return m_hash.finished();
66     }
67 
68     /*
69     * PSSR Encode Operation
70     */
71     override SecureVector!ubyte encodingOf(const ref SecureVector!ubyte msg,
72                                            size_t output_bits,
73                                            RandomNumberGenerator rng)
74     {
75         const size_t HASH_SIZE = m_hash.outputLength;
76         
77         if (msg.length != HASH_SIZE)
78             throw new EncodingError("encodingOf: Bad input length");
79         if (output_bits < 8*HASH_SIZE + 8*m_SALT_SIZE + 9)
80             throw new EncodingError("encodingOf: Output length is too small");
81         
82         const size_t output_length = (output_bits + 7) / 8;
83         
84         SecureVector!ubyte salt = rng.randomVec(m_SALT_SIZE);
85         
86         foreach (size_t j; 0 .. 8)
87             m_hash.update(0);
88         m_hash.update(msg);
89         m_hash.update(salt);
90         SecureVector!ubyte H = m_hash.finished();
91         
92         SecureVector!ubyte EM = SecureVector!ubyte(output_length);
93         
94         EM[output_length - HASH_SIZE - m_SALT_SIZE - 2] = 0x01;
95         bufferInsert(EM, output_length - 1 - HASH_SIZE - m_SALT_SIZE, salt);
96         mgf1Mask(*m_hash, H.ptr, HASH_SIZE, EM.ptr, output_length - HASH_SIZE - 1);
97         EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits);
98         bufferInsert(EM, output_length - 1 - HASH_SIZE, H);
99         EM[output_length-1] = 0xBC;
100         
101         return EM;
102     }
103 
104     /*
105     * PSSR Decode/Verify Operation
106     */
107     override bool verify(const ref SecureVector!ubyte const_coded,
108                          const ref SecureVector!ubyte raw, size_t key_bits)
109     {
110         const size_t HASH_SIZE = m_hash.outputLength;
111         const size_t KEY_BYTES = (key_bits + 7) / 8;
112         
113         if (key_bits < 8*HASH_SIZE + 9)
114             return false;
115         
116         if (raw.length != HASH_SIZE)
117             return false;
118         
119         if (const_coded.length > KEY_BYTES || const_coded.length <= 1)
120             return false;
121         
122         if (const_coded[const_coded.length-1] != 0xBC)
123             return false;
124         
125         SecureVector!ubyte coded = const_coded.clone;
126         if (coded.length < KEY_BYTES)
127         {
128             SecureVector!ubyte temp = SecureVector!ubyte(KEY_BYTES);
129             bufferInsert(temp, KEY_BYTES - coded.length, coded);
130             coded = temp;
131         }
132         
133         const size_t TOP_BITS = 8 * ((key_bits + 7) / 8) - key_bits;
134         if (TOP_BITS > 8 - highBit(coded[0]))
135             return false;
136         
137         ubyte* DB = coded.ptr;
138         const size_t DB_size = coded.length - HASH_SIZE - 1;
139         
140         const(ubyte)* H = &coded[DB_size];
141         const size_t H_size = HASH_SIZE;
142         
143         mgf1Mask(*m_hash, H, H_size, DB, DB_size);
144         DB[0] &= 0xFF >> TOP_BITS;
145         
146         size_t salt_offset = 0;
147         foreach (size_t j; 0 .. DB_size)
148         {
149             if (DB[j] == 0x01)
150             { salt_offset = j + 1; break; }
151             if (DB[j])
152                 return false;
153         }
154         if (salt_offset == 0)
155             return false;
156         
157         foreach (size_t j; 0 .. 8)
158             m_hash.update(0);
159         m_hash.update(raw);
160         m_hash.update(&DB[salt_offset], DB_size - salt_offset);
161         SecureVector!ubyte H2 = m_hash.finished();
162         
163         return sameMem(H, H2.ptr, HASH_SIZE);
164     }
165 
166 private:
167     size_t m_SALT_SIZE;
168     Unique!HashFunction m_hash;
169 }