Account for SHA-512 asking for a 128-bit message length
[libs/crypto.git] / source / sha2.cpp
1 #include <stdexcept>
2 #include "sha2.h"
3
4 using namespace std;
5
6 namespace {
7
8 template<typename T>
9 inline T read_word(const char *data)
10 {
11         const Msp::UInt8 *u8data = reinterpret_cast<const Msp::UInt8 *>(data);
12         T result = 0;
13         for(unsigned i=0; i<sizeof(T); ++i)
14                 result |= static_cast<T>(u8data[i])<<((sizeof(T)-1-i)*8);
15         return result;
16 }
17
18 template<typename T>
19 inline void write_word(T w, char *buf)
20 {
21         for(unsigned i=0; i<sizeof(T); ++i)
22                 buf[i] = w>>((sizeof(T)-1-i)*8);
23 }
24
25 template<typename T>
26 inline T rotate_right(T x, unsigned b)
27 {
28         return (x>>b) | (x<<(sizeof(T)*8-b));
29 }
30
31 }
32
33
34 namespace Msp {
35 namespace Crypto {
36
37 template<typename C>
38 SHA2<C>::SHA2()
39 {
40         init();
41 }
42 template SHA2<SHA2_256Constants>::SHA2();
43 template SHA2<SHA2_512Constants>::SHA2();
44
45 template<typename C>
46 SHA2<C>::SHA2(const char *data, unsigned len)
47 {
48         init();
49         BlockHash<Constants::BLOCK_SIZE>::update(data, len);
50 }
51 template SHA2<SHA2_256Constants>::SHA2(const char *, unsigned);
52 template SHA2<SHA2_512Constants>::SHA2(const char *, unsigned);
53
54 template<typename C>
55 SHA2<C>::SHA2(const string &str)
56 {
57         init();
58         BlockHash<Constants::BLOCK_SIZE>::update(str);
59 }
60 template SHA2<SHA2_256Constants>::SHA2(const string &);
61 template SHA2<SHA2_512Constants>::SHA2(const string &);
62
63 template<typename C>
64 void SHA2<C>::init()
65 {
66         copy(Constants::initial, Constants::initial+8, buffer);
67         processed_bytes = 0;
68 }
69 template void SHA2<SHA2_256Constants>::init();
70 template void SHA2<SHA2_512Constants>::init();
71
72 template<typename C>
73 void SHA2<C>::process_block(const char *data)
74 {
75         WordType message_blocks[Constants::N_ROUNDS];
76         for(unsigned i=0; i<Constants::BLOCK_SIZE/Constants::WORD_SIZE; ++i)
77                 message_blocks[i] = read_word<WordType>(data+i*Constants::WORD_SIZE);
78         const unsigned *const sigma = Constants::sigma_constants;
79         for(unsigned i=16; i<Constants::N_ROUNDS; ++i)
80         {
81                 WordType *block = message_blocks+i;
82                 WordType s1 = (rotate_right(block[-2], sigma[9]) ^ rotate_right(block[-2], sigma[10]) ^ (block[-2]>>sigma[11]));
83                 WordType s0 = (rotate_right(block[-15], sigma[6]) ^ rotate_right(block[-15], sigma[7]) ^ (block[-15]>>sigma[8]));
84                 *block =  s1+block[-7]+s0+block[-16];
85         }
86
87         WordType values[8];
88         copy(buffer, buffer+8, values);
89
90         for(unsigned i=0; i<Constants::N_ROUNDS; ++i)
91         {
92                 WordType s1 = (rotate_right(values[4], sigma[3]) ^ rotate_right(values[4], sigma[4]) ^ rotate_right(values[4], sigma[5]));
93                 WordType ch = ((values[4]&values[5]) ^ (~values[4]&values[6]));
94                 WordType temp1 = values[7]+s1+ch+Constants::round_constants[i]+message_blocks[i];
95                 WordType s0 = (rotate_right(values[0], sigma[0]) ^ rotate_right(values[0], sigma[1]) ^ rotate_right(values[0], sigma[2]));
96                 WordType maj = ((values[0]&values[1]) ^ (values[0]&values[2]) ^ (values[1]&values[2]));
97                 WordType temp2 = s0+maj;
98                 values[7] = values[6];
99                 values[6] = values[5];
100                 values[5] = values[4];
101                 values[4] = values[3]+temp1;
102                 values[3] = values[2];
103                 values[2] = values[1];
104                 values[1] = values[0];
105                 values[0] = temp1+temp2;
106         }
107
108         for(unsigned i=0; i<8; ++i)
109                 buffer[i] += values[i];
110
111         processed_bytes += Constants::BLOCK_SIZE;
112 }
113 template void SHA2<SHA2_256Constants>::process_block(const char *);
114 template void SHA2<SHA2_512Constants>::process_block(const char *);
115
116 template<typename C>
117 unsigned SHA2<C>::get_digest(char *digest, unsigned len) const
118 {
119         if(len<Constants::DIGEST_SIZE)
120                 throw invalid_argument("SHA2::get_digest");
121
122         SHA2<Constants> padded = *this;
123
124         char padding[Constants::BLOCK_SIZE] = { static_cast<char>(0x80) };
125         padded.update(padding, Constants::BLOCK_SIZE-(this->unprocessed_bytes+Constants::MIN_PADDING)%Constants::BLOCK_SIZE);
126
127         padded.update(padding+1, Constants::MIN_PADDING-8);
128         UInt64 message_length = (processed_bytes+this->unprocessed_bytes)*8;
129         write_word(message_length, padding);
130         padded.update(padding, 8);
131
132         for(unsigned i=0; i<8; ++i)
133                 write_word(padded.buffer[i], digest+i*Constants::WORD_SIZE);
134
135         return Constants::DIGEST_SIZE;
136 }
137 template unsigned SHA2<SHA2_256Constants>::get_digest(char *, unsigned) const;
138 template unsigned SHA2<SHA2_512Constants>::get_digest(char *, unsigned) const;
139
140
141 const SHA2_256Constants::WordType SHA2_256Constants::initial[8] =
142 {
143         0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
144 };
145
146 const SHA2_256Constants::WordType SHA2_256Constants::round_constants[SHA2_256Constants::N_ROUNDS] =
147 {
148         0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
149         0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
150         0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
151         0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
152         0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
153         0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
154         0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
155         0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
156 };
157
158 const unsigned SHA2_256Constants::sigma_constants[12] =
159 {
160         2, 13, 22,  // For Σ₀
161         6, 11, 25,  // For Σ₁
162         7, 18, 3,   // For σ₀
163         17, 19, 10  // For σ₁
164 };
165
166 const SHA2_512Constants::WordType SHA2_512Constants::initial[8] =
167 {
168         0x6A09E667F3BCC908, 0xBB67AE8584CAA73B, 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1,
169         0x510E527FADE682D1, 0x9B05688C2B3E6C1F, 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179,
170 };
171
172 const SHA2_512Constants::WordType SHA2_512Constants::round_constants[SHA2_512Constants::N_ROUNDS] =
173 {
174         0x428A2F98D728AE22, 0x7137449123EF65CD, 0xB5C0FBCFEC4D3B2F, 0xE9B5DBA58189DBBC,
175         0x3956C25BF348B538, 0x59F111F1B605D019, 0x923F82A4AF194F9B, 0xAB1C5ED5DA6D8118,
176         0xD807AA98A3030242, 0x12835B0145706FBE, 0x243185BE4EE4B28C, 0x550C7DC3D5FFB4E2,
177         0x72BE5D74F27B896F, 0x80DEB1FE3B1696B1, 0x9BDC06A725C71235, 0xC19BF174CF692694,
178         0xE49B69C19EF14AD2, 0xEFBE4786384F25E3, 0x0FC19DC68B8CD5B5, 0x240CA1CC77AC9C65,
179         0x2DE92C6F592B0275, 0x4A7484AA6EA6E483, 0x5CB0A9DCBD41FBD4, 0x76F988DA831153B5,
180         0x983E5152EE66DFAB, 0xA831C66D2DB43210, 0xB00327C898FB213F, 0xBF597FC7BEEF0EE4,
181         0xC6E00BF33DA88FC2, 0xD5A79147930AA725, 0x06CA6351E003826F, 0x142929670A0E6E70,
182         0x27B70A8546D22FFC, 0x2E1B21385C26C926, 0x4D2C6DFC5AC42AED, 0x53380D139D95B3DF,
183         0x650A73548BAF63DE, 0x766A0ABB3C77B2A8, 0x81C2C92E47EDAEE6, 0x92722C851482353B,
184         0xA2BFE8A14CF10364, 0xA81A664BBC423001, 0xC24B8B70D0F89791, 0xC76C51A30654BE30,
185         0xD192E819D6EF5218, 0xD69906245565A910, 0xF40E35855771202A, 0x106AA07032BBD1B8,
186         0x19A4C116B8D2D0C8, 0x1E376C085141AB53, 0x2748774CDF8EEB99, 0x34B0BCB5E19B48A8,
187         0x391C0CB3C5C95A63, 0x4ED8AA4AE3418ACB, 0x5B9CCA4F7763E373, 0x682E6FF3D6B2B8A3,
188         0x748F82EE5DEFB2FC, 0x78A5636F43172F60, 0x84C87814A1F0AB72, 0x8CC702081A6439EC,
189         0x90BEFFFA23631E28, 0xA4506CEBDE82BDE9, 0xBEF9A3F7B2C67915, 0xC67178F2E372532B,
190         0xCA273ECEEA26619C, 0xD186B8C721C0C207, 0xEADA7DD6CDE0EB1E, 0xF57D4F7FEE6ED178,
191         0x06F067AA72176FBA, 0x0A637DC5A2C898A6, 0x113F9804BEF90DAE, 0x1B710B35131C471B,
192         0x28DB77F523047D84, 0x32CAAB7B40C72493, 0x3C9EBE0A15C9BEBC, 0x431D67C49C100D4C,
193         0x4CC5D4BECB3E42B6, 0x597F299CFC657E2A, 0x5FCB6FAB3AD6FAEC, 0x6C44198C4A475817
194 };
195 const unsigned SHA2_512Constants::sigma_constants[12] =
196 {
197         28, 34, 39,  // For Σ₀
198         14, 18, 41,  // For Σ₁
199         1, 8, 7,     // For σ₀
200         19, 61, 6    // For σ₁
201 };
202
203 } // namespace Crypto
204 } // namespace Msp