Avoid shuffling the data around in memory so much
[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<SHA256Constants>::SHA2();
43 template SHA2<SHA512Constants>::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<SHA256Constants>::SHA2(const char *, unsigned);
52 template SHA2<SHA512Constants>::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<SHA256Constants>::SHA2(const string &);
61 template SHA2<SHA512Constants>::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<SHA256Constants>::init();
70 template void SHA2<SHA512Constants>::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                 const WordType &a = values[(88-i)&7];
93                 const WordType &b = values[(89-i)&7];
94                 const WordType &c = values[(90-i)&7];
95                 WordType &d = values[(91-i)&7];
96                 const WordType &e = values[(92-i)&7];
97                 const WordType &f = values[(93-i)&7];
98                 const WordType &g = values[(94-i)&7];
99                 WordType &h = values[(95-i)&7];
100
101                 WordType s1 = rotate_right(e, sigma[3]) ^ rotate_right(e, sigma[4]) ^ rotate_right(e, sigma[5]);
102                 WordType ch = (e&f) ^ (~e&g);
103                 WordType temp1 = h+s1+ch+Constants::round_constants[i]+message_blocks[i];
104                 WordType s0 = rotate_right(a, sigma[0]) ^ rotate_right(a, sigma[1]) ^ rotate_right(a, sigma[2]);
105                 WordType maj = (a&b) ^ (a&c) ^ (b&c);
106                 WordType temp2 = s0+maj;
107
108                 d += temp1;       // Will be e next round
109                 h = temp1+temp2;  // Will be a next round
110         }
111
112         for(unsigned i=0; i<8; ++i)
113                 buffer[i] += values[i];
114
115         processed_bytes += Constants::BLOCK_SIZE;
116 }
117 template void SHA2<SHA256Constants>::process_block(const char *);
118 template void SHA2<SHA512Constants>::process_block(const char *);
119
120 template<typename C>
121 unsigned SHA2<C>::get_digest(char *digest, unsigned len) const
122 {
123         if(len<Constants::DIGEST_SIZE)
124                 throw invalid_argument("SHA2::get_digest");
125
126         SHA2<Constants> padded = *this;
127
128         char padding[Constants::BLOCK_SIZE] = { static_cast<char>(0x80) };
129         padded.update(padding, Constants::BLOCK_SIZE-(this->unprocessed_bytes+Constants::MIN_PADDING)%Constants::BLOCK_SIZE);
130
131         padded.update(padding+1, Constants::MIN_PADDING-8);
132         UInt64 message_length = (processed_bytes+this->unprocessed_bytes)*8;
133         write_word(message_length, padding);
134         padded.update(padding, 8);
135
136         for(unsigned i=0; i<8; ++i)
137                 write_word(padded.buffer[i], digest+i*Constants::WORD_SIZE);
138
139         return Constants::DIGEST_SIZE;
140 }
141 template unsigned SHA2<SHA256Constants>::get_digest(char *, unsigned) const;
142 template unsigned SHA2<SHA512Constants>::get_digest(char *, unsigned) const;
143
144
145 const SHA256Constants::WordType SHA256Constants::initial[8] =
146 {
147         0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
148 };
149
150 const SHA256Constants::WordType SHA256Constants::round_constants[SHA256Constants::N_ROUNDS] =
151 {
152         0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
153         0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
154         0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
155         0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
156         0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
157         0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
158         0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
159         0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
160 };
161
162 const unsigned SHA256Constants::sigma_constants[12] =
163 {
164         2, 13, 22,  // For Σ₀
165         6, 11, 25,  // For Σ₁
166         7, 18, 3,   // For σ₀
167         17, 19, 10  // For σ₁
168 };
169
170 const SHA512Constants::WordType SHA512Constants::initial[8] =
171 {
172         0x6A09E667F3BCC908, 0xBB67AE8584CAA73B, 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1,
173         0x510E527FADE682D1, 0x9B05688C2B3E6C1F, 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179,
174 };
175
176 const SHA512Constants::WordType SHA512Constants::round_constants[SHA512Constants::N_ROUNDS] =
177 {
178         0x428A2F98D728AE22, 0x7137449123EF65CD, 0xB5C0FBCFEC4D3B2F, 0xE9B5DBA58189DBBC,
179         0x3956C25BF348B538, 0x59F111F1B605D019, 0x923F82A4AF194F9B, 0xAB1C5ED5DA6D8118,
180         0xD807AA98A3030242, 0x12835B0145706FBE, 0x243185BE4EE4B28C, 0x550C7DC3D5FFB4E2,
181         0x72BE5D74F27B896F, 0x80DEB1FE3B1696B1, 0x9BDC06A725C71235, 0xC19BF174CF692694,
182         0xE49B69C19EF14AD2, 0xEFBE4786384F25E3, 0x0FC19DC68B8CD5B5, 0x240CA1CC77AC9C65,
183         0x2DE92C6F592B0275, 0x4A7484AA6EA6E483, 0x5CB0A9DCBD41FBD4, 0x76F988DA831153B5,
184         0x983E5152EE66DFAB, 0xA831C66D2DB43210, 0xB00327C898FB213F, 0xBF597FC7BEEF0EE4,
185         0xC6E00BF33DA88FC2, 0xD5A79147930AA725, 0x06CA6351E003826F, 0x142929670A0E6E70,
186         0x27B70A8546D22FFC, 0x2E1B21385C26C926, 0x4D2C6DFC5AC42AED, 0x53380D139D95B3DF,
187         0x650A73548BAF63DE, 0x766A0ABB3C77B2A8, 0x81C2C92E47EDAEE6, 0x92722C851482353B,
188         0xA2BFE8A14CF10364, 0xA81A664BBC423001, 0xC24B8B70D0F89791, 0xC76C51A30654BE30,
189         0xD192E819D6EF5218, 0xD69906245565A910, 0xF40E35855771202A, 0x106AA07032BBD1B8,
190         0x19A4C116B8D2D0C8, 0x1E376C085141AB53, 0x2748774CDF8EEB99, 0x34B0BCB5E19B48A8,
191         0x391C0CB3C5C95A63, 0x4ED8AA4AE3418ACB, 0x5B9CCA4F7763E373, 0x682E6FF3D6B2B8A3,
192         0x748F82EE5DEFB2FC, 0x78A5636F43172F60, 0x84C87814A1F0AB72, 0x8CC702081A6439EC,
193         0x90BEFFFA23631E28, 0xA4506CEBDE82BDE9, 0xBEF9A3F7B2C67915, 0xC67178F2E372532B,
194         0xCA273ECEEA26619C, 0xD186B8C721C0C207, 0xEADA7DD6CDE0EB1E, 0xF57D4F7FEE6ED178,
195         0x06F067AA72176FBA, 0x0A637DC5A2C898A6, 0x113F9804BEF90DAE, 0x1B710B35131C471B,
196         0x28DB77F523047D84, 0x32CAAB7B40C72493, 0x3C9EBE0A15C9BEBC, 0x431D67C49C100D4C,
197         0x4CC5D4BECB3E42B6, 0x597F299CFC657E2A, 0x5FCB6FAB3AD6FAEC, 0x6C44198C4A475817
198 };
199 const unsigned SHA512Constants::sigma_constants[12] =
200 {
201         28, 34, 39,  // For Σ₀
202         14, 18, 41,  // For Σ₁
203         1, 8, 7,     // For σ₀
204         19, 61, 6    // For σ₁
205 };
206
207 } // namespace Crypto
208 } // namespace Msp