1 /**
2 * EMSA1
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.emsa1;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_EMSA1):
15 
16 public import botan.pk_pad.emsa;
17 import botan.hash.hash;
18 import botan.utils.types;
19 
20 /**
21 * EMSA1 from IEEE 1363
22 * Essentially, sign the hash directly
23 */
24 class EMSA1 : EMSA
25 {
26 public:
27     /**
28     * Params:
29     *  hash = the hash function to use
30     */
31     this(HashFunction hash) 
32     {
33         m_hash = hash;
34     }
35 
36     size_t hashOutputLength() const { return m_hash.outputLength; }
37 
38     override void update(const(ubyte)* input, size_t length)
39     {
40         m_hash.update(input, length);
41     }
42 
43     override SecureVector!ubyte rawData()
44     {
45         return m_hash.finished();
46     }
47 
48     override SecureVector!ubyte encodingOf(const ref SecureVector!ubyte msg,
49                                            size_t output_bits,
50                                            RandomNumberGenerator rng)
51     {
52         //logDebug("EMSA1 Encode");
53         if (msg.length != hashOutputLength())
54             throw new EncodingError("encodingOf: Invalid size for input");
55         return emsa1Encoding(msg, output_bits);
56     }
57 
58     override bool verify(const ref SecureVector!ubyte coded,
59                          const ref SecureVector!ubyte raw, size_t key_bits)
60     {
61         try {
62             if (raw.length != m_hash.outputLength)
63                 throw new EncodingError("encodingOf: Invalid size for input");
64             
65             SecureVector!ubyte our_coding = emsa1Encoding(raw, key_bits);
66             if (our_coding == coded) return true;
67             if (our_coding.empty || our_coding[0] != 0) return false;
68             if (our_coding.length <= coded.length) return false;
69             
70             size_t offset = 0;
71             while (offset < our_coding.length && our_coding[offset] == 0)
72                 ++offset;
73             if (our_coding.length - offset != coded.length)
74                 return false;
75             
76             for (size_t j = 0; j != coded.length; ++j)
77                 if (coded[j] != our_coding[j+offset])
78                     return false;
79             
80             return true;
81         }
82         catch(InvalidArgument)
83         {
84             return false;
85         }
86     }
87 
88     Unique!HashFunction m_hash;
89 }
90 
91 private:
92 
93 SecureVector!ubyte emsa1Encoding(const ref SecureVector!ubyte msg_, size_t output_bits)
94 {
95     SecureVector!ubyte msg = msg_.dup;
96 
97     if (8*msg.length <= output_bits)
98         return msg.move;
99     // logDebug("Generate digest");
100     size_t shift = 8*msg.length - output_bits;
101     
102     size_t byte_shift = shift / 8, bit_shift = shift % 8;
103     SecureVector!ubyte digest = SecureVector!ubyte(msg.length - byte_shift);
104     
105     for (size_t j = 0; j != msg.length - byte_shift; ++j)
106         digest[j] = msg[j];
107     
108     if (bit_shift)
109     {
110         ubyte carry = 0;
111         for (size_t j = 0; j != digest.length; ++j)
112         {
113             ubyte temp = digest[j];
114             digest[j] = (temp >> bit_shift) | carry;
115             carry = cast(ubyte)(temp << (8 - bit_shift));
116         }
117     }
118     return digest.move();
119 }