├── README.md ├── md2-constants ├── README.md ├── md2-constants.c └── md2-constants.py ├── md2 ├── Makefile ├── README.md ├── md2.c ├── md2.h ├── md2test.c ├── rfc1319-The_MD2_Message-Digest_Algorithmpdf.pdf ├── utils.c └── utils.h ├── md4 ├── Makefile ├── TAOCP-Vol.2-2nd_Edition-Table_2-p660.png ├── md4.c ├── md4.h ├── md4test.c ├── utils.c └── utils.h ├── md5 ├── Fast_Collision_Attach_on_MD5-2013.pdf ├── Makefile ├── md5.c ├── md5.h ├── md5test.c ├── utils.c └── utils.h ├── sha1 ├── Makefile ├── sha1.c ├── sha1.h ├── sha1test.c ├── utils.c └── utils.h ├── sha256 ├── Makefile ├── sha256.c ├── sha256.h ├── sha256test.c ├── utils.c └── utils.h ├── sha3 ├── Makefile ├── sha3.c ├── sha3.h ├── sha3test.c ├── utils.c └── utils.h ├── sha512 ├── Makefile ├── sha512.c ├── sha512.h ├── sha512test.c ├── utils.c └── utils.h └── sm3 ├── Makefile ├── sm3.c ├── sm3.h ├── sm3test.c ├── utils.c ├── utils.h └── 国密-SM3密码杂凑算法.pdf /README.md: -------------------------------------------------------------------------------- 1 | # 密码编码学实践 2 | 3 | ## 1. 目录介绍 4 | - [md2-constants](./md2-constants) 5 | - 《MD2中用于随机置换的S盒是如何生成的?》源码 6 | - [md2](./md2) 7 | - 《MD2哈希算法实现(附源码)》源码 8 | - [md4](./md4) 9 | - MD4算法源码 10 | - [md5](./md5) 11 | - MD5算法源码 12 | - [sha1](./sha1) 13 | - SHA1算法源码 14 | - [sha256](./sha256) 15 | - SHA256及SHA224算法源码 16 | - [sha512](./sha512) 17 | - SHA512及SHA384, SHA512-224, SHA512-256, SHA512/t算法源码 18 | - [sm3](./sm3) 19 | - 国密SM3算法源码 20 | 21 | ## 2. 如何使用 22 | 23 | 下载: 24 | ```shell 25 | $ git clone https://github.com/guyongqiangx/cryptography.git 26 | ``` 27 | 28 | 编译, 编译完会自动运行测试。: 29 | ```shell 30 | $ cd cryptography 31 | cryptography$ cd sha1 32 | cryptography/sha1$ 33 | cryptography/sha1$ make 34 | gcc -Wall -g -O2 -c utils.c -o utils.o 35 | gcc -Wall -g -O2 -c sha1.c -o sha1.o 36 | gcc -Wall -g -O2 -c sha1test.c -o sha1test.o 37 | gcc -Wall -g -O2 utils.o sha1.o sha1test.o -o sha1 38 | 39 | Run Test... 40 | ./sha1 -x 41 | Internal hash tests for ./sha1: 42 | ./sha1("") 43 | Expect: da39a3ee5e6b4b0d3255bfef95601890afd80709 44 | Result: da39a3ee5e6b4b0d3255bfef95601890afd80709 45 | 46 | ./sha1("a") 47 | Expect: 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 48 | Result: 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 49 | 50 | ./sha1("abc") 51 | Expect: a9993e364706816aba3e25717850c26c9cd0d89d 52 | Result: a9993e364706816aba3e25717850c26c9cd0d89d 53 | 54 | ./sha1("message digest") 55 | Expect: c12252ceda8be8994d5fa0290a47231c1d16aae3 56 | Result: c12252ceda8be8994d5fa0290a47231c1d16aae3 57 | 58 | ./sha1("abcdefghijklmnopqrstuvwxyz") 59 | Expect: 32d10c7b8cf96570ca04ce37f2a19d84240d3a89 60 | Result: 32d10c7b8cf96570ca04ce37f2a19d84240d3a89 61 | 62 | ./sha1("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") 63 | Expect: 761c457bf73b14d27e9e9265c46f4b4dda11f940 64 | Result: 761c457bf73b14d27e9e9265c46f4b4dda11f940 65 | 66 | ./sha1("12345678901234567890123456789012345678901234567890123456789012345678901234567890") 67 | Expect: 50abf5706a150990a08b2c5ea40fa0e585554732 68 | Result: 50abf5706a150990a08b2c5ea40fa0e585554732 69 | 70 | cryptography/sha1$ 71 | ``` 72 | 73 | 测试例子不仅只是测试,还可以当做哈希工具使用: 74 | ```shell 75 | cryptography/sha1$ ./sha1 -h 76 | Usage: 77 | Common options: [-x|-f file|-s string|-h] 78 | Hash a string: 79 | ./sha1 -s string 80 | Hash a file: 81 | ./sha1 -f file [-k key] 82 | -x Internal string hash test 83 | -h Display this message 84 | ``` 85 | 86 | 计算字符串哈希: 87 | ``` 88 | cryptography/sha1$ ./sha1 -s "I like moon!" 89 | ./sha1("I like moon!") = 60580c84e774081d149596819fa8a2499c76f5d8 90 | cryptography/sha1$ echo -n "I like moon!" | openssl dgst -sha1 91 | (stdin)= 60580c84e774081d149596819fa8a2499c76f5d8 92 | ``` 93 | 94 | 计算文件哈希: 95 | ```shell 96 | cryptography/sha1$ ./sha1 -f sha1.o 97 | ./sha1(sha1.o) = fb70f3ceef0917427fc6eb795816826756132e15 98 | cryptography/sha1$ openssl dgst -sha1 sha1.o 99 | SHA1(sha1.o)= fb70f3ceef0917427fc6eb795816826756132e15 100 | ``` 101 | -------------------------------------------------------------------------------- /md2-constants/README.md: -------------------------------------------------------------------------------- 1 | # MD2中用于随机置换的S盒是如何生成的? 2 | 3 | > https://blog.csdn.net/guyongqiangx/article/details/117856118 4 | 5 | ### 1. 背景 6 | 7 | 最近研究md2哈希函数的设计和实现,官方文档"[rfc1319: The MD2 Message-Digest Algorithm (https://www.rfc-editor.org/rfc/rfc1319.txt)](https://www.rfc-editor.org/rfc/rfc1319.txt)"中提到,生成Checksum时(3.2节)和轮函数中(3.4节)都会使用一个有256个元素的S盒数组。 8 | 9 | 按照文档中的说法,这个S盒数组基于圆周率pi的随机位构造,但没有详细说明。 10 | > ``` 11 | > ...a 256-byte "random" permutation constructed from the digits of pi. 12 | > ``` 13 | 14 | 度娘了一下,发现没有人说过这个东西。 15 | 16 | ### 2. 伪随机S盒的生成算法 17 | 18 | 最后,通过某些方式,在StackExchange上找到了答案。 19 | 20 | 原文链接如下: 21 | 22 | [How is the MD2 hash function S-table constructed from Pi?](https://crypto.stackexchange.com/questions/11935/how-is-the-md2-hash-function-s-table-constructed-from-pi) 23 | - https://crypto.stackexchange.com/questions/11935/how-is-the-md2-hash-function-s-table-constructed-from-pi 24 | 25 | 提问的小哥很好奇md2中的S盒数组到底是如何基于pi生成的。 26 | 结果回答中的这位哥们mikeazo直接写email给MD2算法的设计者Ron Rivest,然后得到了官方的回答。 27 | > 话说这真是一个好办法!点赞! 28 | 29 | 现将Rivest回复的算法伪代码摘录如下: 30 | ``` 31 | S = [0, 1, ..., 255] 32 | digits_Pi = [3, 1, 4, 1, 5, 9, ...] # the digits of pi 33 | 34 | def rand(n): 35 | x = next(digits_Pi) 36 | y = 10 37 | 38 | if n > 10: 39 | x = x*10 + next(digits_Pi) 40 | y = 100 41 | if n > 100: 42 | x = x*10 + next(digits_Pi) 43 | y = 1000 44 | 45 | if x < (n*(y/n)): # division here is integer division 46 | return x % n 47 | else: 48 | # x value is too large, don't use it 49 | return rand(n) 50 | 51 | for i in 2...256: #inclusive 52 | j = rand(i) 53 | tmp = S[j] 54 | S[j] = S[i-1] 55 | S[i-1] = tmp 56 | ``` 57 | 58 | ### 3. Python3实现代码 59 | 60 | 回答中的另外一个小哥ryanc基于Rivest的算法,提供了一个可以运行的python3代码(md2-constants.py): 61 | ``` 62 | #!/usr/bin/env python3 63 | 64 | import io 65 | 66 | # We need 722 decimal digits of pi, including the integer part (3). 67 | pi = io.StringIO('3' 68 | '1415926535897932384626433832795028841971693993751058209749445923078164062' 69 | '8620899862803482534211706798214808651328230664709384460955058223172535940' 70 | '8128481117450284102701938521105559644622948954930381964428810975665933446' 71 | '1284756482337867831652712019091456485669234603486104543266482133936072602' 72 | '4914127372458700660631558817488152092096282925409171536436789259036001133' 73 | '0530548820466521384146951941511609433057270365759591953092186117381932611' 74 | '7931051185480744623799627495673518857527248912279381830119491298336733624' 75 | '4065664308602139494639522473719070217986094370277053921717629317675238467' 76 | '4818467669405132000568127145263560827785771342757789609173637178721468440' 77 | '901224953430146549585371050792279689258923542019956112129021960864034418') 78 | 79 | # Generate a pseudorandom integer in interval [0,n) using decimal 80 | # digits of pi (including the leading 3) as a seed. 81 | def pi_prng(n): 82 | while True: 83 | # based on n, decide how many of digits to work with 84 | if n <= 10: x, y = int(pi.read(1)), 10 85 | elif n <= 100: x, y = int(pi.read(2)), 100 86 | elif n <= 1000: x, y = int(pi.read(3)), 1000 87 | else: raise ValueError(r'Given value of n ({n}) is too big!') 88 | 89 | # Compute the largest integer multiple of n not larger than y. 90 | # If x is smaller than that, we can safely return it modulo n, 91 | # otherwise we need to try again to avoid modulo bias. 92 | if x < (n * (y // n)): return x % n 93 | 94 | # Fischer-Yates/Durstenfeld shuffling algorithm, except counting up 95 | # XXX Does counting up bias the results? 96 | S = list(range(256)) 97 | for i in range(1,256): 98 | # generate pseudorandom j such that 0 ≤ j ≤ i 99 | j = pi_prng(i+1) 100 | S[j], S[i] = S[i], S[j] 101 | 102 | # Print the S-table as shown on Wikipedia. 103 | for i in range(16): 104 | prefix = '{ ' if i == 0 else ' ' 105 | suffix = ' }' if i == 15 else ',' 106 | row = S[i*16:i*16+16] 107 | print(prefix + ', '.join(map(lambda s: '0x%02X' % s, row)) + suffix) 108 | ``` 109 | 110 | - 在Ubuntu 14.04上的执行结果 111 | 112 | ``` 113 | $ python3 --version 114 | Python 3.4.3 115 | $ python3 md2-constants.py 116 | { 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 117 | 0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA, 118 | 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 119 | 0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A, 120 | 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, 121 | 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 122 | 0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6, 123 | 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 124 | 0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02, 125 | 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, 126 | 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 127 | 0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52, 128 | 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 129 | 0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39, 130 | 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, 131 | 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14 } 132 | ``` 133 | 134 | ### 4. C语言实现代码 135 | 136 | 我将这个算法转换成了C语言代码(md2-constants.c),以下是代码和详细注释: 137 | ``` 138 | /* 139 | * md2-constants.c 140 | */ 141 | #include 142 | 143 | /* 144 | * 获取pi常量的下一个字符值(第一位是整数3) 145 | */ 146 | static unsigned int next_pi_digit(void) 147 | { 148 | /* 149 | * Python使用 sympy 工具包可以轻松获得一些数学常量的高精度数值 150 | * 具体参考: 151 | * https://blog.csdn.net/zhuoqingjoking97298/article/details/106635679 152 | * 153 | */ 154 | static char pi[731]="3" 155 | "1415926535897932384626433832795028841971693993751058209749445923078164062" 156 | "8620899862803482534211706798214808651328230664709384460955058223172535940" 157 | "8128481117450284102701938521105559644622948954930381964428810975665933446" 158 | "1284756482337867831652712019091456485669234603486104543266482133936072602" 159 | "4914127372458700660631558817488152092096282925409171536436789259036001133" 160 | "0530548820466521384146951941511609433057270365759591953092186117381932611" 161 | "7931051185480744623799627495673518857527248912279381830119491298336733624" 162 | "4065664308602139494639522473719070217986094370277053921717629317675238467" 163 | "4818467669405132000568127145263560827785771342757789609173637178721468440" 164 | "901224953430146549585371050792279689258923542019956112129021960864034418"; 165 | static unsigned int pos = 0; 166 | 167 | /* 168 | * 危险:取到字符串的最后一位了!!! 169 | * 构造MD2的S盒,256个元素,实际会调用722次 170 | */ 171 | if (pos == 730) 172 | { 173 | printf("WARNING!! pi string is not long enough, wrap around!\n"); 174 | pos = 0; 175 | } 176 | 177 | return pi[pos++]-'0'; 178 | } 179 | 180 | /* 181 | * 基于pi字符串数组构造rand函数用于生成0~n-1的随机数 182 | */ 183 | static unsigned int rand(unsigned int n) 184 | { 185 | unsigned int x, y; 186 | 187 | /* 构造1位随机数x */ 188 | x = next_pi_digit(); 189 | y = 10; 190 | 191 | /* 构造2位随机数x */ 192 | if (n > 10) 193 | { 194 | x = x * 10 + next_pi_digit(); 195 | y = 100; 196 | } 197 | 198 | /* 构造3位随机数x */ 199 | if (n > 100) 200 | { 201 | x = x * 10 + next_pi_digit(); 202 | y = 1000; 203 | } 204 | 205 | /* 206 | * 这里使用n进行整除和取模,所以n不能为0 207 | * 由于基于n进行取模,所以返回值介于0~n 208 | */ 209 | if (x < (n*(y/n))) /* division here is integer division */ 210 | { 211 | return x % n; 212 | } 213 | else 214 | { 215 | /* 216 | * 走到这里,会发生rand(n)内递归调用rand(n), 真的不会产生无限循环吗? 217 | * 答案是不会,因为内部x的状态会随着next_pi_digit()值的不同而变化 218 | */ 219 | /* x value is too large, don't use it */ 220 | return rand(n); 221 | } 222 | } 223 | 224 | /* 225 | * 生成md2算法中的伪随机S盒 226 | */ 227 | static int generate_s_box(unsigned int *S, unsigned int size) 228 | { 229 | unsigned int i; 230 | unsigned int j; 231 | unsigned int tmp; 232 | 233 | /* 初始化随机置换数组为S[0, 1, 2, ..., 255] */ 234 | for (i=0; i S[%3d]=0x%02X\n", j, S[j], i-1, S[i-1]); */ 245 | tmp = S[j]; 246 | S[j] = S[i-1]; 247 | S[i-1] = tmp; 248 | } 249 | 250 | return 0; 251 | } 252 | 253 | int main(int argc, char* argv) 254 | { 255 | unsigned int S[256]; 256 | int i; 257 | 258 | generate_s_box(S, 256); 259 | 260 | printf("S Box:\n"); 261 | for (i=0; i<256; i++) 262 | { 263 | printf("0x%02X, ", (unsigned char)S[i]); 264 | if (i%16 == 15) 265 | printf("\n"); 266 | else if (i==255) 267 | printf("\n"); 268 | } 269 | 270 | return 0; 271 | } 272 | ``` 273 | 274 | - 执行结果 275 | ``` 276 | $ gcc md2-constants.c -o md2-constants 277 | $ ./md2-constants 278 | S Box: 279 | 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 280 | 0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA, 281 | 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 282 | 0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A, 283 | 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, 284 | 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 285 | 0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6, 286 | 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 287 | 0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02, 288 | 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, 289 | 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 290 | 0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52, 291 | 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 292 | 0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39, 293 | 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, 294 | 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14, 295 | ``` 296 | 297 | ### 5. 重点 298 | 299 | - 算法需要的高精度pi值可以通过Python的sympy获取,也可以通过在线网站查询(自行搜索) 300 | - 代码链接: https://github.com/guyongqiangx/cryptography/ 301 | 302 | ### 6. 其它 303 | 304 | 洛奇工作中常常会遇到自己不熟悉的问题,这些问题可能并不难,但因为不了解,找不到人帮忙而瞎折腾,往往导致浪费几天甚至更久的时间。 305 | 306 | 所以我组建了几个微信讨论群(记得微信我说加哪个群,如何加微信见后面),欢迎一起讨论: 307 | - 一个密码编码学讨论组,主要讨论各种加解密,签名校验等算法,请说明加密码学讨论群。 308 | - 一个Android OTA的讨论组,请说明加Android OTA群。 309 | - 一个git和repo的讨论组,请说明加git和repo群。 310 | 311 | 在工作之余,洛奇尽量写一些对大家有用的东西,如果洛奇的这篇文章让您有所收获,解决了您一直以来未能解决的问题,不妨赞赏一下洛奇,这也是对洛奇付出的最大鼓励。扫下面的二维码赞赏洛奇,金额随意: 312 | 313 | ![收钱码](https://img-blog.csdnimg.cn/20190111150810383.png) 314 | 315 | 洛奇自己维护了一个公众号“洛奇看世界”,一个很佛系的公众号,不定期瞎逼逼。公号也提供个人联系方式,一些资源,说不定会有意外的收获,详细内容见公号提示。扫下方二维码关注公众号: 316 | 317 | ![公众号](https://img-blog.csdnimg.cn/20190111150824695.png) 318 | -------------------------------------------------------------------------------- /md2-constants/md2-constants.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 4 | * Refer: How is the MD2 hash function S-table constructed from Pi? 5 | * https://crypto.stackexchange.com/questions/11935/how-is-the-md2-hash-function-s-table-constructed-from-pi 6 | * 7 | * 算法描述: 8 | * 9 | * S = [0, 1, ..., 255] 10 | * digits_Pi = [3, 1, 4, 1, 5, 9, ...] # the digits of pi 11 | * 12 | * def rand(n): 13 | * x = next(digits_Pi) 14 | * y = 10 15 | * 16 | * if n > 10: 17 | * x = x*10 + next(digits_Pi) 18 | * y = 100 19 | * if n > 100: 20 | * x = x*10 + next(digits_Pi) 21 | * y = 1000 22 | * 23 | * if x < (n*(y/n)): # division here is integer division 24 | * return x % n 25 | * else: 26 | * # x value is too large, don't use it 27 | * return rand(n) 28 | * 29 | * for i in 2...256: #inclusive 30 | * j = rand(i) 31 | * tmp = S[j] 32 | * S[j] = S[i-1] 33 | * S[i-1] = tmp 34 | */ 35 | 36 | /* 37 | * 获取pi常量的下一个字符值(第一位是整数3) 38 | */ 39 | static unsigned int next_pi_digit(void) 40 | { 41 | /* 42 | * Python使用 sympy 工具包可以轻松获得一些数学常量的高精度数值 43 | * 具体参考: 44 | * https://blog.csdn.net/zhuoqingjoking97298/article/details/106635679 45 | * 46 | */ 47 | static char pi[731]="3" 48 | "1415926535897932384626433832795028841971693993751058209749445923078164062" 49 | "8620899862803482534211706798214808651328230664709384460955058223172535940" 50 | "8128481117450284102701938521105559644622948954930381964428810975665933446" 51 | "1284756482337867831652712019091456485669234603486104543266482133936072602" 52 | "4914127372458700660631558817488152092096282925409171536436789259036001133" 53 | "0530548820466521384146951941511609433057270365759591953092186117381932611" 54 | "7931051185480744623799627495673518857527248912279381830119491298336733624" 55 | "4065664308602139494639522473719070217986094370277053921717629317675238467" 56 | "4818467669405132000568127145263560827785771342757789609173637178721468440" 57 | "901224953430146549585371050792279689258923542019956112129021960864034418"; 58 | static unsigned int pos = 0; 59 | 60 | /* 61 | * 危险:取到字符串的最后一位了!!! 62 | * 构造MD2的S盒,256个元素,实际会调用722次 63 | */ 64 | if (pos == 730) 65 | { 66 | printf("WARNING!! pi string is not long enough, wrap around!\n"); 67 | pos = 0; 68 | } 69 | 70 | return pi[pos++]-'0'; 71 | } 72 | 73 | /* 74 | * 基于pi字符串数组构造rand函数用于生成0~n-1的随机数 75 | */ 76 | static unsigned int rand(unsigned int n) 77 | { 78 | unsigned int x, y; 79 | 80 | /* 构造1位随机数x */ 81 | x = next_pi_digit(); 82 | y = 10; 83 | 84 | /* 构造2位随机数x */ 85 | if (n > 10) 86 | { 87 | x = x * 10 + next_pi_digit(); 88 | y = 100; 89 | } 90 | 91 | /* 构造3位随机数x */ 92 | if (n > 100) 93 | { 94 | x = x * 10 + next_pi_digit(); 95 | y = 1000; 96 | } 97 | 98 | /* 99 | * 这里使用n进行整除和取模,所以n不能为0 100 | * 由于基于n进行取模,所以返回值介于0~n 101 | */ 102 | if (x < (n*(y/n))) /* division here is integer division */ 103 | { 104 | return x % n; 105 | } 106 | else 107 | { 108 | /* 109 | * 走到这里,会发生rand(n)内递归调用rand(n), 真的不会产生无限循环吗? 110 | * 答案是不会,因为内部x的状态会随着next_pi_digit()值的不同而变化 111 | */ 112 | /* x value is too large, don't use it */ 113 | return rand(n); 114 | } 115 | } 116 | 117 | /* 118 | * 生成md2算法中的伪随机S盒 119 | */ 120 | static int generate_s_box(unsigned int *S, unsigned int size) 121 | { 122 | unsigned int i; 123 | unsigned int j; 124 | unsigned int tmp; 125 | 126 | /* 初始化随机置换数组为S[0, 1, 2, ..., 255] */ 127 | for (i=0; i S[%3d]=0x%02X\n", j, S[j], i-1, S[i-1]); */ 138 | tmp = S[j]; 139 | S[j] = S[i-1]; 140 | S[i-1] = tmp; 141 | } 142 | 143 | return 0; 144 | } 145 | 146 | int main(int argc, char* argv) 147 | { 148 | unsigned int S[256]; 149 | int i; 150 | 151 | generate_s_box(S, 256); 152 | 153 | printf("S Box:\n"); 154 | for (i=0; i<256; i++) 155 | { 156 | printf("0x%02X, ", (unsigned char)S[i]); 157 | if (i%16 == 15) 158 | printf("\n"); 159 | else if (i==255) 160 | printf("\n"); 161 | } 162 | 163 | return 0; 164 | } 165 | 166 | /* 167 | * $ ./md2-constants 168 | * S Box: 169 | * 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 170 | * 0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA, 171 | * 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 172 | * 0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A, 173 | * 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, 174 | * 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 175 | * 0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6, 176 | * 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 177 | * 0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02, 178 | * 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, 179 | * 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 180 | * 0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52, 181 | * 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 182 | * 0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39, 183 | * 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, 184 | * 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14, 185 | */ -------------------------------------------------------------------------------- /md2-constants/md2-constants.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import io 4 | 5 | # We need 722 decimal digits of pi, including the integer part (3). 6 | pi = io.StringIO('3' 7 | '1415926535897932384626433832795028841971693993751058209749445923078164062' 8 | '8620899862803482534211706798214808651328230664709384460955058223172535940' 9 | '8128481117450284102701938521105559644622948954930381964428810975665933446' 10 | '1284756482337867831652712019091456485669234603486104543266482133936072602' 11 | '4914127372458700660631558817488152092096282925409171536436789259036001133' 12 | '0530548820466521384146951941511609433057270365759591953092186117381932611' 13 | '7931051185480744623799627495673518857527248912279381830119491298336733624' 14 | '4065664308602139494639522473719070217986094370277053921717629317675238467' 15 | '4818467669405132000568127145263560827785771342757789609173637178721468440' 16 | '901224953430146549585371050792279689258923542019956112129021960864034418') 17 | 18 | # Generate a pseudorandom integer in interval [0,n) using decimal 19 | # digits of pi (including the leading 3) as a seed. 20 | def pi_prng(n): 21 | while True: 22 | # based on n, decide how many of digits to work with 23 | if n <= 10: x, y = int(pi.read(1)), 10 24 | elif n <= 100: x, y = int(pi.read(2)), 100 25 | elif n <= 1000: x, y = int(pi.read(3)), 1000 26 | else: raise ValueError(r'Given value of n ({n}) is too big!') 27 | 28 | # Compute the largest integer multiple of n not larger than y. 29 | # If x is smaller than that, we can safely return it modulo n, 30 | # otherwise we need to try again to avoid modulo bias. 31 | if x < (n * (y // n)): return x % n 32 | 33 | # Fischer-Yates/Durstenfeld shuffling algorithm, except counting up 34 | # XXX Does counting up bias the results? 35 | S = list(range(256)) 36 | for i in range(1,256): 37 | # generate pseudorandom j such that 0 ≤ j ≤ i 38 | j = pi_prng(i+1) 39 | S[j], S[i] = S[i], S[j] 40 | 41 | # Print the S-table as shown on Wikipedia. 42 | for i in range(16): 43 | prefix = '{ ' if i == 0 else ' ' 44 | suffix = ' }' if i == 15 else ',' 45 | row = S[i*16:i*16+16] 46 | print(prefix + ', '.join(map(lambda s: '0x%02X' % s, row)) + suffix) -------------------------------------------------------------------------------- /md2/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean md2 test 2 | 3 | CROSS_COMPILE= 4 | 5 | CC = $(CROSS_COMPILE)gcc 6 | STRIP = $(CROSS_COMPILE)strip 7 | AR = $(CROSS_COMPILE)ar 8 | ARFLAGS = crs 9 | 10 | RM = rm 11 | RMFLAGS = -rf 12 | 13 | LIBS = 14 | INCLUDE = 15 | CFLAGS = -Wall -g -O2 16 | 17 | SRCS = utils.c md2.c md2test.c 18 | TARGET = md2 19 | 20 | OBJS = $(SRCS:.c=.o) 21 | 22 | all: md2 test 23 | 24 | %.o: %.c 25 | $(CC) $(CFLAGS) -c $< -o $@ 26 | 27 | $(TARGET): $(OBJS) 28 | $(CC) $(CFLAGS) $(OBJS) -o $@ $(LIBS) $(INCLUDE) 29 | # $(STRIP) --strip-unneeded $(TARGET) 30 | 31 | test: $(TARGET) 32 | @echo 33 | @echo "Run Test..." 34 | ./$(TARGET) -x 35 | 36 | clean: 37 | $(RM) $(RMFLAGS) $(TARGET) $(OBJS) 38 | -------------------------------------------------------------------------------- /md2/README.md: -------------------------------------------------------------------------------- 1 | # MD2哈希算法实现(附源码) 2 | 3 | > 相关文章: 4 | > - [MD2中用于随机置换的S盒是如何生成的?](https://blog.csdn.net/guyongqiangx/article/details/117856118) 5 | 6 | 学习MD2哈希算法第一手的参考资料是rfc1319文档,不过这个文档中有一处错误(关于Checksum计算),由于没留意勘误说明,这让我在当初趟了个大坑,按照文档描述计算得到的哈希怎么都不对。 7 | 8 | 如果您打算学习MD2算法,强烈建议直接参考RFC1319,链接如下: 9 | 10 | - RFC1319: The MD2 Message-Digest Algorithm 11 | - https://www.rfc-editor.org/rfc/rfc1319.html 12 | 13 | 虽然rfc1319一共有11页,但是除去第5页开始的参考代码,再除去前言,申明和各种说明,关于算法本身描述只有3页,所以整个MD2算法描述部分倒也简洁。 14 | 15 | 16 | ## 1. MD2算法描述 17 | 18 | 整个MD2哈希算法细节参考官方文档,以下对消息处理进行分层次的描述。 19 | 20 | ### 1.1 消息填充 21 | 22 | - 填充长度 23 | 24 | MD2处理消息时每个block大小为16个字节,通过填充,使其消息长度为16字节的整数倍。 25 | 如果原始消息的长度已经是16字节的整数倍了,则再额外填充一个16字节的数据块。 26 | 27 | - 填充内容 28 | 29 | 那到底要填充什么内容呢?官方文档的原话是: 30 | > ``` 31 | > Padding is performed as follows: "i" bytes of value "i" are appended 32 | > to the message so that the length in bytes of the padded message 33 | > becomes congruent to 0, modulo 16. At least one byte and at most 16 34 | > 16 bytes are appended 35 | > ``` 36 | 37 | 简单来说,缺几个字节,就填几个字节的数值几。 38 | 39 | 例如, 40 | - 缺1个字节,则填充1个字节的0x01; 41 | - 缺2个字节,则填充2个自己的0x012; 42 | - 缺16个字节,则填充16个字节的0x10; 43 | 44 | ### 1.2 追加校验和(Checksum) 45 | 46 | 对填充后的数据,逐块计算,最后得到16字节的校验和(刚好1个block),然后将这个1 block大小的校验和追加到填充消息的后面。 47 | 48 | 校验和的具体算法,参考官方文档的3.2节(Append Checksum)。 49 | 50 | 在校验和计算的描述中,有一个错误: 51 | ``` 52 | /* Process each 16-word block. */ 53 | For i = 0 to N/16-1 do 54 | 55 | /* Checksum block i. */ 56 | For j = 0 to 15 do 57 | Set c to M[i*16+j]. 58 | Set C[j] to S[c xor L]. <-- 这里应该是 "Set C[j] to C[j] xor S[c xor L].",即 C[j] = C[j] ^ S[c ^ L] 59 | Set L to C[j]. 60 | end /* of loop on j */ 61 | end /* of loop on i */ 62 | ``` 63 | 64 | 以下是勘误链接: 65 | - https://www.rfc-editor.org/errata/eid555 66 | 67 | ### 1.3 数据分块处理 68 | 69 | 在整个消息层面对消息填充,并追加了校验和以后,将消息按照每个block 16字节进行分块处理。 70 | 71 | 对每一个块数据的处理又分为三步(实际上是两步)。 72 | 73 | **第一步,数据预处理** 74 | 75 | 缓冲区的前16字节存放上一个block的哈希值。(第一个时为0) 76 | 77 | 将待处理的16字节数据扩展为32字节,并存放到48字节缓冲区的后32个字节中。 78 | 79 | **第二步,处理缓冲区数据** 80 | 81 | 对48字节的缓冲区数据进行18轮替换处理 82 | 83 | **第三步,保留缓冲区前16字节数据** 84 | 85 | 48字节缓冲区数据的前16字节实际上就是到当前block为止的哈希值,需要将这个哈希值作为下一个block的输入之一。 86 | 87 | 每一个block数据在处理时有两个输入数据: 88 | 1. 上一个block的哈希值(第一个block处理时,输入数据为0) 89 | 2. 当前block的数据 90 | 91 | ### 1.4 输出哈希 92 | 93 | 逐块处理数据时,最后一块的数据是整个消息的校验和。 94 | 95 | 在处理完这一块数据以后,输出缓冲区的前16字节作为整个消息的MD2哈希值。 96 | 97 | ## 2. C语言代码(附详细注释) 98 | 99 | 整个代码共5个文件: md2.h, md2.c, md2test.c, utils.h, utils.c, Makefile 100 | 101 | - md2.h, md2.c 102 | - MD2算法实现的核心文件 103 | - md2test.c 104 | - 测试文件,可以直接编译为可执行文件md2,计算计算任何字符串或输入文件的哈希。 105 | - utils.h, utils.c, Makefile 106 | - 辅助文件 107 | 108 | ### 2.1 核心源码及注释 109 | 110 | - md2.h 111 | ``` 112 | #ifndef __ROCKY_MD2__H 113 | #define __ROCKY_MD2__H 114 | 115 | #define ERR_OK 0 116 | #define ERR_ERR -1 /* generic error */ 117 | #define ERR_INV_PARAM -2 /* invalid parameter */ 118 | #define ERR_TOO_LONG -3 /* too long */ 119 | #define ERR_STATE_ERR -4 /* state error */ 120 | 121 | typedef unsigned char uint8_t; 122 | typedef unsigned short uint16_t; 123 | typedef unsigned int uint32_t; 124 | typedef unsigned long long uint64_t; 125 | 126 | typedef struct md2_context { 127 | /* 128 | * 数据总长度 129 | * MD2和SHA3一样,都没有使用长度填充 130 | * 所以total没有什么用,这里保留total为了调试打印第几块数据而已 131 | */ 132 | uint64_t total; 133 | 134 | /* 135 | * 48字节的buffer, 136 | * 前16字节用于处理时保存和传递每个block(16字节)数据的哈希值 137 | * 后32字节在处理每个block作为临时变量 138 | * 所以也可以只定义16字节用于存放哈希,然后在处理每一块时临时申请48字节的buffer 139 | */ 140 | uint8_t X[48]; 141 | 142 | /* 143 | * 一个block(16字节)大小的缓冲区, 144 | * 用于保存处理中不足一个block的数据, 145 | * 以及最后填充的数据块和附加的checksum用于压缩处理 146 | */ 147 | /* last block */ 148 | struct { 149 | uint32_t used; /* used bytes */ 150 | uint8_t buf[16]; /* block data buffer */ 151 | }last; 152 | 153 | /* 校验和 */ 154 | uint8_t checksum[16]; /* checksum */ 155 | }MD2_CTX; 156 | 157 | /* https://www.openssl.org/docs/man1.1.0/man3/MD5_Init.html */ 158 | int MD2_Init(MD2_CTX *c); 159 | int MD2_Update(MD2_CTX *c, const void *data, unsigned long len); 160 | /* int MD2_Update(MD2_CTX *c, const unsigned char *data, unsigned long len); */ 161 | int MD2_Final(unsigned char *md, MD2_CTX *c); 162 | unsigned char *MD2(const unsigned char *d, unsigned long n, unsigned char *md); 163 | 164 | #endif 165 | ``` 166 | 167 | - md2.c 168 | 169 | ``` 170 | #include 171 | #include 172 | 173 | #include "utils.h" 174 | #include "md2.h" 175 | 176 | //#define DEBUG 177 | 178 | #ifdef DEBUG 179 | #define DBG(...) printf(__VA_ARGS__) 180 | #define DUMP_BLOCK_DATA 1 181 | #define DUMP_BLOCK_CHECKSUM 1 182 | #define DUMP_BLOCK_HASH 1 183 | #define DUMP_ROUND_DATA 1 184 | #else 185 | #define DBG(...) 186 | #define DUMP_BLOCK_DATA 0 187 | #define DUMP_BLOCK_CHECKSUM 0 188 | #define DUMP_BLOCK_HASH 0 189 | #define DUMP_ROUND_DATA 0 190 | #endif 191 | 192 | #define HASH_BLOCK_SIZE 16 193 | #define HASH_DIGEST_SIZE 16 194 | #define HASH_ROUND_NUM 18 195 | 196 | /* 只有MD2才会计算一个block大小的CheckSum数据 */ 197 | #define MD2_CHECKSUM_SIZE HASH_BLOCK_SIZE 198 | 199 | /* 200 | * 参考: 201 | * md2中用于随机置换的S盒是如何生成的? 202 | * https://blog.csdn.net/guyongqiangx/article/details/117856118 203 | */ 204 | static const uint8_t S[256] = 205 | { 206 | 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 207 | 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 208 | 0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 209 | 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA, 210 | 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 211 | 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 212 | 0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 213 | 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A, 214 | 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 215 | 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, 216 | 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 217 | 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 218 | 0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 219 | 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6, 220 | 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 221 | 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 222 | 0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 223 | 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02, 224 | 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 225 | 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, 226 | 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 227 | 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 228 | 0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 229 | 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52, 230 | 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 231 | 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 232 | 0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 233 | 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39, 234 | 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 235 | 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, 236 | 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 237 | 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14, 238 | }; 239 | 240 | int MD2_Init(MD2_CTX *c) 241 | { 242 | if (NULL == c) 243 | { 244 | return ERR_INV_PARAM; 245 | } 246 | 247 | memset(c, 0, sizeof(MD2_CTX)); 248 | c->last.used = 0; 249 | 250 | /* Clear X */ 251 | /* Clear last.buf */ 252 | /* Clear checksum */ 253 | 254 | return ERR_OK; 255 | } 256 | 257 | /* 计算单个block的Checksum,下一个block的Checksum需要叠加上一个block的Checksum */ 258 | static int MD2_UpdateChecksum(MD2_CTX *ctx, const uint8_t *M) 259 | { 260 | uint32_t j; 261 | uint8_t c, L; 262 | 263 | if ((NULL == ctx) || (NULL == M)) 264 | { 265 | return ERR_INV_PARAM; 266 | } 267 | 268 | /* 269 | * rfc1319 3.2节处理Checksum时: 270 | * 1. 开始处理前,"Set L to 0",而Checksum全部为0,所以相当于L=Checksum[15] 271 | * 2. 循环处理数据块的每一个bytes时有"Set L to C[j]",数据块处理结束时L=Checksum[15] 272 | */ 273 | L = ctx->checksum[15]; 274 | 275 | /* update checksum */ 276 | for (j=0; jchecksum[j] = S[c ^ L]; 281 | * Description error in rfc1319, see: 282 | * https://www.rfc-editor.org/rfc/inline-errata/rfc1319.html#eid555 283 | */ 284 | ctx->checksum[j] ^= S[c ^ L]; 285 | L = ctx->checksum[j]; 286 | } 287 | 288 | /* 打印每一块的Checksum数据 */ 289 | #if (DUMP_BLOCK_CHECKSUM == 1) 290 | DBG("CHECKSUM:\n"); 291 | print_buffer(ctx->checksum, HASH_BLOCK_SIZE, " "); 292 | #endif 293 | return ERR_OK; 294 | } 295 | 296 | /* 预处理每个block输入数据 */ 297 | static int MD2_PrepareScheduleWord(MD2_CTX *ctx, const void *block) 298 | { 299 | uint32_t j; 300 | uint8_t *X, *M; 301 | 302 | X = (uint8_t *)ctx->X; 303 | M = (uint8_t *)block; 304 | 305 | /* 306 | * 将单块数据的内容处理后放入缓冲区X的后32字节, 307 | * 前16字节为上一块数据处理后的内容) 308 | */ 309 | for (j=0; jtotal/HASH_BLOCK_SIZE); 333 | DBG(" DATA:\n"); 334 | print_buffer(block, HASH_BLOCK_SIZE, " "); 335 | #endif 336 | 337 | X = (uint8_t *)ctx->X; 338 | M = (uint8_t *)block; 339 | 340 | /* 更新Checksum */ 341 | MD2_UpdateChecksum(ctx, M); 342 | 343 | /* 预处理每个block输入数据 */ 344 | /* Copy block i into X. */ 345 | MD2_PrepareScheduleWord(ctx, M); 346 | 347 | t = 0; 348 | 349 | /* 对每个block数据进行18轮处理 */ 350 | /* Do 18 rounds */ 351 | for (j=0; jX[j]); 367 | } 368 | DBG("\n"); 369 | #endif 370 | 371 | return ERR_OK; 372 | } 373 | 374 | /* 375 | * 管理输入数据 376 | * 1. 将每个完整block的数据提交MD2_ProcessBlock处理 377 | * 2. 将不足一个block的部分存放到last.buf缓冲区中 378 | */ 379 | int MD2_Update(MD2_CTX *c, const void *data, unsigned long len) 380 | { 381 | uint32_t copy_len = 0; 382 | 383 | if ((NULL == c) || (NULL == data)) 384 | { 385 | return ERR_INV_PARAM; 386 | } 387 | 388 | /* 389 | * 如果缓冲区还有上一次处理剩余的数据,先凑足一个block处理后,再逐个block处理本次的数据 390 | */ 391 | if (c->last.used != 0) 392 | { 393 | /* 剩余数据和新数据一起还不够一个block,则复制到缓冲区 */ 394 | if (c->last.used + len < HASH_BLOCK_SIZE) 395 | { 396 | memcpy(&c->last.buf[c->last.used], data, len); 397 | c->last.used += len; 398 | 399 | return ERR_OK; 400 | } 401 | else 402 | { 403 | /* 将缓冲区的数据凑够一个block处理 */ 404 | copy_len = HASH_BLOCK_SIZE - c->last.used; 405 | memcpy(&c->last.buf[c->last.used], data, copy_len); 406 | MD2_ProcessBlock(c, &c->last.buf); 407 | 408 | c->total += HASH_BLOCK_SIZE; 409 | 410 | data = (uint8_t *)data + copy_len; 411 | len -= copy_len; 412 | 413 | memset(&c->last.buf[0], 0, HASH_BLOCK_SIZE); 414 | c->last.used = 0; 415 | } 416 | } 417 | 418 | /* 剩余数据不够一个block了,复制到缓冲区 */ 419 | if (len < HASH_BLOCK_SIZE) 420 | { 421 | memcpy(&c->last.buf[c->last.used], data, len); 422 | c->last.used += len; 423 | 424 | return ERR_OK; 425 | } 426 | else 427 | { 428 | /* 逐块处理数据 */ 429 | while (len >= HASH_BLOCK_SIZE) 430 | { 431 | MD2_ProcessBlock(c, data); 432 | c->total += HASH_BLOCK_SIZE; 433 | 434 | data = (uint8_t *)data + HASH_BLOCK_SIZE; 435 | len -= HASH_BLOCK_SIZE; 436 | } 437 | 438 | /* 将剩余数据复制到缓冲区 */ 439 | memcpy(&c->last.buf[0], data, len); 440 | c->last.used = len; 441 | } 442 | 443 | return ERR_OK; 444 | } 445 | 446 | /* 447 | * 管理数据最后的填充,附加计算好的Checksum 448 | * 将剩余数据提交MD2_ProcessBlock处理 449 | * 返回最终的哈希值 450 | */ 451 | int MD2_Final(unsigned char *md, MD2_CTX *c) 452 | { 453 | uint8_t pat; 454 | uint32_t padding_len; 455 | 456 | if ((NULL == c) || (NULL == md)) 457 | { 458 | return ERR_INV_PARAM; 459 | } 460 | 461 | /* Append Padding Bytes */ 462 | /* 剩余数据存放在last.buf缓冲区中,计算需要填充的长度 463 | * 如果原来的数据刚好是一整块,没有剩余,则再新增一整块 464 | */ 465 | padding_len = HASH_BLOCK_SIZE - c->last.used; 466 | /* MD2填充时填充i个值为i的数据, "i" bytes of value "i" */ 467 | pat = padding_len; 468 | memset(&c->last.buf[c->last.used], pat, padding_len); 469 | 470 | /* Process Padding Block */ 471 | /* 处理填充的数据块 */ 472 | MD2_ProcessBlock(c, c->last.buf); 473 | c->total += HASH_BLOCK_SIZE; 474 | c->last.used = 0; 475 | 476 | /* Process Checksum Block */ 477 | /* 最后处理一个block的Checksum数据 */ 478 | memcpy(&c->last.buf[c->last.used], c->checksum, HASH_BLOCK_SIZE); 479 | c->last.used = HASH_BLOCK_SIZE; 480 | MD2_ProcessBlock(c, c->last.buf); 481 | 482 | /* 所有数据处理完成后,48字节缓冲区的前16个字节就是哈希值 */ 483 | memcpy(md, c->X, HASH_DIGEST_SIZE); 484 | 485 | return ERR_OK; 486 | } 487 | 488 | unsigned char *MD2(const unsigned char *d, unsigned long n, unsigned char *md) 489 | { 490 | MD2_CTX c; 491 | 492 | if ((NULL == d) || (NULL == md)) 493 | { 494 | return NULL; 495 | } 496 | 497 | MD2_Init(&c); 498 | MD2_Update(&c, d, n); 499 | MD2_Final(md, &c); 500 | 501 | return md; 502 | } 503 | ``` 504 | 505 | 完整源码,包括测试代码和Makefile等位于: 506 | - https://github.com/guyongqiangx/cryptography/ 507 | 508 | ### 2.2 代码结构说明 509 | 510 | #### API 511 | 512 | 代码一共封装了4个MD2操作的API: 513 | ``` 514 | int MD2_Init(MD2_CTX *c); 515 | int MD2_Update(MD2_CTX *c, const void *data, unsigned long len); 516 | int MD2_Final(unsigned char *md, MD2_CTX *c); 517 | unsigned char *MD2(const unsigned char *d, unsigned long n, unsigned char *md); 518 | ``` 519 | 520 | 和OpenSSL官方的MD2函数接口一样,功能也基本一致: 521 | - https://www.openssl.org/docs/man1.1.0/man3/MD5_Init.html 522 | 523 | 524 | #### 私有实现 525 | 526 | 所有哈希函数的操作基本一致,包括: 527 | 528 | **1. 整个消息层面** 529 | - 填充数据 530 | - 对数据分块 531 | 532 | **2. 数据块层面** 533 | - 对数据块预处理 534 | - 对预处理数据进行多轮处理 535 | - 保存当前数据块的哈希值给下一块数据 536 | 537 | **3. 最后** 538 | - 返回最后一个数据块的哈希值作为整个消息的哈希 539 | 540 | 实际上,不会在一开始就会对整个数据进行填充,最好在处理到最后一块数据时再填充,原因主要是: 541 | - 有些情况下一开始不知道数据大小,没法填充(如串口或网络数据); 542 | - 将全部数据放入内存,填充好以后才开始计算,开销太大 543 | 544 | 所以整个过程有点像流式操作: 545 | ``` 546 | MD2_INIT() 547 | MD2_Update(message1) 548 | --> MD2_ProcessBlock(block1) 549 | --> MD2_ProcessBlock(block2) 550 | --> ... 551 | --> MD2_ProcessBlock(blockn) 552 | MD2_Update(message2) 553 | ... 554 | MD2_Update(messagen) 555 | MD2_Final(&digest) 556 | ``` 557 | 558 | 在每次收到数据时,"MD2_Update"将数据逐个分块,剩余不足一块的数据保存起来,和一下次到达的数据一起处理。 559 | 560 | 在处理每个数据块时,操作也比较模式化: 561 | ``` 562 | MD2_ProcessBlock(data) 563 | { 564 | Preprocess1(data) // 预处理1, 如计算Checksum 565 | Preprocess2(data) // 预处理2, 如对数据进行扩展 566 | for (i=0; i License to use MD2 is granted for non-commerical Internet Privacy-Enhanced Mail [1-3]. 641 | 642 | 这里明确提出MD2的非商业用途。 643 | 644 | 2. 性能 645 | 646 | 从MD2的算法描述看,MD2中的所有操作都是基于单个字节的,但后续哈希算法都基于32或更多字节进行设计,性能上会比单个自己操作更强。 647 | 648 | 关于性能,还需要具体数据进行验证,MD2和同家族的MD4, MD5到底有多大区别。 649 | 650 | ## 5. 其它 651 | 652 | 洛奇工作中常常会遇到自己不熟悉的问题,这些问题可能并不难,但因为不了解,找不到人帮忙而瞎折腾,往往导致浪费几天甚至更久的时间。 653 | 654 | 所以我组建了几个微信讨论群(记得微信我说加哪个群,如何加微信见后面),欢迎一起讨论: 655 | - 一个密码编码学讨论组,主要讨论各种加解密,签名校验等算法,请说明加密码学讨论群。 656 | - 一个Android OTA的讨论组,请说明加Android OTA群。 657 | - 一个git和repo的讨论组,请说明加git和repo群。 658 | 659 | 在工作之余,洛奇尽量写一些对大家有用的东西,如果洛奇的这篇文章让您有所收获,解决了您一直以来未能解决的问题,不妨赞赏一下洛奇,这也是对洛奇付出的最大鼓励。扫下面的二维码赞赏洛奇,金额随意: 660 | 661 | ![收钱码](https://img-blog.csdnimg.cn/20190111150810383.png) 662 | 663 | 洛奇自己维护了一个公众号“洛奇看世界”,一个很佛系的公众号,不定期瞎逼逼。公号也提供个人联系方式,一些资源,说不定会有意外的收获,详细内容见公号提示。扫下方二维码关注公众号: 664 | 665 | ![公众号](https://img-blog.csdnimg.cn/20190111150824695.png) 666 | -------------------------------------------------------------------------------- /md2/md2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "utils.h" 5 | #include "md2.h" 6 | 7 | //#define DEBUG 8 | 9 | #ifdef DEBUG 10 | #define DBG(...) printf(__VA_ARGS__) 11 | #define DUMP_BLOCK_DATA 1 12 | #define DUMP_BLOCK_CHECKSUM 1 13 | #define DUMP_BLOCK_HASH 1 14 | #define DUMP_ROUND_DATA 1 15 | #else 16 | #define DBG(...) 17 | #define DUMP_BLOCK_DATA 0 18 | #define DUMP_BLOCK_CHECKSUM 0 19 | #define DUMP_BLOCK_HASH 0 20 | #define DUMP_ROUND_DATA 0 21 | #endif 22 | 23 | #define HASH_BLOCK_SIZE 16 24 | #define HASH_DIGEST_SIZE 16 25 | #define HASH_ROUND_NUM 18 26 | 27 | #define MD2_CHECKSUM_SIZE 16 28 | 29 | /* 30 | * 31 | * How the S Box of MD2 are generated from Pi digits? 32 | * Refere: https://blog.csdn.net/guyongqiangx/article/details/117856118 33 | * 34 | */ 35 | static const uint8_t S[256] = 36 | { 37 | 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 38 | 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 39 | 0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 40 | 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA, 41 | 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 42 | 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 43 | 0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 44 | 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A, 45 | 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 46 | 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, 47 | 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 48 | 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 49 | 0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 50 | 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6, 51 | 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 52 | 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 53 | 0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 54 | 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02, 55 | 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 56 | 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, 57 | 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 58 | 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 59 | 0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 60 | 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52, 61 | 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 62 | 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 63 | 0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 64 | 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39, 65 | 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 66 | 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, 67 | 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 68 | 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14, 69 | }; 70 | 71 | int MD2_Init(MD2_CTX *c) 72 | { 73 | if (NULL == c) 74 | { 75 | return ERR_INV_PARAM; 76 | } 77 | 78 | memset(c, 0, sizeof(MD2_CTX)); 79 | c->last.used = 0; 80 | 81 | /* Clear X */ 82 | /* Clear last.buf */ 83 | /* Clear checksum */ 84 | 85 | return ERR_OK; 86 | } 87 | 88 | static int MD2_UpdateChecksum(MD2_CTX *ctx, const uint8_t *M) 89 | { 90 | uint32_t j; 91 | uint8_t c, L; 92 | 93 | if ((NULL == ctx) || (NULL == M)) 94 | { 95 | return ERR_INV_PARAM; 96 | } 97 | 98 | L = ctx->checksum[15]; 99 | 100 | /* update checksum */ 101 | for (j=0; jchecksum[j] = S[c ^ L]; 106 | * Description error in rfc1319, see: 107 | * https://www.rfc-editor.org/rfc/inline-errata/rfc1319.html#eid555 108 | */ 109 | ctx->checksum[j] ^= S[c ^ L]; 110 | L = ctx->checksum[j]; 111 | } 112 | 113 | #if (DUMP_BLOCK_CHECKSUM == 1) 114 | DBG("CHECKSUM:\n"); 115 | print_buffer(ctx->checksum, HASH_BLOCK_SIZE, " "); 116 | #endif 117 | return ERR_OK; 118 | } 119 | 120 | static int MD2_PrepareScheduleWord(MD2_CTX *ctx, const void *block) 121 | { 122 | uint32_t j; 123 | uint8_t *X, *M; 124 | 125 | X = (uint8_t *)ctx->X; 126 | M = (uint8_t *)block; 127 | 128 | for (j=0; jtotal/HASH_BLOCK_SIZE); 151 | DBG(" DATA:\n"); 152 | print_buffer(block, HASH_BLOCK_SIZE, " "); 153 | #endif 154 | 155 | X = (uint8_t *)ctx->X; 156 | M = (uint8_t *)block; 157 | 158 | MD2_UpdateChecksum(ctx, M); 159 | 160 | /* Copy block into X */ 161 | MD2_PrepareScheduleWord(ctx, M); 162 | 163 | t = 0; 164 | 165 | /* Do 18 rounds */ 166 | for (j=0; jX[j]); 182 | } 183 | DBG("\n"); 184 | #endif 185 | 186 | return ERR_OK; 187 | } 188 | 189 | int MD2_Update(MD2_CTX *c, const void *data, unsigned long len) 190 | { 191 | uint32_t copy_len = 0; 192 | 193 | if ((NULL == c) || (NULL == data)) 194 | { 195 | return ERR_INV_PARAM; 196 | } 197 | 198 | /* has used data */ 199 | if (c->last.used != 0) 200 | { 201 | /* less than 1 block in total, combine data */ 202 | if (c->last.used + len < HASH_BLOCK_SIZE) 203 | { 204 | memcpy(&c->last.buf[c->last.used], data, len); 205 | c->last.used += len; 206 | 207 | return ERR_OK; 208 | } 209 | else /* more than 1 block */ 210 | { 211 | /* process the block in context buffer */ 212 | copy_len = HASH_BLOCK_SIZE - c->last.used; 213 | memcpy(&c->last.buf[c->last.used], data, copy_len); 214 | MD2_ProcessBlock(c, &c->last.buf); 215 | 216 | c->total += HASH_BLOCK_SIZE; 217 | 218 | data = (uint8_t *)data + copy_len; 219 | len -= copy_len; 220 | 221 | /* reset context buffer */ 222 | memset(&c->last.buf[0], 0, HASH_BLOCK_SIZE); 223 | c->last.used = 0; 224 | } 225 | } 226 | 227 | /* less than 1 block, copy to context buffer */ 228 | if (len < HASH_BLOCK_SIZE) 229 | { 230 | memcpy(&c->last.buf[c->last.used], data, len); 231 | c->last.used += len; 232 | 233 | return ERR_OK; 234 | } 235 | else 236 | { 237 | /* process data blocks */ 238 | while (len >= HASH_BLOCK_SIZE) 239 | { 240 | MD2_ProcessBlock(c, data); 241 | c->total += HASH_BLOCK_SIZE; 242 | 243 | data = (uint8_t *)data + HASH_BLOCK_SIZE; 244 | len -= HASH_BLOCK_SIZE; 245 | } 246 | 247 | /* copy rest data to context buffer */ 248 | memcpy(&c->last.buf[0], data, len); 249 | c->last.used = len; 250 | } 251 | 252 | return ERR_OK; 253 | } 254 | 255 | int MD2_Final(unsigned char *md, MD2_CTX *c) 256 | { 257 | uint8_t pat; 258 | uint32_t padding_len; 259 | 260 | if ((NULL == c) || (NULL == md)) 261 | { 262 | return ERR_INV_PARAM; 263 | } 264 | 265 | /* Append Padding Bytes */ 266 | padding_len = HASH_BLOCK_SIZE - c->last.used; 267 | pat = padding_len; 268 | memset(&c->last.buf[c->last.used], pat, padding_len); 269 | 270 | /* Process Padding Block */ 271 | MD2_ProcessBlock(c, c->last.buf); 272 | c->total += HASH_BLOCK_SIZE; 273 | c->last.used = 0; 274 | 275 | /* Process Checksum Block */ 276 | memcpy(&c->last.buf[c->last.used], c->checksum, HASH_BLOCK_SIZE); 277 | c->last.used = HASH_BLOCK_SIZE; 278 | MD2_ProcessBlock(c, c->last.buf); 279 | 280 | /* output message digest */ 281 | memcpy(md, c->X, HASH_DIGEST_SIZE); 282 | 283 | return ERR_OK; 284 | } 285 | 286 | unsigned char *MD2(const unsigned char *d, unsigned long n, unsigned char *md) 287 | { 288 | MD2_CTX c; 289 | 290 | if ((NULL == d) || (NULL == md)) 291 | { 292 | return NULL; 293 | } 294 | 295 | MD2_Init(&c); 296 | MD2_Update(&c, d, n); 297 | MD2_Final(md, &c); 298 | 299 | return md; 300 | } 301 | -------------------------------------------------------------------------------- /md2/md2.h: -------------------------------------------------------------------------------- 1 | #ifndef __ROCKY_MD2__H 2 | #define __ROCKY_MD2__H 3 | 4 | #define ERR_OK 0 5 | #define ERR_ERR -1 /* generic error */ 6 | #define ERR_INV_PARAM -2 /* invalid parameter */ 7 | #define ERR_TOO_LONG -3 /* too long */ 8 | #define ERR_STATE_ERR -4 /* state error */ 9 | 10 | typedef unsigned char uint8_t; 11 | typedef unsigned short uint16_t; 12 | typedef unsigned int uint32_t; 13 | typedef unsigned long long uint64_t; 14 | 15 | typedef struct md2_context { 16 | /* message total length in bytes */ 17 | uint64_t total; 18 | 19 | /* 48 bytes buffer */ 20 | uint8_t X[48]; 21 | 22 | /* last block */ 23 | struct { 24 | uint32_t used; /* used bytes */ 25 | uint8_t buf[16]; /* block data buffer */ 26 | }last; 27 | 28 | uint8_t checksum[16]; /* checksum */ 29 | }MD2_CTX; 30 | 31 | /* https://www.openssl.org/docs/man1.1.0/man3/MD5_Init.html */ 32 | int MD2_Init(MD2_CTX *c); 33 | int MD2_Update(MD2_CTX *c, const void *data, unsigned long len); 34 | /* int MD2_Update(MD2_CTX *c, const unsigned char *data, unsigned long len); */ 35 | int MD2_Final(unsigned char *md, MD2_CTX *c); 36 | unsigned char *MD2(const unsigned char *d, unsigned long n, unsigned char *md); 37 | #endif 38 | -------------------------------------------------------------------------------- /md2/md2test.c: -------------------------------------------------------------------------------- 1 | #include /* printf, fopen, fread, fclose... */ 2 | #include /* exit */ 3 | #include /* strlen */ 4 | #include /* getopt */ 5 | 6 | #include "md2.h" 7 | 8 | #define HASH_DIGEST_SIZE 16 /* md2 digest size */ 9 | #define FILE_BLOCK_SIZE 1024 10 | 11 | /* 12 | * Print a usage message 13 | */ 14 | void usage(const char *argv0) 15 | { 16 | fprintf(stderr, 17 | "Usage:\n" 18 | "Common options: [-x|-f file|-s string|-h]\n" 19 | "Hash a string:\n" 20 | "\t%s -s string\n" 21 | "Hash a file:\n" 22 | "\t%s -f file [-k key]\n" 23 | "-x\tInternal string hash test\n" 24 | "-h\tDisplay this message\n" 25 | , argv0, argv0); 26 | exit(1); 27 | } 28 | 29 | /* 30 | * Print a message digest in hexadecimal 31 | */ 32 | static int print_digest(unsigned char *digest) 33 | { 34 | uint32_t i; 35 | 36 | for (i = 0; i < HASH_DIGEST_SIZE; i++) 37 | { 38 | printf ("%02x", digest[i]); 39 | } 40 | 41 | return 0; 42 | } 43 | 44 | struct HASH_ITEM { 45 | char *str; 46 | uint32_t len; 47 | unsigned char md[HASH_DIGEST_SIZE*2]; 48 | } hashes[] = 49 | { 50 | { /* 0 */ 51 | "", 52 | 0, 53 | "8350e5a3e24c153df2275c9f80692773" 54 | }, 55 | { /* 1 */ 56 | "a", 57 | 1, 58 | "32ec01ec4a6dac72c0ab96fb34c0b5d1" 59 | }, 60 | { /* 2 */ 61 | "abc", 62 | 3, 63 | "da853b0d3f88d99b30283a69e6ded6bb" 64 | }, 65 | { /* 3 */ 66 | "message digest", 67 | 14, 68 | "ab4f496bfb2a530b219ff33031fe06b0" 69 | }, 70 | { /* 4 */ 71 | "abcdefghijklmnopqrstuvwxyz", 72 | 26, 73 | "4e8ddff3650292ab5a4108c3aa47940b" 74 | }, 75 | { /* 5 */ 76 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 77 | 62, 78 | "da33def2a42df13975352846c30338cd" 79 | }, 80 | { /* 6 */ 81 | "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 82 | 80, 83 | "d5976f79d83d3a0dc9806c3c66f3efd8" 84 | }, 85 | }; 86 | 87 | /* 88 | * Internal digest tests 89 | */ 90 | static int internal_digest_tests(const char *argv0) 91 | { 92 | unsigned char digest[HASH_DIGEST_SIZE]; 93 | struct HASH_ITEM *item; 94 | 95 | printf ("Internal hash tests for %s:\n", argv0); 96 | 97 | for (item=&hashes[0]; item<(&hashes[0]+sizeof(hashes)/sizeof(hashes[0])); item++) 98 | { 99 | printf("%s(\"%s\")\n", argv0, item->str); 100 | MD2((unsigned char*)item->str, item->len, digest); 101 | printf(" Expect: %s\n", item->md); 102 | printf(" Result: "); 103 | print_digest(digest); 104 | printf("\n\n"); 105 | } 106 | 107 | return 0; 108 | } 109 | 110 | /* 111 | * Hash a string and print the digest 112 | */ 113 | static int digest_string(const char *argv0, const unsigned char *string, uint32_t len) 114 | { 115 | unsigned char digest[HASH_DIGEST_SIZE]; 116 | 117 | printf("%s(\"%s\") = ", argv0, string); 118 | 119 | MD2(string, len, digest); 120 | 121 | print_digest(digest); 122 | printf("\n"); 123 | 124 | return 0; 125 | } 126 | 127 | /* 128 | * Hash a file and print the digest 129 | */ 130 | static int digest_file(const char *argv0, const char *filename) 131 | { 132 | MD2_CTX c; 133 | FILE *f; 134 | 135 | unsigned char digest[HASH_DIGEST_SIZE]; 136 | unsigned char buf[FILE_BLOCK_SIZE]; 137 | 138 | int len = 0; 139 | int rc = 0; 140 | 141 | f = fopen(filename, "rb"); 142 | if (NULL == f) 143 | { 144 | printf("Can't open file %s\n", filename); 145 | rc = -1; 146 | } 147 | else 148 | { 149 | printf("%s(%s) = ", argv0, filename); 150 | 151 | MD2_Init(&c); 152 | while ((len = fread(buf, 1, FILE_BLOCK_SIZE, f))) 153 | { 154 | MD2_Update(&c, buf, len); 155 | } 156 | MD2_Final(digest, &c); 157 | 158 | fclose(f); 159 | 160 | print_digest(digest); 161 | printf("\n"); 162 | 163 | rc = 0; 164 | } 165 | 166 | return rc; 167 | } 168 | 169 | /* 170 | * Hash the standard input and prints the digest 171 | */ 172 | static void digest_stdin(const char *argv0) 173 | { 174 | MD2_CTX c; 175 | 176 | int len; 177 | unsigned char digest[HASH_DIGEST_SIZE]; 178 | unsigned char buf[HASH_DIGEST_SIZE]; 179 | 180 | MD2_Init(&c); 181 | while ((len = fread(buf, 1, HASH_DIGEST_SIZE, stdin))) 182 | { 183 | MD2_Update(&c, buf, len); 184 | } 185 | MD2_Final(digest, &c); 186 | 187 | printf("%s(stdin) = ", argv0); 188 | print_digest(digest); 189 | printf("\n"); 190 | } 191 | 192 | /* 193 | * $ md2 -h 194 | * Usage: 195 | * Common options: [-x|-f file|-s string|-h] 196 | * Hash a string: 197 | * md2 -s string 198 | * Hash a file: 199 | * md2 -f file [-k key] 200 | * -x Internal string hash test 201 | * -h Display this message 202 | */ 203 | int main(int argc, char *argv[]) 204 | { 205 | int ch; 206 | int hash_internal = 0; 207 | int hash_str = 0; 208 | int hash_file = 0; 209 | int hash_stdin = 0; 210 | 211 | char *str = NULL; 212 | uint32_t len = 0; 213 | 214 | char *filename = NULL; 215 | 216 | while ((ch = getopt(argc, argv, "s:f:xh")) != -1) 217 | { 218 | switch(ch) 219 | { 220 | case 'x': 221 | hash_internal = 1; 222 | break; 223 | case 's': 224 | hash_str = 1; 225 | str = optarg; 226 | len = strlen(str); 227 | break; 228 | case 'f': 229 | hash_file = 1; 230 | filename = optarg; 231 | break; 232 | case 'h': 233 | default: /* '?' */ 234 | usage(argv[0]); 235 | break; 236 | } 237 | } 238 | 239 | if (argc == 1) 240 | { 241 | hash_stdin = 1; 242 | } 243 | 244 | if (hash_internal) 245 | { 246 | internal_digest_tests(argv[0]); 247 | } 248 | 249 | if (hash_str) 250 | { 251 | digest_string(argv[0], (unsigned char *)str, len); 252 | } 253 | 254 | if (hash_file) 255 | { 256 | digest_file(argv[0], filename); 257 | } 258 | 259 | if (hash_stdin) 260 | { 261 | digest_stdin(argv[0]); 262 | } 263 | 264 | return 0; 265 | } 266 | -------------------------------------------------------------------------------- /md2/rfc1319-The_MD2_Message-Digest_Algorithmpdf.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guyongqiangx/cryptography/9bfd756a980b8958f5242fb7ad383d42420a49b5/md2/rfc1319-The_MD2_Message-Digest_Algorithmpdf.pdf -------------------------------------------------------------------------------- /md2/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "utils.h" 3 | 4 | #define DUMP_LINE_SIZE 16 5 | int print_buffer(const void *buf, unsigned long len, const char *indent) 6 | { 7 | unsigned long i = 0; 8 | for (i=0; i> 8) & 0xff) \ 13 | | (((x) & 0xff) << 8))) 14 | 15 | /* Swap bytes in 32 bit value. */ 16 | #define __bswap_32(x) \ 17 | ((((x) & 0xff000000) >> 24) \ 18 | | (((x) & 0x00ff0000) >> 8) \ 19 | | (((x) & 0x0000ff00) << 8) \ 20 | | (((x) & 0x000000ff) << 24)) 21 | 22 | /* Swap bytes in 64 bit value. */ 23 | #define __bswap_64(x) \ 24 | ((((x) & 0xff00000000000000ull) >> 56) \ 25 | | (((x) & 0x00ff000000000000ull) >> 40) \ 26 | | (((x) & 0x0000ff0000000000ull) >> 24) \ 27 | | (((x) & 0x000000ff00000000ull) >> 8) \ 28 | | (((x) & 0x00000000ff000000ull) << 8) \ 29 | | (((x) & 0x0000000000ff0000ull) << 24) \ 30 | | (((x) & 0x000000000000ff00ull) << 40) \ 31 | | (((x) & 0x00000000000000ffull) << 56)) 32 | 33 | #if (ENDIANNESS == ENDIAN_LITTLE) 34 | #define htole16(x) (x) 35 | #define htole32(x) (x) 36 | #define htole64(x) (x) 37 | 38 | #define htobe16(x) __bswap_16(x) 39 | #define htobe32(x) __bswap_32(x) 40 | #define htobe64(x) __bswap_64(x) 41 | #else 42 | #define htole16(x) __bswap_16(x) 43 | #define htole32(x) __bswap_32(x) 44 | #define htole64(x) __bswap_64(x) 45 | 46 | #define htobe16(x) (x) 47 | #define htobe32(x) (x) 48 | #define htobe64(x) (x) 49 | #endif 50 | 51 | #define le16toh(x) htole16(x) 52 | #define le32toh(x) htole32(x) 53 | #define le64toh(x) htole64(x) 54 | 55 | #define be16toh(x) htobe16(x) 56 | #define be32toh(x) htobe32(x) 57 | #define be64toh(x) htobe64(x) 58 | 59 | int print_buffer(const void *buf, unsigned long len, const char *indent); 60 | 61 | #endif -------------------------------------------------------------------------------- /md4/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean md4 test 2 | 3 | CROSS_COMPILE= 4 | 5 | CC = $(CROSS_COMPILE)gcc 6 | STRIP = $(CROSS_COMPILE)strip 7 | AR = $(CROSS_COMPILE)ar 8 | ARFLAGS = crs 9 | 10 | RM = rm 11 | RMFLAGS = -rf 12 | 13 | LIBS = 14 | INCLUDE = 15 | CFLAGS = -Wall -g -O2 16 | 17 | SRCS = utils.c md4.c md4test.c 18 | TARGET = md4 19 | 20 | OBJS = $(SRCS:.c=.o) 21 | 22 | all: md4 test 23 | 24 | %.o: %.c 25 | $(CC) $(CFLAGS) -c $< -o $@ 26 | 27 | $(TARGET): $(OBJS) 28 | $(CC) $(CFLAGS) $(OBJS) -o $@ $(LIBS) $(INCLUDE) 29 | # $(STRIP) --strip-all $(TARGET) 30 | 31 | test: $(TARGET) 32 | @echo 33 | @echo "Run Test..." 34 | ./$(TARGET) -x 35 | 36 | clean: 37 | $(RM) $(RMFLAGS) $(TARGET) $(OBJS) 38 | -------------------------------------------------------------------------------- /md4/TAOCP-Vol.2-2nd_Edition-Table_2-p660.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guyongqiangx/cryptography/9bfd756a980b8958f5242fb7ad383d42420a49b5/md4/TAOCP-Vol.2-2nd_Edition-Table_2-p660.png -------------------------------------------------------------------------------- /md4/md4.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: md4.c 3 | * @ description: implementation for the MD4 Message-Digest Algorithm 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #include 8 | #include 9 | 10 | #include "utils.h" 11 | #include "md4.h" 12 | 13 | //#define DEBUG 14 | 15 | #ifdef DEBUG 16 | #define DBG(...) printf(__VA_ARGS__) 17 | #define DUMP_BLOCK_DATA 1 18 | #define DUMP_BLOCK_HASH 1 19 | #define DUMP_ROUND_DATA 1 20 | #else 21 | #define DBG(...) 22 | #define DUMP_BLOCK_DATA 0 23 | #define DUMP_BLOCK_HASH 0 24 | #define DUMP_ROUND_DATA 0 25 | #endif 26 | 27 | #define MD4_BLOCK_SIZE 64 /* 512 bits = 64 bytes */ 28 | #define MD4_LEN_SIZE 8 /* 64 bits = 8 bytes */ 29 | #define MD4_LEN_OFFSET (MD4_BLOCK_SIZE - MD4_LEN_SIZE) 30 | #define MD4_DIGEST_SIZE 16 /* 128 bits = 16 bytes */ 31 | 32 | #define MD4_PADDING_PATTERN 0x80 33 | #define MD4_ROUND_NUM 64 34 | 35 | #define HASH_BLOCK_SIZE MD4_BLOCK_SIZE 36 | #define HASH_LEN_SIZE MD4_LEN_SIZE 37 | #define HASH_LEN_OFFSET MD4_LEN_OFFSET 38 | #define HASH_DIGEST_SIZE MD4_DIGEST_SIZE 39 | 40 | #define HASH_PADDING_PATTERN MD4_PADDING_PATTERN 41 | #define HASH_ROUND_NUM MD4_ROUND_NUM 42 | 43 | typedef uint32_t (*md4_func)(uint32_t x, uint32_t y, uint32_t z); 44 | 45 | /* MD4 Round Constants, refer rfc1320, section 3.4 */ 46 | static uint32_t T[3] = 47 | { 48 | 0x00000000, /* Round 1( 0 ~ 15), placeholder of T[idx/16] in MD4_OP */ 49 | 0x5A827999, /* Round 2(16 ~ 31), square root of 2 */ 50 | 0x6ED9EBA1, /* Round 3(32 ~ 47), square root of 3 */ 51 | }; 52 | 53 | /* ROTate Left (circular left shift) */ 54 | static uint32_t ROTL(uint32_t x, uint8_t shift) 55 | { 56 | return (x << shift) | (x >> (32 - shift)); 57 | } 58 | 59 | /* 60 | * F/G/H definition, refer rfc1320, section 3.4 61 | */ 62 | 63 | /* 64 | * Condition 65 | * In each bit position, F acts as a conditional: 66 | * if X then Y else Z. 67 | */ 68 | static uint32_t F(uint32_t x, uint32_t y, uint32_t z) 69 | { 70 | return (x & y) | ((~x) & z); 71 | } 72 | 73 | /* 74 | * Majority 75 | * In each bit position, G acts as a majority function: 76 | * if at least two of X, Y, Z are on, then G has a "1" bit in that bit position, else G has a "0" bit. 77 | */ 78 | static uint32_t G(uint32_t x, uint32_t y, uint32_t z) 79 | { 80 | return (x & y) | (x & z) | (y & z); 81 | } 82 | 83 | /* 84 | * Parity 85 | * H is the bit-wise XOR or "parity" function 86 | */ 87 | static uint32_t H(uint32_t x, uint32_t y, uint32_t z) 88 | { 89 | return x ^ y ^ z; 90 | } 91 | 92 | /* MD4 Functions */ 93 | static md4_func g[3] = 94 | { 95 | F, /* 0 ~ 15 operations */ 96 | G, /* 16 ~ 31 operations */ 97 | H /* 32 ~ 47 operations */ 98 | }; 99 | 100 | int MD4_Init(MD4_CTX *c) 101 | { 102 | if (NULL == c) 103 | { 104 | return ERR_INV_PARAM; 105 | } 106 | 107 | memset(c, 0, sizeof(MD4_CTX)); 108 | 109 | /* MD4 Initial Value, refer rfc1320, section 3.3 */ 110 | c->hash.a = 0x67452301; /* little endian */ 111 | c->hash.b = 0xEFCDAB89; 112 | c->hash.c = 0x98BADCFE; 113 | c->hash.d = 0x10325476; 114 | 115 | c->total = 0; 116 | c->last.used = 0; 117 | 118 | return ERR_OK; 119 | } 120 | 121 | static int MD4_PrepareScheduleWord(const uint32_t *block, uint32_t *X) 122 | { 123 | uint32_t i; 124 | 125 | if ((NULL == block) || (NULL == X)) 126 | { 127 | return ERR_INV_PARAM; 128 | } 129 | 130 | for (i=0; itotal/HASH_BLOCK_SIZE); 164 | DBG(" DATA:\n"); 165 | print_buffer(block, HASH_BLOCK_SIZE, " "); 166 | #endif 167 | 168 | #if (DUMP_BLOCK_HASH == 1) 169 | DBG(" (LE)IV: %08x %08x %08x %08x\n", 170 | ctx->hash.a, ctx->hash.b, ctx->hash.c, ctx->hash.d); 171 | #endif 172 | 173 | /* Copy block into X */ 174 | MD4_PrepareScheduleWord(block, X); 175 | 176 | A = ctx->hash.a; 177 | B = ctx->hash.b; 178 | C = ctx->hash.c; 179 | D = ctx->hash.d; 180 | 181 | idx = 0; 182 | 183 | /* Round 1 */ 184 | MD4_OP(A, B, C, D, 0, 3); MD4_OP(D, A, B, C, 1, 7); MD4_OP(C, D, A, B, 2, 11); MD4_OP(B, C, D, A, 3, 19); 185 | MD4_OP(A, B, C, D, 4, 3); MD4_OP(D, A, B, C, 5, 7); MD4_OP(C, D, A, B, 6, 11); MD4_OP(B, C, D, A, 7, 19); 186 | MD4_OP(A, B, C, D, 8, 3); MD4_OP(D, A, B, C, 9, 7); MD4_OP(C, D, A, B, 10, 11); MD4_OP(B, C, D, A, 11, 19); 187 | MD4_OP(A, B, C, D, 12, 3); MD4_OP(D, A, B, C, 13, 7); MD4_OP(C, D, A, B, 14, 11); MD4_OP(B, C, D, A, 15, 19); 188 | 189 | /* Round 2 */ 190 | MD4_OP(A, B, C, D, 0, 3); MD4_OP(D, A, B, C, 4, 5); MD4_OP(C, D, A, B, 8, 9); MD4_OP(B, C, D, A, 12, 13); 191 | MD4_OP(A, B, C, D, 1, 3); MD4_OP(D, A, B, C, 5, 5); MD4_OP(C, D, A, B, 9, 9); MD4_OP(B, C, D, A, 13, 13); 192 | MD4_OP(A, B, C, D, 2, 3); MD4_OP(D, A, B, C, 6, 5); MD4_OP(C, D, A, B, 10, 9); MD4_OP(B, C, D, A, 14, 13); 193 | MD4_OP(A, B, C, D, 3, 3); MD4_OP(D, A, B, C, 7, 5); MD4_OP(C, D, A, B, 11, 9); MD4_OP(B, C, D, A, 15, 13); 194 | 195 | /* Round 3 */ 196 | MD4_OP(A, B, C, D, 0, 3); MD4_OP(D, A, B, C, 8, 9); MD4_OP(C, D, A, B, 4, 11); MD4_OP(B, C, D, A, 12, 15); 197 | MD4_OP(A, B, C, D, 2, 3); MD4_OP(D, A, B, C, 10, 9); MD4_OP(C, D, A, B, 6, 11); MD4_OP(B, C, D, A, 14, 15); 198 | MD4_OP(A, B, C, D, 1, 3); MD4_OP(D, A, B, C, 9, 9); MD4_OP(C, D, A, B, 5, 11); MD4_OP(B, C, D, A, 13, 15); 199 | MD4_OP(A, B, C, D, 3, 3); MD4_OP(D, A, B, C, 11, 9); MD4_OP(C, D, A, B, 7, 11); MD4_OP(B, C, D, A, 15, 15); 200 | 201 | ctx->hash.a += A; 202 | ctx->hash.b += B; 203 | ctx->hash.c += C; 204 | ctx->hash.d += D; 205 | 206 | #if (DUMP_BLOCK_HASH == 1) 207 | DBG(" (LE)OUT: %08x %08x %08x %08x\n", 208 | ctx->hash.a, ctx->hash.b, ctx->hash.c, ctx->hash.d); 209 | #endif 210 | 211 | return ERR_OK; 212 | } 213 | 214 | int MD4_Update(MD4_CTX *c, const void *data, unsigned long len) 215 | { 216 | uint32_t copy_len = 0; 217 | 218 | if ((NULL == c) || (NULL == data)) 219 | { 220 | return ERR_INV_PARAM; 221 | } 222 | 223 | /* has used data */ 224 | if (c->last.used != 0) 225 | { 226 | /* less than 1 block in total, combine data */ 227 | if (c->last.used + len < HASH_BLOCK_SIZE) 228 | { 229 | memcpy(&c->last.buf[c->last.used], data, len); 230 | c->last.used += len; 231 | 232 | return ERR_OK; 233 | } 234 | else /* more than 1 block */ 235 | { 236 | /* process the block in context buffer */ 237 | copy_len = HASH_BLOCK_SIZE - c->last.used; 238 | memcpy(&c->last.buf[c->last.used], data, copy_len); 239 | MD4_ProcessBlock(c, &c->last.buf); 240 | 241 | c->total += HASH_BLOCK_SIZE; 242 | 243 | data = (uint8_t *)data + copy_len; 244 | len -= copy_len; 245 | 246 | /* reset context buffer */ 247 | memset(&c->last.buf[0], 0, HASH_BLOCK_SIZE); 248 | c->last.used = 0; 249 | } 250 | } 251 | 252 | /* less than 1 block, copy to context buffer */ 253 | if (len < HASH_BLOCK_SIZE) 254 | { 255 | memcpy(&c->last.buf[c->last.used], data, len); 256 | c->last.used += len; 257 | 258 | return ERR_OK; 259 | } 260 | else 261 | { 262 | /* process data blocks */ 263 | while (len >= HASH_BLOCK_SIZE) 264 | { 265 | MD4_ProcessBlock(c, data); 266 | c->total += HASH_BLOCK_SIZE; 267 | 268 | data = (uint8_t *)data + HASH_BLOCK_SIZE; 269 | len -= HASH_BLOCK_SIZE; 270 | } 271 | 272 | /* copy rest data to context buffer */ 273 | memcpy(&c->last.buf[0], data, len); 274 | c->last.used = len; 275 | } 276 | 277 | return ERR_OK; 278 | } 279 | 280 | int MD4_Final(unsigned char *md, MD4_CTX *c) 281 | { 282 | uint32_t *temp; 283 | 284 | if ((NULL == c) || (NULL == md)) 285 | { 286 | return ERR_INV_PARAM; 287 | } 288 | 289 | /* Last block should be less than HASH_BLOCK_SIZE - HASH_LEN_SIZE */ 290 | if (c->last.used >= (HASH_BLOCK_SIZE - HASH_LEN_SIZE)) 291 | { 292 | c->total += c->last.used; 293 | 294 | /* one more block */ 295 | c->last.buf[c->last.used] = HASH_PADDING_PATTERN; 296 | c->last.used++; 297 | 298 | memset(&c->last.buf[c->last.used], 0, HASH_BLOCK_SIZE - c->last.used); 299 | MD4_ProcessBlock(c, &c->last.buf); 300 | 301 | memset(&c->last.buf[0], 0, HASH_BLOCK_SIZE - HASH_LEN_SIZE); 302 | c->last.used = 0; 303 | 304 | /* save length */ 305 | temp = (uint32_t *)&(c->last.buf[HASH_LEN_OFFSET]); 306 | temp[0] = htole32((c->total << 3) & 0xFFFFFFFF); 307 | temp[1] = htole32(((c->total << 3) >> 32) & 0xFFFFFFFF); 308 | 309 | MD4_ProcessBlock(c, &c->last.buf); 310 | } 311 | else /* 0 <= last.used < HASH_BLOCK_SIZE - HASH_LEN_SIZE */ 312 | { 313 | c->total += c->last.used; 314 | 315 | /* one more block */ 316 | c->last.buf[c->last.used] = HASH_PADDING_PATTERN; 317 | c->last.used++; 318 | 319 | /* padding 0s */ 320 | memset(&c->last.buf[c->last.used], 0, HASH_BLOCK_SIZE - HASH_LEN_SIZE - c->last.used); 321 | 322 | /* save length */ 323 | temp = (uint32_t *)&(c->last.buf[HASH_LEN_OFFSET]); 324 | temp[0] = htole32((c->total << 3) & 0xFFFFFFFF); 325 | temp[1] = htole32(((c->total << 3) >> 32) & 0xFFFFFFFF); 326 | 327 | MD4_ProcessBlock(c, &c->last.buf); 328 | } 329 | 330 | /* LE for MD4/MD5, different from SHA family(Big Endian) */ 331 | temp = (uint32_t *)md; 332 | temp[0] = htole32(c->hash.a); 333 | temp[1] = htole32(c->hash.b); 334 | temp[2] = htole32(c->hash.c); 335 | temp[3] = htole32(c->hash.d); 336 | 337 | return ERR_OK; 338 | } 339 | 340 | unsigned char *MD4(const unsigned char *d, unsigned long n, unsigned char *md) 341 | { 342 | MD4_CTX c; 343 | 344 | if ((NULL == d) || (NULL == md)) 345 | { 346 | return NULL; 347 | } 348 | 349 | MD4_Init(&c); 350 | MD4_Update(&c, d, n); 351 | MD4_Final(md, &c); 352 | 353 | return md; 354 | } 355 | -------------------------------------------------------------------------------- /md4/md4.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: md4.h 3 | * @ description: header file for md4.c 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #ifndef __ROCKY_MD4__H 8 | #define __ROCKY_MD4__H 9 | 10 | #define ERR_OK 0 11 | #define ERR_ERR -1 /* generic error */ 12 | #define ERR_INV_PARAM -2 /* invalid parameter */ 13 | #define ERR_TOO_LONG -3 /* too long */ 14 | #define ERR_STATE_ERR -4 /* state error */ 15 | 16 | typedef unsigned char uint8_t; 17 | typedef unsigned short uint16_t; 18 | typedef unsigned int uint32_t; 19 | typedef unsigned long long uint64_t; 20 | 21 | typedef struct md4_context { 22 | /* message total length in bytes */ 23 | uint64_t total; 24 | 25 | /* intermedia hash value for each block */ 26 | struct { 27 | uint32_t a; 28 | uint32_t b; 29 | uint32_t c; 30 | uint32_t d; 31 | uint32_t e; 32 | }hash; 33 | 34 | /* last block */ 35 | struct { 36 | uint32_t used; /* used bytes */ 37 | uint8_t buf[64]; /* block data buffer */ 38 | }last; 39 | }MD4_CTX; 40 | 41 | /* https://www.openssl.org/docs/man1.1.0/man3/MD5_Init.html */ 42 | int MD4_Init(MD4_CTX *c); 43 | int MD4_Update(MD4_CTX *c, const void *data, unsigned long len); 44 | int MD4_Final(unsigned char *md, MD4_CTX *c); 45 | unsigned char *MD4(const unsigned char *d, unsigned long n, unsigned char *md); 46 | #endif 47 | -------------------------------------------------------------------------------- /md4/md4test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: md4test.c 3 | * @ description: test tool for md4 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #include /* printf, fopen, fread, fclose... */ 8 | #include /* exit */ 9 | #include /* strlen */ 10 | #include /* getopt */ 11 | 12 | #include "md4.h" 13 | 14 | #define HASH_DIGEST_SIZE 16 /* md4 digest size */ 15 | #define FILE_BLOCK_SIZE 1024 16 | 17 | /* 18 | * Print a usage message 19 | */ 20 | void usage(const char *argv0) 21 | { 22 | fprintf(stderr, 23 | "Usage:\n" 24 | "Common options: [-x|-f file|-s string|-h]\n" 25 | "Hash a string:\n" 26 | "\t%s -s string\n" 27 | "Hash a file:\n" 28 | "\t%s -f file [-k key]\n" 29 | "-x\tInternal string hash test\n" 30 | "-h\tDisplay this message\n" 31 | , argv0, argv0); 32 | exit(1); 33 | } 34 | 35 | /* 36 | * Print a message digest in hexadecimal 37 | */ 38 | static int print_digest(unsigned char *digest) 39 | { 40 | uint32_t i; 41 | 42 | for (i = 0; i < HASH_DIGEST_SIZE; i++) 43 | { 44 | printf ("%02x", digest[i]); 45 | } 46 | 47 | return 0; 48 | } 49 | 50 | struct HASH_ITEM { 51 | char *str; 52 | uint32_t len; 53 | unsigned char md[HASH_DIGEST_SIZE*2]; 54 | } hashes[] = 55 | { 56 | { /* 0 */ 57 | "", 58 | 0, 59 | "31d6cfe0d16ae931b73c59d7e0c089c0" 60 | }, 61 | { /* 1 */ 62 | "a", 63 | 1, 64 | "bde52cb31de33e46245e05fbdbd6fb24" 65 | }, 66 | { /* 2 */ 67 | "abc", 68 | 3, 69 | "a448017aaf21d8525fc10ae87aa6729d" 70 | }, 71 | { /* 3 */ 72 | "message digest", 73 | 14, 74 | "d9130a8164549fe818874806e1c7014b" 75 | }, 76 | { /* 4 */ 77 | "abcdefghijklmnopqrstuvwxyz", 78 | 26, 79 | "d79e1c308aa5bbcdeea8ed63df412da9" 80 | }, 81 | { /* 5 */ 82 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 83 | 62, 84 | "043f8582f241db351ce627e153e7f0e4" 85 | }, 86 | { /* 6 */ 87 | "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 88 | 80, 89 | "e33b4ddc9c38f2199c3e7b164fcc0536" 90 | }, 91 | }; 92 | 93 | /* 94 | * Internal digest tests 95 | */ 96 | static int internal_digest_tests(const char *argv0) 97 | { 98 | unsigned char digest[HASH_DIGEST_SIZE]; 99 | struct HASH_ITEM *item; 100 | 101 | printf ("Internal hash tests for %s:\n", argv0); 102 | 103 | for (item=&hashes[0]; item<(&hashes[0]+sizeof(hashes)/sizeof(hashes[0])); item++) 104 | { 105 | printf("%s(\"%s\")\n", argv0, item->str); 106 | MD4((unsigned char*)item->str, item->len, digest); 107 | printf(" Expect: %s\n", item->md); 108 | printf(" Result: "); 109 | print_digest(digest); 110 | printf("\n\n"); 111 | } 112 | 113 | return 0; 114 | } 115 | 116 | /* 117 | * Hash a string and print the digest 118 | */ 119 | static int digest_string(const char *argv0, const unsigned char *string, uint32_t len) 120 | { 121 | unsigned char digest[HASH_DIGEST_SIZE]; 122 | 123 | printf("%s(\"%s\") = ", argv0, string); 124 | 125 | MD4(string, len, digest); 126 | 127 | print_digest(digest); 128 | printf("\n"); 129 | 130 | return 0; 131 | } 132 | 133 | /* 134 | * Hash a file and print the digest 135 | */ 136 | static int digest_file(const char *argv0, const char *filename) 137 | { 138 | MD4_CTX c; 139 | FILE *f; 140 | 141 | unsigned char digest[HASH_DIGEST_SIZE]; 142 | unsigned char buf[FILE_BLOCK_SIZE]; 143 | 144 | int len = 0; 145 | int rc = 0; 146 | 147 | f = fopen(filename, "rb"); 148 | if (NULL == f) 149 | { 150 | printf("Can't open file %s\n", filename); 151 | rc = -1; 152 | } 153 | else 154 | { 155 | printf("%s(%s) = ", argv0, filename); 156 | 157 | MD4_Init(&c); 158 | while ((len = fread(buf, 1, FILE_BLOCK_SIZE, f))) 159 | { 160 | MD4_Update(&c, buf, len); 161 | } 162 | MD4_Final(digest, &c); 163 | 164 | fclose(f); 165 | 166 | print_digest(digest); 167 | printf("\n"); 168 | 169 | rc = 0; 170 | } 171 | 172 | return rc; 173 | } 174 | 175 | /* 176 | * Hash the standard input and prints the digest 177 | */ 178 | static void digest_stdin(const char *argv0) 179 | { 180 | MD4_CTX c; 181 | 182 | int len; 183 | unsigned char digest[HASH_DIGEST_SIZE]; 184 | unsigned char buf[HASH_DIGEST_SIZE]; 185 | 186 | MD4_Init(&c); 187 | while ((len = fread(buf, 1, HASH_DIGEST_SIZE, stdin))) 188 | { 189 | MD4_Update(&c, buf, len); 190 | } 191 | MD4_Final(digest, &c); 192 | 193 | printf("%s(stdin) = ", argv0); 194 | print_digest(digest); 195 | printf("\n"); 196 | } 197 | 198 | /* 199 | * $ md4 -h 200 | * Usage: 201 | * Common options: [-x|-f file|-s string|-h] 202 | * Hash a string: 203 | * md4 -s string 204 | * Hash a file: 205 | * md4 -f file [-k key] 206 | * -x Internal string hash test 207 | * -h Display this message 208 | */ 209 | int main(int argc, char *argv[]) 210 | { 211 | int ch; 212 | int hash_internal = 0; 213 | int hash_str = 0; 214 | int hash_file = 0; 215 | int hash_stdin = 0; 216 | 217 | char *str = NULL; 218 | uint32_t len = 0; 219 | 220 | char *filename = NULL; 221 | 222 | while ((ch = getopt(argc, argv, "s:f:xh")) != -1) 223 | { 224 | switch(ch) 225 | { 226 | case 'x': 227 | hash_internal = 1; 228 | break; 229 | case 's': 230 | hash_str = 1; 231 | str = optarg; 232 | len = strlen(str); 233 | break; 234 | case 'f': 235 | hash_file = 1; 236 | filename = optarg; 237 | break; 238 | case 'h': 239 | default: /* '?' */ 240 | usage(argv[0]); 241 | break; 242 | } 243 | } 244 | 245 | if (argc == 1) 246 | { 247 | hash_stdin = 1; 248 | } 249 | 250 | if (hash_internal) 251 | { 252 | internal_digest_tests(argv[0]); 253 | } 254 | 255 | if (hash_str) 256 | { 257 | digest_string(argv[0], (unsigned char *)str, len); 258 | } 259 | 260 | if (hash_file) 261 | { 262 | digest_file(argv[0], filename); 263 | } 264 | 265 | if (hash_stdin) 266 | { 267 | digest_stdin(argv[0]); 268 | } 269 | 270 | return 0; 271 | } 272 | -------------------------------------------------------------------------------- /md4/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "utils.h" 3 | 4 | #define DUMP_LINE_SIZE 16 5 | int print_buffer(const void *buf, unsigned long len, const char *indent) 6 | { 7 | unsigned long i = 0; 8 | for (i=0; i> 8) & 0xff) \ 13 | | (((x) & 0xff) << 8))) 14 | 15 | /* Swap bytes in 32 bit value. */ 16 | #define __bswap_32(x) \ 17 | ((((x) & 0xff000000) >> 24) \ 18 | | (((x) & 0x00ff0000) >> 8) \ 19 | | (((x) & 0x0000ff00) << 8) \ 20 | | (((x) & 0x000000ff) << 24)) 21 | 22 | /* Swap bytes in 64 bit value. */ 23 | #define __bswap_64(x) \ 24 | ((((x) & 0xff00000000000000ull) >> 56) \ 25 | | (((x) & 0x00ff000000000000ull) >> 40) \ 26 | | (((x) & 0x0000ff0000000000ull) >> 24) \ 27 | | (((x) & 0x000000ff00000000ull) >> 8) \ 28 | | (((x) & 0x00000000ff000000ull) << 8) \ 29 | | (((x) & 0x0000000000ff0000ull) << 24) \ 30 | | (((x) & 0x000000000000ff00ull) << 40) \ 31 | | (((x) & 0x00000000000000ffull) << 56)) 32 | 33 | #if (ENDIANNESS == ENDIAN_LITTLE) 34 | #define htole16(x) (x) 35 | #define htole32(x) (x) 36 | #define htole64(x) (x) 37 | 38 | #define htobe16(x) __bswap_16(x) 39 | #define htobe32(x) __bswap_32(x) 40 | #define htobe64(x) __bswap_64(x) 41 | #else 42 | #define htole16(x) __bswap_16(x) 43 | #define htole32(x) __bswap_32(x) 44 | #define htole64(x) __bswap_64(x) 45 | 46 | #define htobe16(x) (x) 47 | #define htobe32(x) (x) 48 | #define htobe64(x) (x) 49 | #endif 50 | 51 | #define le16toh(x) htole16(x) 52 | #define le32toh(x) htole32(x) 53 | #define le64toh(x) htole64(x) 54 | 55 | #define be16toh(x) htobe16(x) 56 | #define be32toh(x) htobe32(x) 57 | #define be64toh(x) htobe64(x) 58 | 59 | int print_buffer(const void *buf, unsigned long len, const char *indent); 60 | 61 | #endif -------------------------------------------------------------------------------- /md5/Fast_Collision_Attach_on_MD5-2013.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guyongqiangx/cryptography/9bfd756a980b8958f5242fb7ad383d42420a49b5/md5/Fast_Collision_Attach_on_MD5-2013.pdf -------------------------------------------------------------------------------- /md5/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean md5 test 2 | 3 | CROSS_COMPILE= 4 | 5 | CC = $(CROSS_COMPILE)gcc 6 | STRIP = $(CROSS_COMPILE)strip 7 | AR = $(CROSS_COMPILE)ar 8 | ARFLAGS = crs 9 | 10 | RM = rm 11 | RMFLAGS = -rf 12 | 13 | LIBS = 14 | INCLUDE = 15 | CFLAGS = -Wall -g -O2 16 | 17 | SRCS = utils.c md5.c md5test.c 18 | TARGET = md5 19 | 20 | OBJS = $(SRCS:.c=.o) 21 | 22 | all: md5 test 23 | 24 | %.o: %.c 25 | $(CC) $(CFLAGS) -c $< -o $@ 26 | 27 | $(TARGET): $(OBJS) 28 | $(CC) $(CFLAGS) $(OBJS) -o $@ $(LIBS) $(INCLUDE) 29 | # $(STRIP) --strip-all $(TARGET) 30 | 31 | test: $(TARGET) 32 | @echo 33 | @echo "Run Test..." 34 | ./$(TARGET) -x 35 | 36 | clean: 37 | $(RM) $(RMFLAGS) $(TARGET) $(OBJS) 38 | -------------------------------------------------------------------------------- /md5/md5.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: md5.c 3 | * @ description: implementation for the MD5 Message-Digest Algorithm 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #include 8 | #include 9 | 10 | #include "utils.h" 11 | #include "md5.h" 12 | 13 | //#define DEBUG 14 | 15 | #ifdef DEBUG 16 | #define DBG(...) printf(__VA_ARGS__) 17 | #define DUMP_BLOCK_DATA 1 18 | #define DUMP_BLOCK_HASH 1 19 | #define DUMP_ROUND_DATA 1 20 | #else 21 | #define DBG(...) 22 | #define DUMP_BLOCK_DATA 0 23 | #define DUMP_BLOCK_HASH 0 24 | #define DUMP_ROUND_DATA 0 25 | #endif 26 | 27 | #define MD5_BLOCK_SIZE 64 /* 512 bits = 64 bytes */ 28 | #define MD5_LEN_SIZE 8 /* 64 bits = 8 bytes */ 29 | #define MD5_LEN_OFFSET (MD5_BLOCK_SIZE - MD5_LEN_SIZE) 30 | #define MD5_DIGEST_SIZE 16 /* 128 bits = 16 bytes */ 31 | 32 | #define MD5_PADDING_PATTERN 0x80 33 | #define MD5_ROUND_NUM 64 34 | 35 | #define HASH_BLOCK_SIZE MD5_BLOCK_SIZE 36 | #define HASH_LEN_SIZE MD5_LEN_SIZE 37 | #define HASH_LEN_OFFSET MD5_LEN_OFFSET 38 | #define HASH_DIGEST_SIZE MD5_DIGEST_SIZE 39 | 40 | #define HASH_PADDING_PATTERN MD5_PADDING_PATTERN 41 | #define HASH_ROUND_NUM MD5_ROUND_NUM 42 | 43 | typedef uint32_t (*md5_func)(uint32_t x, uint32_t y, uint32_t z); 44 | 45 | /* MD5 Constants */ 46 | static uint32_t T[64] = 47 | { 48 | /* Round 1 */ 49 | 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 50 | 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 51 | 52 | /* Round 2 */ 53 | 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 54 | 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 55 | 56 | /* Round 3 */ 57 | 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 58 | 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 59 | 60 | /* Round 4 */ 61 | 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 62 | 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, 63 | }; 64 | 65 | /* ROTate Left (circular left shift) */ 66 | static uint32_t ROTL(uint32_t x, uint8_t shift) 67 | { 68 | return (x << shift) | (x >> (32 - shift)); 69 | } 70 | 71 | static uint32_t F(uint32_t x, uint32_t y, uint32_t z) 72 | { 73 | return (x & y) | ((~x) & z); 74 | } 75 | 76 | static uint32_t G(uint32_t x, uint32_t y, uint32_t z) 77 | { 78 | return (x & z) | (y & (~z)); 79 | } 80 | 81 | static uint32_t H(uint32_t x, uint32_t y, uint32_t z) 82 | { 83 | return x ^ y ^ z; 84 | } 85 | 86 | static uint32_t I(uint32_t x, uint32_t y, uint32_t z) 87 | { 88 | return y ^ (x | (~z));; 89 | } 90 | 91 | /* MD5 Functions */ 92 | static md5_func g[4] = 93 | { 94 | F, G, H, I 95 | }; 96 | 97 | int MD5_Init(MD5_CTX *c) 98 | { 99 | if (NULL == c) 100 | { 101 | return ERR_INV_PARAM; 102 | } 103 | 104 | memset(c, 0, sizeof(MD5_CTX)); 105 | 106 | c->hash.a = 0x67452301; /* little endian */ 107 | c->hash.b = 0xEFCDAB89; 108 | c->hash.c = 0x98BADCFE; 109 | c->hash.d = 0x10325476; 110 | 111 | c->total = 0; 112 | c->last.used = 0; 113 | 114 | return ERR_OK; 115 | } 116 | 117 | static int MD5_PrepareScheduleWord(const uint32_t *block, uint32_t *W) 118 | { 119 | uint32_t i; 120 | 121 | if ((NULL == block) || (NULL == W)) 122 | { 123 | return ERR_INV_PARAM; 124 | } 125 | 126 | for (i=0; i<16; i++) 127 | { 128 | W[i] = le32toh(block[i]); 129 | } 130 | 131 | return ERR_OK; 132 | } 133 | 134 | #if (DUMP_ROUND_DATA == 1) 135 | #define MD5_OP(a,b,c,d,k,s,i) \ 136 | a = b + ROTL(a + (g[(i-1)/16])(b, c, d) + X[k] + T[i-1], s); \ 137 | DBG(" %02d: a=0x%08x, b=0x%08x, c=0x%08x, d=0x%08x, X=0x%08x, T=0x%08x\n", i-1, a, b, c, d, X[k], T[i-1]); 138 | #else 139 | #define MD5_OP(a,b,c,d,k,s,i) \ 140 | a = b + ROTL(a + (g[(i-1)/16])(b, c, d) + X[k] + T[i-1], s); 141 | #endif 142 | 143 | static int MD5_ProcessBlock(MD5_CTX *ctx, const void *block) 144 | { 145 | uint32_t X[16]; 146 | uint32_t a, b, c, d; 147 | 148 | if ((NULL == ctx) || (NULL == block)) 149 | { 150 | return ERR_INV_PARAM; 151 | } 152 | 153 | #if (DUMP_BLOCK_DATA == 1) 154 | DBG("---------------------------------------------------------\n"); 155 | DBG(" BLOCK: %llu\n", ctx->total/HASH_BLOCK_SIZE); 156 | DBG(" DATA:\n"); 157 | print_buffer(block, HASH_BLOCK_SIZE, " "); 158 | #endif 159 | 160 | #if (DUMP_BLOCK_HASH == 1) 161 | DBG(" (LE)IV: %08x %08x %08x %08x\n", 162 | ctx->hash.a, ctx->hash.b, ctx->hash.c, ctx->hash.d); 163 | #endif 164 | 165 | /* prepare schedule word */ 166 | MD5_PrepareScheduleWord(block, X); 167 | 168 | a = ctx->hash.a; 169 | b = ctx->hash.b; 170 | c = ctx->hash.c; 171 | d = ctx->hash.d; 172 | 173 | /* Round 1 */ 174 | MD5_OP(a, b, c, d, 0, 7, 1); MD5_OP(d, a, b, c, 1, 12, 2); MD5_OP(c, d, a, b, 2, 17, 3); MD5_OP(b, c, d, a, 3, 22, 4); 175 | MD5_OP(a, b, c, d, 4, 7, 5); MD5_OP(d, a, b, c, 5, 12, 6); MD5_OP(c, d, a, b, 6, 17, 7); MD5_OP(b, c, d, a, 7, 22, 8); 176 | MD5_OP(a, b, c, d, 8, 7, 9); MD5_OP(d, a, b, c, 9, 12, 10); MD5_OP(c, d, a, b, 10, 17, 11); MD5_OP(b, c, d, a, 11, 22, 12); 177 | MD5_OP(a, b, c, d, 12, 7, 13); MD5_OP(d, a, b, c, 13, 12, 14); MD5_OP(c, d, a, b, 14, 17, 15); MD5_OP(b, c, d, a, 15, 22, 16); 178 | 179 | /* Round 2 */ 180 | MD5_OP(a, b, c, d, 1, 5, 17); MD5_OP(d, a, b, c, 6, 9, 18); MD5_OP(c, d, a, b, 11, 14, 19); MD5_OP(b, c, d, a, 0, 20, 20); 181 | MD5_OP(a, b, c, d, 5, 5, 21); MD5_OP(d, a, b, c, 10, 9, 22); MD5_OP(c, d, a, b, 15, 14, 23); MD5_OP(b, c, d, a, 4, 20, 24); 182 | MD5_OP(a, b, c, d, 9, 5, 25); MD5_OP(d, a, b, c, 14, 9, 26); MD5_OP(c, d, a, b, 3, 14, 27); MD5_OP(b, c, d, a, 8, 20, 28); 183 | MD5_OP(a, b, c, d, 13, 5, 29); MD5_OP(d, a, b, c, 2, 9, 30); MD5_OP(c, d, a, b, 7, 14, 31); MD5_OP(b, c, d, a, 12, 20, 32); 184 | 185 | /* Round 3 */ 186 | MD5_OP(a, b, c, d, 5, 4, 33); MD5_OP(d, a, b, c, 8, 11, 34); MD5_OP(c, d, a, b, 11, 16, 35); MD5_OP(b, c, d, a, 14, 23, 36); 187 | MD5_OP(a, b, c, d, 1, 4, 37); MD5_OP(d, a, b, c, 4, 11, 38); MD5_OP(c, d, a, b, 7, 16, 39); MD5_OP(b, c, d, a, 10, 23, 40); 188 | MD5_OP(a, b, c, d, 13, 4, 41); MD5_OP(d, a, b, c, 0, 11, 42); MD5_OP(c, d, a, b, 3, 16, 43); MD5_OP(b, c, d, a, 6, 23, 44); 189 | MD5_OP(a, b, c, d, 9, 4, 45); MD5_OP(d, a, b, c, 12, 11, 46); MD5_OP(c, d, a, b, 15, 16, 47); MD5_OP(b, c, d, a, 2, 23, 48); 190 | 191 | /* Round 4 */ 192 | MD5_OP(a, b, c, d, 0, 6, 49); MD5_OP(d, a, b, c, 7, 10, 50); MD5_OP(c, d, a, b, 14, 15, 51); MD5_OP(b, c, d, a, 5, 21, 52); 193 | MD5_OP(a, b, c, d, 12, 6, 53); MD5_OP(d, a, b, c, 3, 10, 54); MD5_OP(c, d, a, b, 10, 15, 55); MD5_OP(b, c, d, a, 1, 21, 56); 194 | MD5_OP(a, b, c, d, 8, 6, 57); MD5_OP(d, a, b, c, 15, 10, 58); MD5_OP(c, d, a, b, 6, 15, 59); MD5_OP(b, c, d, a, 13, 21, 60); 195 | MD5_OP(a, b, c, d, 4, 6, 61); MD5_OP(d, a, b, c, 11, 10, 62); MD5_OP(c, d, a, b, 2, 15, 63); MD5_OP(b, c, d, a, 9, 21, 64); 196 | 197 | #if 0 198 | for (t=0; thash.a += a; 215 | ctx->hash.b += b; 216 | ctx->hash.c += c; 217 | ctx->hash.d += d; 218 | #if (DUMP_BLOCK_HASH == 1) 219 | DBG(" (LE)OUT: %08x %08x %08x %08x\n", 220 | ctx->hash.a, ctx->hash.b, ctx->hash.c, ctx->hash.d); 221 | #endif 222 | 223 | return ERR_OK; 224 | } 225 | 226 | int MD5_Update(MD5_CTX *c, const void *data, unsigned long len) 227 | { 228 | uint32_t copy_len = 0; 229 | 230 | if ((NULL == c) || (NULL == data)) 231 | { 232 | return ERR_INV_PARAM; 233 | } 234 | 235 | /* has used data */ 236 | if (c->last.used != 0) 237 | { 238 | /* less than 1 block in total, combine data */ 239 | if (c->last.used + len < HASH_BLOCK_SIZE) 240 | { 241 | memcpy(&c->last.buf[c->last.used], data, len); 242 | c->last.used += len; 243 | 244 | return ERR_OK; 245 | } 246 | else /* more than 1 block */ 247 | { 248 | /* process the block in context buffer */ 249 | copy_len = HASH_BLOCK_SIZE - c->last.used; 250 | memcpy(&c->last.buf[c->last.used], data, copy_len); 251 | MD5_ProcessBlock(c, &c->last.buf); 252 | 253 | c->total += HASH_BLOCK_SIZE; 254 | 255 | data = (uint8_t *)data + copy_len; 256 | len -= copy_len; 257 | 258 | /* reset context buffer */ 259 | memset(&c->last.buf[0], 0, HASH_BLOCK_SIZE); 260 | c->last.used = 0; 261 | } 262 | } 263 | 264 | /* less than 1 block, copy to context buffer */ 265 | if (len < HASH_BLOCK_SIZE) 266 | { 267 | memcpy(&c->last.buf[c->last.used], data, len); 268 | c->last.used += len; 269 | 270 | return ERR_OK; 271 | } 272 | else 273 | { 274 | /* process data blocks */ 275 | while (len >= HASH_BLOCK_SIZE) 276 | { 277 | MD5_ProcessBlock(c, data); 278 | c->total += HASH_BLOCK_SIZE; 279 | 280 | data = (uint8_t *)data + HASH_BLOCK_SIZE; 281 | len -= HASH_BLOCK_SIZE; 282 | } 283 | 284 | /* copy rest data to context buffer */ 285 | memcpy(&c->last.buf[0], data, len); 286 | c->last.used = len; 287 | } 288 | 289 | return ERR_OK; 290 | } 291 | 292 | int MD5_Final(unsigned char *md, MD5_CTX *c) 293 | { 294 | uint32_t *temp; 295 | 296 | if ((NULL == c) || (NULL == md)) 297 | { 298 | return ERR_INV_PARAM; 299 | } 300 | 301 | /* Last block should be less thant HASH_BLOCK_SIZE - HASH_LEN_SIZE */ 302 | if (c->last.used >= (HASH_BLOCK_SIZE - HASH_LEN_SIZE)) 303 | { 304 | c->total += c->last.used; 305 | 306 | /* one more block */ 307 | c->last.buf[c->last.used] = HASH_PADDING_PATTERN; 308 | c->last.used++; 309 | 310 | memset(&c->last.buf[c->last.used], 0, HASH_BLOCK_SIZE - c->last.used); 311 | MD5_ProcessBlock(c, &c->last.buf); 312 | 313 | memset(&c->last.buf[0], 0, HASH_BLOCK_SIZE - HASH_LEN_SIZE); 314 | c->last.used = 0; 315 | 316 | /* save length */ 317 | temp = (uint32_t *)&(c->last.buf[HASH_LEN_OFFSET]); 318 | temp[0] = htole32((c->total << 3) & 0xFFFFFFFF); 319 | temp[1] = htole32(((c->total << 3) >> 32) & 0xFFFFFFFF); 320 | MD5_ProcessBlock(c, &c->last.buf); 321 | } 322 | else /* 0 <= last.used < HASH_BLOCK_SIZE - HASH_LEN_SIZE */ 323 | { 324 | c->total += c->last.used; 325 | 326 | /* one more block */ 327 | c->last.buf[c->last.used] = HASH_PADDING_PATTERN; 328 | c->last.used++; 329 | 330 | /* padding 0s */ 331 | memset(&c->last.buf[c->last.used], 0, HASH_BLOCK_SIZE - HASH_LEN_SIZE - c->last.used); 332 | 333 | /* save length */ 334 | temp = (uint32_t *)&(c->last.buf[HASH_LEN_OFFSET]); 335 | temp[0] = htole32((c->total << 3) & 0xFFFFFFFF); 336 | temp[1] = htole32(((c->total << 3) >> 32) & 0xFFFFFFFF); 337 | MD5_ProcessBlock(c, &c->last.buf); 338 | } 339 | 340 | /* LE format, different from SHA family(big endian) */ 341 | temp = (uint32_t *)md; 342 | temp[0] = htole32(c->hash.a); 343 | temp[1] = htole32(c->hash.b); 344 | temp[2] = htole32(c->hash.c); 345 | temp[3] = htole32(c->hash.d); 346 | 347 | return ERR_OK; 348 | } 349 | 350 | unsigned char *MD5(const unsigned char *d, unsigned long n, unsigned char *md) 351 | { 352 | MD5_CTX c; 353 | 354 | if ((NULL == d) || (NULL == md)) 355 | { 356 | return NULL; 357 | } 358 | 359 | MD5_Init(&c); 360 | MD5_Update(&c, d, n); 361 | MD5_Final(md, &c); 362 | 363 | return md; 364 | } 365 | -------------------------------------------------------------------------------- /md5/md5.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: md5.h 3 | * @ description: header file for md5.c 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #ifndef __ROCKY_MD5__H 8 | #define __ROCKY_MD5__H 9 | 10 | #define ERR_OK 0 11 | #define ERR_ERR -1 /* generic error */ 12 | #define ERR_INV_PARAM -2 /* invalid parameter */ 13 | #define ERR_TOO_LONG -3 /* too long */ 14 | #define ERR_STATE_ERR -4 /* state error */ 15 | 16 | typedef unsigned char uint8_t; 17 | typedef unsigned short uint16_t; 18 | typedef unsigned int uint32_t; 19 | typedef unsigned long long uint64_t; 20 | 21 | typedef struct md5_context { 22 | /* message total length in bytes */ 23 | uint64_t total; 24 | 25 | /* intermedia hash value for each block */ 26 | struct { 27 | uint32_t a; 28 | uint32_t b; 29 | uint32_t c; 30 | uint32_t d; 31 | uint32_t e; 32 | }hash; 33 | 34 | /* last block */ 35 | struct { 36 | uint32_t used; /* used bytes */ 37 | uint8_t buf[64]; /* block data buffer */ 38 | }last; 39 | }MD5_CTX; 40 | 41 | /* https://www.openssl.org/docs/man1.1.0/man3/MD5_Init.html */ 42 | 43 | int MD5_Init(MD5_CTX *c); 44 | int MD5_Update(MD5_CTX *c, const void *data, unsigned long len); 45 | int MD5_Final(unsigned char *md, MD5_CTX *c); 46 | unsigned char *MD5(const unsigned char *d, unsigned long n, unsigned char *md); 47 | #endif 48 | -------------------------------------------------------------------------------- /md5/md5test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: md5test.c 3 | * @ description: test tool for md5 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #include /* printf, fopen, fread, fclose... */ 8 | #include /* exit */ 9 | #include /* strlen */ 10 | #include /* getopt */ 11 | 12 | #include "md5.h" 13 | 14 | #define HASH_DIGEST_SIZE 16 /* md5 digest size */ 15 | #define FILE_BLOCK_SIZE 1024 16 | 17 | /* 18 | * Print a usage message 19 | */ 20 | void usage(const char *argv0) 21 | { 22 | fprintf(stderr, 23 | "Usage:\n" 24 | "Common options: [-x|-f file|-s string|-h]\n" 25 | "Hash a string:\n" 26 | "\t%s -s string\n" 27 | "Hash a file:\n" 28 | "\t%s -f file [-k key]\n" 29 | "-x\tInternal string hash test\n" 30 | "-h\tDisplay this message\n" 31 | , argv0, argv0); 32 | exit(1); 33 | } 34 | 35 | /* 36 | * Print a message digest in hexadecimal 37 | */ 38 | static int print_digest(unsigned char *digest) 39 | { 40 | uint32_t i; 41 | 42 | for (i = 0; i < HASH_DIGEST_SIZE; i++) 43 | { 44 | printf ("%02x", digest[i]); 45 | } 46 | 47 | return 0; 48 | } 49 | 50 | struct HASH_ITEM { 51 | char *str; 52 | uint32_t len; 53 | unsigned char md[HASH_DIGEST_SIZE*2]; 54 | } hashes[] = 55 | { 56 | { /* 0 */ 57 | "", 58 | 0, 59 | "d41d8cd98f00b204e9800998ecf8427e" 60 | }, 61 | { /* 1 */ 62 | "a", 63 | 1, 64 | "0cc175b9c0f1b6a831c399e269772661" 65 | }, 66 | { /* 2 */ 67 | "abc", 68 | 3, 69 | "900150983cd24fb0d6963f7d28e17f72" 70 | }, 71 | { /* 3 */ 72 | "message digest", 73 | 14, 74 | "f96b697d7cb7938d525a2f31aaf161d0" 75 | }, 76 | { /* 4 */ 77 | "abcdefghijklmnopqrstuvwxyz", 78 | 26, 79 | "c3fcd3d76192e4007dfb496cca67e13b" 80 | }, 81 | { /* 5 */ 82 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 83 | 62, 84 | "d174ab98d277d9f5a5611c2c9f419d9f" 85 | }, 86 | { /* 6 */ 87 | "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 88 | 80, 89 | "57edf4a22be3c955ac49da2e2107b67a" 90 | }, 91 | }; 92 | 93 | /* 94 | * Internal digest tests 95 | */ 96 | static int internal_digest_tests(const char *argv0) 97 | { 98 | unsigned char digest[HASH_DIGEST_SIZE]; 99 | struct HASH_ITEM *item; 100 | 101 | printf ("Internal hash tests for %s:\n", argv0); 102 | 103 | for (item=&hashes[0]; item<(&hashes[0]+sizeof(hashes)/sizeof(hashes[0])); item++) 104 | { 105 | printf("%s(\"%s\")\n", argv0, item->str); 106 | MD5((unsigned char*)item->str, item->len, digest); 107 | printf(" Expect: %s\n", item->md); 108 | printf(" Result: "); 109 | print_digest(digest); 110 | printf("\n\n"); 111 | } 112 | 113 | return 0; 114 | } 115 | 116 | /* 117 | * Hash a string and print the digest 118 | */ 119 | static int digest_string(const char *argv0, const unsigned char *string, uint32_t len) 120 | { 121 | unsigned char digest[HASH_DIGEST_SIZE]; 122 | 123 | printf("%s(\"%s\") = ", argv0, string); 124 | 125 | MD5(string, len, digest); 126 | 127 | print_digest(digest); 128 | printf("\n"); 129 | 130 | return 0; 131 | } 132 | 133 | /* 134 | * Hash a file and print the digest 135 | */ 136 | static int digest_file(const char *argv0, const char *filename) 137 | { 138 | MD5_CTX c; 139 | FILE *f; 140 | 141 | unsigned char digest[HASH_DIGEST_SIZE]; 142 | unsigned char buf[FILE_BLOCK_SIZE]; 143 | 144 | int len = 0; 145 | int rc = 0; 146 | 147 | f = fopen(filename, "rb"); 148 | if (NULL == f) 149 | { 150 | printf("Can't open file %s\n", filename); 151 | rc = -1; 152 | } 153 | else 154 | { 155 | printf("%s(%s) = ", argv0, filename); 156 | 157 | MD5_Init(&c); 158 | while ((len = fread(buf, 1, FILE_BLOCK_SIZE, f))) 159 | { 160 | MD5_Update(&c, buf, len); 161 | } 162 | MD5_Final(digest, &c); 163 | 164 | fclose(f); 165 | 166 | print_digest(digest); 167 | printf("\n"); 168 | 169 | rc = 0; 170 | } 171 | 172 | return rc; 173 | } 174 | 175 | /* 176 | * Hash the standard input and prints the digest 177 | */ 178 | static void digest_stdin(const char *argv0) 179 | { 180 | MD5_CTX c; 181 | 182 | int len; 183 | unsigned char digest[HASH_DIGEST_SIZE]; 184 | unsigned char buf[HASH_DIGEST_SIZE]; 185 | 186 | MD5_Init(&c); 187 | while ((len = fread(buf, 1, HASH_DIGEST_SIZE, stdin))) 188 | { 189 | MD5_Update(&c, buf, len); 190 | } 191 | MD5_Final(digest, &c); 192 | 193 | printf("%s(stdin) = ", argv0); 194 | print_digest(digest); 195 | printf("\n"); 196 | } 197 | 198 | /* 199 | * $ md5 -h 200 | * Usage: 201 | * Common options: [-x|-f file|-s string|-h] 202 | * Hash a string: 203 | * md5 -s string 204 | * Hash a file: 205 | * md5 -f file [-k key] 206 | * -x Internal string hash test 207 | * -h Display this message 208 | */ 209 | int main(int argc, char *argv[]) 210 | { 211 | int ch; 212 | int hash_internal = 0; 213 | int hash_str = 0; 214 | int hash_file = 0; 215 | int hash_stdin = 0; 216 | 217 | char *str = NULL; 218 | uint32_t len = 0; 219 | 220 | char *filename = NULL; 221 | 222 | while ((ch = getopt(argc, argv, "s:f:xh")) != -1) 223 | { 224 | switch(ch) 225 | { 226 | case 'x': 227 | hash_internal = 1; 228 | break; 229 | case 's': 230 | hash_str = 1; 231 | str = optarg; 232 | len = strlen(str); 233 | break; 234 | case 'f': 235 | hash_file = 1; 236 | filename = optarg; 237 | break; 238 | case 'h': 239 | default: /* '?' */ 240 | usage(argv[0]); 241 | break; 242 | } 243 | } 244 | 245 | if (argc == 1) 246 | { 247 | hash_stdin = 1; 248 | } 249 | 250 | if (hash_internal) 251 | { 252 | internal_digest_tests(argv[0]); 253 | } 254 | 255 | if (hash_str) 256 | { 257 | digest_string(argv[0], (unsigned char *)str, len); 258 | } 259 | 260 | if (hash_file) 261 | { 262 | digest_file(argv[0], filename); 263 | } 264 | 265 | if (hash_stdin) 266 | { 267 | digest_stdin(argv[0]); 268 | } 269 | 270 | return 0; 271 | } 272 | -------------------------------------------------------------------------------- /md5/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "utils.h" 3 | 4 | #define DUMP_LINE_SIZE 16 5 | int print_buffer(const void *buf, unsigned long len, const char *indent) 6 | { 7 | unsigned long i = 0; 8 | for (i=0; i> 8) & 0xff) \ 13 | | (((x) & 0xff) << 8))) 14 | 15 | /* Swap bytes in 32 bit value. */ 16 | #define __bswap_32(x) \ 17 | ((((x) & 0xff000000) >> 24) \ 18 | | (((x) & 0x00ff0000) >> 8) \ 19 | | (((x) & 0x0000ff00) << 8) \ 20 | | (((x) & 0x000000ff) << 24)) 21 | 22 | /* Swap bytes in 64 bit value. */ 23 | #define __bswap_64(x) \ 24 | ((((x) & 0xff00000000000000ull) >> 56) \ 25 | | (((x) & 0x00ff000000000000ull) >> 40) \ 26 | | (((x) & 0x0000ff0000000000ull) >> 24) \ 27 | | (((x) & 0x000000ff00000000ull) >> 8) \ 28 | | (((x) & 0x00000000ff000000ull) << 8) \ 29 | | (((x) & 0x0000000000ff0000ull) << 24) \ 30 | | (((x) & 0x000000000000ff00ull) << 40) \ 31 | | (((x) & 0x00000000000000ffull) << 56)) 32 | 33 | #if (ENDIANNESS == ENDIAN_LITTLE) 34 | #define htole16(x) (x) 35 | #define htole32(x) (x) 36 | #define htole64(x) (x) 37 | 38 | #define htobe16(x) __bswap_16(x) 39 | #define htobe32(x) __bswap_32(x) 40 | #define htobe64(x) __bswap_64(x) 41 | #else 42 | #define htole16(x) __bswap_16(x) 43 | #define htole32(x) __bswap_32(x) 44 | #define htole64(x) __bswap_64(x) 45 | 46 | #define htobe16(x) (x) 47 | #define htobe32(x) (x) 48 | #define htobe64(x) (x) 49 | #endif 50 | 51 | #define le16toh(x) htole16(x) 52 | #define le32toh(x) htole32(x) 53 | #define le64toh(x) htole64(x) 54 | 55 | #define be16toh(x) htobe16(x) 56 | #define be32toh(x) htobe32(x) 57 | #define be64toh(x) htobe64(x) 58 | 59 | int print_buffer(const void *buf, unsigned long len, const char *indent); 60 | 61 | #endif -------------------------------------------------------------------------------- /sha1/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean sha1 test 2 | 3 | CROSS_COMPILE= 4 | 5 | CC = $(CROSS_COMPILE)gcc 6 | STRIP = $(CROSS_COMPILE)strip 7 | AR = $(CROSS_COMPILE)ar 8 | ARFLAGS = crs 9 | 10 | RM = rm 11 | RMFLAGS = -rf 12 | 13 | LIBS = 14 | INCLUDE = 15 | CFLAGS = -Wall -g -O2 16 | 17 | SRCS = utils.c sha1.c sha1test.c 18 | TARGET = sha1 19 | 20 | OBJS = $(SRCS:.c=.o) 21 | 22 | all: sha1 test 23 | 24 | %.o: %.c 25 | $(CC) $(CFLAGS) -c $< -o $@ 26 | 27 | $(TARGET): $(OBJS) 28 | $(CC) $(CFLAGS) $(OBJS) -o $@ $(LIBS) $(INCLUDE) 29 | # $(STRIP) --strip-all $(TARGET) 30 | 31 | test: $(TARGET) 32 | @echo 33 | @echo "Run Test..." 34 | ./$(TARGET) -x 35 | 36 | clean: 37 | $(RM) $(RMFLAGS) $(TARGET) $(OBJS) 38 | -------------------------------------------------------------------------------- /sha1/sha1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: sha1.c 3 | * @ description: implementation for the SHA1 Secure Hash Algorithm 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #include 8 | #include 9 | 10 | #include "utils.h" 11 | #include "sha1.h" 12 | 13 | //#define DEBUG 14 | 15 | #ifdef DEBUG 16 | #define DBG(...) printf(__VA_ARGS__) 17 | #define DUMP_BLOCK_DATA 1 18 | #define DUMP_BLOCK_HASH 1 19 | #define DUMP_ROUND_DATA 1 20 | #else 21 | #define DBG(...) 22 | #define DUMP_BLOCK_DATA 0 23 | #define DUMP_BLOCK_HASH 0 24 | #define DUMP_ROUND_DATA 0 25 | #endif 26 | 27 | #define SHA1_BLOCK_SIZE 64 /* 512 bits = 64 Bytes */ 28 | #define SHA1_LEN_SIZE 8 /* 64 bits = 8 bytes */ 29 | #define SHA1_LEN_OFFSET (SHA1_BLOCK_SIZE - SHA1_LEN_SIZE) 30 | #define SHA1_DIGEST_SIZE 20 /* 160 bits = 20 bytes */ 31 | 32 | #define SHA1_PADDING_PATTERN 0x80 33 | #define SHA1_ROUND_NUM 80 34 | 35 | #define HASH_BLOCK_SIZE SHA1_BLOCK_SIZE 36 | #define HASH_LEN_SIZE SHA1_LEN_SIZE 37 | #define HASH_LEN_OFFSET SHA1_LEN_OFFSET 38 | #define HASH_DIGEST_SIZE SHA1_DIGEST_SIZE 39 | 40 | #define HASH_PADDING_PATTERN SHA1_PADDING_PATTERN 41 | #define HASH_ROUND_NUM SHA1_ROUND_NUM 42 | 43 | typedef uint32_t (*sha1_func)(uint32_t x, uint32_t y, uint32_t z); 44 | 45 | /* SHA1 Round Constants */ 46 | static uint32_t K[4] = 47 | { 48 | 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 49 | }; 50 | 51 | /* ROTate Left (circular left shift) */ 52 | static uint32_t ROTL(uint32_t x, uint8_t shift) 53 | { 54 | return (x << shift) | (x >> (32 - shift)); 55 | } 56 | 57 | /* Ch ... choose */ 58 | static uint32_t Ch(uint32_t x, uint32_t y, uint32_t z) 59 | { 60 | //DBG(" Ch(0x%08x, 0x%08x, 0x%08x);\n", x, y, z); 61 | return (x & y) ^ (~x & z) ; 62 | } 63 | 64 | /* Par ... parity */ 65 | static uint32_t Parity(uint32_t x, uint32_t y, uint32_t z) 66 | { 67 | //DBG("Parity(0x%08x, 0x%08x, 0x%08x);\n", x, y, z); 68 | return x ^ y ^ z; 69 | } 70 | 71 | /* Maj ... majority */ 72 | static uint32_t Maj(uint32_t x, uint32_t y, uint32_t z) 73 | { 74 | //DBG(" Maj(0x%08x, 0x%08x, 0x%08x);\n", x, y, z); 75 | return (x & y) ^ (x & z) ^ (y & z); 76 | } 77 | 78 | /* SHA1 Functions */ 79 | static sha1_func F[4] = 80 | { 81 | Ch, Parity, Maj, Parity 82 | }; 83 | 84 | int SHA1_Init(SHA_CTX *c) 85 | { 86 | if (NULL == c) 87 | { 88 | return ERR_INV_PARAM; 89 | } 90 | 91 | memset(c, 0, sizeof(SHA_CTX)); 92 | 93 | c->hash.a = 0x67452301; 94 | c->hash.b = 0xEFCDAB89; 95 | c->hash.c = 0x98BADCFE; 96 | c->hash.d = 0x10325476; 97 | c->hash.e = 0xC3D2E1F0; 98 | 99 | c->total = 0; 100 | c->last.used = 0; 101 | 102 | return ERR_OK; 103 | } 104 | 105 | static int SHA1_PrepareScheduleWord(const uint32_t *block, uint32_t *W) 106 | { 107 | uint32_t t; 108 | 109 | if ((NULL == block) || (NULL == W)) 110 | { 111 | return ERR_INV_PARAM; 112 | } 113 | 114 | for (t=0; ttotal/HASH_BLOCK_SIZE); 140 | DBG(" DATA:\n"); 141 | print_buffer(block, HASH_BLOCK_SIZE, " "); 142 | #endif 143 | 144 | /* prepare schedule word */ 145 | SHA1_PrepareScheduleWord(block, W); 146 | 147 | a = ctx->hash.a; 148 | b = ctx->hash.b; 149 | c = ctx->hash.c; 150 | d = ctx->hash.d; 151 | e = ctx->hash.e; 152 | 153 | #if (DUMP_BLOCK_HASH == 1) 154 | DBG(" IV: %08x %08x %08x %08x %08x\n", 155 | ctx->hash.a, ctx->hash.b, ctx->hash.c, ctx->hash.d, ctx->hash.e); 156 | #endif 157 | 158 | for (t=0; thash.a += a; 174 | ctx->hash.b += b; 175 | ctx->hash.c += c; 176 | ctx->hash.d += d; 177 | ctx->hash.e += e; 178 | 179 | #if (DUMP_BLOCK_HASH == 1) 180 | DBG(" HASH: %08x %08x %08x %08x %08x\n", 181 | ctx->hash.a, ctx->hash.b, ctx->hash.c, ctx->hash.d, ctx->hash.e); 182 | #endif 183 | 184 | return ERR_OK; 185 | } 186 | 187 | int SHA1_Update(SHA_CTX *c, const void *data, size_t len) 188 | { 189 | uint32_t copy_len = 0; 190 | 191 | if ((NULL == c) || (NULL == data)) 192 | { 193 | return ERR_INV_PARAM; 194 | } 195 | 196 | /* has used data */ 197 | if (c->last.used != 0) 198 | { 199 | /* less than 1 block in total, combine data */ 200 | if (c->last.used + len < HASH_BLOCK_SIZE) 201 | { 202 | memcpy(&c->last.buf[c->last.used], data, len); 203 | c->last.used += len; 204 | 205 | return ERR_OK; 206 | } 207 | else /* more than 1 block */ 208 | { 209 | /* process the block in context buffer */ 210 | copy_len = HASH_BLOCK_SIZE - c->last.used; 211 | memcpy(&c->last.buf[c->last.used], data, copy_len); 212 | SHA1_ProcessBlock(c, &c->last.buf); 213 | c->total += HASH_BLOCK_SIZE; 214 | 215 | data = (uint8_t *)data + copy_len; 216 | len -= copy_len; 217 | 218 | /* reset context buffer */ 219 | memset(&c->last.buf[0], 0, HASH_BLOCK_SIZE); 220 | c->last.used = 0; 221 | } 222 | } 223 | 224 | /* less than 1 block, copy to context buffer */ 225 | if (len < HASH_BLOCK_SIZE) 226 | { 227 | memcpy(&c->last.buf[c->last.used], data, len); 228 | c->last.used += len; 229 | 230 | return ERR_OK; 231 | } 232 | else 233 | { 234 | /* process data blocks */ 235 | while (len >= HASH_BLOCK_SIZE) 236 | { 237 | SHA1_ProcessBlock(c, data); 238 | c->total += HASH_BLOCK_SIZE; 239 | 240 | data = (uint8_t *)data + HASH_BLOCK_SIZE; 241 | len -= HASH_BLOCK_SIZE; 242 | } 243 | 244 | /* copy rest data to context buffer */ 245 | memcpy(&c->last.buf[0], data, len); 246 | c->last.used = len; 247 | } 248 | 249 | return ERR_OK; 250 | } 251 | 252 | int SHA1_Final(unsigned char *md, SHA_CTX *c) 253 | { 254 | uint32_t *temp; 255 | //uint64_t *buf; 256 | 257 | if ((NULL == c) || (NULL == md)) 258 | { 259 | return ERR_INV_PARAM; 260 | } 261 | 262 | /* Last block should be less thant HASH_BLOCK_SIZE - HASH_LEN_SIZE */ 263 | if (c->last.used >= (HASH_BLOCK_SIZE - HASH_LEN_SIZE)) 264 | { 265 | c->total += c->last.used; 266 | 267 | /* one more block */ 268 | c->last.buf[c->last.used] = HASH_PADDING_PATTERN; 269 | c->last.used++; 270 | 271 | memset(&c->last.buf[c->last.used], 0, HASH_BLOCK_SIZE - c->last.used); 272 | SHA1_ProcessBlock(c, &c->last.buf); 273 | 274 | memset(&c->last.buf[0], 0, HASH_BLOCK_SIZE - HASH_LEN_SIZE); 275 | c->last.used = 0; 276 | 277 | /* save length */ 278 | //buf = (uint64_t *)&(c->last.buf[HASH_LEN_OFFSET]); 279 | //*buf = htobe64(c->total << 3); 280 | temp = (uint32_t *)&(c->last.buf[HASH_LEN_OFFSET]); 281 | temp[0] = htobe32((c->total << 3) >> 32 & 0xFFFFFFFF); 282 | temp[1] = htobe32((c->total << 3) & 0xFFFFFFFF); 283 | 284 | SHA1_ProcessBlock(c, &c->last.buf); 285 | } 286 | else /* 0 <= last.used < HASH_BLOCK_SIZE - HASH_LEN_SIZE */ 287 | { 288 | c->total += c->last.used; 289 | 290 | /* one more block */ 291 | c->last.buf[c->last.used] = HASH_PADDING_PATTERN; 292 | c->last.used++; 293 | 294 | /* padding 0s */ 295 | memset(&c->last.buf[c->last.used], 0, HASH_BLOCK_SIZE - HASH_LEN_SIZE - c->last.used); 296 | 297 | /* save length */ 298 | //buf = (uint64_t *)&(c->last.buf[HASH_LEN_OFFSET]); 299 | //*buf = htobe64(c->total << 3); 300 | temp = (uint32_t *)&(c->last.buf[HASH_LEN_OFFSET]); 301 | temp[0] = htobe32((c->total << 3) >> 32 & 0xFFFFFFFF); 302 | temp[1] = htobe32((c->total << 3) & 0xFFFFFFFF); 303 | 304 | SHA1_ProcessBlock(c, &c->last.buf); 305 | } 306 | 307 | temp = (uint32_t *)md; 308 | temp[0] = htobe32(c->hash.a); 309 | temp[1] = htobe32(c->hash.b); 310 | temp[2] = htobe32(c->hash.c); 311 | temp[3] = htobe32(c->hash.d); 312 | temp[4] = htobe32(c->hash.e); 313 | 314 | return ERR_OK; 315 | } 316 | 317 | unsigned char *SHA1(const unsigned char *d, size_t n, unsigned char *md) 318 | { 319 | SHA_CTX c; 320 | 321 | if ((NULL == d) || (NULL == md)) 322 | { 323 | return NULL; 324 | } 325 | 326 | SHA1_Init(&c); 327 | SHA1_Update(&c, d, n); 328 | SHA1_Final(md, &c); 329 | 330 | return md; 331 | } 332 | -------------------------------------------------------------------------------- /sha1/sha1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: sha1.h 3 | * @ description: header file for sha1.c 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #ifndef __ROCKY_SHA1__H 8 | #define __ROCKY_SHA1__H 9 | 10 | #define ERR_OK 0 11 | #define ERR_ERR -1 /* generic error */ 12 | #define ERR_INV_PARAM -2 /* invalid parameter */ 13 | #define ERR_TOO_LONG -3 /* too long */ 14 | #define ERR_STATE_ERR -4 /* state error */ 15 | 16 | typedef unsigned char uint8_t; 17 | typedef unsigned short uint16_t; 18 | typedef unsigned int uint32_t; 19 | typedef unsigned long long uint64_t; 20 | 21 | typedef struct sha1_context { 22 | /* message total length in bytes */ 23 | uint64_t total; 24 | 25 | /* intermedia hash value for each block */ 26 | struct { 27 | uint32_t a; 28 | uint32_t b; 29 | uint32_t c; 30 | uint32_t d; 31 | uint32_t e; 32 | }hash; 33 | 34 | /* last block */ 35 | struct { 36 | uint32_t used; /* used bytes */ 37 | uint8_t buf[64]; /* block data buffer */ 38 | }last; 39 | }SHA_CTX; 40 | 41 | /* https://www.openssl.org/docs/man1.1.1/man3/SHA256_Final.html */ 42 | int SHA1_Init(SHA_CTX *c); 43 | int SHA1_Update(SHA_CTX *c, const void *data, size_t len); 44 | int SHA1_Final(unsigned char *md, SHA_CTX *c); 45 | unsigned char *SHA1(const unsigned char *d, size_t n, unsigned char *md); 46 | #endif 47 | -------------------------------------------------------------------------------- /sha1/sha1test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: sha1test.c 3 | * @ description: test tool for sha1 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #include /* printf, fopen, fread, fclose... */ 8 | #include /* exit */ 9 | #include /* strlen */ 10 | #include /* getopt */ 11 | 12 | #include "sha1.h" 13 | 14 | #define HASH_DIGEST_SIZE 20 /* sha1 digest size */ 15 | #define FILE_BLOCK_SIZE 1024 16 | 17 | /* 18 | * Print a usage message 19 | */ 20 | void usage(const char *argv0) 21 | { 22 | fprintf(stderr, 23 | "Usage:\n" 24 | "Common options: [-x|-f file|-s string|-h]\n" 25 | "Hash a string:\n" 26 | "\t%s -s string\n" 27 | "Hash a file:\n" 28 | "\t%s -f file [-k key]\n" 29 | "-x\tInternal string hash test\n" 30 | "-h\tDisplay this message\n" 31 | , argv0, argv0); 32 | exit(1); 33 | } 34 | 35 | /* 36 | * Print a message digest in hexadecimal 37 | */ 38 | static int print_digest(unsigned char *digest) 39 | { 40 | uint32_t i; 41 | 42 | for (i = 0; i < HASH_DIGEST_SIZE; i++) 43 | { 44 | printf ("%02x", digest[i]); 45 | } 46 | 47 | return 0; 48 | } 49 | 50 | struct HASH_ITEM { 51 | char *str; 52 | uint32_t len; 53 | unsigned char md[HASH_DIGEST_SIZE*2]; 54 | } hashes[] = 55 | { 56 | { /* 0 */ 57 | "", 58 | 0, 59 | "da39a3ee5e6b4b0d3255bfef95601890afd80709" 60 | }, 61 | { /* 1 */ 62 | "a", 63 | 1, 64 | "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8" 65 | }, 66 | { /* 2 */ 67 | "abc", 68 | 3, 69 | "a9993e364706816aba3e25717850c26c9cd0d89d" 70 | }, 71 | { /* 3 */ 72 | "message digest", 73 | 14, 74 | "c12252ceda8be8994d5fa0290a47231c1d16aae3" 75 | }, 76 | { /* 4 */ 77 | "abcdefghijklmnopqrstuvwxyz", 78 | 26, 79 | "32d10c7b8cf96570ca04ce37f2a19d84240d3a89" 80 | }, 81 | { /* 5 */ 82 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 83 | 62, 84 | "761c457bf73b14d27e9e9265c46f4b4dda11f940" 85 | }, 86 | { /* 6 */ 87 | "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 88 | 80, 89 | "50abf5706a150990a08b2c5ea40fa0e585554732" 90 | }, 91 | }; 92 | 93 | /* 94 | * Internal digest tests 95 | */ 96 | static int internal_digest_tests(const char *argv0) 97 | { 98 | unsigned char digest[HASH_DIGEST_SIZE]; 99 | struct HASH_ITEM *item; 100 | 101 | printf ("Internal hash tests for %s:\n", argv0); 102 | 103 | for (item=&hashes[0]; item<(&hashes[0]+sizeof(hashes)/sizeof(hashes[0])); item++) 104 | { 105 | printf("%s(\"%s\")\n", argv0, item->str); 106 | SHA1((unsigned char*)item->str, item->len, digest); 107 | printf(" Expect: %s\n", item->md); 108 | printf(" Result: "); 109 | print_digest(digest); 110 | printf("\n\n"); 111 | } 112 | 113 | return 0; 114 | } 115 | 116 | /* 117 | * Hash a string and print the digest 118 | */ 119 | static int digest_string(const char *argv0, const unsigned char *string, uint32_t len) 120 | { 121 | unsigned char digest[HASH_DIGEST_SIZE]; 122 | 123 | printf("%s(\"%s\") = ", argv0, string); 124 | 125 | SHA1(string, len, digest); 126 | 127 | print_digest(digest); 128 | printf("\n"); 129 | 130 | return 0; 131 | } 132 | 133 | /* 134 | * Hash a file and print the digest 135 | */ 136 | static int digest_file(const char *argv0, const char *filename) 137 | { 138 | SHA_CTX c; 139 | FILE *f; 140 | 141 | unsigned char digest[HASH_DIGEST_SIZE]; 142 | unsigned char buf[FILE_BLOCK_SIZE]; 143 | 144 | int len = 0; 145 | int rc = 0; 146 | 147 | f = fopen(filename, "rb"); 148 | if (NULL == f) 149 | { 150 | printf("Can't open file %s\n", filename); 151 | rc = -1; 152 | } 153 | else 154 | { 155 | printf("%s(%s) = ", argv0, filename); 156 | 157 | SHA1_Init(&c); 158 | while ((len = fread(buf, 1, FILE_BLOCK_SIZE, f))) 159 | { 160 | SHA1_Update(&c, buf, len); 161 | } 162 | SHA1_Final(digest, &c); 163 | 164 | fclose(f); 165 | 166 | print_digest(digest); 167 | printf("\n"); 168 | 169 | rc = 0; 170 | } 171 | 172 | return rc; 173 | } 174 | 175 | /* 176 | * Hash the standard input and prints the digest 177 | */ 178 | static void digest_stdin(const char *argv0) 179 | { 180 | SHA_CTX c; 181 | 182 | int len; 183 | unsigned char digest[HASH_DIGEST_SIZE]; 184 | unsigned char buf[HASH_DIGEST_SIZE]; 185 | 186 | SHA1_Init(&c); 187 | while ((len = fread(buf, 1, HASH_DIGEST_SIZE, stdin))) 188 | { 189 | SHA1_Update(&c, buf, len); 190 | } 191 | SHA1_Final(digest, &c); 192 | 193 | printf("%s(stdin) = ", argv0); 194 | print_digest(digest); 195 | printf("\n"); 196 | } 197 | 198 | /* 199 | * $ sha1 -h 200 | * Usage: 201 | * Common options: [-x|-f file|-s string|-h] 202 | * Hash a string: 203 | * sha1 -s string 204 | * Hash a file: 205 | * sha1 -f file [-k key] 206 | * -x Internal string hash test 207 | * -h Display this message 208 | */ 209 | int main(int argc, char *argv[]) 210 | { 211 | int ch; 212 | int hash_internal = 0; 213 | int hash_str = 0; 214 | int hash_file = 0; 215 | int hash_stdin = 0; 216 | 217 | char *str = NULL; 218 | uint32_t len = 0; 219 | 220 | char *filename = NULL; 221 | 222 | while ((ch = getopt(argc, argv, "s:f:xh")) != -1) 223 | { 224 | switch(ch) 225 | { 226 | case 'x': 227 | hash_internal = 1; 228 | break; 229 | case 's': 230 | hash_str = 1; 231 | str = optarg; 232 | len = strlen(str); 233 | break; 234 | case 'f': 235 | hash_file = 1; 236 | filename = optarg; 237 | break; 238 | case 'h': 239 | default: /* '?' */ 240 | usage(argv[0]); 241 | break; 242 | } 243 | } 244 | 245 | if (argc == 1) 246 | { 247 | hash_stdin = 1; 248 | } 249 | 250 | if (hash_internal) 251 | { 252 | internal_digest_tests(argv[0]); 253 | } 254 | 255 | if (hash_str) 256 | { 257 | digest_string(argv[0], (unsigned char *)str, len); 258 | } 259 | 260 | if (hash_file) 261 | { 262 | digest_file(argv[0], filename); 263 | } 264 | 265 | if (hash_stdin) 266 | { 267 | digest_stdin(argv[0]); 268 | } 269 | 270 | return 0; 271 | } 272 | -------------------------------------------------------------------------------- /sha1/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "utils.h" 3 | 4 | #define DUMP_LINE_SIZE 16 5 | int print_buffer(const void *buf, unsigned long len, const char *indent) 6 | { 7 | unsigned long i = 0; 8 | for (i=0; i> 8) & 0xff) \ 13 | | (((x) & 0xff) << 8))) 14 | 15 | /* Swap bytes in 32 bit value. */ 16 | #define __bswap_32(x) \ 17 | ((((x) & 0xff000000) >> 24) \ 18 | | (((x) & 0x00ff0000) >> 8) \ 19 | | (((x) & 0x0000ff00) << 8) \ 20 | | (((x) & 0x000000ff) << 24)) 21 | 22 | /* Swap bytes in 64 bit value. */ 23 | #define __bswap_64(x) \ 24 | ((((x) & 0xff00000000000000ull) >> 56) \ 25 | | (((x) & 0x00ff000000000000ull) >> 40) \ 26 | | (((x) & 0x0000ff0000000000ull) >> 24) \ 27 | | (((x) & 0x000000ff00000000ull) >> 8) \ 28 | | (((x) & 0x00000000ff000000ull) << 8) \ 29 | | (((x) & 0x0000000000ff0000ull) << 24) \ 30 | | (((x) & 0x000000000000ff00ull) << 40) \ 31 | | (((x) & 0x00000000000000ffull) << 56)) 32 | 33 | #if (ENDIANNESS == ENDIAN_LITTLE) 34 | #define htole16(x) (x) 35 | #define htole32(x) (x) 36 | #define htole64(x) (x) 37 | 38 | #define htobe16(x) __bswap_16(x) 39 | #define htobe32(x) __bswap_32(x) 40 | #define htobe64(x) __bswap_64(x) 41 | #else 42 | #define htole16(x) __bswap_16(x) 43 | #define htole32(x) __bswap_32(x) 44 | #define htole64(x) __bswap_64(x) 45 | 46 | #define htobe16(x) (x) 47 | #define htobe32(x) (x) 48 | #define htobe64(x) (x) 49 | #endif 50 | 51 | #define le16toh(x) htole16(x) 52 | #define le32toh(x) htole32(x) 53 | #define le64toh(x) htole64(x) 54 | 55 | #define be16toh(x) htobe16(x) 56 | #define be32toh(x) htobe32(x) 57 | #define be64toh(x) htobe64(x) 58 | 59 | int print_buffer(const void *buf, unsigned long len, const char *indent); 60 | 61 | #endif -------------------------------------------------------------------------------- /sha256/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean sha256 test 2 | 3 | CROSS_COMPILE= 4 | 5 | CC = $(CROSS_COMPILE)gcc 6 | STRIP = $(CROSS_COMPILE)strip 7 | AR = $(CROSS_COMPILE)ar 8 | ARFLAGS = crs 9 | 10 | RM = rm 11 | RMFLAGS = -rf 12 | 13 | LIBS = 14 | INCLUDE = 15 | CFLAGS = -Wall -g -O2 16 | 17 | SRCS = utils.c sha256.c sha256test.c 18 | TARGET = sha256 19 | 20 | OBJS = $(SRCS:.c=.o) 21 | 22 | all: sha256 test 23 | 24 | %.o: %.c 25 | $(CC) $(CFLAGS) -c $< -o $@ 26 | 27 | $(TARGET): $(OBJS) 28 | $(CC) $(CFLAGS) $(OBJS) -o $@ $(LIBS) $(INCLUDE) 29 | # $(STRIP) --strip-all $(TARGET) 30 | 31 | test: $(TARGET) 32 | @echo 33 | @echo "Run Test..." 34 | ./$(TARGET) -a sha224 -x 35 | ./$(TARGET) -a sha256 -x 36 | 37 | clean: 38 | $(RM) $(RMFLAGS) $(TARGET) $(OBJS) 39 | -------------------------------------------------------------------------------- /sha256/sha256.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: sha256.c 3 | * @ description: implementation for the SHA224/SHA256 Secure Hash Algorithm 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #include 8 | #include 9 | 10 | #include "utils.h" 11 | #include "sha256.h" 12 | 13 | //#define DEBUG 14 | 15 | #ifdef DEBUG 16 | #define DBG(...) printf(__VA_ARGS__) 17 | #define DUMP_BLOCK_DATA 1 18 | #define DUMP_BLOCK_HASH 1 19 | #define DUMP_ROUND_DATA 1 20 | #else 21 | #define DBG(...) 22 | #define DUMP_BLOCK_DATA 0 23 | #define DUMP_BLOCK_HASH 0 24 | #define DUMP_ROUND_DATA 0 25 | #endif 26 | 27 | #define SHA256_BLOCK_SIZE 64 /* 512 bits = 64 Bytes */ 28 | #define SHA256_LEN_SIZE 8 /* 64 bits = 8 bytes */ 29 | #define SHA256_LEN_OFFSET (SHA256_BLOCK_SIZE - SHA256_LEN_SIZE) 30 | 31 | #define SHA256_DIGEST_SIZE 32 /* 256 bits = 32 bytes */ 32 | #define SHA224_DIGEST_SIZE 28 /* 224 bits = 28 bytes */ 33 | 34 | #define SHA256_PADDING_PATTERN 0x80 35 | #define SHA256_ROUND_NUM 64 36 | 37 | #define HASH_BLOCK_SIZE SHA256_BLOCK_SIZE 38 | #define HASH_LEN_SIZE SHA256_LEN_SIZE 39 | #define HASH_LEN_OFFSET SHA256_LEN_OFFSET 40 | 41 | #define HASH_DIGEST_SIZE SHA256_DIGEST_SIZE /* use sha256 digest size */ 42 | 43 | #define HASH_PADDING_PATTERN SHA256_PADDING_PATTERN 44 | #define HASH_ROUND_NUM SHA256_ROUND_NUM 45 | 46 | /* SHA256 Constants */ 47 | static const uint32_t K256[HASH_ROUND_NUM] = { 48 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 49 | 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 50 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 51 | 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 52 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 53 | 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 54 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 55 | 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 56 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 57 | 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 58 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 59 | 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 60 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 61 | 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 62 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 63 | 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 64 | }; 65 | 66 | /* ROTate Right (cirular right shift) */ 67 | static uint32_t ROTR(uint32_t x, uint8_t shift) 68 | { 69 | return (x >> shift) | (x << (32 - shift)); 70 | } 71 | 72 | /* Right SHift */ 73 | static uint32_t SHR(uint32_t x, uint8_t shift) 74 | { 75 | return (x >> shift); 76 | } 77 | 78 | /* Ch ... choose */ 79 | static uint32_t Ch(uint32_t x, uint32_t y, uint32_t z) 80 | { 81 | return (x & y) ^ (~x & z) ; 82 | } 83 | 84 | /* Maj ... majority */ 85 | static uint32_t Maj(uint32_t x, uint32_t y, uint32_t z) 86 | { 87 | return (x & y) ^ (x & z) ^ (y & z); 88 | } 89 | 90 | /* SIGMA0 */ 91 | static uint32_t SIGMA0(uint32_t x) 92 | { 93 | return ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22); 94 | } 95 | 96 | /* SIGMA1 */ 97 | static uint32_t SIGMA1(uint32_t x) 98 | { 99 | return ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25); 100 | } 101 | 102 | /* sigma0, different from SIGMA0 */ 103 | static uint32_t sigma0(uint32_t x) 104 | { 105 | return ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3); 106 | } 107 | 108 | /* sigma1, different from SIGMA1 */ 109 | static uint32_t sigma1(uint32_t x) 110 | { 111 | return ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10); 112 | } 113 | 114 | int SHA256_Init(SHA256_CTX *c) 115 | { 116 | if (NULL == c) 117 | { 118 | return ERR_INV_PARAM; 119 | } 120 | 121 | memset(c, 0, sizeof(SHA256_CTX)); 122 | 123 | /* Initial Value for SHA256 */ 124 | c->hash.a = 0x6a09e667; 125 | c->hash.b = 0xbb67ae85; 126 | c->hash.c = 0x3c6ef372; 127 | c->hash.d = 0xa54ff53a; 128 | c->hash.e = 0x510e527f; 129 | c->hash.f = 0x9b05688c; 130 | c->hash.g = 0x1f83d9ab; 131 | c->hash.h = 0x5be0cd19; 132 | 133 | return ERR_OK; 134 | } 135 | 136 | static int SHA256_PrepareScheduleWord(const uint32_t *block, uint32_t *W) 137 | { 138 | uint32_t t; 139 | 140 | if ((NULL == block) || (NULL == W)) 141 | { 142 | return ERR_INV_PARAM; 143 | } 144 | 145 | for (t=0; ttotal/HASH_BLOCK_SIZE); 171 | DBG(" DATA:\n"); 172 | print_buffer(block, HASH_BLOCK_SIZE, " "); 173 | #endif 174 | 175 | /* prepare schedule word */ 176 | SHA256_PrepareScheduleWord(block, W); 177 | 178 | a = ctx->hash.a; 179 | b = ctx->hash.b; 180 | c = ctx->hash.c; 181 | d = ctx->hash.d; 182 | e = ctx->hash.e; 183 | f = ctx->hash.f; 184 | g = ctx->hash.g; 185 | h = ctx->hash.h; 186 | 187 | #if (DUMP_BLOCK_HASH == 1) 188 | DBG(" IV: %08x %08x %08x %08x %08x %08x %08x %08x\n", 189 | ctx->hash.a, ctx->hash.b, ctx->hash.c, ctx->hash.d, ctx->hash.e, ctx->hash.f, ctx->hash.g, ctx->hash.h); 190 | #endif 191 | 192 | for (t=0; thash.a += a; 213 | ctx->hash.b += b; 214 | ctx->hash.c += c; 215 | ctx->hash.d += d; 216 | ctx->hash.e += e; 217 | ctx->hash.f += f; 218 | ctx->hash.g += g; 219 | ctx->hash.h += h; 220 | 221 | #if (DUMP_BLOCK_HASH == 1) 222 | DBG(" HASH: %08x %08x %08x %08x %08x %08x %08x %08x\n", 223 | ctx->hash.a, ctx->hash.b, ctx->hash.c, ctx->hash.d, ctx->hash.e, ctx->hash.f, ctx->hash.g, ctx->hash.h); 224 | #endif 225 | 226 | return ERR_OK; 227 | } 228 | 229 | 230 | int SHA256_Update(SHA256_CTX *c, const void *data, size_t len) 231 | { 232 | uint32_t copy_len = 0; 233 | 234 | if ((NULL == c) || (NULL == data)) 235 | { 236 | return ERR_INV_PARAM; 237 | } 238 | 239 | /* has used data */ 240 | if (c->last.used != 0) 241 | { 242 | /* less than 1 block in total, combine data */ 243 | if (c->last.used + len < HASH_BLOCK_SIZE) 244 | { 245 | memcpy(&c->last.buf[c->last.used], data, len); 246 | c->last.used += len; 247 | 248 | return ERR_OK; 249 | } 250 | else /* more than 1 block */ 251 | { 252 | /* process the block in context buffer */ 253 | copy_len = HASH_BLOCK_SIZE - c->last.used; 254 | memcpy(&c->last.buf[c->last.used], data, copy_len); 255 | SHA256_ProcessBlock(c, &c->last.buf); 256 | c->total += HASH_BLOCK_SIZE; 257 | 258 | data = (uint8_t *)data + copy_len; 259 | len -= copy_len; 260 | 261 | /* reset context buffer */ 262 | memset(&c->last.buf[0], 0, HASH_BLOCK_SIZE); 263 | c->last.used = 0; 264 | } 265 | } 266 | 267 | /* less than 1 block, copy to context buffer */ 268 | if (len < HASH_BLOCK_SIZE) 269 | { 270 | memcpy(&c->last.buf[c->last.used], data, len); 271 | c->last.used += len; 272 | 273 | return ERR_OK; 274 | } 275 | else 276 | { 277 | /* process data blocks */ 278 | while (len >= HASH_BLOCK_SIZE) 279 | { 280 | SHA256_ProcessBlock(c, data); 281 | c->total += HASH_BLOCK_SIZE; 282 | 283 | data = (uint8_t *)data + HASH_BLOCK_SIZE; 284 | len -= HASH_BLOCK_SIZE; 285 | } 286 | 287 | /* copy rest data to context buffer */ 288 | memcpy(&c->last.buf[0], data, len); 289 | c->last.used = len; 290 | } 291 | 292 | return ERR_OK; 293 | } 294 | 295 | int SHA256_Final(unsigned char *md, SHA256_CTX *c) 296 | { 297 | uint32_t *temp; 298 | //uint64_t *buf; 299 | 300 | if ((NULL == c) || (NULL == md)) 301 | { 302 | return ERR_INV_PARAM; 303 | } 304 | 305 | /* Last block should be less thant HASH_BLOCK_SIZE - HASH_LEN_SIZE */ 306 | if (c->last.used >= (HASH_BLOCK_SIZE - HASH_LEN_SIZE)) 307 | { 308 | c->total += c->last.used; 309 | 310 | /* one more block */ 311 | c->last.buf[c->last.used] = HASH_PADDING_PATTERN; 312 | c->last.used++; 313 | 314 | memset(&c->last.buf[c->last.used], 0, HASH_BLOCK_SIZE - c->last.used); 315 | SHA256_ProcessBlock(c, &c->last.buf); 316 | 317 | memset(&c->last.buf[0], 0, HASH_BLOCK_SIZE - HASH_LEN_SIZE); 318 | c->last.used = 0; 319 | 320 | /* save length */ 321 | //buf = (uint64_t *)&(c->last.buf[HASH_LEN_OFFSET]); 322 | //*buf = htobe64(c->total << 3); 323 | temp = (uint32_t *)&(c->last.buf[HASH_LEN_OFFSET]); 324 | temp[0] = htobe32((c->total << 3) >> 32 & 0xFFFFFFFF); 325 | temp[1] = htobe32((c->total << 3) & 0xFFFFFFFF); 326 | 327 | SHA256_ProcessBlock(c, &c->last.buf); 328 | } 329 | else /* 0 <= last.used < HASH_BLOCK_SIZE - HASH_LEN_SIZE */ 330 | { 331 | c->total += c->last.used; 332 | 333 | /* one more block */ 334 | c->last.buf[c->last.used] = HASH_PADDING_PATTERN; 335 | c->last.used++; 336 | 337 | /* padding 0s */ 338 | memset(&c->last.buf[c->last.used], 0, HASH_BLOCK_SIZE - HASH_LEN_SIZE - c->last.used); 339 | 340 | /* save length */ 341 | //buf = (uint64_t *)&(c->last.buf[HASH_LEN_OFFSET]); 342 | //*buf = htobe64(c->total << 3); 343 | temp = (uint32_t *)&(c->last.buf[HASH_LEN_OFFSET]); 344 | temp[0] = htobe32((c->total << 3) >> 32 & 0xFFFFFFFF); 345 | temp[1] = htobe32((c->total << 3) & 0xFFFFFFFF); 346 | 347 | SHA256_ProcessBlock(c, &c->last.buf); 348 | } 349 | 350 | temp = (uint32_t *)md; 351 | temp[0] = htobe32(c->hash.a); 352 | temp[1] = htobe32(c->hash.b); 353 | temp[2] = htobe32(c->hash.c); 354 | temp[3] = htobe32(c->hash.d); 355 | temp[4] = htobe32(c->hash.e); 356 | temp[5] = htobe32(c->hash.f); 357 | temp[6] = htobe32(c->hash.g); 358 | temp[7] = htobe32(c->hash.h); 359 | 360 | return ERR_OK; 361 | } 362 | 363 | unsigned char *SHA256(const unsigned char *d, size_t n, unsigned char *md) 364 | { 365 | SHA256_CTX c; 366 | 367 | if ((NULL == d) || (NULL == md)) 368 | { 369 | return NULL; 370 | } 371 | 372 | SHA256_Init(&c); 373 | SHA256_Update(&c, d, n); 374 | SHA256_Final(md, &c); 375 | 376 | return md; 377 | } 378 | 379 | int SHA224_Init(SHA256_CTX *c) 380 | { 381 | if (NULL == c) 382 | { 383 | return ERR_INV_PARAM; 384 | } 385 | 386 | memset(c, 0, sizeof(SHA256_CTX)); 387 | 388 | c->hash.a = 0xc1059ed8; 389 | c->hash.b = 0x367cd507; 390 | c->hash.c = 0x3070dd17; 391 | c->hash.d = 0xf70e5939; 392 | c->hash.e = 0xffc00b31; 393 | c->hash.f = 0x68581511; 394 | c->hash.g = 0x64f98fa7; 395 | c->hash.h = 0xbefa4fa4; 396 | 397 | return ERR_OK; 398 | } 399 | 400 | int SHA224_Update(SHA256_CTX *c, const void *data, size_t len) 401 | { 402 | return SHA256_Update(c, data, len); 403 | } 404 | 405 | int SHA224_Final(unsigned char *md, SHA256_CTX *c) 406 | { 407 | int rc = ERR_OK; 408 | unsigned char sha256_md[SHA256_DIGEST_SIZE]; 409 | 410 | memset(&sha256_md, 0, sizeof(sha256_md)); 411 | 412 | rc = SHA256_Final(sha256_md, c); 413 | 414 | memcpy(md, sha256_md, SHA224_DIGEST_SIZE); 415 | 416 | return rc; 417 | } 418 | 419 | unsigned char *SHA224(const unsigned char *d, size_t n, unsigned char *md) 420 | { 421 | SHA256_CTX c; 422 | 423 | if ((NULL == d) || (NULL == md)) 424 | { 425 | return NULL; 426 | } 427 | 428 | SHA224_Init(&c); 429 | SHA224_Update(&c, d, n); 430 | SHA224_Final(md, &c); 431 | 432 | return md; 433 | } 434 | 435 | -------------------------------------------------------------------------------- /sha256/sha256.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: sha256.h 3 | * @ description: header file for sha256.c 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #ifndef __ROCKY_SHA256__H 8 | #define __ROCKY_SHA256__H 9 | 10 | #define ERR_OK 0 11 | #define ERR_ERR -1 /* generic error */ 12 | #define ERR_INV_PARAM -2 /* invalid parameter */ 13 | #define ERR_TOO_LONG -3 /* too long */ 14 | #define ERR_STATE_ERR -4 /* state error */ 15 | 16 | typedef unsigned char uint8_t; 17 | typedef unsigned short uint16_t; 18 | typedef unsigned int uint32_t; 19 | typedef unsigned long long uint64_t; 20 | 21 | typedef struct sha256_context { 22 | /* message total length in bytes */ 23 | uint64_t total; 24 | 25 | /* intermedia hash value for each block */ 26 | struct { 27 | uint32_t a; 28 | uint32_t b; 29 | uint32_t c; 30 | uint32_t d; 31 | uint32_t e; 32 | uint32_t f; 33 | uint32_t g; 34 | uint32_t h; 35 | }hash; 36 | 37 | /* last block */ 38 | struct { 39 | uint32_t used; /* used bytes */ 40 | uint8_t buf[64]; /* block data buffer */ 41 | }last; 42 | }SHA256_CTX; 43 | 44 | /* https://www.openssl.org/docs/man1.1.1/man3/SHA256_Final.html */ 45 | int SHA224_Init(SHA256_CTX *c); 46 | int SHA224_Update(SHA256_CTX *c, const void *data, size_t len); 47 | int SHA224_Final(unsigned char *md, SHA256_CTX *c); 48 | unsigned char *SHA224(const unsigned char *d, size_t n, unsigned char *md); 49 | 50 | int SHA256_Init(SHA256_CTX *c); 51 | int SHA256_Update(SHA256_CTX *c, const void *data, size_t len); 52 | int SHA256_Final(unsigned char *md, SHA256_CTX *c); 53 | unsigned char *SHA256(const unsigned char *d, size_t n, unsigned char *md); 54 | #endif 55 | -------------------------------------------------------------------------------- /sha256/sha256test.c: -------------------------------------------------------------------------------- 1 | #include /* printf, fopen, fread, fclose... */ 2 | #include /* exit */ 3 | #include /* strlen */ 4 | #include /* getopt */ 5 | 6 | #include "sha256.h" 7 | 8 | #define SHA224_DIGEST_SIZE 28 9 | #define SHA256_DIGEST_SIZE 32 10 | 11 | #define HASH_DIGEST_SIZE SHA256_DIGEST_SIZE /* sha256 digest size */ 12 | #define FILE_BLOCK_SIZE 1024 13 | 14 | /* Hash Algorithm List */ 15 | typedef enum { 16 | HASH_MD2, 17 | HASH_MD4, 18 | HASH_MD5, 19 | HASH_SHA1, 20 | HASH_SHA224, 21 | HASH_SHA256, 22 | HASH_SHA384, 23 | HASH_SHA512, 24 | HASH_SHA512_224, 25 | HASH_SHA512_256, 26 | HASH_SHA3_224, 27 | HASH_SHA3_256, 28 | HASH_SHA3_384, 29 | HASH_SHA3_512, 30 | } HASH_ALG; 31 | 32 | typedef struct { 33 | SHA256_CTX impl; 34 | HASH_ALG alg; 35 | unsigned char md[HASH_DIGEST_SIZE]; 36 | uint32_t md_size; 37 | int (* init)(SHA256_CTX *c); 38 | int (* update)(SHA256_CTX *c, const void *data, size_t len); 39 | int (* final)(unsigned char *md, SHA256_CTX *c); 40 | unsigned char * (* hash)(const unsigned char *d, size_t n, unsigned char *md); 41 | } HASH_CTX; 42 | 43 | /* 44 | * Print a usage message 45 | */ 46 | void usage(const char *argv0) 47 | { 48 | fprintf(stderr, 49 | "Usage:\n" 50 | "Common options: [-x|-f file|-s string| -a sha224|sha256 | -h]\n" 51 | "Hash a string:\n" 52 | "\t%s -a sha224|sha256 -s string\n" 53 | "Hash a file:\n" 54 | "\t%s -a sha224|sha256 -f file [-k key]\n" 55 | "-a\tSecure hash algorithm: \"sha224\", \"sha256\"\n" 56 | "-x\tInternal string hash test\n" 57 | "-h\tDisplay this message\n" 58 | , argv0, argv0); 59 | exit(1); 60 | } 61 | 62 | /* 63 | * Print a message digest in hexadecimal 64 | */ 65 | static int print_digest(unsigned char *digest, uint32_t len) 66 | { 67 | uint32_t i; 68 | 69 | for (i = 0; i < len; i++) 70 | { 71 | printf ("%02x", digest[i]); 72 | } 73 | 74 | return 0; 75 | } 76 | 77 | struct HASH_ITEM { 78 | char *str; 79 | uint32_t len; 80 | unsigned char md[HASH_DIGEST_SIZE*2]; 81 | // unsigned char *md; 82 | }; 83 | 84 | /* 85 | * $ for alg in "sha224" "sha256"; \ 86 | * do \ 87 | * echo "Algorithm: $alg"; \ 88 | * for str in "" "a" "abc" "message digest" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" "12345678901234567890123456789012345678901234567890123456789012345678901234567890"; \ 89 | * do \ 90 | * echo "echo -n \"$str\" | openssl dgst -$alg"; \ 91 | * echo -n $str | openssl dgst -$alg; \ 92 | * done; \ 93 | * echo; \ 94 | * done; 95 | * 96 | * Algorithm: sha224 97 | * echo -n "" | openssl dgst -sha224 98 | * (stdin)= d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f 99 | * echo -n "a" | openssl dgst -sha224 100 | * (stdin)= abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5 101 | * echo -n "abc" | openssl dgst -sha224 102 | * (stdin)= 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 103 | * echo -n "message digest" | openssl dgst -sha224 104 | * (stdin)= 2cb21c83ae2f004de7e81c3c7019cbcb65b71ab656b22d6d0c39b8eb 105 | * echo -n "abcdefghijklmnopqrstuvwxyz" | openssl dgst -sha224 106 | * (stdin)= 45a5f72c39c5cff2522eb3429799e49e5f44b356ef926bcf390dccc2 107 | * echo -n "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" | openssl dgst -sha224 108 | * (stdin)= bff72b4fcb7d75e5632900ac5f90d219e05e97a7bde72e740db393d9 109 | * echo -n "12345678901234567890123456789012345678901234567890123456789012345678901234567890" | openssl dgst -sha224 110 | * (stdin)= b50aecbe4e9bb0b57bc5f3ae760a8e01db24f203fb3cdcd13148046e 111 | * 112 | * Algorithm: sha256 113 | * echo -n "" | openssl dgst -sha256 114 | * (stdin)= e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 115 | * echo -n "a" | openssl dgst -sha256 116 | * (stdin)= ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb 117 | * echo -n "abc" | openssl dgst -sha256 118 | * (stdin)= ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad 119 | * echo -n "message digest" | openssl dgst -sha256 120 | * (stdin)= f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650 121 | * echo -n "abcdefghijklmnopqrstuvwxyz" | openssl dgst -sha256 122 | * (stdin)= 71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 123 | * echo -n "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" | openssl dgst -sha256 124 | * (stdin)= db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0 125 | * echo -n "12345678901234567890123456789012345678901234567890123456789012345678901234567890" | openssl dgst -sha256 126 | * (stdin)= f371bc4a311f2b009eef952dd83ca80e2b60026c8e935592d0f9c308453c813e 127 | * 128 | */ 129 | 130 | struct HASH_ITEM sha224_hashes[] = 131 | { 132 | { /* 0 */ 133 | "", 134 | 0, 135 | "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f" 136 | }, 137 | { /* 1 */ 138 | "a", 139 | 1, 140 | "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5" 141 | }, 142 | { /* 2 */ 143 | "abc", 144 | 3, 145 | "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7" 146 | }, 147 | { /* 3 */ 148 | "message digest", 149 | 14, 150 | "2cb21c83ae2f004de7e81c3c7019cbcb65b71ab656b22d6d0c39b8eb" 151 | }, 152 | { /* 4 */ 153 | "abcdefghijklmnopqrstuvwxyz", 154 | 26, 155 | "45a5f72c39c5cff2522eb3429799e49e5f44b356ef926bcf390dccc2" 156 | }, 157 | { /* 5 */ 158 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 159 | 62, 160 | "bff72b4fcb7d75e5632900ac5f90d219e05e97a7bde72e740db393d9" 161 | }, 162 | { /* 6 */ 163 | "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 164 | 80, 165 | "b50aecbe4e9bb0b57bc5f3ae760a8e01db24f203fb3cdcd13148046e" 166 | }, 167 | { /* End */ 168 | NULL, 0, "" 169 | } 170 | }; 171 | 172 | struct HASH_ITEM sha256_hashes[] = 173 | { 174 | { /* 0 */ 175 | "", 176 | 0, 177 | "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 178 | }, 179 | { /* 1 */ 180 | "a", 181 | 1, 182 | "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb" 183 | }, 184 | { /* 2 */ 185 | "abc", 186 | 3, 187 | "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" 188 | }, 189 | { /* 3 */ 190 | "message digest", 191 | 14, 192 | "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650" 193 | }, 194 | { /* 4 */ 195 | "abcdefghijklmnopqrstuvwxyz", 196 | 26, 197 | "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73" 198 | }, 199 | { /* 5 */ 200 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 201 | 62, 202 | "db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0" 203 | }, 204 | { /* 6 */ 205 | "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 206 | 80, 207 | "f371bc4a311f2b009eef952dd83ca80e2b60026c8e935592d0f9c308453c813e" 208 | }, 209 | { /* End */ 210 | NULL, 0, "" 211 | } 212 | }; 213 | 214 | /* 215 | * Internal digest tests 216 | */ 217 | static int internal_digest_tests(const char *argv0, HASH_CTX *ctx) 218 | { 219 | struct HASH_ITEM *tests, *item; 220 | 221 | if (ctx->alg == HASH_SHA224) 222 | { 223 | printf("Internal hash tests for %s(SHA224):\n", argv0); 224 | tests = sha224_hashes; 225 | } 226 | else /* if (ctx->alg == HASH_SHA256) */ 227 | { 228 | printf("Internal hash tests for %s(SHA256):\n", argv0); 229 | tests = sha256_hashes; 230 | } 231 | 232 | for (item=tests; item->str != NULL; item++) 233 | { 234 | printf("%s(\"%s\")\n", argv0, item->str); 235 | ctx->hash((unsigned char*)item->str, item->len, ctx->md); 236 | printf(" Expect: %s\n", item->md); 237 | printf(" Result: "); 238 | print_digest(ctx->md, ctx->md_size); 239 | printf("\n\n"); 240 | } 241 | 242 | return 0; 243 | } 244 | 245 | /* 246 | * Hash a string and print the digest 247 | */ 248 | static int digest_string(const char *argv0, HASH_CTX *ctx, const unsigned char *string, uint32_t len) 249 | { 250 | printf("%s(\"%s\") = ", argv0, string); 251 | 252 | ctx->hash(string, len, ctx->md); 253 | 254 | print_digest(ctx->md, ctx->md_size); 255 | printf("\n"); 256 | 257 | return 0; 258 | } 259 | 260 | /* 261 | * Hash a file and print the digest 262 | */ 263 | static int digest_file(const char *argv0, HASH_CTX *ctx, const char *filename) 264 | { 265 | FILE *f; 266 | 267 | unsigned char buf[FILE_BLOCK_SIZE]; 268 | 269 | int len = 0; 270 | int rc = 0; 271 | 272 | f = fopen(filename, "rb"); 273 | if (NULL == f) 274 | { 275 | printf("Can't open file %s\n", filename); 276 | rc = -1; 277 | } 278 | else 279 | { 280 | printf("%s(%s) = ", argv0, filename); 281 | ctx->init(&ctx->impl); 282 | while ((len = fread(buf, 1, FILE_BLOCK_SIZE, f))) 283 | { 284 | ctx->update(&ctx->impl, buf, len); 285 | } 286 | ctx->final(ctx->md, &ctx->impl); 287 | 288 | fclose(f); 289 | 290 | print_digest(ctx->md, ctx->md_size); 291 | printf("\n"); 292 | 293 | rc = 0; 294 | } 295 | 296 | return rc; 297 | } 298 | 299 | /* 300 | * Hash the standard input and prints the digest 301 | */ 302 | static void digest_stdin(const char *argv0, HASH_CTX *ctx) 303 | { 304 | int len; 305 | unsigned char buf[HASH_DIGEST_SIZE]; 306 | 307 | ctx->init(&ctx->impl); 308 | while ((len = fread(buf, 1, HASH_DIGEST_SIZE, stdin))) 309 | { 310 | ctx->update(&ctx->impl, buf, len); 311 | } 312 | ctx->final(ctx->md, &ctx->impl); 313 | 314 | printf("%s(stdin) = ", argv0); 315 | print_digest(ctx->md, ctx->md_size); 316 | printf("\n"); 317 | } 318 | 319 | /* 320 | * $ sha256 -h 321 | * Usage: 322 | * Common options: [-x|-f file|-s string|-h] 323 | * Hash a string: 324 | * sha256 -s string 325 | * Hash a file: 326 | * sha256 -f file [-k key] 327 | * -x Internal string hash test 328 | * -h Display this message 329 | */ 330 | int main(int argc, char *argv[]) 331 | { 332 | int ch; 333 | int hash_internal = 0; 334 | int hash_str = 0; 335 | int hash_file = 0; 336 | int hash_stdin = 0; 337 | 338 | char *alg = NULL; 339 | 340 | char *str = NULL; 341 | uint32_t len = 0; 342 | 343 | char *filename = NULL; 344 | 345 | HASH_CTX ctx; 346 | memset(&ctx, 0, sizeof(HASH_CTX)); 347 | 348 | while ((ch = getopt(argc, argv, "a:s:f:xh")) != -1) 349 | { 350 | switch(ch) 351 | { 352 | case 'a': 353 | alg = optarg; 354 | break; 355 | case 'x': 356 | hash_internal = 1; 357 | break; 358 | case 's': 359 | hash_str = 1; 360 | str = optarg; 361 | len = strlen(str); 362 | break; 363 | case 'f': 364 | hash_file = 1; 365 | filename = optarg; 366 | break; 367 | case 'h': 368 | default: /* '?' */ 369 | usage(argv[0]); 370 | break; 371 | } 372 | } 373 | 374 | if (argc == 1) 375 | { 376 | hash_stdin = 1; 377 | } 378 | 379 | /* 380 | * Setup ctx according to algorithm 381 | */ 382 | if ((NULL == alg) || (strncmp(alg, "sha256", 6) == 0)) 383 | { 384 | ctx.alg = HASH_SHA256; 385 | ctx.md_size = SHA256_DIGEST_SIZE; 386 | ctx.init = SHA256_Init; 387 | ctx.update = SHA256_Update; 388 | ctx.final = SHA256_Final; 389 | ctx.hash = SHA256; 390 | } 391 | else if (strncmp(alg, "sha224", 6) == 0) 392 | { 393 | ctx.alg = HASH_SHA224; 394 | ctx.md_size = SHA224_DIGEST_SIZE; 395 | ctx.init = SHA224_Init; 396 | ctx.update = SHA224_Update; 397 | ctx.final = SHA224_Final; 398 | ctx.hash = SHA224; 399 | } 400 | else 401 | { 402 | usage(argv[0]); 403 | } 404 | 405 | if (hash_internal) 406 | { 407 | internal_digest_tests(argv[0], &ctx); 408 | } 409 | 410 | if (hash_str) 411 | { 412 | digest_string(argv[0], &ctx, (unsigned char *)str, len); 413 | } 414 | 415 | if (hash_file) 416 | { 417 | digest_file(argv[0], &ctx, filename); 418 | } 419 | 420 | if (hash_stdin) 421 | { 422 | digest_stdin(argv[0], &ctx); 423 | } 424 | 425 | return 0; 426 | } 427 | -------------------------------------------------------------------------------- /sha256/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: utils.c 3 | * @ description: utilities for hash algorithem implementation 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #include 8 | #include "utils.h" 9 | 10 | #define DUMP_LINE_SIZE 16 11 | int print_buffer(const void *buf, unsigned long len, const char *indent) 12 | { 13 | unsigned long i = 0; 14 | for (i=0; i> 8) & 0xff) \ 19 | | (((x) & 0xff) << 8))) 20 | 21 | /* Swap bytes in 32 bit value. */ 22 | #define __bswap_32(x) \ 23 | ((((x) & 0xff000000) >> 24) \ 24 | | (((x) & 0x00ff0000) >> 8) \ 25 | | (((x) & 0x0000ff00) << 8) \ 26 | | (((x) & 0x000000ff) << 24)) 27 | 28 | /* Swap bytes in 64 bit value. */ 29 | #define __bswap_64(x) \ 30 | ((((x) & 0xff00000000000000ull) >> 56) \ 31 | | (((x) & 0x00ff000000000000ull) >> 40) \ 32 | | (((x) & 0x0000ff0000000000ull) >> 24) \ 33 | | (((x) & 0x000000ff00000000ull) >> 8) \ 34 | | (((x) & 0x00000000ff000000ull) << 8) \ 35 | | (((x) & 0x0000000000ff0000ull) << 24) \ 36 | | (((x) & 0x000000000000ff00ull) << 40) \ 37 | | (((x) & 0x00000000000000ffull) << 56)) 38 | 39 | #if (ENDIANNESS == ENDIAN_LITTLE) 40 | #define htole16(x) (x) 41 | #define htole32(x) (x) 42 | #define htole64(x) (x) 43 | 44 | #define htobe16(x) __bswap_16(x) 45 | #define htobe32(x) __bswap_32(x) 46 | #define htobe64(x) __bswap_64(x) 47 | #else 48 | #define htole16(x) __bswap_16(x) 49 | #define htole32(x) __bswap_32(x) 50 | #define htole64(x) __bswap_64(x) 51 | 52 | #define htobe16(x) (x) 53 | #define htobe32(x) (x) 54 | #define htobe64(x) (x) 55 | #endif 56 | 57 | #define le16toh(x) htole16(x) 58 | #define le32toh(x) htole32(x) 59 | #define le64toh(x) htole64(x) 60 | 61 | #define be16toh(x) htobe16(x) 62 | #define be32toh(x) htobe32(x) 63 | #define be64toh(x) htobe64(x) 64 | 65 | int print_buffer(const void *buf, unsigned long len, const char *indent); 66 | 67 | #endif -------------------------------------------------------------------------------- /sha3/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean sha3 test 2 | 3 | CROSS_COMPILE= 4 | 5 | CC = $(CROSS_COMPILE)gcc 6 | STRIP = $(CROSS_COMPILE)strip 7 | AR = $(CROSS_COMPILE)ar 8 | ARFLAGS = crs 9 | 10 | RM = rm 11 | RMFLAGS = -rf 12 | 13 | LIBS = 14 | INCLUDE = 15 | CFLAGS = -Wall -g -O2 16 | 17 | SRCS = utils.c sha3.c sha3test.c 18 | TARGET = sha3 19 | 20 | OBJS = $(SRCS:.c=.o) 21 | 22 | all: sha3 test 23 | 24 | %.o: %.c 25 | $(CC) $(CFLAGS) -c $< -o $@ 26 | 27 | $(TARGET): $(OBJS) 28 | $(CC) $(CFLAGS) $(OBJS) -o $@ $(LIBS) $(INCLUDE) 29 | # $(STRIP) --strip-all $(TARGET) 30 | 31 | test: $(TARGET) 32 | @echo 33 | @echo "Run Test..." 34 | ./$(TARGET) -a sha3-224 -x 35 | ./$(TARGET) -a sha3-256 -x 36 | ./$(TARGET) -a sha3-384 -x 37 | ./$(TARGET) -a sha3-512 -x 38 | ./$(TARGET) -a shake128 -d 128 -x 39 | ./$(TARGET) -a shake128 -x 40 | ./$(TARGET) -a shake256 -d 256 -x 41 | ./$(TARGET) -a shake256 -x 42 | ./$(TARGET) -a sha3-224 -f $(TARGET) 43 | ./$(TARGET) -a sha3-256 -f $(TARGET) 44 | ./$(TARGET) -a sha3-384 -f $(TARGET) 45 | ./$(TARGET) -a sha3-512 -f $(TARGET) 46 | ./$(TARGET) -a shake128 -d 128 -f $(TARGET) 47 | ./$(TARGET) -a shake128 -f $(TARGET) 48 | ./$(TARGET) -a shake256 -d 256 -f $(TARGET) 49 | ./$(TARGET) -a shake256 -f $(TARGET) 50 | 51 | clean: 52 | $(RM) $(RMFLAGS) $(TARGET) $(OBJS) 53 | -------------------------------------------------------------------------------- /sha3/sha3.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: sha3.c 3 | * @ description: implementation for the SHA3 Secure Hash Algorithm 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #include 8 | #include 9 | 10 | #include "utils.h" 11 | #include "sha3.h" 12 | 13 | //#define DEBUG 14 | 15 | #ifdef DEBUG 16 | #define DBG(...) printf(__VA_ARGS__) 17 | #define DUMP_BLOCK_DATA 1 18 | #define DUMP_BLOCK_HASH 1 19 | #define DUMP_ROUND_DATA 1 20 | #define DUMP_SCHED_DATA 1 21 | #else 22 | #define DBG(...) 23 | #define DUMP_BLOCK_DATA 0 24 | #define DUMP_BLOCK_HASH 0 25 | #define DUMP_ROUND_DATA 0 26 | #define DUMP_SCHED_DATA 0 27 | #endif 28 | 29 | /* 30 | * FIPS-202, sec B.2: 31 | * |---------------|------------------------| 32 | * | Padding Bytes | Padding Message | 33 | * |---------------|------------------------| 34 | * | q=1 | M||0x86 | 35 | * |---------------|------------------------| 36 | * | q=2 | M||0x0680 | 37 | * |---------------|------------------------| 38 | * | q>2 | M||0x06||0x00...||0x80 | 39 | * |---------------|------------------------| 40 | * 41 | * refer: 42 | * https://cryptologie.net/article/387/byte-ordering-and-bit-numbering-in-keccak-and-sha-3/ 43 | */ 44 | 45 | /* 46 | * SHA3 Delimiter + Padding 47 | * 01 + 10*1 48 | */ 49 | 50 | /* q=1: 01 10 0001 <--reverse-- 1000 01 10, 1 byte, 0x86 */ 51 | #define SHA3_PADDING_STD1 0x86 52 | 53 | /* q>=2: 01 10 0000....0000 0001 <--reverse-- 0000 01 10....1000 0000, 2 bytes, 0x06...0x80 */ 54 | #define SHA3_PADDING_STD2_BEGIN 0x06 55 | #define SHA3_PADDING_STD2_END 0x80 56 | 57 | /* 58 | * SHA3 XOF Delimiter + Padding 59 | * 1111 + 10*1 60 | */ 61 | /* q=1: 1111 1001 <--reverse-- 1001 1111, 1 byte, 0x9F */ 62 | #define SHA3_PADDING_XOF1 0x9F 63 | 64 | /* q>=2: 1111 1000....0000 0001 <--reverse 0001 1111....1000 0000, 2 bytes, 0x1F...0x80 */ 65 | #define SHA3_PADDING_XOF2_BEGIN 0x1F 66 | #define SHA3_PADDING_XOF2_END 0x80 67 | 68 | /* ROTate Left (circular left shift) */ 69 | static uint64_t ROTL(uint64_t x, uint8_t shift) 70 | { 71 | return (x << shift) | (x >> (64 - shift)); 72 | } 73 | 74 | static uint32_t theta(uint64_t A[5][5]) 75 | { 76 | uint32_t x, y; 77 | uint64_t Ap[5][5]; 78 | uint64_t C[5], D[5]; 79 | 80 | memset(C, 0, sizeof(C)); 81 | memset(D, 0, sizeof(D)); 82 | memset(Ap, 0, sizeof(Ap)); 83 | 84 | for (x=0; x<5; x++) 85 | { 86 | C[x] = A[0][x] ^ A[1][x] ^ A[2][x] ^ A[3][x] ^ A[4][x]; 87 | } 88 | 89 | for (x=0; x<5; x++) 90 | { 91 | /* D[x] = C[x-1] ^ ROTR(C[x+1], 1) */ 92 | D[x] = C[(x+4)%5] ^ ROTL(C[(x+1)%5], 1); 93 | } 94 | 95 | for (y=0; y<5; y++) 96 | { 97 | for (x=0; x<5; x++) 98 | { 99 | Ap[y][x] = A[y][x] ^ D[x]; 100 | } 101 | } 102 | 103 | memcpy(A, Ap, sizeof(Ap)); 104 | return 0; 105 | } 106 | 107 | /* rotation constants, aka rotation offsets */ 108 | static uint32_t Rp[5][5] = 109 | { 110 | { 0, 1, 190, 28, 91}, 111 | { 36, 300, 6, 55, 276}, 112 | { 3, 10, 171, 153, 231}, 113 | { 105, 45, 15, 21, 136}, 114 | { 210, 66, 253, 120, 78} 115 | }; 116 | static uint32_t rho(uint64_t A[5][5]) 117 | { 118 | uint64_t Ap[5][5]; 119 | uint32_t x, y, m; 120 | uint32_t t; 121 | 122 | memset(Ap, 0, sizeof(Ap)); 123 | /* let A'[0,0,z]=A[0,0,z] */ 124 | memcpy(Ap[0], A[0], sizeof(Ap[0])); 125 | 126 | /* let (x,y) = (1,0) */ 127 | x = 1; 128 | y = 0; 129 | #if 0 130 | /* calculate directly */ 131 | for (t=0; t<24; t++) 132 | { 133 | Ap[y][x] = ROTL(A[y][x], ((t+1)*(t+2)/2)%64); 134 | m = x; 135 | x = y; 136 | y = (2*m + 3*y) % 5; 137 | } 138 | #else 139 | /* look up table */ 140 | for (t=0; t<24; t++) 141 | { 142 | Ap[y][x] = ROTL(A[y][x], Rp[y][x]%64); 143 | /* let (x,y) = (y,(2x+3y)%5) */ 144 | m = x; 145 | x = y; 146 | y = (2*m+3*y) % 5; 147 | } 148 | #endif 149 | 150 | memcpy(A, Ap, sizeof(Ap)); 151 | return 0; 152 | } 153 | 154 | static uint32_t pi(uint64_t A[5][5]) 155 | { 156 | uint64_t Ap[5][5]; 157 | uint32_t x, y; 158 | 159 | memset(Ap, 0, sizeof(Ap)); 160 | for (y=0; y<5; y++) 161 | { 162 | for (x=0; x<5; x++) 163 | { 164 | Ap[y][x] = A[x][(x+3*y)%5]; 165 | } 166 | } 167 | 168 | memcpy(A, Ap, sizeof(Ap)); 169 | return 0; 170 | } 171 | 172 | static uint32_t chi(uint64_t A[5][5]) 173 | { 174 | uint64_t Ap[5][5]; 175 | uint32_t x, y; 176 | 177 | memset(Ap, 0, sizeof(Ap)); 178 | for (y=0; y<5; y++) 179 | { 180 | for (x=0; x<5; x++) 181 | { 182 | Ap[y][x] = A[y][x] ^ ((~A[y][(x+1)%5]) & A[y][(x+2)%5]); 183 | } 184 | } 185 | 186 | memcpy(A, Ap, sizeof(Ap)); 187 | return 0; 188 | } 189 | 190 | static uint64_t RC[24] = 191 | { 192 | 0x0000000000000001, 193 | 0x0000000000008082, 194 | 0x800000000000808a, 195 | 0x8000000080008000, 196 | 0x000000000000808b, 197 | 0x0000000080000001, 198 | 0x8000000080008081, 199 | 0x8000000000008009, 200 | 0x000000000000008a, 201 | 0x0000000000000088, 202 | 0x0000000080008009, 203 | 0x000000008000000a, 204 | 0x000000008000808b, 205 | 0x800000000000008b, 206 | 0x8000000000008089, 207 | 0x8000000000008003, 208 | 0x8000000000008002, 209 | 0x8000000000000080, 210 | 0x000000000000800a, 211 | 0x800000008000000a, 212 | 0x8000000080008081, 213 | 0x8000000000008080, 214 | 0x0000000080000001, 215 | 0x8000000080008008, 216 | }; 217 | static uint32_t iota(uint64_t A[5][5], uint32_t i) 218 | { 219 | A[0][0] = A[0][0] ^ RC[i]; 220 | 221 | return 0; 222 | } 223 | 224 | int SHA3_Init(SHA3_CTX *c, SHA3_ALG alg) 225 | { 226 | if (NULL == c) 227 | { 228 | return ERR_INV_PARAM; 229 | } 230 | 231 | if ((alg == SHAKE128) || (alg == SHAKE256)) 232 | { 233 | return ERR_INV_PARAM; 234 | } 235 | 236 | memset(c, 0, sizeof(SHA3_CTX)); 237 | 238 | /* bits */ 239 | // c->l = 6; 240 | // c->w = 64; /* c->w = 2 ^ l */ 241 | 242 | /* bytes */ 243 | c->b = 200; /* 1600 bits, c->b = 25 * 2 ^ c->l; */ 244 | c->alg = alg; 245 | switch (alg) 246 | { 247 | case SHA3_224: /* SHA3-224(M) = KECCAK[448](M||01,224), FIPS-202, sec 6.1 */ 248 | c->r = 144; /* 1152 bits */ 249 | c->c = 56; /* 448 bits */ 250 | c->md_size = 28; /* 224 bits */ 251 | break; 252 | case SHA3_256: /* SHA3-256(M) = KECCAK[512](M||01,256), FIPS-202, sec 6.1 */ 253 | c->r = 136; /* 1088 bits */ 254 | c->c = 64; /* 512 bits */ 255 | c->md_size = 32; /* 256 bits */ 256 | break; 257 | case SHA3_384: /* SHA3-384(M) = KECCAK[768](M||01,384), FIPS-202, sec 6.1 */ 258 | c->r = 104; /* 832 bits */ 259 | c->c = 96; /* 768 bits */ 260 | c->md_size = 48; /* 384 bits */ 261 | break; 262 | default: /* default Keccak setting: SHA3_512 */ 263 | case SHA3_512: /* SHA3-512(M) = KECCAK[1024](M||01,512), FIPS-202, sec 6.1 */ 264 | c->r = 72; /* 576 bits */ 265 | c->c = 128; /* 1024 bits */ 266 | c->md_size = 64; /* 512 bits */ 267 | break; 268 | } 269 | 270 | c->nr = 24; /* nr = 24 = 12 + 2 * l */ 271 | c->absorbing = 1; /* absorbing phase */ 272 | 273 | return ERR_OK; 274 | } 275 | 276 | #if (DUMP_SCHED_DATA == 1) 277 | #define sched_show_buffer(info,ptr,len) \ 278 | DBG(info); \ 279 | print_buffer((ptr),(len)," "); 280 | #else 281 | #define sched_show_buffer(info,ptr,len) 282 | #endif 283 | 284 | #if (DUMP_ROUND_DATA == 1) 285 | #define round_show_buffer(info) \ 286 | DBG(info); \ 287 | print_buffer(&ctx->lane[0][0], ctx->b, " "); 288 | 289 | static void dump_lane_buffer(uint64_t lane[5][5]) 290 | { 291 | uint32_t x, y; 292 | 293 | for (y=0; y<5; y++) /* row */ 294 | { 295 | for (x=0; x<5; x++) /* col */ 296 | { 297 | DBG("[%d, %d]: %016llx ", x, y, lane[y][x]); 298 | } 299 | DBG("\n"); 300 | } 301 | return; 302 | } 303 | #else 304 | #define round_show_buffer(info) 305 | 306 | static void dump_lane_buffer(uint64_t lane[5][5]) {} 307 | #endif 308 | 309 | static int SHA3_PrepareScheduleWord(SHA3_CTX *ctx, const uint64_t *block) 310 | { 311 | uint32_t i; 312 | uint64_t *data; 313 | uint64_t temp[25]; 314 | 315 | if ((NULL == ctx) || (NULL == block)) 316 | { 317 | return ERR_INV_PARAM; 318 | } 319 | 320 | for (i=0; ib/8; i++) 321 | { 322 | if (ir/8) 323 | { 324 | temp[i] = le64toh(block[i]); 325 | } 326 | else 327 | { 328 | temp[i] = 0x0; 329 | } 330 | } 331 | 332 | sched_show_buffer("Data to absorbed:\n", temp, ctx->b); 333 | sched_show_buffer(" SchedWord: [before]\n", &ctx->lane[0][0], ctx->b); 334 | 335 | /* initial S */ 336 | data = &ctx->lane[0][0]; 337 | 338 | for (i=0; ib/8; i++) 339 | { 340 | data[i] ^= temp[i]; 341 | } 342 | 343 | sched_show_buffer(" SchedWord: [after]\n", &ctx->lane[0][0], ctx->b); 344 | 345 | return ERR_OK; 346 | } 347 | 348 | /* r bytes for each block */ 349 | static int SHA3_ProcessBlock(SHA3_CTX *ctx, const void *block) 350 | { 351 | uint32_t t; 352 | 353 | if ((NULL == ctx) || (ctx->absorbing && (NULL == block))) 354 | { 355 | return ERR_INV_PARAM; 356 | } 357 | 358 | #if (DUMP_BLOCK_DATA == 1) 359 | DBG("---------------------------------------------------------\n"); 360 | DBG(" BLOCK DATA:\n"); 361 | print_buffer(block, ctx->r, " "); 362 | #endif 363 | 364 | if (ctx->absorbing) 365 | { 366 | SHA3_PrepareScheduleWord(ctx, block); 367 | } 368 | 369 | for (t=0; tnr; t++) 370 | { 371 | #if (DUMP_ROUND_DATA == 1) 372 | DBG(" Round #%02d:\n", t); 373 | #endif 374 | theta(ctx->lane); 375 | round_show_buffer("After Theta:\n"); 376 | 377 | rho(ctx->lane); 378 | round_show_buffer(" After Rho:\n"); 379 | 380 | pi(ctx->lane); 381 | round_show_buffer(" After Pi:\n"); 382 | 383 | chi(ctx->lane); 384 | round_show_buffer(" After Chi:\n"); 385 | 386 | iota(ctx->lane, t); 387 | round_show_buffer(" After Iota:\n"); 388 | } 389 | 390 | round_show_buffer("After Permutation:\n"); 391 | #if (DUMP_BLOCK_HASH == 1) 392 | DBG(" BLOCK HASH:\n"); 393 | print_buffer(&ctx->lane[0][0], ctx->b, " "); 394 | #endif 395 | 396 | return ERR_OK; 397 | } 398 | 399 | int SHA3_Update(SHA3_CTX *c, const void *data, size_t len) 400 | { 401 | uint64_t copy_len = 0; 402 | 403 | if ((NULL == c) || (NULL == data)) 404 | { 405 | return ERR_INV_PARAM; 406 | } 407 | 408 | /* has used data */ 409 | if (c->last.used != 0) 410 | { 411 | /* less than 1 block in total, combine data */ 412 | if (c->last.used + len < c->r) 413 | { 414 | memcpy(&c->last.buf[c->last.used], data, len); 415 | c->last.used += len; 416 | 417 | return ERR_OK; 418 | } 419 | else /* more than 1 block */ 420 | { 421 | /* process the block in context buffer */ 422 | copy_len = c->r - c->last.used; 423 | memcpy(&c->last.buf[c->last.used], data, copy_len); 424 | SHA3_ProcessBlock(c, &c->last.buf); 425 | 426 | data = (uint8_t *)data + copy_len; 427 | len -= copy_len; 428 | 429 | /* reset context buffer */ 430 | memset(&c->last.buf[0], 0, c->r); 431 | c->last.used = 0; 432 | } 433 | } 434 | 435 | /* less than 1 block, copy to context buffer */ 436 | if (len < c->r) 437 | { 438 | memcpy(&c->last.buf[c->last.used], data, len); 439 | c->last.used += len; 440 | 441 | return ERR_OK; 442 | } 443 | else 444 | { 445 | /* process data blocks */ 446 | while (len >= c->r) 447 | { 448 | SHA3_ProcessBlock(c, data); 449 | 450 | data = (uint8_t *)data + c->r; 451 | len -= c->r; 452 | } 453 | 454 | /* copy rest data to context buffer */ 455 | memcpy(&c->last.buf[0], data, len); 456 | c->last.used = len; 457 | } 458 | 459 | return ERR_OK; 460 | } 461 | 462 | int SHA3_Final(unsigned char *md, SHA3_CTX *c) 463 | { 464 | uint32_t md_size = 0; /* message digest size used */ 465 | 466 | if ((NULL == c) || (NULL == md)) 467 | { 468 | return ERR_INV_PARAM; 469 | } 470 | 471 | /* more than 2 bytes left */ 472 | if (c->last.used <= (c->r - 2)) 473 | { 474 | /* one more block */ 475 | if ((c->alg == SHAKE128) || (c->alg == SHAKE256)) /* XOFs */ 476 | { 477 | c->last.buf[c->last.used] = SHA3_PADDING_XOF2_BEGIN; 478 | } 479 | else 480 | { 481 | c->last.buf[c->last.used] = SHA3_PADDING_STD2_BEGIN; 482 | } 483 | c->last.used++; 484 | 485 | memset(&c->last.buf[c->last.used], 0, (c->r - 1) - c->last.used); 486 | c->last.used = c->r - 1; 487 | 488 | if ((c->alg == SHAKE128) || (c->alg == SHAKE256)) /* XOFs */ 489 | { 490 | c->last.buf[c->last.used] = SHA3_PADDING_XOF2_END; 491 | } 492 | else 493 | { 494 | c->last.buf[c->last.used] = SHA3_PADDING_STD2_END; 495 | } 496 | c->last.used++; 497 | } 498 | else /* if (c->last.used == (c->r - 1)) */ /* only 1 bytes left */ 499 | { 500 | if ((c->alg == SHAKE128) || (c->alg == SHAKE256)) /* XOFs */ 501 | { 502 | c->last.buf[c->last.used] = SHA3_PADDING_XOF1; 503 | } 504 | else 505 | { 506 | c->last.buf[c->last.used] = SHA3_PADDING_STD1; 507 | } 508 | c->last.used++; 509 | } 510 | 511 | SHA3_ProcessBlock(c, &c->last.buf); 512 | c->last.used = 0; 513 | 514 | /* Absorbing Phase End */ 515 | c->absorbing = 0; 516 | 517 | dump_lane_buffer(c->lane); 518 | 519 | if (c->md_size <= c->r) 520 | { 521 | memcpy(md, &c->lane[0][0], c->md_size); 522 | } 523 | else 524 | { 525 | memcpy(md, &c->lane[0][0], c->r); 526 | md_size = c->r; 527 | 528 | /* squeeze */ 529 | while (md_size < c->md_size) 530 | { 531 | SHA3_ProcessBlock(c, NULL); 532 | if (c->md_size - md_size > c->r) 533 | { 534 | memcpy(&md[md_size], &c->lane[0][0], c->r); 535 | md_size += c->r; 536 | } 537 | else 538 | { 539 | memcpy(&md[md_size], &c->lane[0][0], c->md_size - md_size); 540 | md_size = c->md_size; 541 | } 542 | } 543 | } 544 | 545 | return ERR_OK; 546 | } 547 | 548 | unsigned char *SHA3(SHA3_ALG alg, const unsigned char *data, size_t n, unsigned char *md) 549 | { 550 | SHA3_CTX c; 551 | 552 | if ((NULL == data) || (NULL == md)) 553 | { 554 | return NULL; 555 | } 556 | 557 | SHA3_Init(&c, alg); 558 | SHA3_Update(&c, data, n); 559 | SHA3_Final(md, &c); 560 | 561 | return md; 562 | } 563 | 564 | /* d is d value for SHAKE128/SHAKE256, md_size = d / 8 */ 565 | int SHA3_XOF_Init(SHA3_CTX *c, SHA3_ALG alg, uint32_t d) 566 | { 567 | if (NULL == c) 568 | { 569 | return ERR_INV_PARAM; 570 | } 571 | 572 | /* only for SHAKE128/SHAKE256 */ 573 | if ((alg != SHAKE128) && (alg != SHAKE256)) 574 | { 575 | return ERR_INV_PARAM; 576 | } 577 | 578 | /* using SHA3-512 as default */ 579 | SHA3_Init(c, SHA3_512); 580 | 581 | c->alg = alg; 582 | 583 | /* update for SHAKE128/SHAKE256 */ 584 | switch(alg) 585 | { 586 | case SHAKE128: /* SHAKE128(M,d) = KECCAK[256](M||1111,d), FIPS-202, sec 6.2 */ 587 | c->r = 168; /* 1344 bits */ 588 | c->c = 32; /* 256 bits */ 589 | c->md_size = d / 8; 590 | break; 591 | default: 592 | case SHAKE256: /* SHAKE256(M,d) = KECCAK[512](M||1111,d), FIPS-202, sec 6.2 */ 593 | c->r = 136; /* 1088 bits */ 594 | c->c = 64; /* 512 bits */ 595 | c->md_size = d / 8; 596 | break; 597 | } 598 | 599 | return ERR_OK; 600 | } 601 | 602 | int SHA3_XOF_Update(SHA3_CTX *c, const void *data, size_t len) 603 | { 604 | return SHA3_Update(c, data, len); 605 | } 606 | 607 | int SHA3_XOF_Final(unsigned char *md, SHA3_CTX *c) 608 | { 609 | return SHA3_Final(md, c); 610 | } 611 | 612 | unsigned char *SHA3_XOF(SHA3_ALG alg, const unsigned char *data, size_t n, unsigned char *md, uint32_t d) 613 | { 614 | SHA3_CTX c; 615 | 616 | if ((NULL == data) || (NULL == md)) 617 | { 618 | return NULL; 619 | } 620 | 621 | /* only for SHAKE128/SHAKE256 */ 622 | if ((alg != SHAKE128) && (alg != SHAKE256)) 623 | { 624 | return NULL; 625 | } 626 | 627 | SHA3_XOF_Init(&c, alg, d); 628 | SHA3_XOF_Update(&c, data, n); 629 | SHA3_XOF_Final(md, &c); 630 | 631 | return md; 632 | } 633 | -------------------------------------------------------------------------------- /sha3/sha3.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: sha512.h 3 | * @ description: header file for sha3.c 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #ifndef __ROCKY_SHA3__H 8 | #define __ROCKY_SHA3__H 9 | 10 | #define ERR_OK 0 11 | #define ERR_ERR -1 /* generic error */ 12 | #define ERR_INV_PARAM -2 /* invalid parameter */ 13 | #define ERR_TOO_LONG -3 /* too long */ 14 | #define ERR_STATE_ERR -4 /* state error */ 15 | 16 | typedef unsigned char uint8_t; 17 | typedef unsigned short uint16_t; 18 | typedef unsigned int uint32_t; 19 | typedef unsigned long long uint64_t; 20 | typedef struct { 21 | uint64_t high; /* high 64 bits */ 22 | uint64_t low; /* low 64 bits */ 23 | } uint128_t; 24 | 25 | /* 26 | * Standard: 27 | * SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions 28 | * https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf 29 | * 30 | * Understanding-Cryptography-Keccak.pdf 31 | * SHA-3 and The Hash Function Keccak 32 | * https://www.crypto-textbook.com/download/Understanding-Cryptography-Keccak.pdf 33 | */ 34 | 35 | typedef enum sha3_algorithm { 36 | SHA3_224, 37 | SHA3_256, 38 | SHA3_384, 39 | SHA3_512, 40 | SHAKE128, 41 | SHAKE256 42 | }SHA3_ALG; 43 | 44 | typedef struct sha3_context { 45 | /* intermedia hash value for each block */ 46 | uint64_t lane[5][5]; /* 5 x 5 x 64 = 1600 bits */ 47 | 48 | /* last block */ 49 | struct { 50 | uint32_t used; /* used bytes */ 51 | uint8_t buf[200]; /* block data buffer, 200 x 8 = 1600 bits */ 52 | }last; 53 | 54 | SHA3_ALG alg; 55 | 56 | /* 57 | * |-------------------------------------------------------------| 58 | * | l | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 59 | * |-------------------------------------------------------------| 60 | * | w = 2^l | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 61 | * |-------------------------------------------------------------| 62 | * | b = 25*2^l | 25 | 50 | 100 | 200 | 400 | 800 | 1600 | 63 | * |-------------------------------------------------------------| 64 | * | SHA3: l = 6, w = 64, b = 1600 * | 65 | * |-------------------------------------------------------------| 66 | */ 67 | 68 | // uint32_t l; /* binary logarithm of lane size */ 69 | // uint32_t w; /* lane size in bits */ 70 | uint32_t b; /* width of the state, b = r + c */ 71 | uint32_t r; /* bit rate, rate of a sponge function, length of one message block */ 72 | uint32_t c; /* capacity, r + c = b */ 73 | 74 | uint32_t nr; /* round number, nr = 12 + 2l */ 75 | 76 | uint32_t md_size; /* message digest size in bytes */ 77 | 78 | uint32_t absorbing; /* 1: absorbe; 0: squeeze */ 79 | }SHA3_CTX; 80 | 81 | int SHA3_Init(SHA3_CTX *c, SHA3_ALG alg); 82 | int SHA3_Update(SHA3_CTX *c, const void *data, size_t len); 83 | int SHA3_Final(unsigned char *md, SHA3_CTX *c); 84 | unsigned char *SHA3(SHA3_ALG alg, const unsigned char *data, size_t n, unsigned char *md); 85 | 86 | /* Extendable-Output Functions: SHAKE128, SHAKE256 */ 87 | int SHA3_XOF_Init(SHA3_CTX *c, SHA3_ALG alg, uint32_t d); 88 | int SHA3_XOF_Update(SHA3_CTX *c, const void *data, size_t len); 89 | int SHA3_XOF_Final(unsigned char *md, SHA3_CTX *c); 90 | unsigned char *SHA3_XOF(SHA3_ALG alg, const unsigned char *data, size_t n, unsigned char *md, uint32_t d); 91 | #endif 92 | -------------------------------------------------------------------------------- /sha3/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: utils.c 3 | * @ description: utilities for hash algorithem implementation 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #include 8 | #include "utils.h" 9 | 10 | #define DUMP_LINE_SIZE 16 11 | int print_buffer(const void *buf, unsigned long len, const char *indent) 12 | { 13 | unsigned long i = 0; 14 | for (i=0; i> 8) & 0xff) \ 19 | | (((x) & 0xff) << 8))) 20 | 21 | /* Swap bytes in 32 bit value. */ 22 | #define __bswap_32(x) \ 23 | ((((x) & 0xff000000) >> 24) \ 24 | | (((x) & 0x00ff0000) >> 8) \ 25 | | (((x) & 0x0000ff00) << 8) \ 26 | | (((x) & 0x000000ff) << 24)) 27 | 28 | /* Swap bytes in 64 bit value. */ 29 | #define __bswap_64(x) \ 30 | ((((x) & 0xff00000000000000ull) >> 56) \ 31 | | (((x) & 0x00ff000000000000ull) >> 40) \ 32 | | (((x) & 0x0000ff0000000000ull) >> 24) \ 33 | | (((x) & 0x000000ff00000000ull) >> 8) \ 34 | | (((x) & 0x00000000ff000000ull) << 8) \ 35 | | (((x) & 0x0000000000ff0000ull) << 24) \ 36 | | (((x) & 0x000000000000ff00ull) << 40) \ 37 | | (((x) & 0x00000000000000ffull) << 56)) 38 | 39 | #if (ENDIANNESS == ENDIAN_LITTLE) 40 | #define htole16(x) (x) 41 | #define htole32(x) (x) 42 | #define htole64(x) (x) 43 | 44 | #define htobe16(x) __bswap_16(x) 45 | #define htobe32(x) __bswap_32(x) 46 | #define htobe64(x) __bswap_64(x) 47 | #else 48 | #define htole16(x) __bswap_16(x) 49 | #define htole32(x) __bswap_32(x) 50 | #define htole64(x) __bswap_64(x) 51 | 52 | #define htobe16(x) (x) 53 | #define htobe32(x) (x) 54 | #define htobe64(x) (x) 55 | #endif 56 | 57 | #define le16toh(x) htole16(x) 58 | #define le32toh(x) htole32(x) 59 | #define le64toh(x) htole64(x) 60 | 61 | #define be16toh(x) htobe16(x) 62 | #define be32toh(x) htobe32(x) 63 | #define be64toh(x) htobe64(x) 64 | 65 | int print_buffer(const void *buf, unsigned long len, const char *indent); 66 | 67 | #endif -------------------------------------------------------------------------------- /sha512/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean sha512 test 2 | 3 | CROSS_COMPILE= 4 | 5 | CC = $(CROSS_COMPILE)gcc 6 | STRIP = $(CROSS_COMPILE)strip 7 | AR = $(CROSS_COMPILE)ar 8 | ARFLAGS = crs 9 | 10 | RM = rm 11 | RMFLAGS = -rf 12 | 13 | LIBS = 14 | INCLUDE = 15 | CFLAGS = -Wall -g -O2 16 | 17 | SRCS = utils.c sha512.c sha512test.c 18 | TARGET = sha512 19 | 20 | OBJS = $(SRCS:.c=.o) 21 | 22 | all: sha512 test 23 | 24 | %.o: %.c 25 | $(CC) $(CFLAGS) -c $< -o $@ 26 | 27 | $(TARGET): $(OBJS) 28 | $(CC) $(CFLAGS) $(OBJS) -o $@ $(LIBS) $(INCLUDE) 29 | # $(STRIP) --strip-all $(TARGET) 30 | 31 | test: $(TARGET) 32 | @echo 33 | @echo "Run Test..." 34 | ./$(TARGET) -a sha384 -x 35 | ./$(TARGET) -a sha512 -x 36 | ./$(TARGET) -a sha512-224 -x 37 | ./$(TARGET) -a sha512-256 -x 38 | ./$(TARGET) -a sha512t -t 224 -x 39 | ./$(TARGET) -a sha384 -f $(TARGET) 40 | ./$(TARGET) -a sha512 -f $(TARGET) 41 | ./$(TARGET) -a sha512-224 -f $(TARGET) 42 | ./$(TARGET) -a sha512-256 -f $(TARGET) 43 | ./$(TARGET) -a sha512t -t 224 -f $(TARGET) 44 | 45 | clean: 46 | $(RM) $(RMFLAGS) $(TARGET) $(OBJS) 47 | -------------------------------------------------------------------------------- /sha512/sha512.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: sha512.h 3 | * @ description: header file for sha512.c 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #ifndef __ROCKY_SHA512__H 8 | #define __ROCKY_SHA512__H 9 | 10 | #define ERR_OK 0 11 | #define ERR_ERR -1 /* generic error */ 12 | #define ERR_INV_PARAM -2 /* invalid parameter */ 13 | #define ERR_TOO_LONG -3 /* too long */ 14 | #define ERR_STATE_ERR -4 /* state error */ 15 | 16 | typedef unsigned char uint8_t; 17 | typedef unsigned short uint16_t; 18 | typedef unsigned int uint32_t; 19 | typedef unsigned long long uint64_t; 20 | typedef struct { 21 | uint64_t high; /* high 64 bits */ 22 | uint64_t low; /* low 64 bits */ 23 | } uint128_t; 24 | 25 | typedef struct sha512_context { 26 | /* message total length in bytes */ 27 | uint128_t total; 28 | 29 | /* intermedia hash value for each block */ 30 | struct { 31 | uint64_t a; 32 | uint64_t b; 33 | uint64_t c; 34 | uint64_t d; 35 | uint64_t e; 36 | uint64_t f; 37 | uint64_t g; 38 | uint64_t h; 39 | }hash; 40 | 41 | /* last block */ 42 | struct { 43 | uint32_t used; /* used bytes */ 44 | uint8_t buf[128]; /* block data buffer */ 45 | }last; 46 | 47 | uint32_t ext; /* t value of SHA512/t */ 48 | }SHA512_CTX; 49 | 50 | /* https://www.openssl.org/docs/man1.1.1/man3/SHA256_Final.html */ 51 | int SHA384_Init(SHA512_CTX *c); 52 | int SHA384_Update(SHA512_CTX *c, const void *data, size_t len); 53 | int SHA384_Final(unsigned char *md, SHA512_CTX *c); 54 | unsigned char *SHA384(const unsigned char *d, size_t n, unsigned char *md); 55 | 56 | int SHA512_Init(SHA512_CTX *c); 57 | int SHA512_Update(SHA512_CTX *c, const void *data, size_t len); 58 | int SHA512_Final(unsigned char *md, SHA512_CTX *c); 59 | unsigned char *SHA512(const unsigned char *d, size_t n, unsigned char *md); 60 | 61 | /* SHA512/224 */ 62 | int SHA512_224_Init(SHA512_CTX *c); 63 | int SHA512_224_Update(SHA512_CTX *c, const void *data, size_t len); 64 | int SHA512_224_Final(unsigned char *md, SHA512_CTX *c); 65 | unsigned char *SHA512_224(const unsigned char *d, size_t n, unsigned char *md); 66 | 67 | /* SHA512/256 */ 68 | int SHA512_256_Init(SHA512_CTX *c); 69 | int SHA512_256_Update(SHA512_CTX *c, const void *data, size_t len); 70 | int SHA512_256_Final(unsigned char *md, SHA512_CTX *c); 71 | unsigned char *SHA512_256(const unsigned char *d, size_t n, unsigned char *md); 72 | 73 | int SHA512t_Init(SHA512_CTX *c, unsigned int t); 74 | int SHA512t_Update(SHA512_CTX *c, const void *data, size_t len); 75 | int SHA512t_Final(unsigned char *md, SHA512_CTX *c); 76 | unsigned char *SHA512t(const unsigned char *d, size_t n, unsigned char *md, unsigned int t); 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /sha512/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: utils.c 3 | * @ description: utilities for hash algorithem implementation 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #include 8 | #include "utils.h" 9 | 10 | #define DUMP_LINE_SIZE 16 11 | int print_buffer(const void *buf, unsigned long len, const char *indent) 12 | { 13 | unsigned long i = 0; 14 | for (i=0; i> 8) & 0xff) \ 19 | | (((x) & 0xff) << 8))) 20 | 21 | /* Swap bytes in 32 bit value. */ 22 | #define __bswap_32(x) \ 23 | ((((x) & 0xff000000) >> 24) \ 24 | | (((x) & 0x00ff0000) >> 8) \ 25 | | (((x) & 0x0000ff00) << 8) \ 26 | | (((x) & 0x000000ff) << 24)) 27 | 28 | /* Swap bytes in 64 bit value. */ 29 | #define __bswap_64(x) \ 30 | ((((x) & 0xff00000000000000ull) >> 56) \ 31 | | (((x) & 0x00ff000000000000ull) >> 40) \ 32 | | (((x) & 0x0000ff0000000000ull) >> 24) \ 33 | | (((x) & 0x000000ff00000000ull) >> 8) \ 34 | | (((x) & 0x00000000ff000000ull) << 8) \ 35 | | (((x) & 0x0000000000ff0000ull) << 24) \ 36 | | (((x) & 0x000000000000ff00ull) << 40) \ 37 | | (((x) & 0x00000000000000ffull) << 56)) 38 | 39 | #if (ENDIANNESS == ENDIAN_LITTLE) 40 | #define htole16(x) (x) 41 | #define htole32(x) (x) 42 | #define htole64(x) (x) 43 | 44 | #define htobe16(x) __bswap_16(x) 45 | #define htobe32(x) __bswap_32(x) 46 | #define htobe64(x) __bswap_64(x) 47 | #else 48 | #define htole16(x) __bswap_16(x) 49 | #define htole32(x) __bswap_32(x) 50 | #define htole64(x) __bswap_64(x) 51 | 52 | #define htobe16(x) (x) 53 | #define htobe32(x) (x) 54 | #define htobe64(x) (x) 55 | #endif 56 | 57 | #define le16toh(x) htole16(x) 58 | #define le32toh(x) htole32(x) 59 | #define le64toh(x) htole64(x) 60 | 61 | #define be16toh(x) htobe16(x) 62 | #define be32toh(x) htobe32(x) 63 | #define be64toh(x) htobe64(x) 64 | 65 | int print_buffer(const void *buf, unsigned long len, const char *indent); 66 | 67 | #endif -------------------------------------------------------------------------------- /sm3/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean sm3 test 2 | 3 | CROSS_COMPILE= 4 | 5 | CC = $(CROSS_COMPILE)gcc 6 | STRIP = $(CROSS_COMPILE)strip 7 | AR = $(CROSS_COMPILE)ar 8 | ARFLAGS = crs 9 | 10 | RM = rm 11 | RMFLAGS = -rf 12 | 13 | LIBS = 14 | INCLUDE = 15 | CFLAGS = -Wall -g -O2 16 | 17 | SRCS = utils.c sm3.c sm3test.c 18 | TARGET = sm3 19 | 20 | OBJS = $(SRCS:.c=.o) 21 | 22 | all: sm3 test 23 | 24 | %.o: %.c 25 | $(CC) $(CFLAGS) -c $< -o $@ 26 | 27 | $(TARGET): $(OBJS) 28 | $(CC) $(CFLAGS) $(OBJS) -o $@ $(LIBS) $(INCLUDE) 29 | # $(STRIP) --strip-all $(TARGET) 30 | 31 | test: $(TARGET) 32 | @echo 33 | @echo "Run Test..." 34 | ./$(TARGET) -x 35 | 36 | clean: 37 | $(RM) $(RMFLAGS) $(TARGET) $(OBJS) 38 | -------------------------------------------------------------------------------- /sm3/sm3.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: sm3.c 3 | * @ description: implementation for the SM3 Cryptographic Hash Algorithm 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #include 8 | #include 9 | 10 | #include "utils.h" 11 | #include "sm3.h" 12 | 13 | // #define DEBUG 14 | 15 | #ifdef DEBUG 16 | #define DBG(...) printf(__VA_ARGS__) 17 | #define DUMP_SCHED_DATA 1 18 | #define DUMP_BLOCK_DATA 1 19 | #define DUMP_BLOCK_HASH 1 20 | #define DUMP_ROUND_DATA 1 21 | #else 22 | #define DBG(...) 23 | #define DUMP_SCHED_DATA 0 24 | #define DUMP_BLOCK_DATA 0 25 | #define DUMP_BLOCK_HASH 0 26 | #define DUMP_ROUND_DATA 0 27 | #endif 28 | 29 | #define HASH_BLOCK_SIZE 64 /* 512 bits = 64 Bytes */ 30 | #define HASH_LEN_SIZE 8 /* 64 bits = 8 bytes */ 31 | #define HASH_LEN_OFFSET (HASH_BLOCK_SIZE - HASH_LEN_SIZE) 32 | 33 | #define HASH_DIGEST_SIZE 32 /* 256 bits = 32 bytes */ 34 | 35 | #define HASH_PADDING_PATTERN 0x80 36 | #define HASH_ROUND_NUM 64 37 | 38 | /* SM3 Constants */ 39 | static uint32_t T[2] = 40 | { 41 | 0x79CC4519, 0x7A879D8A 42 | }; 43 | 44 | /* ROTate Left (circular left shift) */ 45 | static uint32_t ROTL(uint32_t x, uint8_t shift) 46 | { 47 | shift %= 32; 48 | return (x << shift) | (x >> (32 - shift)); 49 | } 50 | 51 | static uint32_t FF(uint32_t x, uint32_t y, uint32_t z, uint32_t j) 52 | { 53 | if (j<16) /* 0 <= j <= 15 */ 54 | { 55 | return x ^ y ^ z; 56 | } 57 | else /* 16 <= j <= 63 */ 58 | { 59 | return (x & y) | (x & z) | (y & z); 60 | } 61 | } 62 | 63 | static uint32_t GG(uint32_t x, uint32_t y, uint32_t z, uint32_t j) 64 | { 65 | if (j<16) /* 0 <= j <= 15 */ 66 | { 67 | return x ^ y ^ z; 68 | } 69 | else /* 16 <= j <= 63 */ 70 | { 71 | return (x & y) | (~x & z); 72 | } 73 | } 74 | 75 | /* P0, Permutation 0 */ 76 | static uint32_t P0(uint32_t x) 77 | { 78 | return x ^ ROTL(x, 9) ^ ROTL(x, 17); 79 | } 80 | 81 | /* P1, Permutation 1 */ 82 | static uint32_t P1(uint32_t x) 83 | { 84 | return x ^ ROTL(x, 15) ^ ROTL(x, 23); 85 | } 86 | 87 | int SM3_Init(SM3_CTX *c) 88 | { 89 | if (NULL == c) 90 | { 91 | return ERR_INV_PARAM; 92 | } 93 | 94 | memset(c, 0, sizeof(SM3_CTX)); 95 | 96 | /* Initial Value for SM3 */ 97 | c->hash.a = 0x7380166f; 98 | c->hash.b = 0x4914b2b9; 99 | c->hash.c = 0x172442d7; 100 | c->hash.d = 0xda8a0600; 101 | c->hash.e = 0xa96f30bc; 102 | c->hash.f = 0x163138aa; 103 | c->hash.g = 0xe38dee4d; 104 | c->hash.h = 0xb0fb0e4e; 105 | 106 | return ERR_OK; 107 | } 108 | 109 | static int SM3_PrepareScheduleWord(const uint32_t *block, uint32_t *W, uint32_t *Wp) 110 | { 111 | uint32_t j; 112 | 113 | if ((NULL == block) || (NULL == W) || (NULL == Wp)) 114 | { 115 | return ERR_INV_PARAM; 116 | } 117 | 118 | /* Array W */ 119 | for (j=0; j<(HASH_ROUND_NUM+4); j++) 120 | { 121 | if (j<=15) /* 0 <= j <= 15 */ 122 | W[j] = be32toh(block[j]); 123 | else /* 16 <= j <= 67 */ 124 | W[j] = P1(W[j-16] ^ W[j-9] ^ ROTL(W[j-3],15)) ^ ROTL(W[j-13],7) ^ W[j-6]; 125 | } 126 | 127 | /* Array W Prime */ 128 | for (j=0; jtotal/HASH_BLOCK_SIZE); 194 | DBG(" DATA:\n"); 195 | print_buffer(block, HASH_BLOCK_SIZE, " "); 196 | #endif 197 | 198 | /* prepare schedule word */ 199 | SM3_PrepareScheduleWord(block, W, Wp); 200 | 201 | A = ctx->hash.a; 202 | B = ctx->hash.b; 203 | C = ctx->hash.c; 204 | D = ctx->hash.d; 205 | E = ctx->hash.e; 206 | F = ctx->hash.f; 207 | G = ctx->hash.g; 208 | H = ctx->hash.h; 209 | 210 | #if (DUMP_BLOCK_HASH == 1) 211 | DBG(" IV: %08x %08x %08x %08x %08x %08x %08x %08x\n", 212 | ctx->hash.a, ctx->hash.b, ctx->hash.c, ctx->hash.d, ctx->hash.e, ctx->hash.f, ctx->hash.g, ctx->hash.h); 213 | #endif 214 | 215 | for (j=0; jhash.a ^= A; 243 | ctx->hash.b ^= B; 244 | ctx->hash.c ^= C; 245 | ctx->hash.d ^= D; 246 | ctx->hash.e ^= E; 247 | ctx->hash.f ^= F; 248 | ctx->hash.g ^= G; 249 | ctx->hash.h ^= H; 250 | 251 | #if (DUMP_BLOCK_HASH == 1) 252 | DBG(" HASH: %08x %08x %08x %08x %08x %08x %08x %08x\n", 253 | ctx->hash.a, ctx->hash.b, ctx->hash.c, ctx->hash.d, ctx->hash.e, ctx->hash.f, ctx->hash.g, ctx->hash.h); 254 | #endif 255 | 256 | return ERR_OK; 257 | } 258 | 259 | 260 | int SM3_Update(SM3_CTX *c, const void *data, size_t len) 261 | { 262 | uint32_t copy_len = 0; 263 | 264 | if ((NULL == c) || (NULL == data)) 265 | { 266 | return ERR_INV_PARAM; 267 | } 268 | 269 | /* has used data */ 270 | if (c->last.used != 0) 271 | { 272 | /* less than 1 block in total, combine data */ 273 | if (c->last.used + len < HASH_BLOCK_SIZE) 274 | { 275 | memcpy(&c->last.buf[c->last.used], data, len); 276 | c->last.used += len; 277 | 278 | return ERR_OK; 279 | } 280 | else /* more than 1 block */ 281 | { 282 | /* process the block in context buffer */ 283 | copy_len = HASH_BLOCK_SIZE - c->last.used; 284 | memcpy(&c->last.buf[c->last.used], data, copy_len); 285 | SM3_ProcessBlock(c, &c->last.buf); 286 | c->total += HASH_BLOCK_SIZE; 287 | 288 | data = (uint8_t *)data + copy_len; 289 | len -= copy_len; 290 | 291 | /* reset context buffer */ 292 | memset(&c->last.buf[0], 0, HASH_BLOCK_SIZE); 293 | c->last.used = 0; 294 | } 295 | } 296 | 297 | /* less than 1 block, copy to context buffer */ 298 | if (len < HASH_BLOCK_SIZE) 299 | { 300 | memcpy(&c->last.buf[c->last.used], data, len); 301 | c->last.used += len; 302 | 303 | return ERR_OK; 304 | } 305 | else 306 | { 307 | /* process data blocks */ 308 | while (len >= HASH_BLOCK_SIZE) 309 | { 310 | SM3_ProcessBlock(c, data); 311 | c->total += HASH_BLOCK_SIZE; 312 | 313 | data = (uint8_t *)data + HASH_BLOCK_SIZE; 314 | len -= HASH_BLOCK_SIZE; 315 | } 316 | 317 | /* copy rest data to context buffer */ 318 | memcpy(&c->last.buf[0], data, len); 319 | c->last.used = len; 320 | } 321 | 322 | return ERR_OK; 323 | } 324 | 325 | int SM3_Final(unsigned char *md, SM3_CTX *c) 326 | { 327 | uint32_t *temp; 328 | //uint64_t *buf; 329 | 330 | if ((NULL == c) || (NULL == md)) 331 | { 332 | return ERR_INV_PARAM; 333 | } 334 | 335 | /* Last block should be less thant HASH_BLOCK_SIZE - HASH_LEN_SIZE */ 336 | if (c->last.used >= (HASH_BLOCK_SIZE - HASH_LEN_SIZE)) 337 | { 338 | c->total += c->last.used; 339 | 340 | /* one more block */ 341 | c->last.buf[c->last.used] = HASH_PADDING_PATTERN; 342 | c->last.used++; 343 | 344 | memset(&c->last.buf[c->last.used], 0, HASH_BLOCK_SIZE - c->last.used); 345 | SM3_ProcessBlock(c, &c->last.buf); 346 | 347 | memset(&c->last.buf[0], 0, HASH_BLOCK_SIZE - HASH_LEN_SIZE); 348 | c->last.used = 0; 349 | 350 | /* save length */ 351 | //buf = (uint64_t *)&(c->last.buf[HASH_LEN_OFFSET]); 352 | //*buf = htobe64(c->total << 3); 353 | temp = (uint32_t *)&(c->last.buf[HASH_LEN_OFFSET]); 354 | temp[0] = htobe32((c->total << 3) >> 32 & 0xFFFFFFFF); 355 | temp[1] = htobe32((c->total << 3) & 0xFFFFFFFF); 356 | 357 | SM3_ProcessBlock(c, &c->last.buf); 358 | } 359 | else /* 0 <= last.used < HASH_BLOCK_SIZE - HASH_LEN_SIZE */ 360 | { 361 | c->total += c->last.used; 362 | 363 | /* one more block */ 364 | c->last.buf[c->last.used] = HASH_PADDING_PATTERN; 365 | c->last.used++; 366 | 367 | /* padding 0s */ 368 | memset(&c->last.buf[c->last.used], 0, HASH_BLOCK_SIZE - HASH_LEN_SIZE - c->last.used); 369 | 370 | /* save length */ 371 | //buf = (uint64_t *)&(c->last.buf[HASH_LEN_OFFSET]); 372 | //*buf = htobe64(c->total << 3); 373 | temp = (uint32_t *)&(c->last.buf[HASH_LEN_OFFSET]); 374 | temp[0] = htobe32((c->total << 3) >> 32 & 0xFFFFFFFF); 375 | temp[1] = htobe32((c->total << 3) & 0xFFFFFFFF); 376 | 377 | SM3_ProcessBlock(c, &c->last.buf); 378 | } 379 | 380 | temp = (uint32_t *)md; 381 | temp[0] = htobe32(c->hash.a); 382 | temp[1] = htobe32(c->hash.b); 383 | temp[2] = htobe32(c->hash.c); 384 | temp[3] = htobe32(c->hash.d); 385 | temp[4] = htobe32(c->hash.e); 386 | temp[5] = htobe32(c->hash.f); 387 | temp[6] = htobe32(c->hash.g); 388 | temp[7] = htobe32(c->hash.h); 389 | 390 | return ERR_OK; 391 | } 392 | 393 | unsigned char *SM3(const unsigned char *d, size_t n, unsigned char *md) 394 | { 395 | SM3_CTX c; 396 | 397 | if ((NULL == d) || (NULL == md)) 398 | { 399 | return NULL; 400 | } 401 | 402 | SM3_Init(&c); 403 | SM3_Update(&c, d, n); 404 | SM3_Final(md, &c); 405 | 406 | return md; 407 | } 408 | -------------------------------------------------------------------------------- /sm3/sm3.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: sm3.h 3 | * @ description: header file for sm3.c 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #ifndef __ROCKY_SM3__H 8 | #define __ROCKY_SM3__H 9 | 10 | #define ERR_OK 0 11 | #define ERR_ERR -1 /* generic error */ 12 | #define ERR_INV_PARAM -2 /* invalid parameter */ 13 | #define ERR_TOO_LONG -3 /* too long */ 14 | #define ERR_STATE_ERR -4 /* state error */ 15 | 16 | typedef unsigned char uint8_t; 17 | typedef unsigned short uint16_t; 18 | typedef unsigned int uint32_t; 19 | typedef unsigned long long uint64_t; 20 | 21 | typedef struct sm3_context { 22 | /* message total length in bytes */ 23 | uint64_t total; 24 | 25 | /* intermedia hash value for each block */ 26 | struct { 27 | uint32_t a; 28 | uint32_t b; 29 | uint32_t c; 30 | uint32_t d; 31 | uint32_t e; 32 | uint32_t f; 33 | uint32_t g; 34 | uint32_t h; 35 | }hash; 36 | 37 | /* last block */ 38 | struct { 39 | uint32_t used; /* used bytes */ 40 | uint8_t buf[64]; /* block data buffer */ 41 | }last; 42 | }SM3_CTX; 43 | 44 | /* https://www.openssl.org/docs/man1.1.1/man3/SHA256_Final.html */ 45 | 46 | int SM3_Init(SM3_CTX *c); 47 | int SM3_Update(SM3_CTX *c, const void *data, size_t len); 48 | int SM3_Final(unsigned char *md, SM3_CTX *c); 49 | unsigned char *SM3(const unsigned char *d, size_t n, unsigned char *md); 50 | #endif 51 | -------------------------------------------------------------------------------- /sm3/sm3test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @ file: sm3test.c 3 | * @ description: test tool for sm3 4 | * @ author: Gu Yongqiang 5 | * @ blog: https://blog.csdn.net/guyongqiangx 6 | */ 7 | #include /* printf, fopen, fread, fclose... */ 8 | #include /* exit */ 9 | #include /* strlen */ 10 | #include /* getopt */ 11 | 12 | #include "sm3.h" 13 | 14 | #define HASH_DIGEST_SIZE 32 /* sm3 digest size */ 15 | #define FILE_BLOCK_SIZE 1024 16 | 17 | /* 18 | * Print a usage message 19 | */ 20 | void usage(const char *argv0) 21 | { 22 | fprintf(stderr, 23 | "Usage:\n" 24 | "Common options: [-x|-f file|-s string|-h]\n" 25 | "Hash a string:\n" 26 | "\t%s -s string\n" 27 | "Hash a file:\n" 28 | "\t%s -f file [-k key]\n" 29 | "-x\tInternal string hash test\n" 30 | "-h\tDisplay this message\n" 31 | , argv0, argv0); 32 | exit(1); 33 | } 34 | 35 | /* 36 | * Print a message digest in hexadecimal 37 | */ 38 | static int print_digest(unsigned char *digest) 39 | { 40 | uint32_t i; 41 | 42 | for (i = 0; i < HASH_DIGEST_SIZE; i++) 43 | { 44 | printf ("%02x", digest[i]); 45 | } 46 | 47 | return 0; 48 | } 49 | 50 | struct HASH_ITEM { 51 | char *str; 52 | uint32_t len; 53 | unsigned char md[HASH_DIGEST_SIZE*2]; 54 | } hashes[] = 55 | { 56 | { /* 0 */ 57 | "", 58 | 0, 59 | "1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b" 60 | }, 61 | { /* 1 */ 62 | "a", 63 | 1, 64 | "623476ac18f65a2909e43c7fec61b49c7e764a91a18ccb82f1917a29c86c5e88" 65 | }, 66 | { /* 2 */ 67 | "abc", 68 | 3, 69 | "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0" 70 | }, 71 | { /* 3 */ 72 | "message digest", 73 | 14, 74 | "c522a942e89bd80d97dd666e7a5531b36188c9817149e9b258dfe51ece98ed77" 75 | }, 76 | { /* 4 */ 77 | "abcdefghijklmnopqrstuvwxyz", 78 | 26, 79 | "b80fe97a4da24afc277564f66a359ef440462ad28dcc6d63adb24d5c20a61595" 80 | }, 81 | { /* 5 */ 82 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 83 | 62, 84 | "2971d10c8842b70c979e55063480c50bacffd90e98e2e60d2512ab8abfdfcec5" 85 | }, 86 | { /* 6 */ 87 | "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 88 | 80, 89 | "ad81805321f3e69d251235bf886a564844873b56dd7dde400f055b7dde39307a" 90 | }, 91 | { /* 7 */ 92 | "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd", 93 | 64, 94 | "debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732" 95 | }, 96 | }; 97 | 98 | /* 99 | * Internal digest tests 100 | */ 101 | static int internal_digest_tests(const char *argv0) 102 | { 103 | unsigned char digest[HASH_DIGEST_SIZE]; 104 | struct HASH_ITEM *item; 105 | 106 | printf ("Internal hash tests for %s:\n", argv0); 107 | 108 | for (item=&hashes[0]; item<(&hashes[0]+sizeof(hashes)/sizeof(hashes[0])); item++) 109 | { 110 | printf("%s(\"%s\")\n", argv0, item->str); 111 | SM3((unsigned char*)item->str, item->len, digest); 112 | printf(" Expect: %s\n", item->md); 113 | printf(" Result: "); 114 | print_digest(digest); 115 | printf("\n\n"); 116 | } 117 | 118 | return 0; 119 | } 120 | 121 | /* 122 | * Hash a string and print the digest 123 | */ 124 | static int digest_string(const char *argv0, const unsigned char *string, uint32_t len) 125 | { 126 | unsigned char digest[HASH_DIGEST_SIZE]; 127 | 128 | printf("%s(\"%s\") = ", argv0, string); 129 | 130 | SM3(string, len, digest); 131 | 132 | print_digest(digest); 133 | printf("\n"); 134 | 135 | return 0; 136 | } 137 | 138 | /* 139 | * Hash a file and print the digest 140 | */ 141 | static int digest_file(const char *argv0, const char *filename) 142 | { 143 | SM3_CTX c; 144 | FILE *f; 145 | 146 | unsigned char digest[HASH_DIGEST_SIZE]; 147 | unsigned char buf[FILE_BLOCK_SIZE]; 148 | 149 | int len = 0; 150 | int rc = 0; 151 | 152 | f = fopen(filename, "rb"); 153 | if (NULL == f) 154 | { 155 | printf("Can't open file %s\n", filename); 156 | rc = -1; 157 | } 158 | else 159 | { 160 | printf("%s(%s) = ", argv0, filename); 161 | 162 | SM3_Init(&c); 163 | while ((len = fread(buf, 1, FILE_BLOCK_SIZE, f))) 164 | { 165 | SM3_Update(&c, buf, len); 166 | } 167 | SM3_Final(digest, &c); 168 | 169 | fclose(f); 170 | 171 | print_digest(digest); 172 | printf("\n"); 173 | 174 | rc = 0; 175 | } 176 | 177 | return rc; 178 | } 179 | 180 | /* 181 | * Hash the standard input and prints the digest 182 | */ 183 | static void digest_stdin(const char *argv0) 184 | { 185 | SM3_CTX c; 186 | 187 | int len; 188 | unsigned char digest[HASH_DIGEST_SIZE]; 189 | unsigned char buf[HASH_DIGEST_SIZE]; 190 | 191 | SM3_Init(&c); 192 | while ((len = fread(buf, 1, HASH_DIGEST_SIZE, stdin))) 193 | { 194 | SM3_Update(&c, buf, len); 195 | } 196 | SM3_Final(digest, &c); 197 | 198 | printf("%s(stdin) = ", argv0); 199 | print_digest(digest); 200 | printf("\n"); 201 | } 202 | 203 | /* 204 | * $ sm3 -h 205 | * Usage: 206 | * Common options: [-x|-f file|-s string|-h] 207 | * Hash a string: 208 | * sm3 -s string 209 | * Hash a file: 210 | * sm3 -f file [-k key] 211 | * -x Internal string hash test 212 | * -h Display this message 213 | */ 214 | int main(int argc, char *argv[]) 215 | { 216 | int ch; 217 | int hash_internal = 0; 218 | int hash_str = 0; 219 | int hash_file = 0; 220 | int hash_stdin = 0; 221 | 222 | char *str = NULL; 223 | uint32_t len = 0; 224 | 225 | char *filename = NULL; 226 | 227 | while ((ch = getopt(argc, argv, "s:f:xh")) != -1) 228 | { 229 | switch(ch) 230 | { 231 | case 'x': 232 | hash_internal = 1; 233 | break; 234 | case 's': 235 | hash_str = 1; 236 | str = optarg; 237 | len = strlen(str); 238 | break; 239 | case 'f': 240 | hash_file = 1; 241 | filename = optarg; 242 | break; 243 | case 'h': 244 | default: /* '?' */ 245 | usage(argv[0]); 246 | break; 247 | } 248 | } 249 | 250 | if (argc == 1) 251 | { 252 | hash_stdin = 1; 253 | } 254 | 255 | if (hash_internal) 256 | { 257 | internal_digest_tests(argv[0]); 258 | } 259 | 260 | if (hash_str) 261 | { 262 | digest_string(argv[0], (unsigned char *)str, len); 263 | } 264 | 265 | if (hash_file) 266 | { 267 | digest_file(argv[0], filename); 268 | } 269 | 270 | if (hash_stdin) 271 | { 272 | digest_stdin(argv[0]); 273 | } 274 | 275 | return 0; 276 | } 277 | -------------------------------------------------------------------------------- /sm3/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "utils.h" 3 | 4 | #define DUMP_LINE_SIZE 16 5 | int print_buffer(const void *buf, unsigned long len, const char *indent) 6 | { 7 | unsigned long i = 0; 8 | for (i=0; i> 8) & 0xff) \ 13 | | (((x) & 0xff) << 8))) 14 | 15 | /* Swap bytes in 32 bit value. */ 16 | #define __bswap_32(x) \ 17 | ((((x) & 0xff000000) >> 24) \ 18 | | (((x) & 0x00ff0000) >> 8) \ 19 | | (((x) & 0x0000ff00) << 8) \ 20 | | (((x) & 0x000000ff) << 24)) 21 | 22 | /* Swap bytes in 64 bit value. */ 23 | #define __bswap_64(x) \ 24 | ((((x) & 0xff00000000000000ull) >> 56) \ 25 | | (((x) & 0x00ff000000000000ull) >> 40) \ 26 | | (((x) & 0x0000ff0000000000ull) >> 24) \ 27 | | (((x) & 0x000000ff00000000ull) >> 8) \ 28 | | (((x) & 0x00000000ff000000ull) << 8) \ 29 | | (((x) & 0x0000000000ff0000ull) << 24) \ 30 | | (((x) & 0x000000000000ff00ull) << 40) \ 31 | | (((x) & 0x00000000000000ffull) << 56)) 32 | 33 | #if (ENDIANNESS == ENDIAN_LITTLE) 34 | #define htole16(x) (x) 35 | #define htole32(x) (x) 36 | #define htole64(x) (x) 37 | 38 | #define htobe16(x) __bswap_16(x) 39 | #define htobe32(x) __bswap_32(x) 40 | #define htobe64(x) __bswap_64(x) 41 | #else 42 | #define htole16(x) __bswap_16(x) 43 | #define htole32(x) __bswap_32(x) 44 | #define htole64(x) __bswap_64(x) 45 | 46 | #define htobe16(x) (x) 47 | #define htobe32(x) (x) 48 | #define htobe64(x) (x) 49 | #endif 50 | 51 | #define le16toh(x) htole16(x) 52 | #define le32toh(x) htole32(x) 53 | #define le64toh(x) htole64(x) 54 | 55 | #define be16toh(x) htobe16(x) 56 | #define be32toh(x) htobe32(x) 57 | #define be64toh(x) htobe64(x) 58 | 59 | int print_buffer(const void *buf, unsigned long len, const char *indent); 60 | 61 | #endif -------------------------------------------------------------------------------- /sm3/国密-SM3密码杂凑算法.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guyongqiangx/cryptography/9bfd756a980b8958f5242fb7ad383d42420a49b5/sm3/国密-SM3密码杂凑算法.pdf --------------------------------------------------------------------------------