DotNetDupe 4.0.6
C++17/20 Implementation of the .NET Base Class Library (BCL)
Loading...
Searching...
No Matches
HMACSHA256.cpp
Go to the documentation of this file.
1#include "pch.h"
4#include <cstring>
5
6namespace DotNetDupe {
7 namespace System {
8 namespace Security {
9 namespace Cryptography {
10
11 // --- SHA256 Helper Implementation ---
12 #define SHA2_SHFR(x, n) (x >> n)
13 #define SHA2_ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
14 #define SHA2_CH(x, y, z) ((x & y) ^ (~x & z))
15 #define SHA2_MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
16 #define SHA256_F1(x) (SHA2_ROTR(x, 2) ^ SHA2_ROTR(x, 13) ^ SHA2_ROTR(x, 22))
17 #define SHA256_F2(x) (SHA2_ROTR(x, 6) ^ SHA2_ROTR(x, 11) ^ SHA2_ROTR(x, 25))
18 #define SHA256_F3(x) (SHA2_ROTR(x, 7) ^ SHA2_ROTR(x, 18) ^ SHA2_SHFR(x, 3))
19 #define SHA256_F4(x) (SHA2_ROTR(x, 17) ^ SHA2_ROTR(x, 19) ^ SHA2_SHFR(x, 10))
20
21 #define SHA2_UNPACK32(x, str) \
22 { \
23 *((str) + 3) = (unsigned char) ((x) ); \
24 *((str) + 2) = (unsigned char) ((x) >> 8); \
25 *((str) + 1) = (unsigned char) ((x) >> 16); \
26 *((str) + 0) = (unsigned char) ((x) >> 24); \
27 }
28
29 #define SHA2_PACK32(str, x) \
30 { \
31 *(x) = ((unsigned int) *((str) + 3) ) \
32 | ((unsigned int) *((str) + 2) << 8) \
33 | ((unsigned int) *((str) + 1) << 16) \
34 | ((unsigned int) *((str) + 0) << 24);\
35 }
36
37 static const unsigned int sha256_k[64] = {
38 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
39 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
40 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
41 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
42 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
43 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
44 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
45 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
46 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
47 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
48 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
49 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
50 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
51 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
52 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
53 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
54 };
55
56 class SHA256Impl {
57 public:
58 void Init() {
60 h[0] = 0x6a09e667;
61 h[1] = 0xbb67ae85;
62 h[2] = 0x3c6ef372;
63 h[3] = 0xa54ff53a;
64 h[4] = 0x510e527f;
65 h[5] = 0x9b05688c;
66 h[6] = 0x1f83d9ab;
67 h[7] = 0x5be0cd19;
68 len = 0;
69 tot_len = 0;
70 }
71
72 void Transform(const unsigned char* message, unsigned int block_nb) {
74 unsigned int w[64];
75 unsigned int wv[8];
76 unsigned int t1, t2;
77 const unsigned char* sub_block;
78 for (unsigned int i = 0; i < block_nb; i++) {
79 sub_block = message + (i << 6);
80 for (unsigned int j = 0; j < 16; j++) {
81 SHA2_PACK32(&sub_block[j << 2], &w[j]);
82 }
83 for (unsigned int j = 16; j < 64; j++) {
84 w[j] = SHA256_F4(w[j - 2]) + w[j - 7] + SHA256_F3(w[j - 15]) + w[j - 16];
85 }
86 for (unsigned int j = 0; j < 8; j++) {
87 wv[j] = h[j];
88 }
89 for (unsigned int j = 0; j < 64; j++) {
90 t1 = wv[7] + SHA256_F2(wv[4]) + SHA2_CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j];
91 t2 = SHA256_F1(wv[0]) + SHA2_MAJ(wv[0], wv[1], wv[2]);
92 wv[7] = wv[6];
93 wv[6] = wv[5];
94 wv[5] = wv[4];
95 wv[4] = wv[3] + t1;
96 wv[3] = wv[2];
97 wv[2] = wv[1];
98 wv[1] = wv[0];
99 wv[0] = t1 + t2;
100 }
101 for (unsigned int j = 0; j < 8; j++) {
102 h[j] += wv[j];
103 }
104 }
105 }
106
107 void Update(const unsigned char* message, unsigned int message_len) {
109 unsigned int tmp_len = 64 - len;
110 unsigned int rem_len = message_len < tmp_len ? message_len : tmp_len;
111 std::memcpy(&block[len], message, rem_len);
112 if (len + message_len < 64) {
113 len += message_len;
114 return;
115 }
116 Transform(block, 1);
117 unsigned int block_nb = (message_len - rem_len) >> 6;
118 Transform(message + rem_len, block_nb);
119 rem_len += (block_nb << 6);
120 len = message_len - rem_len;
121 std::memcpy(block, message + rem_len, len);
122 tot_len += (block_nb + 1) << 6;
123 }
124
125 void Final(unsigned char* digest) {
127 unsigned int block_nb = (64 - 9 < len) ? 2 : 1;
128 tot_len += len;
129 std::memset(&block[len], 0, 64 - len);
130 block[len] = 0x80;
131 if (block_nb == 2) {
132 Transform(block, 1);
133 std::memset(block, 0, 64);
134 }
135 SHA2_UNPACK32(tot_len << 3, &block[60]);
136 Transform(block, 1);
137 for (int i = 0; i < 8; i++) {
138 SHA2_UNPACK32(h[i], &digest[i << 2]);
139 }
140 }
141
142 private:
143 unsigned int tot_len;
144 unsigned int len;
145 unsigned char block[64];
146 unsigned int h[8];
147 };
148
149 // --- HMACSHA256 implementation ---
150
153 }
154
155 HMACSHA256::HMACSHA256(const Array<char>& key) : m_key(key) {
157 }
158
161 return ComputeHash(buffer, m_key);
162 }
163
164 static void PrepareHmacPads(const Array<char>& key, unsigned char* k_ipad, unsigned char* k_opad) {
166 unsigned char key_hashed[32];
167 int key_len = key.GetLength();
168 const unsigned char* key_data = reinterpret_cast<const unsigned char*>(key.GetData());
169 if (key_len > 64) {
170 SHA256Impl sha; sha.Init(); sha.Update(key_data, key_len); sha.Final(key_hashed);
171 key_data = key_hashed; key_len = 32;
172 }
173 std::memset(k_ipad, 0, 64); std::memset(k_opad, 0, 64);
174 if (key_len > 0) { std::memcpy(k_ipad, key_data, key_len); std::memcpy(k_opad, key_data, key_len); }
175 for (int i = 0; i < 64; i++) { k_ipad[i] ^= 0x36; k_opad[i] ^= 0x5c; }
176 }
177
178 static void ComputeHmacDigests(const unsigned char* k_ipad, const unsigned char* k_opad, const Array<char>& buffer, unsigned char* outer_digest) {
180 unsigned char inner_digest[32];
181 SHA256Impl sha_inner; sha_inner.Init(); sha_inner.Update(k_ipad, 64);
182 if (buffer.GetLength() > 0) sha_inner.Update(reinterpret_cast<const unsigned char*>(buffer.GetData()), buffer.GetLength());
183 sha_inner.Final(inner_digest);
184
185 SHA256Impl sha_outer; sha_outer.Init(); sha_outer.Update(k_opad, 64); sha_outer.Update(inner_digest, 32);
186 sha_outer.Final(outer_digest);
187 }
188
191 unsigned char k_ipad[64], k_opad[64], outer_digest[32];
192 PrepareHmacPads(key, k_ipad, k_opad);
193 ComputeHmacDigests(k_ipad, k_opad, buffer, outer_digest);
194 Array<char> result(32);
195 for (int i = 0; i < 32; i++) result[i] = static_cast<char>(outer_digest[i]);
196 return result;
197 }
198
199 }
200 }
201 }
202}
Defines the exception thrown when a null reference is passed to a method that does not accept it.
#define SHA256_F1(x)
#define SHA2_CH(x, y, z)
#define SHA2_UNPACK32(x, str)
#define SHA2_PACK32(str, x)
#define SHA256_F3(x)
#define SHA2_MAJ(x, y, z)
#define SHA256_F2(x)
#define SHA256_F4(x)
Hash-based Message Authentication Code using SHA-256 per RFC 2104.
Provides methods for creating, manipulating, searching, and sorting arrays, thereby serving as the ba...
Definition Array.h:29
int GetLength() const
Gets the total number of elements in all dimensions of the Array.
Definition Array.h:142
T * GetData()
Gets a pointer to the contiguous internal element buffer.
Definition Array.h:146
HMACSHA256()
Initializes a new instance of the HMACSHA256 class with a randomly generated key.
Array< char > ComputeHash(const Array< char > &buffer)
Computes the HMAC hash value for the specified byte array.
static const unsigned int sha256_k[64]
static void PrepareHmacPads(const Array< char > &key, unsigned char *k_ipad, unsigned char *k_opad)
static void ComputeHmacDigests(const unsigned char *k_ipad, const unsigned char *k_opad, const Array< char > &buffer, unsigned char *outer_digest)