Skip to content

Commit 4929dac

Browse files
committed
Add files
1 parent 294b5e3 commit 4929dac

File tree

5 files changed

+619
-1
lines changed

5 files changed

+619
-1
lines changed

CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
cmake_minimum_required(VERSION 3.2)
2+
project(cpp-sha256-hmac)
3+
4+
set(CMAKE_CXX_STANDARD 17)
5+
6+
add_library(cpp-sha256-hmac cpp-sha256-hmac.cpp cpp-sha256-hmac.hpp)
7+
add_executable(cpp-sha256-hmac_test test.cpp)
8+
target_link_libraries(cpp-sha256-hmac_test cpp-sha256-hmac)

README.md

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,49 @@
1-
# cpp-sha256-hmac
1+
# cpp-sha256-hmac
2+
C++ library for SHA256 & SHA256-HMAC calculation.
3+
4+
## Usage
5+
```cpp
6+
#include "cpp-sha256-hmac.hpp"
7+
8+
using namespace YukiWorkshop::Crypto;
9+
```
10+
11+
```cpp
12+
SHA256 s;
13+
s.update("0123456789");
14+
15+
std::vector<uint8_t> r0 = s.finalize();
16+
17+
for (auto &it : r0) {
18+
printf("%02x", it);
19+
}
20+
```
21+
22+
```cpp
23+
SHA256 s2;
24+
s2 << "abcdefghij";
25+
26+
std::vector<uint8_t> r1;
27+
s2 >> r1;
28+
29+
for (auto &it : r1) {
30+
printf("%02x", it);
31+
}
32+
```
33+
34+
```cpp
35+
uint8_t k[] = "some secret key, don't use human readable password";
36+
SHA256_HMAC sh(k, sizeof(k));
37+
s.update("0123456789");
38+
std::vector<uint8_t> r2 = sh.finalize();
39+
40+
for (auto &it : r2) {
41+
printf("%02x", it);
42+
}
43+
```
44+
45+
## License
46+
MIT
47+
48+
## Acknowledgements
49+
This library makes use of [jb55/sha256.c](https://github.com/jb55/sha256.c) and [aperezdc/hmac-sha256](https://github.com/aperezdc/hmac-sha256).

cpp-sha256-hmac.cpp

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
/*
2+
This file is part of cpp-sha256-hmac.
3+
Copyright (C) 2020 ReimuNotMoe
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the MIT License.
7+
8+
This program is distributed in the hope that it will be useful,
9+
but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11+
12+
Algorithm credits: https://github.com/jb55/sha256.c
13+
https://github.com/aperezdc/hmac-sha256
14+
15+
*/
16+
17+
#include "cpp-sha256-hmac.hpp"
18+
19+
#define _SHA256_UNROLL
20+
#define _SHA256_UNROLL2
21+
22+
#define U8V(v) ((uint8_t)(v) & 0xFFU)
23+
#define U16V(v) ((uint16_t)(v) & 0xFFFFU)
24+
#define U32V(v) ((uint32_t)(v) & 0xFFFFFFFFU)
25+
#define U64V(v) ((uint64_t)(v) & 0xFFFFFFFFFFFFFFFFU)
26+
27+
#define ROTL32(v, n) \
28+
(U32V((uint32_t)(v) << (n)) | ((uint32_t)(v) >> (32 - (n))))
29+
30+
// tests fail if we don't have this cast...
31+
#define ROTL64(v, n) \
32+
(U64V((uint64_t)(v) << (n)) | ((uint64_t)(v) >> (64 - (n))))
33+
34+
#define ROTR32(v, n) ROTL32(v, 32 - (n))
35+
#define ROTR64(v, n) ROTL64(v, 64 - (n))
36+
37+
38+
#define S0(x) (ROTR32(x, 2) ^ ROTR32(x,13) ^ ROTR32(x, 22))
39+
#define S1(x) (ROTR32(x, 6) ^ ROTR32(x,11) ^ ROTR32(x, 25))
40+
#define s0(x) (ROTR32(x, 7) ^ ROTR32(x,18) ^ (x >> 3))
41+
#define s1(x) (ROTR32(x,17) ^ ROTR32(x,19) ^ (x >> 10))
42+
43+
#define blk0(i) (W[i] = data[i])
44+
#define blk2(i) (W[i&15] += s1(W[(i-2)&15]) + W[(i-7)&15] + s0(W[(i-15)&15]))
45+
46+
#define Ch(x,y,z) (z^(x&(y^z)))
47+
#define Maj(x,y,z) ((x&y)|(z&(x|y)))
48+
49+
#define a(i) T[(0-(i))&7]
50+
#define b(i) T[(1-(i))&7]
51+
#define c(i) T[(2-(i))&7]
52+
#define d(i) T[(3-(i))&7]
53+
#define e(i) T[(4-(i))&7]
54+
#define f(i) T[(5-(i))&7]
55+
#define g(i) T[(6-(i))&7]
56+
#define h(i) T[(7-(i))&7]
57+
58+
59+
#ifdef _SHA256_UNROLL2
60+
61+
#define R(a,b,c,d,e,f,g,h, i) h += S1(e) + Ch(e,f,g) + K[i+j] + (j?blk2(i):blk0(i));\
62+
d += h; h += S0(a) + Maj(a, b, c)
63+
64+
#define RX_8(i) \
65+
R(a,b,c,d,e,f,g,h, i); \
66+
R(h,a,b,c,d,e,f,g, (i+1)); \
67+
R(g,h,a,b,c,d,e,f, (i+2)); \
68+
R(f,g,h,a,b,c,d,e, (i+3)); \
69+
R(e,f,g,h,a,b,c,d, (i+4)); \
70+
R(d,e,f,g,h,a,b,c, (i+5)); \
71+
R(c,d,e,f,g,h,a,b, (i+6)); \
72+
R(b,c,d,e,f,g,h,a, (i+7))
73+
74+
#else
75+
76+
#define R(i) h(i) += S1(e(i)) + Ch(e(i),f(i),g(i)) + K[i+j] + (j?blk2(i):blk0(i));\
77+
d(i) += h(i); h(i) += S0(a(i)) + Maj(a(i), b(i), c(i))
78+
79+
#ifdef _SHA256_UNROLL
80+
81+
#define RX_8(i) R(i+0); R(i+1); R(i+2); R(i+3); R(i+4); R(i+5); R(i+6); R(i+7);
82+
83+
#endif
84+
85+
#endif
86+
87+
static const uint32_t K[64] = {
88+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
89+
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
90+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
91+
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
92+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
93+
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
94+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
95+
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
96+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
97+
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
98+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
99+
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
100+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
101+
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
102+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
103+
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
104+
};
105+
106+
static void sha256_transform(uint32_t *state, const uint32_t *data) {
107+
uint32_t W[16];
108+
unsigned j;
109+
#ifdef _SHA256_UNROLL2
110+
uint32_t a,b,c,d,e,f,g,h;
111+
a = state[0];
112+
b = state[1];
113+
c = state[2];
114+
d = state[3];
115+
e = state[4];
116+
f = state[5];
117+
g = state[6];
118+
h = state[7];
119+
#else
120+
uint32_t T[8];
121+
for (j = 0; j < 8; j++)
122+
T[j] = state[j];
123+
#endif
124+
125+
for (j = 0; j < 64; j += 16)
126+
{
127+
#if defined(_SHA256_UNROLL) || defined(_SHA256_UNROLL2)
128+
RX_8(0); RX_8(8);
129+
#else
130+
unsigned i;
131+
for (i = 0; i < 16; i++) { R(i); }
132+
#endif
133+
}
134+
135+
#ifdef _SHA256_UNROLL2
136+
state[0] += a;
137+
state[1] += b;
138+
state[2] += c;
139+
state[3] += d;
140+
state[4] += e;
141+
state[5] += f;
142+
state[6] += g;
143+
state[7] += h;
144+
#else
145+
for (j = 0; j < 8; j++)
146+
state[j] += T[j];
147+
#endif
148+
149+
/* Wipe variables */
150+
/* memset(W, 0, sizeof(W)); */
151+
/* memset(T, 0, sizeof(T)); */
152+
}
153+
154+
#undef S0
155+
#undef S1
156+
#undef s0
157+
#undef s1
158+
159+
using namespace YukiWorkshop::Crypto;
160+
161+
void SHA256::sha256_write_byte_block() {
162+
uint32_t data32[16];
163+
unsigned i;
164+
for (i = 0; i < 16; i++)
165+
data32[i] =
166+
((uint32_t)(buffer[i * 4 ]) << 24) +
167+
((uint32_t)(buffer[i * 4 + 1]) << 16) +
168+
((uint32_t)(buffer[i * 4 + 2]) << 8) +
169+
((uint32_t)(buffer[i * 4 + 3]));
170+
sha256_transform(state, data32);
171+
}
172+
173+
void SHA256::reset() noexcept {
174+
state[0] = 0x6a09e667;
175+
state[1] = 0xbb67ae85;
176+
state[2] = 0x3c6ef372;
177+
state[3] = 0xa54ff53a;
178+
state[4] = 0x510e527f;
179+
state[5] = 0x9b05688c;
180+
state[6] = 0x1f83d9ab;
181+
state[7] = 0x5be0cd19;
182+
count = 0;
183+
}
184+
185+
void SHA256::__update(SHA256 *p, const void *__data, size_t __len) noexcept {
186+
auto *data = (uint8_t *)__data;
187+
188+
uint32_t curBufferPos = (uint32_t)p->count & 0x3F;
189+
while (__len > 0)
190+
{
191+
p->buffer[curBufferPos++] = *data++;
192+
p->count++;
193+
__len--;
194+
if (curBufferPos == 64)
195+
{
196+
curBufferPos = 0;
197+
p->sha256_write_byte_block();
198+
}
199+
}
200+
}
201+
202+
203+
void SHA256::__finalize(SHA256 *p, void *__digest) noexcept {
204+
auto *digest = (uint8_t *)__digest;
205+
uint64_t lenInBits = (p->count << 3);
206+
uint32_t curBufferPos = (uint32_t)p->count & 0x3F;
207+
unsigned i;
208+
p->buffer[curBufferPos++] = 0x80;
209+
while (curBufferPos != (64 - 8)) {
210+
curBufferPos &= 0x3F;
211+
if (curBufferPos == 0)
212+
p->sha256_write_byte_block();
213+
p->buffer[curBufferPos++] = 0;
214+
}
215+
for (i = 0; i < 8; i++) {
216+
p->buffer[curBufferPos++] = (unsigned char)(lenInBits >> 56);
217+
lenInBits <<= 8;
218+
}
219+
p->sha256_write_byte_block();
220+
221+
for (i = 0; i < 8; i++) {
222+
*digest++ = (unsigned char)(p->state[i] >> 24);
223+
*digest++ = (unsigned char)(p->state[i] >> 16);
224+
*digest++ = (unsigned char)(p->state[i] >> 8);
225+
*digest++ = (unsigned char)(p->state[i]);
226+
}
227+
228+
p->reset();
229+
}
230+
231+
void SHA256::update(const void *__data, size_t __len) noexcept {
232+
__update(this, __data, __len);
233+
}
234+
235+
void SHA256::finalize(void *__digest) noexcept {
236+
__finalize(this, __digest);
237+
}
238+
239+
/*
240+
* HMAC(H, K) == H(K ^ opad, H(K ^ ipad, text))
241+
*
242+
* H: Hash function (sha256)
243+
* K: Secret key
244+
* B: Block byte length
245+
* L: Byte length of hash function output
246+
*
247+
* https://tools.ietf.org/html/rfc2104
248+
*/
249+
250+
#define SHA256_DIGEST_SIZE 32
251+
#define B 64
252+
#define L (SHA256_DIGEST_SIZE)
253+
#define K (SHA256_DIGEST_SIZE * 2)
254+
255+
#define I_PAD 0x36
256+
#define O_PAD 0x5C
257+
258+
void SHA256_HMAC::set_key(const void *__data, size_t __len) {
259+
260+
/*
261+
* If the key length is bigger than the buffer size B, apply the hash
262+
* function to it first and use the result instead.
263+
*/
264+
265+
if (__len > B) {
266+
__update(this, __data, __len);
267+
key_buf.resize(SHA256_DIGEST_SIZE);
268+
__finalize(this, key_buf.data());
269+
} else {
270+
key_buf.insert(key_buf.begin(), (uint8_t *)__data, ((uint8_t *)__data)+__len);
271+
}
272+
273+
/*
274+
* (1) append zeros to the end of K to create a B byte string
275+
* (e.g., if K is of length 20 bytes and B=64, then K will be
276+
* appended with 44 zero bytes 0x00)
277+
* (2) XOR (bitwise exclusive-OR) the B byte string computed in step
278+
* (1) with ipad
279+
*/
280+
for (size_t i = 0; i < key_buf.size(); i++) kx[i] = I_PAD ^ key_buf[i];
281+
for (size_t i = key_buf.size(); i < B; i++) kx[i] = I_PAD ^ 0;
282+
283+
/*
284+
* (3) append the stream of data 'text' to the B byte string resulting
285+
* from step (2)
286+
* (4) apply H to the stream generated in step (3)
287+
*/
288+
__update(this, kx, B);
289+
}
290+
291+
void SHA256_HMAC::__hmac_finalize(SHA256_HMAC *p, void *__digest) noexcept {
292+
__finalize(p, __digest);
293+
/*
294+
* (5) XOR (bitwise exclusive-OR) the B byte string computed in
295+
* step (1) with opad
296+
*
297+
* NOTE: The "kx" variable is reused.
298+
*/
299+
for (size_t i = 0; i < p->key_buf.size(); i++) p->kx[i] = O_PAD ^ p->key_buf[i];
300+
for (size_t i = p->key_buf.size(); i < B; i++) p->kx[i] = O_PAD ^ 0;
301+
302+
/*
303+
* (6) append the H result from step (4) to the B byte string
304+
* resulting from step (5)
305+
* (7) apply H to the stream generated in step (6) and output
306+
* the result
307+
*/
308+
309+
__update(p, p->kx, B);
310+
__update(p, __digest, SHA256_DIGEST_SIZE);
311+
__finalize(p, __digest);
312+
}

0 commit comments

Comments
 (0)