]> git.tdb.fi Git - libs/crypto.git/blob - source/sha2.cpp
Implement the SHA2 hash family
[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+8)%Constants::BLOCK_SIZE);
126
127         UInt64 message_length = (processed_bytes+this->unprocessed_bytes)*8;
128         write_word(message_length, padding);
129         padded.update(padding, 8);
130
131         for(unsigned i=0; i<8; ++i)
132                 write_word(padded.buffer[i], digest+i*Constants::WORD_SIZE);
133
134         return Constants::DIGEST_SIZE;
135 }
136 template unsigned SHA2<SHA2_256Constants>::get_digest(char *, unsigned) const;
137 template unsigned SHA2<SHA2_512Constants>::get_digest(char *, unsigned) const;
138
139
140 const SHA2_256Constants::WordType SHA2_256Constants::initial[8] =
141 {
142         0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
143 };
144
145 const SHA2_256Constants::WordType SHA2_256Constants::round_constants[SHA2_256Constants::N_ROUNDS] =
146 {
147         0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
148         0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
149         0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
150         0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
151         0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
152         0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
153         0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
154         0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
155 };
156
157 const unsigned SHA2_256Constants::sigma_constants[12] =
158 {
159         2, 13, 22,  // For Σ₀
160         6, 11, 25,  // For Σ₁
161         7, 18, 3,   // For σ₀
162         17, 19, 10  // For σ₁
163 };
164
165 const SHA2_512Constants::WordType SHA2_512Constants::initial[8] =
166 {
167         0x6A09E667F3BCC908, 0xBB67AE8584CAA73B, 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1,
168         0x510E527FADE682D1, 0x9B05688C2B3E6C1F, 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179,
169 };
170
171 const SHA2_512Constants::WordType SHA2_512Constants::round_constants[SHA2_512Constants::N_ROUNDS] =
172 {
173         0x428A2F98D728AE22, 0x7137449123EF65CD, 0xB5C0FBCFEC4D3B2F, 0xE9B5DBA58189DBBC,
174         0x3956C25BF348B538, 0x59F111F1B605D019, 0x923F82A4AF194F9B, 0xAB1C5ED5DA6D8118,
175         0xD807AA98A3030242, 0x12835B0145706FBE, 0x243185BE4EE4B28C, 0x550C7DC3D5FFB4E2,
176         0x72BE5D74F27B896F, 0x80DEB1FE3B1696B1, 0x9BDC06A725C71235, 0xC19BF174CF692694,
177         0xE49B69C19EF14AD2, 0xEFBE4786384F25E3, 0x0FC19DC68B8CD5B5, 0x240CA1CC77AC9C65,
178         0x2DE92C6F592B0275, 0x4A7484AA6EA6E483, 0x5CB0A9DCBD41FBD4, 0x76F988DA831153B5,
179         0x983E5152EE66DFAB, 0xA831C66D2DB43210, 0xB00327C898FB213F, 0xBF597FC7BEEF0EE4,
180         0xC6E00BF33DA88FC2, 0xD5A79147930AA725, 0x06CA6351E003826F, 0x142929670A0E6E70,
181         0x27B70A8546D22FFC, 0x2E1B21385C26C926, 0x4D2C6DFC5AC42AED, 0x53380D139D95B3DF,
182         0x650A73548BAF63DE, 0x766A0ABB3C77B2A8, 0x81C2C92E47EDAEE6, 0x92722C851482353B,
183         0xA2BFE8A14CF10364, 0xA81A664BBC423001, 0xC24B8B70D0F89791, 0xC76C51A30654BE30,
184         0xD192E819D6EF5218, 0xD69906245565A910, 0xF40E35855771202A, 0x106AA07032BBD1B8,
185         0x19A4C116B8D2D0C8, 0x1E376C085141AB53, 0x2748774CDF8EEB99, 0x34B0BCB5E19B48A8,
186         0x391C0CB3C5C95A63, 0x4ED8AA4AE3418ACB, 0x5B9CCA4F7763E373, 0x682E6FF3D6B2B8A3,
187         0x748F82EE5DEFB2FC, 0x78A5636F43172F60, 0x84C87814A1F0AB72, 0x8CC702081A6439EC,
188         0x90BEFFFA23631E28, 0xA4506CEBDE82BDE9, 0xBEF9A3F7B2C67915, 0xC67178F2E372532B,
189         0xCA273ECEEA26619C, 0xD186B8C721C0C207, 0xEADA7DD6CDE0EB1E, 0xF57D4F7FEE6ED178,
190         0x06F067AA72176FBA, 0x0A637DC5A2C898A6, 0x113F9804BEF90DAE, 0x1B710B35131C471B,
191         0x28DB77F523047D84, 0x32CAAB7B40C72493, 0x3C9EBE0A15C9BEBC, 0x431D67C49C100D4C,
192         0x4CC5D4BECB3E42B6, 0x597F299CFC657E2A, 0x5FCB6FAB3AD6FAEC, 0x6C44198C4A475817
193 };
194 const unsigned SHA2_512Constants::sigma_constants[12] =
195 {
196         28, 34, 39,  // For Σ₀
197         14, 18, 41,  // For Σ₁
198         1, 8, 7,     // For σ₀
199         19, 61, 6    // For σ₁
200 };
201
202 } // namespace Crypto
203 } // namespace Msp