-
Notifications
You must be signed in to change notification settings - Fork 0
/
sha1.cpp
158 lines (130 loc) · 3.79 KB
/
sha1.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include <cmath>
#include <bitset>
#include <vector>
#include <string>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <iostream>
std::string fileContents(const std::string& path) {
std::ifstream in(path);
std::stringstream buffer;
if (not in.fail()) {
buffer << in.rdbuf();
}
return buffer.str();
}
#define BYTE_ROTATE_LEFT32(value, bits) (((value) << (bits)) | (((value) & 0xffffffff) >> (32 - (bits))))
using var = uint32_t;
using var64 = uint64_t;
// CHUNK_BYTES = WORDS_BYTES * WORDS_NUMS
constexpr unsigned int CHUNK_BYTES = 64; // 512 bit
constexpr unsigned int WORDS_BYTES = 4; // 32 bit
constexpr unsigned int WORDS_NUMS = 16;
constexpr unsigned int DIGEST_NUMS = 5;
std::string m;
var64 ml;
void padding() {
// Step1
// m에 padding을 추가하기 전 length (bit size)
ml = m.size()*8;
// message에 '1' 비트 1개 추가 (실제론 0b10000000 추가)
// 이 다음 과정에서 m + ml이 64bytes(512bit)로 나누어 떨어지도록
// '0'비트를 계속 추가하기 때문에 미리 byte 단위로 추가 함.
m += (char)0x80;
while (m.size() % CHUNK_BYTES != CHUNK_BYTES - sizeof(ml)) {
m += (char)0x00;
}
for (int i=7; i>=0; i--) {
char byte = (ml >> 8*i) & 0xff;
m += byte;
}
// 이제 m은 64bytes(512bit) 즉 CHUNK_BYTES로 나누어 떨어진다.
}
std::vector<var> chunkToWords(const std::string& chunk) {
std::vector<var> words(WORDS_NUMS);
// Step2
for (unsigned int i = 0; i < WORDS_NUMS; i++) {
words[i] = (chunk[4*i+3] & 0xff)
| (chunk[4*i+2] & 0xff)<<8
| (chunk[4*i+1] & 0xff)<<16
| (chunk[4*i+0] & 0xff)<<24;
}
return words;
}
var h[DIGEST_NUMS] = {
0x67452301,
0xEFCDAB89,
0x98BADCFE,
0x10325476,
0xC3D2E1F0,
};
void processChunck(unsigned int index) {
std::string chunk = m.substr(index * CHUNK_BYTES, CHUNK_BYTES);
std::vector<var> w = chunkToWords(chunk);
// Step3
// Extend the sixteen 32-bit words into eighty 32-bit words:
for (unsigned int i = 16; i <= 79; i++) {
var word = w[i-3] xor w[i-8] xor w[i-14] xor w[i-16];
word = BYTE_ROTATE_LEFT32(word, 1);
w.push_back(word);
}
// Initialize hash value for this chunk:
var a = h[0];
var b = h[1];
var c = h[2];
var d = h[3];
var e = h[4];
var f, k;
// Step4
// Main loop:
for (unsigned int i = 0; i <= 79; i++) {
if (0 <= i && i <= 19) {
f = (b bitand c) bitor (~b bitand d);
k = 0x5A827999;
}
else if (20 <= i && i <= 39) {
f = b xor c xor d;
k = 0x6ED9EBA1;
}
else if (40 <= i && i <= 59) {
f = (b bitand c) bitor (b bitand d) bitor (c bitand d);
k = 0x8F1BBCDC;
}
else if (60 <= i && i <= 79) {
f = b xor c xor d;
k = 0xCA62C1D6;
}
var temp = BYTE_ROTATE_LEFT32(a, 5) + f + e + k + w[i];
e = d;
d = c;
c = BYTE_ROTATE_LEFT32(b, 30);
b = a;
a = temp;
}
// Add this chunk's hash to result so far:
h[0] = h[0] + a;
h[1] = h[1] + b;
h[2] = h[2] + c;
h[3] = h[3] + d;
h[4] = h[4] + e;
}
int main(int argc, char* argv[]) {
if (argc < 2) {
fprintf(stderr, "usage: %s {filename}\n", argv[0]);
return 0;
}
m = fileContents(argv[1]);
padding();
var64 chunkNums = m.size() / CHUNK_BYTES;
for (unsigned int i = 0; i < chunkNums; i++) {
processChunck(i);
}
// Hex std::string
std::ostringstream hh;
for (unsigned int i = 0; i < DIGEST_NUMS; i++) {
hh << std::hex << std::setfill('0') << std::setw(8);
hh << h[i];
}
std::cout << hh.str() << std::endl;
}