├── .gitignore ├── LICENSE └── src ├── sha1.cc ├── sm3.cc ├── sha2_256.cc ├── sha3_512.cc ├── sha3_256.cc ├── sm4_ecb.cc ├── sm4_cbc.cc ├── sm4_ofb.cc ├── sm4_ctr.cc ├── sha2_512.cc ├── aes_ecb.cc ├── aes_ofb.cc ├── aes_cbc.cc ├── aes_ctr.cc ├── des_ecb.cc ├── des_cfb.cc ├── des_ofb.cc ├── des_cbc.cc ├── des_ctr.cc └── aes_gcm.cc /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jamis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /src/sha1.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: sha1.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 11, 2015 12 | * Time: 15:47:06 13 | * Description: SHA-1 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | void sha1_iteration(const uint8_t* data, uint32_t h[]) { 22 | // rotate functions 23 | auto left_rotate = [](uint32_t x, const size_t i)->uint32_t { 24 | return x << i | x >> (sizeof(uint32_t) * 8 - i); 25 | }; 26 | 27 | // extend 16 32-bit words to 80 32-bit words 28 | uint32_t word[80]; 29 | for (size_t j = 0; j < 16; ++j) 30 | word[j] = data[4 * j + 0] << 24 | data[4 * j + 1] << 16 | 31 | data[4 * j + 2] << 8 | data[4 * j + 3]; 32 | 33 | for (size_t j = 16; j < 80; ++j) 34 | word[j] = left_rotate(word[j - 3] ^ word[j - 8] ^ word[j - 14] ^ word[j - 16], 1); 35 | 36 | 37 | uint32_t a = h[0], b = h[1], c = h[2], d = h[3], e = h[4]; 38 | 39 | // main loop 40 | for (size_t j = 0; j < 80; ++j) { 41 | int f, k; 42 | if (j < 20) 43 | f = (b & c) | (~b & d), k = 0x5A827999; 44 | else if (j < 40) 45 | f = b ^ c ^ d, k = 0x6ED9EBA1; 46 | else if (j < 60) 47 | f = (b & c) | (b & d) | (c & d), k = 0x8F1BBCDC; 48 | else 49 | f = b ^ c ^ d, k = 0xCA62C1D6; 50 | 51 | uint32_t tmp = left_rotate(a, 5) + f + e + k + word[j]; 52 | e = d, d = c, c = left_rotate(b, 30), b = a, a = tmp; 53 | } 54 | 55 | h[0] += a, h[1] += b, h[2] += c, h[3] += d, h[4] += e; 56 | } 57 | 58 | // len: in bytes 59 | // hash: at least 20 bytes available 60 | void sha1(const void* data, size_t len, char* hash) { 61 | uint8_t* data_ = (uint8_t*)data; 62 | constexpr size_t block_size = 64; 63 | 64 | uint32_t h[5] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; 65 | 66 | size_t ml = len * 8; 67 | 68 | for (size_t i = 0; i < len / block_size; ++i) 69 | sha1_iteration(data_ + i * block_size, h); 70 | 71 | uint8_t buffer[block_size]; 72 | 73 | memcpy(buffer, data_ + len / block_size * block_size, len % block_size); 74 | len %= block_size; 75 | 76 | // append bit '1' 77 | buffer[len++] = 0x80; 78 | 79 | if (len % block_size == 0) { 80 | sha1_iteration(buffer, h); 81 | len = 0; 82 | } 83 | 84 | // append until the resulting message length (in bits) is congruent to 448 (mod 512) 85 | while (len % block_size != 56) { 86 | buffer[len++] = 0x00; 87 | if (len % block_size == 0) { 88 | sha1_iteration(buffer, h); 89 | len = 0; 90 | } 91 | } 92 | 93 | // append length 94 | buffer[len++] = ml >> 56, buffer[len++] = ml >> 48, 95 | buffer[len++] = ml >> 40, buffer[len++] = ml >> 32, 96 | buffer[len++] = ml >> 24, buffer[len++] = ml >> 16, 97 | buffer[len++] = ml >> 8, buffer[len++] = ml; 98 | 99 | sha1_iteration(buffer, h); 100 | 101 | for (size_t i = 0; i < 20; i += 4) 102 | hash[i] = h[i / 4] >> 24, hash[i + 1] = h[i / 4] >> 16, 103 | hash[i + 2] = h[i / 4] >> 8, hash[i + 3] = h[i / 4]; 104 | } 105 | 106 | 107 | 108 | int main(int argc, char** argv) { 109 | uint8_t hash[20]; 110 | 111 | if (argc == 1) return 0; 112 | 113 | std::ifstream fin(argv[1]); 114 | 115 | fin.seekg(0, std::ios::end); 116 | std::string buffer; 117 | buffer.reserve(fin.tellg()); 118 | fin.seekg(0, std::ios::beg); 119 | 120 | buffer.assign((std::istreambuf_iterator(fin)), 121 | std::istreambuf_iterator()); 122 | 123 | 124 | sha1(buffer.data(), buffer.length(), (char*)hash); 125 | 126 | for (int i = 0; i < 20; ++i) 127 | printf("%02x", int(hash[i]) & 0xff); 128 | printf("\n"); 129 | 130 | } 131 | -------------------------------------------------------------------------------- /src/sm3.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: sm3.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 11, 2015 12 | * Time: 22:13:27 13 | * Description: SM3 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | void sm3_iteration(const uint8_t* data, uint32_t hi[]) { 22 | // rotate function 23 | auto left_rotate = [](uint32_t x, const size_t i)->uint32_t { 24 | return x << i | x >> (sizeof(uint32_t) * 8 - i); 25 | }; 26 | 27 | uint32_t T[64]; 28 | for (size_t i = 0; i < 16; ++i) T[i] = 0x79CC4519; 29 | for (size_t i = 16; i < 64; ++i) T[i] = 0x7A879D8A; 30 | 31 | uint32_t W[68]; 32 | for (size_t i = 0; i < 16; ++i) 33 | W[i] = data[4 * i + 0] << 24 | data[4 * i + 1] << 16 | 34 | data[4 * i + 2] << 8 | data[4 * i + 3] << 0; 35 | for (size_t i = 16; i < 68; ++i) { 36 | uint32_t tmp = W[i - 16] ^ W[i - 9] ^ left_rotate(W[i - 3], 15); 37 | tmp = tmp ^ left_rotate(tmp, 15) ^ left_rotate(tmp, 23); 38 | W[i] = tmp ^ left_rotate(W[i - 13], 7) ^ W[i - 6]; 39 | } 40 | 41 | 42 | uint32_t W1[64]; 43 | for (size_t i = 0; i < 64; ++i) 44 | W1[i] = W[i] ^ W[i + 4]; 45 | 46 | uint32_t A = hi[0], B = hi[1], C = hi[2], D = hi[3], 47 | E = hi[4], F = hi[5], G = hi[6], H = hi[7]; 48 | 49 | for (size_t i = 0; i < 16; ++i) { 50 | uint32_t SS1 = left_rotate(left_rotate(A, 12) + E + left_rotate(T[i], i), 7); 51 | uint32_t SS2 = SS1 ^ left_rotate(A, 12); 52 | uint32_t TT1 = (A ^ B ^ C) + D + SS2 + W1[i]; 53 | uint32_t TT2 = (E ^ F ^ G) + H + SS1 + W[i]; 54 | D = C; 55 | C = left_rotate(B, 9); 56 | B = A; 57 | A = TT1; 58 | H = G; 59 | G = left_rotate(F, 19); 60 | F = E; 61 | E = TT2 ^ left_rotate(TT2, 9) ^ left_rotate(TT2, 17); 62 | } 63 | 64 | for (size_t i = 16; i < 64; ++i) { 65 | uint32_t SS1 = left_rotate(left_rotate(A, 12) + E + left_rotate(T[i], i), 7); 66 | uint32_t SS2 = SS1 ^ left_rotate(A, 12); 67 | uint32_t TT1 = ((A & B) | (B & C) | (A & C)) + D + SS2 + W1[i]; 68 | uint32_t TT2 = ((E & F) | (~E & G)) + H + SS1 + W[i]; 69 | D = C; 70 | C = left_rotate(B, 9); 71 | B = A; 72 | A = TT1; 73 | H = G; 74 | G = left_rotate(F, 19); 75 | F = E; 76 | E = TT2 ^ left_rotate(TT2, 9) ^ left_rotate(TT2, 17); 77 | } 78 | 79 | hi[0] ^= A, hi[1] ^= B, hi[2] ^= C, hi[3] ^= D, 80 | hi[4] ^= E, hi[5] ^= F, hi[6] ^= G, hi[7] ^= H; 81 | } 82 | 83 | // len: in bytes 84 | // hash: at least 32 bytes available 85 | void sm3(const void* data, size_t len, char* hash) { 86 | uint8_t* data_ = (uint8_t*)data; 87 | constexpr size_t block_size = 64; 88 | 89 | uint32_t h[8] = { 0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600, 90 | 0xA96F30BC, 0x163138AA, 0xE38DEE4D, 0xB0FB0E4E }; 91 | 92 | size_t ml = len * 8; 93 | 94 | for (size_t i = 0; i < len / block_size; ++i) 95 | sm3_iteration(data_ + i * block_size, h); 96 | 97 | uint8_t buffer[block_size]; 98 | 99 | memcpy(buffer, data_ + len / block_size * block_size, len % block_size); 100 | len %= block_size; 101 | 102 | // append bit '1' 103 | buffer[len++] = 0x80; 104 | 105 | if (len % block_size == 0) { 106 | sm3_iteration(buffer, h); 107 | len = 0; 108 | } 109 | 110 | // append until the resulting message length (in bits) is congruent to 448 (mod 512) 111 | while (len % block_size != 56) { 112 | buffer[len++] = 0x00; 113 | if (len % block_size == 0) { 114 | sm3_iteration(buffer, h); 115 | len = 0; 116 | } 117 | } 118 | 119 | // append length 120 | buffer[len++] = ml >> 56, buffer[len++] = ml >> 48, 121 | buffer[len++] = ml >> 40, buffer[len++] = ml >> 32, 122 | buffer[len++] = ml >> 24, buffer[len++] = ml >> 16, 123 | buffer[len++] = ml >> 8, buffer[len++] = ml; 124 | 125 | sm3_iteration(buffer, h); 126 | 127 | for (size_t i = 0; i < 32; i += 4) 128 | hash[i] = h[i / 4] >> 24, hash[i + 1] = h[i / 4] >> 16, 129 | hash[i + 2] = h[i / 4] >> 8, hash[i + 3] = h[i / 4]; 130 | } 131 | 132 | 133 | 134 | int main(int argc, char** argv) { 135 | uint8_t hash[32]; 136 | 137 | if (argc == 1) return 0; 138 | 139 | std::ifstream fin(argv[1]); 140 | 141 | fin.seekg(0, std::ios::end); 142 | std::string buffer; 143 | buffer.reserve(fin.tellg()); 144 | fin.seekg(0, std::ios::beg); 145 | 146 | buffer.assign((std::istreambuf_iterator(fin)), 147 | std::istreambuf_iterator()); 148 | 149 | 150 | sm3(buffer.data(), buffer.length(), (char*)hash); 151 | 152 | for (int i = 0; i < 32; ++i) 153 | printf("%02x", int(hash[i]) & 0xff); 154 | printf("\n"); 155 | 156 | } 157 | -------------------------------------------------------------------------------- /src/sha2_256.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: sha2_256.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 11, 2015 12 | * Time: 22:13:27 13 | * Description: SHA-2 (256 bit) 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | void sha2_iteration(const uint8_t* data, uint32_t hi[]) { 22 | // rotate function 23 | auto right_rotate = [](uint32_t x, const size_t i)->uint32_t { 24 | return x >> i | x << (sizeof(uint32_t) * 8 - i); 25 | }; 26 | 27 | constexpr uint32_t k[64] = { 28 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 29 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 30 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 31 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 32 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 33 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 34 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 35 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 36 | }; 37 | 38 | // extend 16 32-bit words to 80 32-bit words 39 | uint32_t word[80]; 40 | for (size_t j = 0; j < 16; ++j) 41 | word[j] = data[4 * j + 0] << 24 | data[4 * j + 1] << 16 | 42 | data[4 * j + 2] << 8 | data[4 * j + 3]; 43 | 44 | for (size_t j = 16; j < 80; ++j) { 45 | uint32_t s0 = right_rotate(word[j - 15], 7) ^ 46 | right_rotate(word[j - 15], 18) ^ 47 | word[j - 15] >> 3; 48 | uint32_t s1 = right_rotate(word[j - 2], 17) ^ 49 | right_rotate(word[j - 2], 19) ^ 50 | word[j - 2] >> 10; 51 | word[j] = word[j - 16] + s0 + word[j - 7] + s1; 52 | } 53 | 54 | uint32_t a = hi[0], b = hi[1], c = hi[2], d = hi[3], 55 | e = hi[4], f = hi[5], g = hi[6], h = hi[7]; 56 | 57 | 58 | // main loop 59 | for (size_t i = 0; i < 64; ++i) { 60 | uint32_t S1 = right_rotate(e, 6) ^ 61 | right_rotate(e, 11) ^ 62 | right_rotate(e, 25); 63 | uint32_t ch = (e & f) ^ (~e & g); 64 | uint32_t tmp1 = h + S1 + ch + k[i] + word[i]; 65 | uint32_t S0 = right_rotate(a, 2) ^ 66 | right_rotate(a, 13) ^ 67 | right_rotate(a, 22); 68 | uint32_t maj = (a & b) ^ (a & c) ^ (b & c); 69 | uint32_t tmp2 = S0 + maj; 70 | 71 | h = g, g = f, f = e, e = d + tmp1, d = c, c = b, b = a, a = tmp1 + tmp2; 72 | } 73 | 74 | hi[0] += a, hi[1] += b, hi[2] += c, hi[3] += d, 75 | hi[4] += e, hi[5] += f, hi[6] += g, hi[7] += h; 76 | } 77 | 78 | // len: in bytes 79 | // hash: at least 32 bytes available 80 | void sha2(const void* data, size_t len, char* hash) { 81 | uint8_t* data_ = (uint8_t*)data; 82 | constexpr size_t block_size = 64; 83 | 84 | uint32_t h[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 }; 85 | 86 | size_t ml = len * 8; 87 | 88 | for (size_t i = 0; i < len / block_size; ++i) 89 | sha2_iteration(data_ + i * block_size, h); 90 | 91 | uint8_t buffer[block_size]; 92 | 93 | memcpy(buffer, data_ + len / block_size * block_size, len % block_size); 94 | len %= block_size; 95 | 96 | // append bit '1' 97 | buffer[len++] = 0x80; 98 | 99 | if (len % block_size == 0) { 100 | sha2_iteration(buffer, h); 101 | len = 0; 102 | } 103 | 104 | // append until the resulting message length (in bits) is congruent to 448 (mod 512) 105 | while (len % block_size != 56) { 106 | buffer[len++] = 0x00; 107 | if (len % block_size == 0) { 108 | sha2_iteration(buffer, h); 109 | len = 0; 110 | } 111 | } 112 | 113 | // append length 114 | buffer[len++] = ml >> 56, buffer[len++] = ml >> 48, 115 | buffer[len++] = ml >> 40, buffer[len++] = ml >> 32, 116 | buffer[len++] = ml >> 24, buffer[len++] = ml >> 16, 117 | buffer[len++] = ml >> 8, buffer[len++] = ml; 118 | 119 | sha2_iteration(buffer, h); 120 | 121 | for (size_t i = 0; i < 32; i += 4) 122 | hash[i] = h[i / 4] >> 24, hash[i + 1] = h[i / 4] >> 16, 123 | hash[i + 2] = h[i / 4] >> 8, hash[i + 3] = h[i / 4]; 124 | } 125 | 126 | 127 | 128 | int main(int argc, char** argv) { 129 | uint8_t hash[32]; 130 | 131 | if (argc == 1) return 0; 132 | 133 | std::ifstream fin(argv[1]); 134 | 135 | fin.seekg(0, std::ios::end); 136 | std::string buffer; 137 | buffer.reserve(fin.tellg()); 138 | fin.seekg(0, std::ios::beg); 139 | 140 | buffer.assign((std::istreambuf_iterator(fin)), 141 | std::istreambuf_iterator()); 142 | 143 | 144 | sha2(buffer.data(), buffer.length(), (char*)hash); 145 | 146 | for (int i = 0; i < 32; ++i) 147 | printf("%02x", int(hash[i]) & 0xff); 148 | printf("\n"); 149 | 150 | } 151 | -------------------------------------------------------------------------------- /src/sha3_512.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: sha3_512.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 20, 2015 12 | * Time: 10:01:31 13 | * Description: SHA-3 (512 bit) 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | 22 | // rotate functions 23 | inline uint64_t right_rotate(uint64_t x, const size_t i) { 24 | return x >>i | x << (sizeof(uint64_t) * 8 - i); 25 | } 26 | 27 | inline uint64_t left_rotate(uint64_t x, const size_t i) { 28 | return x << i | x >> (sizeof(uint64_t) * 8 - i); 29 | } 30 | 31 | inline void keccak_theta(uint64_t A[]) { 32 | uint64_t C[5], D[5]; 33 | for (size_t i = 0; i < 5; ++i) 34 | C[i] = A[i] ^ A[i + 5] ^ A[i + 10] ^ A[i + 15] ^ A[i + 20]; 35 | 36 | D[0] = left_rotate(C[1], 1) ^ C[4]; 37 | D[1] = left_rotate(C[2], 1) ^ C[0]; 38 | D[2] = left_rotate(C[3], 1) ^ C[1]; 39 | D[3] = left_rotate(C[4], 1) ^ C[2]; 40 | D[4] = left_rotate(C[0], 1) ^ C[3]; 41 | 42 | for (size_t i = 0; i < 5; ++i) { 43 | A[i] ^= D[i]; 44 | A[i + 5] ^= D[i]; 45 | A[i + 10] ^= D[i]; 46 | A[i + 15] ^= D[i]; 47 | A[i + 20] ^= D[i]; 48 | } 49 | } 50 | 51 | inline void keccak_pi(uint64_t A[]) { 52 | uint64_t A1 = A[1]; 53 | A[ 1] = A[ 6], A[ 6] = A[ 9], A[ 9] = A[22], A[22] = A[14], 54 | A[14] = A[20], A[20] = A[ 2], A[ 2] = A[12], A[12] = A[13], 55 | A[13] = A[19], A[19] = A[23], A[23] = A[15], A[15] = A[ 4], 56 | A[ 4] = A[24], A[24] = A[21], A[21] = A[ 8], A[ 8] = A[16], 57 | A[16] = A[ 5], A[ 5] = A[ 3], A[ 3] = A[18], A[18] = A[17], 58 | A[17] = A[11], A[11] = A[ 7], A[ 7] = A[10], A[10] = A1; 59 | } 60 | 61 | inline void keccak_chi(uint64_t A[]) { 62 | for (size_t i = 0; i < 25; i += 5) { 63 | uint64_t A0 = A[0 + i], A1 = A[1 + i]; 64 | A[0 + i] ^= ~A1 & A[2 + i]; 65 | A[1 + i] ^= ~A[2 + i] & A[3 + i]; 66 | A[2 + i] ^= ~A[3 + i] & A[4 + i]; 67 | A[3 + i] ^= ~A[4 + i] & A0; 68 | A[4 + i] ^= ~A0 & A1; 69 | } 70 | } 71 | 72 | inline void sha3_permutation(uint64_t state[]) { 73 | constexpr uint64_t keccak_round_constants[24] = { 74 | 0x0000000000000001, 0x0000000000008082, 0x800000000000808A, 75 | 0x8000000080008000, 0x000000000000808B, 0x0000000080000001, 76 | 0x8000000080008081, 0x8000000000008009, 0x000000000000008A, 77 | 0x0000000000000088, 0x0000000080008009, 0x000000008000000A, 78 | 0x000000008000808B, 0x800000000000008B, 0x8000000000008089, 79 | 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 80 | 0x000000000000800A, 0x800000008000000A, 0x8000000080008081, 81 | 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, 82 | }; 83 | for (size_t round = 0; round < 24; round++) { 84 | keccak_theta(state); 85 | 86 | state[ 1] = left_rotate(state[ 1], 1); 87 | state[ 2] = left_rotate(state[ 2], 62); 88 | state[ 3] = left_rotate(state[ 3], 28); 89 | state[ 4] = left_rotate(state[ 4], 27); 90 | state[ 5] = left_rotate(state[ 5], 36); 91 | state[ 6] = left_rotate(state[ 6], 44); 92 | state[ 7] = left_rotate(state[ 7], 6); 93 | state[ 8] = left_rotate(state[ 8], 55); 94 | state[ 9] = left_rotate(state[ 9], 20); 95 | state[10] = left_rotate(state[10], 3); 96 | state[11] = left_rotate(state[11], 10); 97 | state[12] = left_rotate(state[12], 43); 98 | state[13] = left_rotate(state[13], 25); 99 | state[14] = left_rotate(state[14], 39); 100 | state[15] = left_rotate(state[15], 41); 101 | state[16] = left_rotate(state[16], 45); 102 | state[17] = left_rotate(state[17], 15); 103 | state[18] = left_rotate(state[18], 21); 104 | state[19] = left_rotate(state[19], 8); 105 | state[20] = left_rotate(state[20], 18); 106 | state[21] = left_rotate(state[21], 2); 107 | state[22] = left_rotate(state[22], 61); 108 | state[23] = left_rotate(state[23], 56); 109 | state[24] = left_rotate(state[24], 14); 110 | 111 | keccak_pi(state); 112 | keccak_chi(state); 113 | 114 | *state ^= keccak_round_constants[round]; 115 | } 116 | } 117 | 118 | void sha3_iteration(const uint8_t* data, uint64_t h[]) { 119 | for (size_t i = 0; i <= 8; ++i) 120 | h[i] ^= uint64_t(data[8 * i + 0]) << 0 | 121 | uint64_t(data[8 * i + 1]) << 8 | 122 | uint64_t(data[8 * i + 2]) << 16 | 123 | uint64_t(data[8 * i + 3]) << 24 | 124 | uint64_t(data[8 * i + 4]) << 32 | 125 | uint64_t(data[8 * i + 5]) << 40 | 126 | uint64_t(data[8 * i + 6]) << 48 | 127 | uint64_t(data[8 * i + 7]) << 56; 128 | sha3_permutation(h); 129 | } 130 | 131 | // len: in bytes 132 | // hash: at least 32 bytes available 133 | void sha3(const void* data, size_t len, char* hash) { 134 | uint8_t* data_ = (uint8_t*)data; 135 | constexpr size_t block_size = 72; 136 | 137 | uint64_t h[25] = { 0 }; 138 | 139 | 140 | for (size_t i = 0; i < len / block_size; ++i) 141 | sha3_iteration(data_ + i * block_size, h); 142 | 143 | uint8_t buffer[block_size] = { 0 }; 144 | 145 | memcpy(buffer, data_ + len / block_size * block_size, len % block_size); 146 | len %= block_size; 147 | 148 | buffer[len] |= 0x06; 149 | buffer[block_size - 1] |= 0x80; 150 | 151 | sha3_iteration(buffer, h); 152 | 153 | 154 | memcpy(hash, h, 64); 155 | } 156 | 157 | 158 | int main(int argc, char** argv) { 159 | uint8_t hash[64]; 160 | 161 | if (argc == 1) return 0; 162 | 163 | std::ifstream fin(argv[1]); 164 | 165 | fin.seekg(0, std::ios::end); 166 | std::string buffer; 167 | buffer.reserve(fin.tellg()); 168 | fin.seekg(0, std::ios::beg); 169 | 170 | buffer.assign((std::istreambuf_iterator(fin)), 171 | std::istreambuf_iterator()); 172 | 173 | 174 | sha3(buffer.data(), buffer.length(), (char*)hash); 175 | 176 | for (int i = 0; i < 64; ++i) 177 | printf("%02x", int(hash[i]) & 0xff); 178 | printf("\n"); 179 | 180 | } 181 | 182 | -------------------------------------------------------------------------------- /src/sha3_256.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: sha3_256.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 13, 2015 12 | * Time: 22:49:20 13 | * Description: SHA-3 (256 bit) 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | 22 | // rotate functions 23 | inline uint64_t right_rotate(uint64_t x, const size_t i) { 24 | return x >>i | x << (sizeof(uint64_t) * 8 - i); 25 | } 26 | 27 | inline uint64_t left_rotate(uint64_t x, const size_t i) { 28 | return x << i | x >> (sizeof(uint64_t) * 8 - i); 29 | } 30 | 31 | inline void keccak_theta(uint64_t A[]) { 32 | uint64_t C[5], D[5]; 33 | for (size_t i = 0; i < 5; ++i) 34 | C[i] = A[i] ^ A[i + 5] ^ A[i + 10] ^ A[i + 15] ^ A[i + 20]; 35 | 36 | D[0] = left_rotate(C[1], 1) ^ C[4]; 37 | D[1] = left_rotate(C[2], 1) ^ C[0]; 38 | D[2] = left_rotate(C[3], 1) ^ C[1]; 39 | D[3] = left_rotate(C[4], 1) ^ C[2]; 40 | D[4] = left_rotate(C[0], 1) ^ C[3]; 41 | 42 | for (size_t i = 0; i < 5; ++i) { 43 | A[i] ^= D[i]; 44 | A[i + 5] ^= D[i]; 45 | A[i + 10] ^= D[i]; 46 | A[i + 15] ^= D[i]; 47 | A[i + 20] ^= D[i]; 48 | } 49 | } 50 | 51 | inline void keccak_pi(uint64_t A[]) { 52 | uint64_t A1 = A[1]; 53 | A[ 1] = A[ 6], A[ 6] = A[ 9], A[ 9] = A[22], A[22] = A[14], 54 | A[14] = A[20], A[20] = A[ 2], A[ 2] = A[12], A[12] = A[13], 55 | A[13] = A[19], A[19] = A[23], A[23] = A[15], A[15] = A[ 4], 56 | A[ 4] = A[24], A[24] = A[21], A[21] = A[ 8], A[ 8] = A[16], 57 | A[16] = A[ 5], A[ 5] = A[ 3], A[ 3] = A[18], A[18] = A[17], 58 | A[17] = A[11], A[11] = A[ 7], A[ 7] = A[10], A[10] = A1; 59 | } 60 | 61 | inline void keccak_chi(uint64_t A[]) { 62 | for (size_t i = 0; i < 25; i += 5) { 63 | uint64_t A0 = A[0 + i], A1 = A[1 + i]; 64 | A[0 + i] ^= ~A1 & A[2 + i]; 65 | A[1 + i] ^= ~A[2 + i] & A[3 + i]; 66 | A[2 + i] ^= ~A[3 + i] & A[4 + i]; 67 | A[3 + i] ^= ~A[4 + i] & A0; 68 | A[4 + i] ^= ~A0 & A1; 69 | } 70 | } 71 | 72 | inline void sha3_permutation(uint64_t state[]) { 73 | constexpr uint64_t keccak_round_constants[24] = { 74 | 0x0000000000000001, 0x0000000000008082, 0x800000000000808A, 75 | 0x8000000080008000, 0x000000000000808B, 0x0000000080000001, 76 | 0x8000000080008081, 0x8000000000008009, 0x000000000000008A, 77 | 0x0000000000000088, 0x0000000080008009, 0x000000008000000A, 78 | 0x000000008000808B, 0x800000000000008B, 0x8000000000008089, 79 | 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 80 | 0x000000000000800A, 0x800000008000000A, 0x8000000080008081, 81 | 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, 82 | }; 83 | for (size_t round = 0; round < 24; round++) { 84 | keccak_theta(state); 85 | 86 | state[ 1] = left_rotate(state[ 1], 1); 87 | state[ 2] = left_rotate(state[ 2], 62); 88 | state[ 3] = left_rotate(state[ 3], 28); 89 | state[ 4] = left_rotate(state[ 4], 27); 90 | state[ 5] = left_rotate(state[ 5], 36); 91 | state[ 6] = left_rotate(state[ 6], 44); 92 | state[ 7] = left_rotate(state[ 7], 6); 93 | state[ 8] = left_rotate(state[ 8], 55); 94 | state[ 9] = left_rotate(state[ 9], 20); 95 | state[10] = left_rotate(state[10], 3); 96 | state[11] = left_rotate(state[11], 10); 97 | state[12] = left_rotate(state[12], 43); 98 | state[13] = left_rotate(state[13], 25); 99 | state[14] = left_rotate(state[14], 39); 100 | state[15] = left_rotate(state[15], 41); 101 | state[16] = left_rotate(state[16], 45); 102 | state[17] = left_rotate(state[17], 15); 103 | state[18] = left_rotate(state[18], 21); 104 | state[19] = left_rotate(state[19], 8); 105 | state[20] = left_rotate(state[20], 18); 106 | state[21] = left_rotate(state[21], 2); 107 | state[22] = left_rotate(state[22], 61); 108 | state[23] = left_rotate(state[23], 56); 109 | state[24] = left_rotate(state[24], 14); 110 | 111 | keccak_pi(state); 112 | keccak_chi(state); 113 | 114 | *state ^= keccak_round_constants[round]; 115 | } 116 | } 117 | 118 | void sha3_iteration(const uint8_t* data, uint64_t h[]) { 119 | for (size_t i = 0; i <= 16; ++i) 120 | h[i] ^= uint64_t(data[8 * i + 0]) << 0 | 121 | uint64_t(data[8 * i + 1]) << 8 | 122 | uint64_t(data[8 * i + 2]) << 16 | 123 | uint64_t(data[8 * i + 3]) << 24 | 124 | uint64_t(data[8 * i + 4]) << 32 | 125 | uint64_t(data[8 * i + 5]) << 40 | 126 | uint64_t(data[8 * i + 6]) << 48 | 127 | uint64_t(data[8 * i + 7]) << 56; 128 | sha3_permutation(h); 129 | } 130 | 131 | // len: in bytes 132 | // hash: at least 32 bytes available 133 | void sha3(const void* data, size_t len, char* hash) { 134 | uint8_t* data_ = (uint8_t*)data; 135 | constexpr size_t block_size = 136; 136 | 137 | uint64_t h[25] = { 0 }; 138 | 139 | 140 | for (size_t i = 0; i < len / block_size; ++i) 141 | sha3_iteration(data_ + i * block_size, h); 142 | 143 | uint8_t buffer[block_size] = { 0 }; 144 | 145 | memcpy(buffer, data_ + len / block_size * block_size, len % block_size); 146 | len %= block_size; 147 | 148 | buffer[len] |= 0x06; 149 | buffer[block_size - 1] |= 0x80; 150 | 151 | sha3_iteration(buffer, h); 152 | 153 | 154 | memcpy(hash, h, 32); 155 | } 156 | 157 | 158 | int main(int argc, char** argv) { 159 | uint8_t hash[32]; 160 | 161 | if (argc == 1) return 0; 162 | 163 | std::ifstream fin(argv[1]); 164 | 165 | fin.seekg(0, std::ios::end); 166 | std::string buffer; 167 | buffer.reserve(fin.tellg()); 168 | fin.seekg(0, std::ios::beg); 169 | 170 | buffer.assign((std::istreambuf_iterator(fin)), 171 | std::istreambuf_iterator()); 172 | 173 | 174 | sha3(buffer.data(), buffer.length(), (char*)hash); 175 | 176 | for (int i = 0; i < 32; ++i) 177 | printf("%02x", int(hash[i]) & 0xff); 178 | printf("\n"); 179 | 180 | } 181 | 182 | -------------------------------------------------------------------------------- /src/sm4_ecb.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: sm4_ecb.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 16, 2015 12 | * Time: 17:01:33 13 | * Description: SM4(128 bit) Electronic Codebook Mode(ECB) 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | inline uint32_t left_rotate(const uint32_t x, const size_t i) { 22 | return x << i | (x >> (sizeof(uint32_t) * 8 - i)); 23 | } 24 | 25 | inline uint32_t tauTransformation(const uint32_t x) { 26 | constexpr uint8_t Sbox[256] = { 27 | 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05, 28 | 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, 29 | 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62, 30 | 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6, 31 | 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8, 32 | 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35, 33 | 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87, 34 | 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e, 35 | 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1, 36 | 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3, 37 | 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f, 38 | 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, 39 | 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, 40 | 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, 41 | 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84, 42 | 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48 43 | }; 44 | uint32_t val; 45 | val = Sbox[x >> 0 & 0xff] << 0 | Sbox[x >> 8 & 0xff] << 8 | 46 | Sbox[x >> 16 & 0xff] << 16 | Sbox[x >> 24 & 0xff] << 24; 47 | return val; 48 | } 49 | 50 | inline uint32_t endianConvert(const uint32_t x) { 51 | return (x << 24 & 0xff000000) | (x << 8 & 0x00ff0000) | 52 | (x >> 8 & 0x0000ff00) | (x >> 24 & 0x000000ff); 53 | } 54 | 55 | inline uint32_t LTransformation(const uint32_t x) { 56 | return x ^ 57 | left_rotate(x, 2) ^ left_rotate(x, 10) ^ 58 | left_rotate(x, 18) ^ left_rotate(x, 24); 59 | } 60 | 61 | inline uint32_t L1Transformation(const uint32_t x) { 62 | return x ^ left_rotate(x, 13) ^ left_rotate(x, 23); 63 | } 64 | 65 | inline uint32_t TTransformation(const uint32_t x) { 66 | return LTransformation(tauTransformation(x)); 67 | } 68 | 69 | inline uint32_t FFunction(const uint32_t x[], const uint32_t rkey) { 70 | return x[0] ^ TTransformation(x[1] ^ x[2] ^ x[3] ^ rkey); 71 | } 72 | 73 | // key: 16 bytes 74 | // keys: 32 * 4 bytes 75 | void keyExpansion(const uint8_t key[], uint32_t keys[]) { 76 | uint32_t mk[4]; 77 | mk[0] = key[ 0] << 24 | key[ 1] << 16 | key[ 2] << 8 | key[ 3] << 0; 78 | mk[1] = key[ 4] << 24 | key[ 5] << 16 | key[ 6] << 8 | key[ 7] << 0; 79 | mk[2] = key[ 8] << 24 | key[ 9] << 16 | key[10] << 8 | key[11] << 0; 80 | mk[3] = key[12] << 24 | key[13] << 16 | key[14] << 8 | key[15] << 0; 81 | constexpr uint32_t FK[4] = { 0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC }; 82 | constexpr uint32_t CK[32] = { 83 | 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 84 | 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, 85 | 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 86 | 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, 87 | 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 88 | 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, 89 | 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 90 | 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279 91 | }; 92 | uint32_t k[36]; 93 | k[0] = mk[0] ^ FK[0], k[1] = mk[1] ^ FK[1], 94 | k[2] = mk[2] ^ FK[2], k[3] = mk[3] ^ FK[3]; 95 | 96 | for (size_t i = 0; i < 32; ++i) 97 | keys[i] = k[i + 4] = k[i] ^ L1Transformation(tauTransformation(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ CK[i])); 98 | } 99 | 100 | void sm4Iteration(const uint32_t plain[], const uint32_t keys[], uint32_t cipher[]) { 101 | uint32_t x[36]; 102 | x[0] = endianConvert(plain[0]); 103 | x[1] = endianConvert(plain[1]); 104 | x[2] = endianConvert(plain[2]); 105 | x[3] = endianConvert(plain[3]); 106 | 107 | for (size_t i = 0; i < 32; ++i) 108 | x[i + 4] = FFunction(x + i, keys[i]); 109 | 110 | cipher[0] = endianConvert(x[35]); 111 | cipher[1] = endianConvert(x[34]); 112 | cipher[2] = endianConvert(x[33]); 113 | cipher[3] = endianConvert(x[32]); 114 | } 115 | 116 | void sm4_ecb(const void* plain, const size_t length, const void* key, void* cipher) { 117 | const uint32_t* plain_ = (const uint32_t*)(plain); 118 | uint32_t* cipher_ = (uint32_t*)(cipher); 119 | 120 | uint32_t keys[32]; 121 | keyExpansion((const uint8_t*)(key), keys); 122 | 123 | for (size_t i = 0; i < length / 16; ++i) { 124 | sm4Iteration(plain_ + 4 * i, keys, cipher_ + 4 * i); 125 | } 126 | } 127 | 128 | int main(int argc, char** argv) { 129 | if (argc == 1) return 0; 130 | 131 | std::ifstream fin(argv[1]); 132 | 133 | fin.seekg(0, std::ios::end); 134 | std::string buffer; 135 | size_t len = fin.tellg(); 136 | buffer.reserve(len); 137 | fin.seekg(0, std::ios::beg); 138 | 139 | if (len % 16) { 140 | printf("Length of plain text should be multiple of 16 bytes. \n"); 141 | return 0; 142 | } 143 | 144 | buffer.assign((std::istreambuf_iterator(fin)), 145 | std::istreambuf_iterator()); 146 | 147 | fin.close(); 148 | 149 | // 128 bit key size 150 | unsigned char key[16] = { 0 }; 151 | 152 | if (argc == 3) { 153 | fin.open(argv[2]); 154 | fin.seekg(0, std::ios::beg); 155 | char buffer[3] = { 0 }; 156 | for (size_t i = 0; i < 16; ++i) { 157 | fin.read(buffer, 2); 158 | key[i] = std::stoi(buffer, 0, 16); 159 | } 160 | fin.close(); 161 | } 162 | 163 | std::vector cipher(buffer.length(), 0); 164 | sm4_ecb(buffer.data(), buffer.length(), key, &cipher[0]); 165 | 166 | for (size_t i = 0; i < buffer.length(); ++i) 167 | printf("%02x", int(cipher[i]) & 0xff); 168 | printf("\n"); 169 | 170 | } 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /src/sm4_cbc.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: sm4_cbc.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 16, 2015 12 | * Time: 17:01:33 13 | * Description: SM4(128 bit) Cipher Block Chaining Mode(CBC) 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | inline uint32_t left_rotate(const uint32_t x, const size_t i) { 22 | return x << i | (x >> (sizeof(uint32_t) * 8 - i)); 23 | } 24 | 25 | inline uint32_t tauTransformation(const uint32_t x) { 26 | constexpr uint8_t Sbox[256] = { 27 | 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05, 28 | 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, 29 | 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62, 30 | 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6, 31 | 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8, 32 | 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35, 33 | 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87, 34 | 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e, 35 | 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1, 36 | 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3, 37 | 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f, 38 | 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, 39 | 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, 40 | 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, 41 | 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84, 42 | 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48 43 | }; 44 | uint32_t val; 45 | val = Sbox[x >> 0 & 0xff] << 0 | Sbox[x >> 8 & 0xff] << 8 | 46 | Sbox[x >> 16 & 0xff] << 16 | Sbox[x >> 24 & 0xff] << 24; 47 | return val; 48 | } 49 | 50 | inline uint32_t endianConvert(const uint32_t x) { 51 | return (x << 24 & 0xff000000) | (x << 8 & 0x00ff0000) | 52 | (x >> 8 & 0x0000ff00) | (x >> 24 & 0x000000ff); 53 | } 54 | 55 | inline uint32_t LTransformation(const uint32_t x) { 56 | return x ^ 57 | left_rotate(x, 2) ^ left_rotate(x, 10) ^ 58 | left_rotate(x, 18) ^ left_rotate(x, 24); 59 | } 60 | 61 | inline uint32_t L1Transformation(const uint32_t x) { 62 | return x ^ left_rotate(x, 13) ^ left_rotate(x, 23); 63 | } 64 | 65 | inline uint32_t TTransformation(const uint32_t x) { 66 | return LTransformation(tauTransformation(x)); 67 | } 68 | 69 | inline uint32_t FFunction(const uint32_t x[], const uint32_t rkey) { 70 | return x[0] ^ TTransformation(x[1] ^ x[2] ^ x[3] ^ rkey); 71 | } 72 | 73 | // key: 16 bytes 74 | // keys: 32 * 4 bytes 75 | void keyExpansion(const uint8_t key[], uint32_t keys[]) { 76 | uint32_t mk[4]; 77 | mk[0] = key[ 0] << 24 | key[ 1] << 16 | key[ 2] << 8 | key[ 3] << 0; 78 | mk[1] = key[ 4] << 24 | key[ 5] << 16 | key[ 6] << 8 | key[ 7] << 0; 79 | mk[2] = key[ 8] << 24 | key[ 9] << 16 | key[10] << 8 | key[11] << 0; 80 | mk[3] = key[12] << 24 | key[13] << 16 | key[14] << 8 | key[15] << 0; 81 | constexpr uint32_t FK[4] = { 0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC }; 82 | constexpr uint32_t CK[32] = { 83 | 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 84 | 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, 85 | 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 86 | 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, 87 | 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 88 | 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, 89 | 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 90 | 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279 91 | }; 92 | uint32_t k[36]; 93 | k[0] = mk[0] ^ FK[0], k[1] = mk[1] ^ FK[1], 94 | k[2] = mk[2] ^ FK[2], k[3] = mk[3] ^ FK[3]; 95 | 96 | for (size_t i = 0; i < 32; ++i) 97 | keys[i] = k[i + 4] = k[i] ^ L1Transformation(tauTransformation(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ CK[i])); 98 | } 99 | 100 | void sm4Iteration(const uint32_t plain[], const uint32_t keys[], uint32_t cipher[]) { 101 | uint32_t x[36]; 102 | x[0] = endianConvert(plain[0]); 103 | x[1] = endianConvert(plain[1]); 104 | x[2] = endianConvert(plain[2]); 105 | x[3] = endianConvert(plain[3]); 106 | 107 | for (size_t i = 0; i < 32; ++i) 108 | x[i + 4] = FFunction(x + i, keys[i]); 109 | 110 | cipher[0] = endianConvert(x[35]); 111 | cipher[1] = endianConvert(x[34]); 112 | cipher[2] = endianConvert(x[33]); 113 | cipher[3] = endianConvert(x[32]); 114 | } 115 | 116 | void sm4_cbc(const void* plain, const size_t length, const void* key, const void* IV, void* cipher) { 117 | const uint32_t* plain_ = (const uint32_t*)(plain); 118 | uint32_t* cipher_ = (uint32_t*)(cipher); 119 | 120 | uint32_t keys[32]; 121 | keyExpansion((const uint8_t*)(key), keys); 122 | 123 | uint32_t buffer[4]; 124 | memcpy(buffer, IV, 16); 125 | 126 | for (size_t i = 0; i < length / 16; ++i) { 127 | for (size_t j = 0; j < 4; ++j) 128 | buffer[j] ^= plain_[4 * i + j]; 129 | sm4Iteration(buffer, keys, cipher_ + 4 * i); 130 | memcpy(buffer, cipher_ + 4 * i, 16); 131 | } 132 | } 133 | 134 | int main(int argc, char** argv) { 135 | if (argc == 1) return 0; 136 | 137 | std::ifstream fin(argv[1]); 138 | 139 | fin.seekg(0, std::ios::end); 140 | std::string buffer; 141 | size_t len = fin.tellg(); 142 | buffer.reserve(len); 143 | fin.seekg(0, std::ios::beg); 144 | 145 | if (len % 16) { 146 | printf("Length of plain text should be multiple of 16 bytes. \n"); 147 | return 0; 148 | } 149 | 150 | buffer.assign((std::istreambuf_iterator(fin)), 151 | std::istreambuf_iterator()); 152 | 153 | fin.close(); 154 | 155 | // 128 bit key size 156 | unsigned char key[16] = { 0 }; 157 | unsigned char IV[16] = { 0 }; 158 | 159 | if (argc == 3) { 160 | fin.open(argv[2]); 161 | fin.seekg(0, std::ios::beg); 162 | char buffer[3] = { 0 }; 163 | for (size_t i = 0; i < 16; ++i) { 164 | fin.read(buffer, 2); 165 | key[i] = std::stoi(buffer, 0, 16); 166 | } 167 | fin.close(); 168 | } 169 | 170 | std::vector cipher(buffer.length(), 0); 171 | sm4_cbc(buffer.data(), buffer.length(), key, IV, &cipher[0]); 172 | 173 | for (size_t i = 0; i < buffer.length(); ++i) 174 | printf("%02x", int(cipher[i]) & 0xff); 175 | printf("\n"); 176 | 177 | } 178 | 179 | 180 | 181 | -------------------------------------------------------------------------------- /src/sm4_ofb.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: sm4_ofb.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 16, 2015 12 | * Time: 17:01:33 13 | * Description: SM4(128 bit) Output Feedback Block(in 8 bit) Mode (OFB) 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | inline uint32_t left_rotate(const uint32_t x, const size_t i) { 22 | return x << i | (x >> (sizeof(uint32_t) * 8 - i)); 23 | } 24 | 25 | inline uint32_t tauTransformation(const uint32_t x) { 26 | constexpr uint8_t Sbox[256] = { 27 | 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05, 28 | 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, 29 | 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62, 30 | 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6, 31 | 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8, 32 | 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35, 33 | 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87, 34 | 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e, 35 | 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1, 36 | 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3, 37 | 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f, 38 | 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, 39 | 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, 40 | 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, 41 | 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84, 42 | 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48 43 | }; 44 | uint32_t val; 45 | val = Sbox[x >> 0 & 0xff] << 0 | Sbox[x >> 8 & 0xff] << 8 | 46 | Sbox[x >> 16 & 0xff] << 16 | Sbox[x >> 24 & 0xff] << 24; 47 | return val; 48 | } 49 | 50 | inline uint32_t endianConvert(const uint32_t x) { 51 | return (x << 24 & 0xff000000) | (x << 8 & 0x00ff0000) | 52 | (x >> 8 & 0x0000ff00) | (x >> 24 & 0x000000ff); 53 | } 54 | 55 | inline uint32_t LTransformation(const uint32_t x) { 56 | return x ^ 57 | left_rotate(x, 2) ^ left_rotate(x, 10) ^ 58 | left_rotate(x, 18) ^ left_rotate(x, 24); 59 | } 60 | 61 | inline uint32_t L1Transformation(const uint32_t x) { 62 | return x ^ left_rotate(x, 13) ^ left_rotate(x, 23); 63 | } 64 | 65 | inline uint32_t TTransformation(const uint32_t x) { 66 | return LTransformation(tauTransformation(x)); 67 | } 68 | 69 | inline uint32_t FFunction(const uint32_t x[], const uint32_t rkey) { 70 | return x[0] ^ TTransformation(x[1] ^ x[2] ^ x[3] ^ rkey); 71 | } 72 | 73 | // key: 16 bytes 74 | // keys: 32 * 4 bytes 75 | void keyExpansion(const uint8_t key[], uint32_t keys[]) { 76 | uint32_t mk[4]; 77 | mk[0] = key[ 0] << 24 | key[ 1] << 16 | key[ 2] << 8 | key[ 3] << 0; 78 | mk[1] = key[ 4] << 24 | key[ 5] << 16 | key[ 6] << 8 | key[ 7] << 0; 79 | mk[2] = key[ 8] << 24 | key[ 9] << 16 | key[10] << 8 | key[11] << 0; 80 | mk[3] = key[12] << 24 | key[13] << 16 | key[14] << 8 | key[15] << 0; 81 | constexpr uint32_t FK[4] = { 0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC }; 82 | constexpr uint32_t CK[32] = { 83 | 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 84 | 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, 85 | 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 86 | 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, 87 | 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 88 | 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, 89 | 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 90 | 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279 91 | }; 92 | uint32_t k[36]; 93 | k[0] = mk[0] ^ FK[0], k[1] = mk[1] ^ FK[1], 94 | k[2] = mk[2] ^ FK[2], k[3] = mk[3] ^ FK[3]; 95 | 96 | for (size_t i = 0; i < 32; ++i) 97 | keys[i] = k[i + 4] = k[i] ^ L1Transformation(tauTransformation(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ CK[i])); 98 | } 99 | 100 | void sm4Iteration(const uint32_t plain[], const uint32_t keys[], uint32_t cipher[]) { 101 | uint32_t x[36]; 102 | x[0] = endianConvert(plain[0]); 103 | x[1] = endianConvert(plain[1]); 104 | x[2] = endianConvert(plain[2]); 105 | x[3] = endianConvert(plain[3]); 106 | 107 | for (size_t i = 0; i < 32; ++i) 108 | x[i + 4] = FFunction(x + i, keys[i]); 109 | 110 | cipher[0] = endianConvert(x[35]); 111 | cipher[1] = endianConvert(x[34]); 112 | cipher[2] = endianConvert(x[33]); 113 | cipher[3] = endianConvert(x[32]); 114 | } 115 | 116 | void sm4_ofb(const void* plain, const size_t length, const void* key, const void* IV, void* cipher) { 117 | // I cannot guarantee this is correct. 118 | // The endian of SM4 is way too complicated 119 | // nor can I find any documentation about SM4 OFB mode 120 | const uint8_t* plain_ = (const uint8_t*)(plain); 121 | uint8_t* cipher_ = (uint8_t*)(cipher); 122 | 123 | uint32_t keys[32]; 124 | keyExpansion((const uint8_t*)(key), keys); 125 | 126 | uint8_t buffer[16]; 127 | memcpy(buffer, IV, 16); 128 | 129 | for (size_t i = 0; i < length; ++i) { 130 | sm4Iteration((const uint32_t*)buffer, keys, (uint32_t*)(cipher_ + i)); 131 | 132 | for (size_t j = 0; j < 15; ++j) 133 | buffer[j] = buffer[j + 1]; 134 | buffer[15] = cipher_[i]; 135 | cipher_[i] ^= plain_[i]; 136 | } 137 | } 138 | 139 | int main(int argc, char** argv) { 140 | if (argc == 1) return 0; 141 | 142 | std::ifstream fin(argv[1]); 143 | 144 | fin.seekg(0, std::ios::end); 145 | std::string buffer; 146 | size_t len = fin.tellg(); 147 | buffer.reserve(len); 148 | fin.seekg(0, std::ios::beg); 149 | 150 | 151 | buffer.assign((std::istreambuf_iterator(fin)), 152 | std::istreambuf_iterator()); 153 | 154 | fin.close(); 155 | 156 | // 128 bit key size 157 | unsigned char key[16] = { 0 }; 158 | unsigned char IV[16] = { 0 }; 159 | 160 | if (argc == 3) { 161 | fin.open(argv[2]); 162 | fin.seekg(0, std::ios::beg); 163 | char buffer[3] = { 0 }; 164 | for (size_t i = 0; i < 16; ++i) { 165 | fin.read(buffer, 2); 166 | key[i] = std::stoi(buffer, 0, 16); 167 | } 168 | fin.close(); 169 | } 170 | 171 | std::vector cipher(buffer.length() + 16, 0); 172 | sm4_ofb(buffer.data(), buffer.length(), key, IV, &cipher[0]); 173 | 174 | for (size_t i = 0; i < buffer.length(); ++i) 175 | printf("%02x", int(cipher[i]) & 0xff); 176 | printf("\n"); 177 | 178 | } 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /src/sm4_ctr.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: sm4_ctr.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 16, 2015 12 | * Time: 17:01:33 13 | * Description: SM4(128 bit) Counter Mode (CTR) 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | inline uint32_t left_rotate(const uint32_t x, const size_t i) { 22 | return x << i | (x >> (sizeof(uint32_t) * 8 - i)); 23 | } 24 | 25 | inline uint32_t tauTransformation(const uint32_t x) { 26 | constexpr uint8_t Sbox[256] = { 27 | 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05, 28 | 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, 29 | 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62, 30 | 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6, 31 | 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8, 32 | 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35, 33 | 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87, 34 | 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e, 35 | 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1, 36 | 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3, 37 | 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f, 38 | 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, 39 | 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, 40 | 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, 41 | 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84, 42 | 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48 43 | }; 44 | uint32_t val; 45 | val = Sbox[x >> 0 & 0xff] << 0 | Sbox[x >> 8 & 0xff] << 8 | 46 | Sbox[x >> 16 & 0xff] << 16 | Sbox[x >> 24 & 0xff] << 24; 47 | return val; 48 | } 49 | 50 | inline uint32_t endianConvert(const uint32_t x) { 51 | return (x << 24 & 0xff000000) | (x << 8 & 0x00ff0000) | 52 | (x >> 8 & 0x0000ff00) | (x >> 24 & 0x000000ff); 53 | } 54 | 55 | inline uint32_t LTransformation(const uint32_t x) { 56 | return x ^ 57 | left_rotate(x, 2) ^ left_rotate(x, 10) ^ 58 | left_rotate(x, 18) ^ left_rotate(x, 24); 59 | } 60 | 61 | inline uint32_t L1Transformation(const uint32_t x) { 62 | return x ^ left_rotate(x, 13) ^ left_rotate(x, 23); 63 | } 64 | 65 | inline uint32_t TTransformation(const uint32_t x) { 66 | return LTransformation(tauTransformation(x)); 67 | } 68 | 69 | inline uint32_t FFunction(const uint32_t x[], const uint32_t rkey) { 70 | return x[0] ^ TTransformation(x[1] ^ x[2] ^ x[3] ^ rkey); 71 | } 72 | 73 | // key: 16 bytes 74 | // keys: 32 * 4 bytes 75 | void keyExpansion(const uint8_t key[], uint32_t keys[]) { 76 | uint32_t mk[4]; 77 | mk[0] = key[ 0] << 24 | key[ 1] << 16 | key[ 2] << 8 | key[ 3] << 0; 78 | mk[1] = key[ 4] << 24 | key[ 5] << 16 | key[ 6] << 8 | key[ 7] << 0; 79 | mk[2] = key[ 8] << 24 | key[ 9] << 16 | key[10] << 8 | key[11] << 0; 80 | mk[3] = key[12] << 24 | key[13] << 16 | key[14] << 8 | key[15] << 0; 81 | constexpr uint32_t FK[4] = { 0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC }; 82 | constexpr uint32_t CK[32] = { 83 | 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 84 | 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, 85 | 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 86 | 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, 87 | 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 88 | 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, 89 | 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 90 | 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279 91 | }; 92 | uint32_t k[36]; 93 | k[0] = mk[0] ^ FK[0], k[1] = mk[1] ^ FK[1], 94 | k[2] = mk[2] ^ FK[2], k[3] = mk[3] ^ FK[3]; 95 | 96 | for (size_t i = 0; i < 32; ++i) 97 | keys[i] = k[i + 4] = k[i] ^ L1Transformation(tauTransformation(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ CK[i])); 98 | } 99 | 100 | void sm4Iteration(const uint32_t plain[], const uint32_t keys[], uint32_t cipher[]) { 101 | uint32_t x[36]; 102 | x[0] = endianConvert(plain[0]); 103 | x[1] = endianConvert(plain[1]); 104 | x[2] = endianConvert(plain[2]); 105 | x[3] = endianConvert(plain[3]); 106 | 107 | for (size_t i = 0; i < 32; ++i) 108 | x[i + 4] = FFunction(x + i, keys[i]); 109 | 110 | cipher[0] = endianConvert(x[35]); 111 | cipher[1] = endianConvert(x[34]); 112 | cipher[2] = endianConvert(x[33]); 113 | cipher[3] = endianConvert(x[32]); 114 | } 115 | 116 | void sm4_ctr(const void* plain, const size_t length, const void* key, const void* IV, void* cipher) { 117 | // I cannot guarantee this is correct. 118 | // The endian of SM4 is way too complicated 119 | // nor can I find any documentation about SM4 CTR mode 120 | const uint8_t* plain_ = (const uint8_t*)(plain); 121 | uint8_t* cipher_ = (uint8_t*)(cipher); 122 | 123 | uint32_t keys[32]; 124 | keyExpansion((const uint8_t*)(key), keys); 125 | 126 | uint8_t buffer[16]; 127 | 128 | uint8_t counter[8] = { 0 }; 129 | uint64_t* ctr = (uint64_t*)counter; 130 | 131 | for (size_t i = 0; i < length; ++i) { 132 | // any lossless operation is ok 133 | // we use XOR here 134 | memcpy(buffer, IV, 16); 135 | for (size_t j = 0; j < 8; ++j) 136 | buffer[j] ^= counter[7 - j]; 137 | 138 | sm4Iteration((const uint32_t*)buffer, keys, (uint32_t*)(cipher_ + i)); 139 | 140 | ++(*ctr); 141 | 142 | cipher_[i] ^= plain_[i]; 143 | } 144 | } 145 | 146 | int main(int argc, char** argv) { 147 | if (argc == 1) return 0; 148 | 149 | std::ifstream fin(argv[1]); 150 | 151 | fin.seekg(0, std::ios::end); 152 | std::string buffer; 153 | size_t len = fin.tellg(); 154 | buffer.reserve(len); 155 | fin.seekg(0, std::ios::beg); 156 | 157 | 158 | buffer.assign((std::istreambuf_iterator(fin)), 159 | std::istreambuf_iterator()); 160 | 161 | fin.close(); 162 | 163 | // 128 bit key size 164 | unsigned char key[16] = { 0 }; 165 | unsigned char IV[16] = { 0 }; 166 | 167 | if (argc == 3) { 168 | fin.open(argv[2]); 169 | fin.seekg(0, std::ios::beg); 170 | char buffer[3] = { 0 }; 171 | for (size_t i = 0; i < 16; ++i) { 172 | fin.read(buffer, 2); 173 | key[i] = std::stoi(buffer, 0, 16); 174 | } 175 | fin.close(); 176 | } 177 | 178 | std::vector cipher(buffer.length() + 16, 0); 179 | sm4_ctr(buffer.data(), buffer.length(), key, IV, &cipher[0]); 180 | 181 | for (size_t i = 0; i < buffer.length(); ++i) 182 | printf("%02x", int(cipher[i]) & 0xff); 183 | printf("\n"); 184 | 185 | } 186 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /src/sha2_512.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: sha2_512.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 11, 2015 12 | * Time: 22:13:27 13 | * Description: SHA-2 (512 bit) 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | void sha2_iteration(const uint8_t* data, uint64_t hi[]) { 22 | // rotate function 23 | auto right_rotate = [](uint64_t x, const size_t i)->uint64_t { 24 | return x >> i | x << (sizeof(uint64_t) * 8 - i); 25 | }; 26 | 27 | constexpr uint64_t k[80] = { 28 | 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 29 | 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, 30 | 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 31 | 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 32 | 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab, 33 | 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 34 | 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 35 | 0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, 36 | 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, 37 | 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 38 | 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 39 | 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, 40 | 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c, 41 | 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 42 | 0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 43 | 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 44 | }; 45 | 46 | // extend 16 64-bit words to 80 64-bit words 47 | uint64_t word[80]; 48 | for (size_t j = 0; j < 16; ++j) 49 | word[j] = uint64_t(data[8 * j + 0]) << 56 | uint64_t(data[8 * j + 1]) << 48 | 50 | uint64_t(data[8 * j + 2]) << 40 | uint64_t(data[8 * j + 3]) << 32 | 51 | uint64_t(data[8 * j + 4]) << 24 | uint64_t(data[8 * j + 5]) << 16 | 52 | uint64_t(data[8 * j + 6]) << 8 | uint64_t(data[8 * j + 7]) << 0; 53 | 54 | for (size_t j = 16; j < 80; ++j) { 55 | uint64_t s0 = right_rotate(word[j - 15], 1) ^ 56 | right_rotate(word[j - 15], 8) ^ 57 | word[j - 15] >> 7; 58 | uint64_t s1 = right_rotate(word[j - 2], 19) ^ 59 | right_rotate(word[j - 2], 61) ^ 60 | word[j - 2] >> 6; 61 | word[j] = word[j - 16] + s0 + word[j - 7] + s1; 62 | } 63 | 64 | uint64_t a = hi[0], b = hi[1], c = hi[2], d = hi[3], 65 | e = hi[4], f = hi[5], g = hi[6], h = hi[7]; 66 | 67 | 68 | // main loop 69 | for (size_t i = 0; i < 80; ++i) { 70 | uint64_t S1 = right_rotate(e, 14) ^ 71 | right_rotate(e, 18) ^ 72 | right_rotate(e, 41); 73 | uint64_t ch = (e & f) ^ (~e & g); 74 | uint64_t tmp1 = h + S1 + ch + k[i] + word[i]; 75 | uint64_t S0 = right_rotate(a, 28) ^ 76 | right_rotate(a, 34) ^ 77 | right_rotate(a, 39); 78 | uint64_t maj = (a & b) ^ (a & c) ^ (b & c); 79 | uint64_t tmp2 = S0 + maj; 80 | 81 | 82 | h = g, g = f, f = e, e = d + tmp1, d = c, c = b, b = a, a = tmp1 + tmp2; 83 | } 84 | 85 | hi[0] += a, hi[1] += b, hi[2] += c, hi[3] += d, 86 | hi[4] += e, hi[5] += f, hi[6] += g, hi[7] += h; 87 | } 88 | 89 | // len: in bytes 90 | // hash: at least 64 bytes available 91 | void sha2(const void* data, size_t len, char* hash) { 92 | uint8_t* data_ = (uint8_t*)data; 93 | constexpr size_t block_size = 128; 94 | 95 | uint64_t h[8] = { 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 96 | 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 97 | 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 98 | 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 }; 99 | 100 | size_t ml = len * 8; 101 | 102 | for (size_t i = 0; i < len / block_size; ++i) 103 | sha2_iteration(data_ + i * block_size, h); 104 | 105 | uint8_t buffer[block_size]; 106 | 107 | memcpy(buffer, data_ + len / block_size * block_size, len % block_size); 108 | len %= block_size; 109 | 110 | // append bit '1' 111 | buffer[len++] = 0x80; 112 | 113 | if (len % block_size == 0) { 114 | sha2_iteration(buffer, h); 115 | len = 0; 116 | } 117 | 118 | // append until the resulting message length (in bits) is congruent to 896 (mod 1024) 119 | while (len % block_size != block_size - 16) { 120 | buffer[len++] = 0x00; 121 | if (len % block_size == 0) { 122 | sha2_iteration(buffer, h); 123 | len = 0; 124 | } 125 | } 126 | 127 | 128 | // append length 129 | 130 | while (len % block_size) { 131 | size_t shift_count = 120 - (len - block_size + 16) * 8; 132 | if (shift_count >= sizeof(size_t) * 8) 133 | buffer[len] = 0; 134 | else 135 | buffer[len] = ml >> shift_count; 136 | ++len; 137 | } 138 | 139 | 140 | // Code below may get a better performance on pipeline CPU than code above 141 | // because it has no branch instruction 142 | // But size_t is 64 bits long for now, so code below will lead to 143 | // undefined behavior. 144 | // When size_t is 128 bits long, replace code above with that below. 145 | 146 | // Plus, Please tell me if anybody knows how to concisely switch these 147 | // tow pieces of code according to width of size_t at compiling time. 148 | // Thanks. 149 | 150 | /* 151 | buffer[len++] = ml >> 120, buffer[len++] = ml >> 112, 152 | buffer[len++] = ml >> 104, buffer[len++] = ml >> 96, 153 | buffer[len++] = ml >> 88, buffer[len++] = ml >> 80, 154 | buffer[len++] = ml >> 72, buffer[len++] = ml >> 64, 155 | buffer[len++] = ml >> 56, buffer[len++] = ml >> 48, 156 | buffer[len++] = ml >> 40, buffer[len++] = ml >> 32, 157 | buffer[len++] = ml >> 24, buffer[len++] = ml >> 16, 158 | buffer[len++] = ml >> 8, buffer[len++] = ml; 159 | */ 160 | 161 | 162 | sha2_iteration(buffer, h); 163 | 164 | /* 165 | for (size_t i = 0; i < 64; i += 8) 166 | hash[i] = h[i / 4] >> 24, hash[i + 1] = h[i / 4] >> 16, 167 | hash[i + 2] = h[i / 4] >> 8, hash[i + 3] = h[i / 4]; 168 | */ 169 | for (size_t i = 0; i < 64; i += 8) 170 | hash[i + 0] = h[i / 8] >> 56, hash[i + 1] = h[i / 8] >> 48, 171 | hash[i + 2] = h[i / 8] >> 40, hash[i + 3] = h[i / 8] >> 32, 172 | hash[i + 4] = h[i / 8] >> 24, hash[i + 5] = h[i / 8] >> 16, 173 | hash[i + 6] = h[i / 8] >> 8, hash[i + 7] = h[i / 8] >> 0; 174 | } 175 | 176 | 177 | 178 | int main(int argc, char** argv) { 179 | uint8_t hash[64]; 180 | 181 | if (argc == 1) return 0; 182 | 183 | std::ifstream fin(argv[1]); 184 | 185 | fin.seekg(0, std::ios::end); 186 | std::string buffer; 187 | buffer.reserve(fin.tellg()); 188 | fin.seekg(0, std::ios::beg); 189 | 190 | buffer.assign((std::istreambuf_iterator(fin)), 191 | std::istreambuf_iterator()); 192 | 193 | 194 | sha2(buffer.data(), buffer.length(), (char*)hash); 195 | 196 | for (int i = 0; i < 64; ++i) 197 | printf("%02x", int(hash[i]) & 0xff); 198 | printf("\n"); 199 | 200 | } 201 | -------------------------------------------------------------------------------- /src/aes_ecb.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: aes_ecb.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 16, 2015 12 | * Time: 09:15:58 13 | * Description: AES(128, 192, 256 bit) Electronic Codebook Mode(ECB) 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | inline uint8_t gmult(uint8_t a, uint8_t b) { 22 | uint8_t p = 0, hbs = 0; 23 | 24 | for (size_t i = 0; i < 8; i++) { 25 | if (b & 1) 26 | p ^= a; 27 | 28 | hbs = a & 0x80; 29 | a <<= 1; 30 | if (hbs) a ^= 0x1b; // 0000 0001 0001 1011 31 | b >>= 1; 32 | } 33 | 34 | return (uint8_t)p; 35 | } 36 | 37 | constexpr uint8_t SubBytes[256] = { 38 | 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 39 | 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 40 | 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 41 | 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 42 | 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 43 | 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 44 | 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 45 | 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 46 | 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 47 | 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 48 | 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 49 | 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 50 | 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 51 | 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 52 | 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 53 | 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 54 | }; 55 | 56 | // key: initial key: 16 or 24 or 32 bytes 57 | // keys : 4 * (6 + key_length / 4 + 1) * 4 bytes 58 | void keyExpansion(const uint8_t key[], uint8_t keys[], const size_t key_length) { 59 | constexpr uint8_t RCON[10][4] = { 60 | { 0x01, 0x00, 0x00, 0x00 }, 61 | { 0x02, 0x00, 0x00, 0x00 }, 62 | { 0x04, 0x00, 0x00, 0x00 }, 63 | { 0x08, 0x00, 0x00, 0x00 }, 64 | { 0x10, 0x00, 0x00, 0x00 }, 65 | { 0x20, 0x00, 0x00, 0x00 }, 66 | { 0x40, 0x00, 0x00, 0x00 }, 67 | { 0x80, 0x00, 0x00, 0x00 }, 68 | { 0x1b, 0x00, 0x00, 0x00 }, 69 | { 0x36, 0x00, 0x00, 0x00 } 70 | }; 71 | 72 | 73 | memcpy(keys, key, key_length); 74 | 75 | for (size_t i = key_length / 4; i < 4 * (6 + key_length / 4 + 1); ++i) { 76 | uint8_t tmp[4] = { keys[4 * (i - 1) + 0], keys[4 * (i - 1) + 1], 77 | keys[4 * (i - 1) + 2], keys[4 * (i - 1) + 3] }; 78 | if (i % (key_length / 4) == 0) { 79 | // rotate left one byte 80 | uint8_t temp = tmp[0]; 81 | tmp[0] = tmp[1], tmp[1] = tmp[2], tmp[2] = tmp[3], tmp[3] = temp; 82 | // SubBytes 83 | tmp[0] = SubBytes[tmp[0]]; 84 | tmp[1] = SubBytes[tmp[1]]; 85 | tmp[2] = SubBytes[tmp[2]]; 86 | tmp[3] = SubBytes[tmp[3]]; 87 | // XOR round constants 88 | tmp[0] ^= RCON[i / (key_length / 4) - 1][0], tmp[1] ^= RCON[i / (key_length / 4) - 1][1], 89 | tmp[2] ^= RCON[i / (key_length / 4) - 1][2], tmp[3] ^= RCON[i / (key_length / 4) - 1][3]; 90 | } else if (key_length > 24 && i % (key_length / 4) == 4) { 91 | tmp[0] = SubBytes[tmp[0]]; 92 | tmp[1] = SubBytes[tmp[1]]; 93 | tmp[2] = SubBytes[tmp[2]]; 94 | tmp[3] = SubBytes[tmp[3]]; 95 | } 96 | keys[4 * i + 0] = tmp[0], keys[4 * i + 1] = tmp[1], 97 | keys[4 * i + 2] = tmp[2], keys[4 * i + 3] = tmp[3]; 98 | keys[4 * i + 0] ^= keys[4 * (i - key_length / 4) + 0], 99 | keys[4 * i + 1] ^= keys[4 * (i - key_length / 4) + 1], 100 | keys[4 * i + 2] ^= keys[4 * (i - key_length / 4) + 2], 101 | keys[4 * i + 3] ^= keys[4 * (i - key_length / 4) + 3]; 102 | } 103 | 104 | } 105 | 106 | 107 | inline void subBytes(uint8_t state[]) { 108 | for (size_t i = 0; i < 16; ++i) 109 | state[i] = SubBytes[state[i]]; 110 | } 111 | 112 | inline void shiftRows(uint8_t state[]) { 113 | uint8_t tmp = state[1]; 114 | state[1] = state[5]; 115 | state[5] = state[9]; 116 | state[9] = state[13]; 117 | state[13] = tmp; 118 | 119 | tmp = state[2]; 120 | state[2] = state[10]; 121 | state[10] = tmp; 122 | tmp = state[6]; 123 | state[6] = state[14]; 124 | state[14] = tmp; 125 | 126 | tmp = state[3]; 127 | state[3] = state[15]; 128 | state[15] = state[11]; 129 | state[11] = state[7]; 130 | state[7] = tmp; 131 | } 132 | 133 | inline void mixColumns(uint8_t state[]) { 134 | uint8_t tmp[4]; 135 | for (size_t i = 0; i < 4; ++i) { 136 | tmp[0] = gmult(2, state[4 * i + 0]) ^ 137 | gmult(3, state[4 * i + 1]) ^ 138 | gmult(1, state[4 * i + 2]) ^ 139 | gmult(1, state[4 * i + 3]); 140 | tmp[1] = gmult(1, state[4 * i + 0]) ^ 141 | gmult(2, state[4 * i + 1]) ^ 142 | gmult(3, state[4 * i + 2]) ^ 143 | gmult(1, state[4 * i + 3]); 144 | tmp[2] = gmult(1, state[4 * i + 0]) ^ 145 | gmult(1, state[4 * i + 1]) ^ 146 | gmult(2, state[4 * i + 2]) ^ 147 | gmult(3, state[4 * i + 3]); 148 | tmp[3] = gmult(3, state[4 * i + 0]) ^ 149 | gmult(1, state[4 * i + 1]) ^ 150 | gmult(1, state[4 * i + 2]) ^ 151 | gmult(2, state[4 * i + 3]); 152 | state[4 * i + 0] = tmp[0], state[4 * i + 1] = tmp[1], 153 | state[4 * i + 2] = tmp[2], state[4 * i + 3] = tmp[3]; 154 | } 155 | } 156 | 157 | inline void addRoundKey(uint8_t state[], const uint8_t word[]) { 158 | for (size_t i = 0; i < 16; ++i) 159 | state[i] ^= word[i]; 160 | } 161 | 162 | // in: 16 bytes 163 | // out: 16 bytes 164 | // key: 4 * (round + 1) * 4 bytes 165 | void aesIteration(const uint8_t in[], uint8_t out[], const uint8_t key[], size_t total_round) { 166 | uint8_t* state = out; 167 | memcpy(state, in, 16); 168 | 169 | // add round key 170 | addRoundKey(state, key); 171 | 172 | for (size_t round = 0; round < total_round - 1; ++round) { 173 | subBytes(state); 174 | shiftRows(state); 175 | mixColumns(state); 176 | addRoundKey(state, key + 16 * round + 16); 177 | } 178 | subBytes(state); 179 | shiftRows(state); 180 | addRoundKey(state, key + 16 * total_round); 181 | } 182 | 183 | void aes_ecb(const void* plain, size_t length, const void* key, const size_t key_length, void* cipher) { 184 | uint8_t keys[60 * 4]; 185 | keyExpansion((uint8_t*)(key), keys, key_length); 186 | 187 | for (size_t i = 0; i < length / 16; ++i) 188 | aesIteration((uint8_t*)(plain) + 16 * i, (uint8_t*)(cipher) + 16 * i, keys, 6 + key_length / 4); 189 | } 190 | 191 | int main(int argc, char** argv) { 192 | if (argc == 1) return 0; 193 | 194 | std::ifstream fin(argv[1]); 195 | 196 | fin.seekg(0, std::ios::end); 197 | std::string buffer; 198 | size_t len = fin.tellg(); 199 | buffer.reserve(len); 200 | fin.seekg(0, std::ios::beg); 201 | 202 | if (len % 16) { 203 | printf("Length of plain text should be multiple of 16 bytes. \n"); 204 | return 0; 205 | } 206 | 207 | buffer.assign((std::istreambuf_iterator(fin)), 208 | std::istreambuf_iterator()); 209 | 210 | fin.close(); 211 | 212 | // 128 bit or 192 bit or 256 bit key size 213 | unsigned char key[32] = { 0 }; 214 | size_t key_length = 0; 215 | 216 | if (argc == 3) { 217 | fin.open(argv[2]); 218 | fin.seekg(0, std::ios::beg); 219 | char buffer[3] = { 0 }; 220 | for (size_t i = 0; i < 32; ++i) { 221 | if (!fin.read(buffer, 2)) break; 222 | key[i] = std::stoi(buffer, 0, 16); 223 | ++key_length; 224 | } 225 | fin.close(); 226 | } 227 | 228 | if (key_length != 16 && key_length != 24 && key_length != 32) { 229 | printf("Length of key should be 16 or 24 or 32 bytes. \n"); 230 | return 0; 231 | } 232 | 233 | std::vector cipher(buffer.length(), 0); 234 | aes_ecb(buffer.data(), buffer.length(), key, key_length, &cipher[0]); 235 | 236 | for (size_t i = 0; i < buffer.length(); ++i) 237 | printf("%02x", int(cipher[i]) & 0xff); 238 | printf("\n"); 239 | 240 | } 241 | 242 | 243 | -------------------------------------------------------------------------------- /src/aes_ofb.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: aes_ofb.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 16, 2015 12 | * Time: 15:51:03 13 | * Description: AES(128, 192, 256 bit), Output Feedback Block(in 8 bit) Mode (OFB) 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | inline uint8_t gmult(uint8_t a, uint8_t b) { 22 | uint8_t p = 0, hbs = 0; 23 | 24 | for (size_t i = 0; i < 8; i++) { 25 | if (b & 1) 26 | p ^= a; 27 | 28 | hbs = a & 0x80; 29 | a <<= 1; 30 | if (hbs) a ^= 0x1b; // 0000 0001 0001 1011 31 | b >>= 1; 32 | } 33 | 34 | return (uint8_t)p; 35 | } 36 | 37 | constexpr uint8_t SubBytes[256] = { 38 | 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 39 | 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 40 | 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 41 | 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 42 | 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 43 | 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 44 | 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 45 | 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 46 | 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 47 | 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 48 | 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 49 | 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 50 | 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 51 | 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 52 | 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 53 | 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 54 | }; 55 | 56 | // key: initial key: 16 or 24 or 32 bytes 57 | // keys : 4 * (6 + key_length / 4 + 1) * 4 bytes 58 | void keyExpansion(const uint8_t key[], uint8_t keys[], const size_t key_length) { 59 | constexpr uint8_t RCON[10][4] = { 60 | { 0x01, 0x00, 0x00, 0x00 }, 61 | { 0x02, 0x00, 0x00, 0x00 }, 62 | { 0x04, 0x00, 0x00, 0x00 }, 63 | { 0x08, 0x00, 0x00, 0x00 }, 64 | { 0x10, 0x00, 0x00, 0x00 }, 65 | { 0x20, 0x00, 0x00, 0x00 }, 66 | { 0x40, 0x00, 0x00, 0x00 }, 67 | { 0x80, 0x00, 0x00, 0x00 }, 68 | { 0x1b, 0x00, 0x00, 0x00 }, 69 | { 0x36, 0x00, 0x00, 0x00 } 70 | }; 71 | 72 | 73 | memcpy(keys, key, key_length); 74 | 75 | for (size_t i = key_length / 4; i < 4 * (6 + key_length / 4 + 1); ++i) { 76 | uint8_t tmp[4] = { keys[4 * (i - 1) + 0], keys[4 * (i - 1) + 1], 77 | keys[4 * (i - 1) + 2], keys[4 * (i - 1) + 3] }; 78 | if (i % (key_length / 4) == 0) { 79 | // rotate left one byte 80 | uint8_t temp = tmp[0]; 81 | tmp[0] = tmp[1], tmp[1] = tmp[2], tmp[2] = tmp[3], tmp[3] = temp; 82 | // SubBytes 83 | tmp[0] = SubBytes[tmp[0]]; 84 | tmp[1] = SubBytes[tmp[1]]; 85 | tmp[2] = SubBytes[tmp[2]]; 86 | tmp[3] = SubBytes[tmp[3]]; 87 | // XOR round constants 88 | tmp[0] ^= RCON[i / (key_length / 4) - 1][0], tmp[1] ^= RCON[i / (key_length / 4) - 1][1], 89 | tmp[2] ^= RCON[i / (key_length / 4) - 1][2], tmp[3] ^= RCON[i / (key_length / 4) - 1][3]; 90 | } else if (key_length > 24 && i % (key_length / 4) == 4) { 91 | tmp[0] = SubBytes[tmp[0]]; 92 | tmp[1] = SubBytes[tmp[1]]; 93 | tmp[2] = SubBytes[tmp[2]]; 94 | tmp[3] = SubBytes[tmp[3]]; 95 | } 96 | keys[4 * i + 0] = tmp[0], keys[4 * i + 1] = tmp[1], 97 | keys[4 * i + 2] = tmp[2], keys[4 * i + 3] = tmp[3]; 98 | keys[4 * i + 0] ^= keys[4 * (i - key_length / 4) + 0], 99 | keys[4 * i + 1] ^= keys[4 * (i - key_length / 4) + 1], 100 | keys[4 * i + 2] ^= keys[4 * (i - key_length / 4) + 2], 101 | keys[4 * i + 3] ^= keys[4 * (i - key_length / 4) + 3]; 102 | } 103 | 104 | } 105 | 106 | inline void subBytes(uint8_t state[]) { 107 | for (size_t i = 0; i < 16; ++i) 108 | state[i] = SubBytes[state[i]]; 109 | } 110 | 111 | inline void shiftRows(uint8_t state[]) { 112 | uint8_t tmp = state[1]; 113 | state[1] = state[5]; 114 | state[5] = state[9]; 115 | state[9] = state[13]; 116 | state[13] = tmp; 117 | 118 | tmp = state[2]; 119 | state[2] = state[10]; 120 | state[10] = tmp; 121 | tmp = state[6]; 122 | state[6] = state[14]; 123 | state[14] = tmp; 124 | 125 | tmp = state[3]; 126 | state[3] = state[15]; 127 | state[15] = state[11]; 128 | state[11] = state[7]; 129 | state[7] = tmp; 130 | } 131 | 132 | inline void mixColumns(uint8_t state[]) { 133 | uint8_t tmp[4]; 134 | for (size_t i = 0; i < 4; ++i) { 135 | tmp[0] = gmult(2, state[4 * i + 0]) ^ 136 | gmult(3, state[4 * i + 1]) ^ 137 | gmult(1, state[4 * i + 2]) ^ 138 | gmult(1, state[4 * i + 3]); 139 | tmp[1] = gmult(1, state[4 * i + 0]) ^ 140 | gmult(2, state[4 * i + 1]) ^ 141 | gmult(3, state[4 * i + 2]) ^ 142 | gmult(1, state[4 * i + 3]); 143 | tmp[2] = gmult(1, state[4 * i + 0]) ^ 144 | gmult(1, state[4 * i + 1]) ^ 145 | gmult(2, state[4 * i + 2]) ^ 146 | gmult(3, state[4 * i + 3]); 147 | tmp[3] = gmult(3, state[4 * i + 0]) ^ 148 | gmult(1, state[4 * i + 1]) ^ 149 | gmult(1, state[4 * i + 2]) ^ 150 | gmult(2, state[4 * i + 3]); 151 | state[4 * i + 0] = tmp[0], state[4 * i + 1] = tmp[1], 152 | state[4 * i + 2] = tmp[2], state[4 * i + 3] = tmp[3]; 153 | } 154 | } 155 | 156 | inline void addRoundKey(uint8_t state[], const uint8_t word[]) { 157 | for (size_t i = 0; i < 16; ++i) 158 | state[i] ^= word[i]; 159 | } 160 | 161 | // in: 16 bytes 162 | // out: 16 bytes 163 | // key: 4 * (round + 1) * 4 bytes 164 | void aesIteration(const uint8_t in[], uint8_t out[], const uint8_t key[], size_t total_round) { 165 | uint8_t* state = out; 166 | memcpy(state, in, 16); 167 | 168 | // add round key 169 | addRoundKey(state, key); 170 | 171 | for (size_t round = 0; round < total_round - 1; ++round) { 172 | subBytes(state); 173 | shiftRows(state); 174 | mixColumns(state); 175 | addRoundKey(state, key + 16 * round + 16); 176 | } 177 | subBytes(state); 178 | shiftRows(state); 179 | addRoundKey(state, key + 16 * total_round); 180 | } 181 | 182 | void aes_ofb(const void* plain, size_t length, const void* key, const size_t key_length, const void* IV, void* cipher) { 183 | uint8_t keys[60 * 4]; 184 | keyExpansion((uint8_t*)(key), keys, key_length); 185 | 186 | uint8_t buffer[16]; 187 | memcpy(buffer, IV, 16); 188 | 189 | for (size_t i = 0; i < length; ++i) { 190 | aesIteration(buffer, (uint8_t*)(cipher) + i, keys, 6 + key_length / 4); 191 | for (size_t j = 0; j < 15; ++j) 192 | buffer[j] = buffer[j + 1]; 193 | buffer[15] = ((uint8_t*)(cipher))[i]; 194 | ((uint8_t*)(cipher))[i] ^= ((uint8_t*)(plain))[i]; 195 | } 196 | } 197 | 198 | int main(int argc, char** argv) { 199 | if (argc == 1) return 0; 200 | 201 | std::ifstream fin(argv[1]); 202 | 203 | fin.seekg(0, std::ios::end); 204 | std::string buffer; 205 | size_t len = fin.tellg(); 206 | buffer.reserve(len); 207 | fin.seekg(0, std::ios::beg); 208 | 209 | buffer.assign((std::istreambuf_iterator(fin)), 210 | std::istreambuf_iterator()); 211 | 212 | fin.close(); 213 | 214 | // 128 bit or 192 bit or 256 bit key size 215 | unsigned char key[32] = { 0 }; 216 | unsigned char IV[16] = { 0 }; 217 | size_t key_length = 0; 218 | 219 | if (argc == 3) { 220 | fin.open(argv[2]); 221 | fin.seekg(0, std::ios::beg); 222 | char buffer[3] = { 0 }; 223 | for (size_t i = 0; i < 32; ++i) { 224 | if (!fin.read(buffer, 2)) break; 225 | key[i] = std::stoi(buffer, 0, 16); 226 | ++key_length; 227 | } 228 | fin.close(); 229 | } 230 | 231 | if (key_length != 16 && key_length != 24 && key_length != 32) { 232 | printf("Length of key should be 16 or 24 or 32 bytes. \n"); 233 | return 0; 234 | } 235 | 236 | std::vector cipher(buffer.length() + 16, 0); 237 | aes_ofb(buffer.data(), buffer.length(), key, key_length, IV, &cipher[0]); 238 | 239 | for (size_t i = 0; i < buffer.length(); ++i) 240 | printf("%02x", int(cipher[i]) & 0xff); 241 | printf("\n"); 242 | 243 | } 244 | 245 | 246 | -------------------------------------------------------------------------------- /src/aes_cbc.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: aes_cbc.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 16, 2015 12 | * Time: 15:51:03 13 | * Description: AES(128, 192, 256 bit) Cipher Block Chaining Mode(CBC) 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | inline uint8_t gmult(uint8_t a, uint8_t b) { 22 | uint8_t p = 0, hbs = 0; 23 | 24 | for (size_t i = 0; i < 8; i++) { 25 | if (b & 1) 26 | p ^= a; 27 | 28 | hbs = a & 0x80; 29 | a <<= 1; 30 | if (hbs) a ^= 0x1b; // 0000 0001 0001 1011 31 | b >>= 1; 32 | } 33 | 34 | return (uint8_t)p; 35 | } 36 | 37 | constexpr uint8_t SubBytes[256] = { 38 | 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 39 | 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 40 | 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 41 | 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 42 | 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 43 | 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 44 | 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 45 | 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 46 | 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 47 | 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 48 | 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 49 | 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 50 | 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 51 | 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 52 | 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 53 | 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 54 | }; 55 | 56 | // key: initial key: 16 or 24 or 32 bytes 57 | // keys : 4 * (6 + key_length / 4 + 1) * 4 bytes 58 | void keyExpansion(const uint8_t key[], uint8_t keys[], const size_t key_length) { 59 | constexpr uint8_t RCON[10][4] = { 60 | { 0x01, 0x00, 0x00, 0x00 }, 61 | { 0x02, 0x00, 0x00, 0x00 }, 62 | { 0x04, 0x00, 0x00, 0x00 }, 63 | { 0x08, 0x00, 0x00, 0x00 }, 64 | { 0x10, 0x00, 0x00, 0x00 }, 65 | { 0x20, 0x00, 0x00, 0x00 }, 66 | { 0x40, 0x00, 0x00, 0x00 }, 67 | { 0x80, 0x00, 0x00, 0x00 }, 68 | { 0x1b, 0x00, 0x00, 0x00 }, 69 | { 0x36, 0x00, 0x00, 0x00 } 70 | }; 71 | 72 | 73 | memcpy(keys, key, key_length); 74 | 75 | for (size_t i = key_length / 4; i < 4 * (6 + key_length / 4 + 1); ++i) { 76 | uint8_t tmp[4] = { keys[4 * (i - 1) + 0], keys[4 * (i - 1) + 1], 77 | keys[4 * (i - 1) + 2], keys[4 * (i - 1) + 3] }; 78 | if (i % (key_length / 4) == 0) { 79 | // rotate left one byte 80 | uint8_t temp = tmp[0]; 81 | tmp[0] = tmp[1], tmp[1] = tmp[2], tmp[2] = tmp[3], tmp[3] = temp; 82 | // SubBytes 83 | tmp[0] = SubBytes[tmp[0]]; 84 | tmp[1] = SubBytes[tmp[1]]; 85 | tmp[2] = SubBytes[tmp[2]]; 86 | tmp[3] = SubBytes[tmp[3]]; 87 | // XOR round constants 88 | tmp[0] ^= RCON[i / (key_length / 4) - 1][0], tmp[1] ^= RCON[i / (key_length / 4) - 1][1], 89 | tmp[2] ^= RCON[i / (key_length / 4) - 1][2], tmp[3] ^= RCON[i / (key_length / 4) - 1][3]; 90 | } else if (key_length > 24 && i % (key_length / 4) == 4) { 91 | tmp[0] = SubBytes[tmp[0]]; 92 | tmp[1] = SubBytes[tmp[1]]; 93 | tmp[2] = SubBytes[tmp[2]]; 94 | tmp[3] = SubBytes[tmp[3]]; 95 | } 96 | keys[4 * i + 0] = tmp[0], keys[4 * i + 1] = tmp[1], 97 | keys[4 * i + 2] = tmp[2], keys[4 * i + 3] = tmp[3]; 98 | keys[4 * i + 0] ^= keys[4 * (i - key_length / 4) + 0], 99 | keys[4 * i + 1] ^= keys[4 * (i - key_length / 4) + 1], 100 | keys[4 * i + 2] ^= keys[4 * (i - key_length / 4) + 2], 101 | keys[4 * i + 3] ^= keys[4 * (i - key_length / 4) + 3]; 102 | } 103 | 104 | } 105 | 106 | 107 | inline void subBytes(uint8_t state[]) { 108 | for (size_t i = 0; i < 16; ++i) 109 | state[i] = SubBytes[state[i]]; 110 | } 111 | 112 | inline void shiftRows(uint8_t state[]) { 113 | uint8_t tmp = state[1]; 114 | state[1] = state[5]; 115 | state[5] = state[9]; 116 | state[9] = state[13]; 117 | state[13] = tmp; 118 | 119 | tmp = state[2]; 120 | state[2] = state[10]; 121 | state[10] = tmp; 122 | tmp = state[6]; 123 | state[6] = state[14]; 124 | state[14] = tmp; 125 | 126 | tmp = state[3]; 127 | state[3] = state[15]; 128 | state[15] = state[11]; 129 | state[11] = state[7]; 130 | state[7] = tmp; 131 | } 132 | 133 | inline void mixColumns(uint8_t state[]) { 134 | uint8_t tmp[4]; 135 | for (size_t i = 0; i < 4; ++i) { 136 | tmp[0] = gmult(2, state[4 * i + 0]) ^ 137 | gmult(3, state[4 * i + 1]) ^ 138 | gmult(1, state[4 * i + 2]) ^ 139 | gmult(1, state[4 * i + 3]); 140 | tmp[1] = gmult(1, state[4 * i + 0]) ^ 141 | gmult(2, state[4 * i + 1]) ^ 142 | gmult(3, state[4 * i + 2]) ^ 143 | gmult(1, state[4 * i + 3]); 144 | tmp[2] = gmult(1, state[4 * i + 0]) ^ 145 | gmult(1, state[4 * i + 1]) ^ 146 | gmult(2, state[4 * i + 2]) ^ 147 | gmult(3, state[4 * i + 3]); 148 | tmp[3] = gmult(3, state[4 * i + 0]) ^ 149 | gmult(1, state[4 * i + 1]) ^ 150 | gmult(1, state[4 * i + 2]) ^ 151 | gmult(2, state[4 * i + 3]); 152 | state[4 * i + 0] = tmp[0], state[4 * i + 1] = tmp[1], 153 | state[4 * i + 2] = tmp[2], state[4 * i + 3] = tmp[3]; 154 | } 155 | } 156 | 157 | inline void addRoundKey(uint8_t state[], const uint8_t word[]) { 158 | for (size_t i = 0; i < 16; ++i) 159 | state[i] ^= word[i]; 160 | } 161 | 162 | // in: 16 bytes 163 | // out: 16 bytes 164 | // key: 4 * (round + 1) * 4 bytes 165 | void aesIteration(const uint8_t in[], uint8_t out[], const uint8_t key[], size_t total_round) { 166 | uint8_t* state = out; 167 | memcpy(state, in, 16); 168 | 169 | // add round key 170 | addRoundKey(state, key); 171 | 172 | for (size_t round = 0; round < total_round - 1; ++round) { 173 | subBytes(state); 174 | shiftRows(state); 175 | mixColumns(state); 176 | addRoundKey(state, key + 16 * round + 16); 177 | } 178 | subBytes(state); 179 | shiftRows(state); 180 | addRoundKey(state, key + 16 * total_round); 181 | } 182 | 183 | 184 | void aes_cbc(const void* plain, size_t length, const void* key, const size_t key_length, const void* IV, void* cipher) { 185 | uint8_t keys[60 * 4]; 186 | keyExpansion((uint8_t*)(key), keys, key_length); 187 | 188 | uint8_t buffer[16]; 189 | memcpy(buffer, IV, 16); 190 | 191 | for (size_t i = 0; i < length / 16; ++i) { 192 | for (size_t j = 0; j < 16; ++j) 193 | buffer[j] ^= ((uint8_t*)(plain))[16 * i + j]; 194 | aesIteration(buffer, (uint8_t*)(cipher) + 16 * i, keys, 6 + key_length / 4); 195 | memcpy(buffer, (uint8_t*)(cipher) + 16 * i, 16); 196 | } 197 | } 198 | 199 | int main(int argc, char** argv) { 200 | if (argc == 1) return 0; 201 | 202 | std::ifstream fin(argv[1]); 203 | 204 | fin.seekg(0, std::ios::end); 205 | std::string buffer; 206 | size_t len = fin.tellg(); 207 | buffer.reserve(len); 208 | fin.seekg(0, std::ios::beg); 209 | 210 | if (len % 16) { 211 | printf("Length of plain text should be multiple of 16 bytes. \n"); 212 | return 0; 213 | } 214 | 215 | buffer.assign((std::istreambuf_iterator(fin)), 216 | std::istreambuf_iterator()); 217 | 218 | fin.close(); 219 | 220 | 221 | // 128 bit or 192 bit or 256 bit key size 222 | unsigned char key[32] = { 0 }; 223 | unsigned char IV[16] = { 0 }; 224 | size_t key_length = 0; 225 | 226 | if (argc == 3) { 227 | fin.open(argv[2]); 228 | fin.seekg(0, std::ios::beg); 229 | char buffer[3] = { 0 }; 230 | for (size_t i = 0; i < 32; ++i) { 231 | if (!fin.read(buffer, 2)) break; 232 | key[i] = std::stoi(buffer, 0, 16); 233 | ++key_length; 234 | } 235 | fin.close(); 236 | } 237 | 238 | if (key_length != 16 && key_length != 24 && key_length != 32) { 239 | printf("Length of key should be 16 or 24 or 32 bytes. \n"); 240 | return 0; 241 | } 242 | 243 | 244 | std::vector cipher(buffer.length(), 0); 245 | aes_cbc(buffer.data(), buffer.length(), key, key_length, IV, &cipher[0]); 246 | 247 | for (size_t i = 0; i < buffer.length(); ++i) 248 | printf("%02x", int(cipher[i]) & 0xff); 249 | printf("\n"); 250 | 251 | } 252 | 253 | 254 | -------------------------------------------------------------------------------- /src/aes_ctr.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: aes_ctr.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 16, 2015 12 | * Time: 15:51:03 13 | * Description: AES(128, 192, 256 bit), Counter Mode (CTR) 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | inline uint8_t gmult(uint8_t a, uint8_t b) { 22 | uint8_t p = 0, hbs = 0; 23 | 24 | for (size_t i = 0; i < 8; i++) { 25 | if (b & 1) 26 | p ^= a; 27 | 28 | hbs = a & 0x80; 29 | a <<= 1; 30 | if (hbs) a ^= 0x1b; // 0000 0001 0001 1011 31 | b >>= 1; 32 | } 33 | 34 | return (uint8_t)p; 35 | } 36 | 37 | constexpr uint8_t SubBytes[256] = { 38 | 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 39 | 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 40 | 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 41 | 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 42 | 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 43 | 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 44 | 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 45 | 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 46 | 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 47 | 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 48 | 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 49 | 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 50 | 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 51 | 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 52 | 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 53 | 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 54 | }; 55 | 56 | // key: initial key: 16 or 24 or 32 bytes 57 | // keys : 4 * (6 + key_length / 4 + 1) * 4 bytes 58 | void keyExpansion(const uint8_t key[], uint8_t keys[], const size_t key_length) { 59 | constexpr uint8_t RCON[10][4] = { 60 | { 0x01, 0x00, 0x00, 0x00 }, 61 | { 0x02, 0x00, 0x00, 0x00 }, 62 | { 0x04, 0x00, 0x00, 0x00 }, 63 | { 0x08, 0x00, 0x00, 0x00 }, 64 | { 0x10, 0x00, 0x00, 0x00 }, 65 | { 0x20, 0x00, 0x00, 0x00 }, 66 | { 0x40, 0x00, 0x00, 0x00 }, 67 | { 0x80, 0x00, 0x00, 0x00 }, 68 | { 0x1b, 0x00, 0x00, 0x00 }, 69 | { 0x36, 0x00, 0x00, 0x00 } 70 | }; 71 | 72 | 73 | memcpy(keys, key, key_length); 74 | 75 | for (size_t i = key_length / 4; i < 4 * (6 + key_length / 4 + 1); ++i) { 76 | uint8_t tmp[4] = { keys[4 * (i - 1) + 0], keys[4 * (i - 1) + 1], 77 | keys[4 * (i - 1) + 2], keys[4 * (i - 1) + 3] }; 78 | if (i % (key_length / 4) == 0) { 79 | // rotate left one byte 80 | uint8_t temp = tmp[0]; 81 | tmp[0] = tmp[1], tmp[1] = tmp[2], tmp[2] = tmp[3], tmp[3] = temp; 82 | // SubBytes 83 | tmp[0] = SubBytes[tmp[0]]; 84 | tmp[1] = SubBytes[tmp[1]]; 85 | tmp[2] = SubBytes[tmp[2]]; 86 | tmp[3] = SubBytes[tmp[3]]; 87 | // XOR round constants 88 | tmp[0] ^= RCON[i / (key_length / 4) - 1][0], tmp[1] ^= RCON[i / (key_length / 4) - 1][1], 89 | tmp[2] ^= RCON[i / (key_length / 4) - 1][2], tmp[3] ^= RCON[i / (key_length / 4) - 1][3]; 90 | } else if (key_length > 24 && i % (key_length / 4) == 4) { 91 | tmp[0] = SubBytes[tmp[0]]; 92 | tmp[1] = SubBytes[tmp[1]]; 93 | tmp[2] = SubBytes[tmp[2]]; 94 | tmp[3] = SubBytes[tmp[3]]; 95 | } 96 | keys[4 * i + 0] = tmp[0], keys[4 * i + 1] = tmp[1], 97 | keys[4 * i + 2] = tmp[2], keys[4 * i + 3] = tmp[3]; 98 | keys[4 * i + 0] ^= keys[4 * (i - key_length / 4) + 0], 99 | keys[4 * i + 1] ^= keys[4 * (i - key_length / 4) + 1], 100 | keys[4 * i + 2] ^= keys[4 * (i - key_length / 4) + 2], 101 | keys[4 * i + 3] ^= keys[4 * (i - key_length / 4) + 3]; 102 | } 103 | 104 | } 105 | 106 | inline void subBytes(uint8_t state[]) { 107 | for (size_t i = 0; i < 16; ++i) 108 | state[i] = SubBytes[state[i]]; 109 | } 110 | 111 | inline void shiftRows(uint8_t state[]) { 112 | uint8_t tmp = state[1]; 113 | state[1] = state[5]; 114 | state[5] = state[9]; 115 | state[9] = state[13]; 116 | state[13] = tmp; 117 | 118 | tmp = state[2]; 119 | state[2] = state[10]; 120 | state[10] = tmp; 121 | tmp = state[6]; 122 | state[6] = state[14]; 123 | state[14] = tmp; 124 | 125 | tmp = state[3]; 126 | state[3] = state[15]; 127 | state[15] = state[11]; 128 | state[11] = state[7]; 129 | state[7] = tmp; 130 | } 131 | 132 | inline void mixColumns(uint8_t state[]) { 133 | uint8_t tmp[4]; 134 | for (size_t i = 0; i < 4; ++i) { 135 | tmp[0] = gmult(2, state[4 * i + 0]) ^ 136 | gmult(3, state[4 * i + 1]) ^ 137 | gmult(1, state[4 * i + 2]) ^ 138 | gmult(1, state[4 * i + 3]); 139 | tmp[1] = gmult(1, state[4 * i + 0]) ^ 140 | gmult(2, state[4 * i + 1]) ^ 141 | gmult(3, state[4 * i + 2]) ^ 142 | gmult(1, state[4 * i + 3]); 143 | tmp[2] = gmult(1, state[4 * i + 0]) ^ 144 | gmult(1, state[4 * i + 1]) ^ 145 | gmult(2, state[4 * i + 2]) ^ 146 | gmult(3, state[4 * i + 3]); 147 | tmp[3] = gmult(3, state[4 * i + 0]) ^ 148 | gmult(1, state[4 * i + 1]) ^ 149 | gmult(1, state[4 * i + 2]) ^ 150 | gmult(2, state[4 * i + 3]); 151 | state[4 * i + 0] = tmp[0], state[4 * i + 1] = tmp[1], 152 | state[4 * i + 2] = tmp[2], state[4 * i + 3] = tmp[3]; 153 | } 154 | } 155 | 156 | inline void addRoundKey(uint8_t state[], const uint8_t word[]) { 157 | for (size_t i = 0; i < 16; ++i) 158 | state[i] ^= word[i]; 159 | } 160 | 161 | // in: 16 bytes 162 | // out: 16 bytes 163 | // key: 4 * (round + 1) * 4 bytes 164 | void aesIteration(const uint8_t in[], uint8_t out[], const uint8_t key[], size_t total_round) { 165 | uint8_t* state = out; 166 | memcpy(state, in, 16); 167 | 168 | // add round key 169 | addRoundKey(state, key); 170 | 171 | for (size_t round = 0; round < total_round - 1; ++round) { 172 | subBytes(state); 173 | shiftRows(state); 174 | mixColumns(state); 175 | addRoundKey(state, key + 16 * round + 16); 176 | } 177 | subBytes(state); 178 | shiftRows(state); 179 | addRoundKey(state, key + 16 * total_round); 180 | } 181 | 182 | void aes_ctr(const void* plain, size_t length, const void* key, const size_t key_length, const void* IV, void* cipher) { 183 | uint8_t keys[60 * 4]; 184 | keyExpansion((uint8_t*)(key), keys, key_length); 185 | 186 | uint8_t buffer[16]; 187 | 188 | uint8_t counter[8] = { 0 }; 189 | uint64_t* ctr = (uint64_t*)counter; 190 | 191 | for (size_t i = 0; i < length; ++i) { 192 | // any lossless operation is ok 193 | // we use XOR here 194 | memcpy(buffer, IV, 16); 195 | for (size_t j = 0; j < 8; ++j) 196 | buffer[j] ^= counter[7 - j]; 197 | 198 | aesIteration(buffer, (uint8_t*)(cipher) + i, keys, 6 + key_length / 4); 199 | 200 | ++(*ctr); 201 | 202 | ((uint8_t*)(cipher))[i] ^= ((uint8_t*)(plain))[i]; 203 | } 204 | } 205 | 206 | int main(int argc, char** argv) { 207 | if (argc == 1) return 0; 208 | 209 | std::ifstream fin(argv[1]); 210 | 211 | fin.seekg(0, std::ios::end); 212 | std::string buffer; 213 | size_t len = fin.tellg(); 214 | buffer.reserve(len); 215 | fin.seekg(0, std::ios::beg); 216 | 217 | buffer.assign((std::istreambuf_iterator(fin)), 218 | std::istreambuf_iterator()); 219 | 220 | fin.close(); 221 | 222 | // 128 bit or 192 bit or 256 bit key size 223 | unsigned char key[32] = { 0 }; 224 | unsigned char IV[16] = { 0 }; 225 | size_t key_length = 0; 226 | 227 | if (argc == 3) { 228 | fin.open(argv[2]); 229 | fin.seekg(0, std::ios::beg); 230 | char buffer[3] = { 0 }; 231 | for (size_t i = 0; i < 32; ++i) { 232 | if (!fin.read(buffer, 2)) break; 233 | key[i] = std::stoi(buffer, 0, 16); 234 | ++key_length; 235 | } 236 | fin.close(); 237 | } 238 | 239 | if (key_length != 16 && key_length != 24 && key_length != 32) { 240 | printf("Length of key should be 16 or 24 or 32 bytes. \n"); 241 | return 0; 242 | } 243 | 244 | 245 | std::vector cipher(buffer.length() + 16, 0); 246 | aes_ctr(buffer.data(), buffer.length(), key, key_length, IV, &cipher[0]); 247 | 248 | for (size_t i = 0; i < buffer.length(); ++i) 249 | printf("%02x", int(cipher[i]) & 0xff); 250 | printf("\n"); 251 | 252 | } 253 | 254 | 255 | -------------------------------------------------------------------------------- /src/des_ecb.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: des_ecb.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 15, 2015 12 | * Time: 14:04:14 13 | * Description: DES, Electronic Codebook Mode(ECB) 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | inline void setbit(void* ptr, size_t i, bool val) { 24 | if (val) 25 | ((uint8_t*)ptr)[i / 8] |= '\x01' << (7 - i % 8); 26 | else 27 | ((uint8_t*)ptr)[i / 8] &= ~('\x01' << (7 - i % 8)); 28 | } 29 | 30 | inline bool getbit(const void* ptr, size_t i) { 31 | return (((uint8_t*)ptr)[i / 8] & ('\x01' << (7 - i % 8)))? 1: 0; 32 | } 33 | 34 | 35 | // key is 64 bits 36 | std::array, 16> generateSubkeys(const uint8_t key[]) { 37 | constexpr size_t pc1[56] = { 57, 49, 41, 33, 25, 17, 9, 38 | 1, 58, 50, 42, 34, 26, 18, 39 | 10, 2, 59, 51, 43, 35, 27, 40 | 19, 11, 3, 60, 52, 44, 36, 41 | 63, 55, 47, 39, 31, 23, 15, 42 | 7, 62, 54, 46, 38, 30, 22, 43 | 14, 6, 61, 53, 45, 37, 29, 44 | 21, 13, 5, 28, 20, 12, 4 }; 45 | constexpr size_t pc2[48] = { 14, 17, 11, 24, 1, 5, 3, 28, 46 | 15, 6, 21, 10, 23, 19, 12, 4, 47 | 26, 8, 16, 7, 27, 20, 13, 2, 48 | 41, 52, 31, 37, 47, 55, 30, 40, 49 | 51, 45, 33, 48, 44, 49, 39, 56, 50 | 34, 53, 46, 42, 50, 36, 29, 32 }; 51 | // left shift both half-keys 1 bit 52 | auto key_shift = [](uint8_t key[])->void { 53 | bool a = getbit(key, 0); 54 | bool b = getbit(key, 28); 55 | for (size_t i = 0; i < 55; ++i) 56 | setbit(key, i, getbit(key, i + 1)); 57 | setbit(key, 27, a); 58 | setbit(key, 55, b); 59 | }; 60 | 61 | uint8_t key_p[7] = { 0 }; 62 | 63 | for (size_t i = 0; i < 56; ++i) 64 | setbit(key_p, i, getbit(key, pc1[i] - 1)); 65 | 66 | std::array, 16> subkeys; 67 | 68 | 69 | for (size_t i = 0; i < 16; ++i) { 70 | key_shift(key_p); 71 | if (i != 0 && i != 1 && i != 8 && i != 15) key_shift(key_p); 72 | for (size_t j = 0; j < 48; ++j) 73 | setbit(&subkeys[i][0], j, getbit(key_p, pc2[j] - 1)); 74 | } 75 | 76 | 77 | return subkeys; 78 | } 79 | 80 | inline uint32_t f_function(const uint32_t rn_1, const std::array& key_n) { 81 | constexpr size_t E[] = { 32, 1, 2, 3, 4, 5, 82 | 4, 5, 6, 7, 8, 9, 83 | 8, 9, 10, 11, 12, 13, 84 | 12, 13, 14, 15, 16, 17, 85 | 16, 17, 18, 19, 20, 21, 86 | 20, 21, 22, 23, 24, 25, 87 | 24, 25, 26, 27, 28, 29, 88 | 28, 29, 30, 31, 32, 1 }; 89 | constexpr size_t S[8][64] = { 90 | { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 91 | 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 92 | 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 93 | 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 }, 94 | { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 95 | 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 96 | 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 97 | 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 }, 98 | { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 99 | 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 100 | 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 101 | 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 }, 102 | { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 103 | 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 104 | 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 105 | 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 }, 106 | { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 107 | 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 108 | 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 109 | 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 }, 110 | { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 111 | 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 112 | 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 113 | 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 }, 114 | { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 115 | 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 116 | 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 117 | 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}, 118 | { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 119 | 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 120 | 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 121 | 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 } 122 | }; 123 | 124 | uint8_t e[6]; 125 | for (size_t i = 0; i < 48; ++i) 126 | setbit(e, i, getbit(&rn_1, E[i] - 1)); 127 | 128 | for (size_t i = 0; i < 6; ++i) 129 | e[i] ^= key_n[i]; 130 | 131 | uint32_t val = 0; 132 | 133 | for (size_t i = 0; i < 8; ++i) { 134 | uint8_t Sbox_value = S[i][(getbit(e, 6 * i + 0)) << 5 | 135 | (getbit(e, 6 * i + 5)) << 4 | 136 | (getbit(e, 6 * i + 1)) << 3 | 137 | (getbit(e, 6 * i + 2)) << 2 | 138 | (getbit(e, 6 * i + 3)) << 1 | 139 | (getbit(e, 6 * i + 4)) << 0 140 | ]; 141 | setbit(&val, i * 4 + 0, getbit(&Sbox_value, 4)); 142 | setbit(&val, i * 4 + 1, getbit(&Sbox_value, 5)); 143 | setbit(&val, i * 4 + 2, getbit(&Sbox_value, 6)); 144 | setbit(&val, i * 4 + 3, getbit(&Sbox_value, 7)); 145 | } 146 | 147 | constexpr size_t P[32] = { 16, 7, 20, 21, 29, 12, 28, 17, 148 | 1, 15, 23, 26, 5, 18, 31, 10, 149 | 2, 8, 24, 14, 32, 27, 3, 9, 150 | 19, 13, 30, 6, 22, 11, 4, 25 }; 151 | uint32_t p_val; 152 | for (size_t i = 0; i < 32; ++i) 153 | setbit(&p_val, i, getbit(&val, P[i] - 1)); 154 | 155 | return p_val; 156 | } 157 | 158 | // plain is 64 bits, cipher is 64 bits 159 | void des_ecb_iteration(const uint8_t* plain, const std::array, 16>& key, uint8_t* cipher) { 160 | constexpr size_t IP[64] = { 58, 50, 42, 34, 26, 18, 10, 2, 161 | 60, 52, 44, 36, 28, 20, 12, 4, 162 | 62, 54, 46, 38, 30, 22, 14, 6, 163 | 64, 56, 48, 40, 32, 24, 16, 8, 164 | 57, 49, 41, 33, 25, 17, 9, 1, 165 | 59, 51, 43, 35, 27, 19, 11, 3, 166 | 61, 53, 45, 37, 29, 21, 13, 5, 167 | 63, 55, 47, 39, 31, 23, 15, 7 }; 168 | // plain text after ip 169 | uint8_t ip[8]; 170 | for (size_t i = 0; i < 64; ++i) 171 | setbit(ip, i, getbit(plain, IP[i] - 1)); 172 | 173 | uint32_t ln, rn, ln_1, rn_1; 174 | ln_1 = ip[0] << 0 | ip[1] << 8 | ip[2] << 16 | ip[3] << 24; 175 | rn_1 = ip[4] << 0 | ip[5] << 8 | ip[6] << 16 | ip[7] << 24; 176 | 177 | for (size_t i = 0; i < 16; ++i) { 178 | ln = rn_1; 179 | rn = ln_1 ^ f_function(rn_1, key[i]); 180 | 181 | ln_1 = ln; 182 | rn_1 = rn; 183 | } 184 | 185 | constexpr size_t IP_i[64] = { 40, 8, 48, 16, 56, 24, 64, 32, 186 | 39, 7, 47, 15, 55, 23, 63, 31, 187 | 38, 6, 46, 14, 54, 22, 62, 30, 188 | 37, 5, 45, 13, 53, 21, 61, 29, 189 | 36, 4, 44, 12, 52, 20, 60, 28, 190 | 35, 3, 43, 11, 51, 19, 59, 27, 191 | 34, 2, 42, 10, 50, 18, 58, 26, 192 | 33, 1, 41, 9, 49, 17, 57, 25 }; 193 | uint64_t rnln = uint64_t(ln) << 32 | rn; 194 | uint64_t ip_i_rnln; 195 | for (size_t i = 0; i < 64; ++i) 196 | setbit(&ip_i_rnln, i, getbit(&rnln, IP_i[i] - 1)); 197 | 198 | cipher[0] = ip_i_rnln >> 0; 199 | cipher[1] = ip_i_rnln >> 8; 200 | cipher[2] = ip_i_rnln >> 16; 201 | cipher[3] = ip_i_rnln >> 24; 202 | cipher[4] = ip_i_rnln >> 32; 203 | cipher[5] = ip_i_rnln >> 40; 204 | cipher[6] = ip_i_rnln >> 48; 205 | cipher[7] = ip_i_rnln >> 56; 206 | } 207 | 208 | 209 | void des_ecb(const void* plain, const size_t length, const void* key, void* cipher) { 210 | uint8_t* plain_ = (uint8_t*)plain; 211 | const uint8_t* key_ = (const uint8_t*)key; 212 | uint8_t* cipher_ = (uint8_t*)cipher; 213 | 214 | auto subkeys = generateSubkeys(key_); 215 | for (size_t i = 0; i < length / 8; ++i) 216 | des_ecb_iteration(plain_ + 8 * i, subkeys, cipher_ + 8 * i); 217 | } 218 | 219 | int main(int argc, char** argv) { 220 | if (argc == 1) return 0; 221 | 222 | std::ifstream fin(argv[1]); 223 | 224 | fin.seekg(0, std::ios::end); 225 | std::string buffer; 226 | size_t len = fin.tellg(); 227 | buffer.reserve(len); 228 | fin.seekg(0, std::ios::beg); 229 | 230 | if (len % 8) { 231 | printf("Length of plain text should be multiple of 8 bytes. \n"); 232 | return 0; 233 | } 234 | 235 | buffer.assign((std::istreambuf_iterator(fin)), 236 | std::istreambuf_iterator()); 237 | 238 | fin.close(); 239 | 240 | unsigned char key[8] = { 0 }; 241 | 242 | if (argc == 3) { 243 | fin.open(argv[2]); 244 | fin.seekg(0, std::ios::beg); 245 | char buffer[3] = { 0 }; 246 | for (size_t i = 0; i < 8; ++i) { 247 | fin.read(buffer, 2); 248 | key[i] = std::stoi(buffer, 0, 16); 249 | } 250 | fin.close(); 251 | } 252 | 253 | 254 | std::vector cipher(buffer.length(), 0); 255 | des_ecb(buffer.data(), buffer.length(), key, &cipher[0]); 256 | 257 | for (size_t i = 0; i < buffer.length(); ++i) 258 | printf("%02x", int(cipher[i]) & 0xff); 259 | printf("\n"); 260 | 261 | } 262 | 263 | -------------------------------------------------------------------------------- /src/des_cfb.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: des_cfb.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 15, 2015 12 | * Time: 21:09:32 13 | * Description: DES, Cypher Feedback Block(in 8 bit) Mode(CFB) 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | inline void setbit(void* ptr, size_t i, bool val) { 24 | if (val) 25 | ((uint8_t*)ptr)[i / 8] |= '\x01' << (7 - i % 8); 26 | else 27 | ((uint8_t*)ptr)[i / 8] &= ~('\x01' << (7 - i % 8)); 28 | } 29 | 30 | inline bool getbit(const void* ptr, size_t i) { 31 | return (((uint8_t*)ptr)[i / 8] & ('\x01' << (7 - i % 8)))? 1: 0; 32 | } 33 | 34 | 35 | // key is 64 bits 36 | std::array, 16> generateSubkeys(const uint8_t key[]) { 37 | constexpr size_t pc1[56] = { 57, 49, 41, 33, 25, 17, 9, 38 | 1, 58, 50, 42, 34, 26, 18, 39 | 10, 2, 59, 51, 43, 35, 27, 40 | 19, 11, 3, 60, 52, 44, 36, 41 | 63, 55, 47, 39, 31, 23, 15, 42 | 7, 62, 54, 46, 38, 30, 22, 43 | 14, 6, 61, 53, 45, 37, 29, 44 | 21, 13, 5, 28, 20, 12, 4 }; 45 | constexpr size_t pc2[48] = { 14, 17, 11, 24, 1, 5, 3, 28, 46 | 15, 6, 21, 10, 23, 19, 12, 4, 47 | 26, 8, 16, 7, 27, 20, 13, 2, 48 | 41, 52, 31, 37, 47, 55, 30, 40, 49 | 51, 45, 33, 48, 44, 49, 39, 56, 50 | 34, 53, 46, 42, 50, 36, 29, 32 }; 51 | // left shift both half-keys 1 bit 52 | auto key_shift = [](uint8_t key[])->void { 53 | bool a = getbit(key, 0); 54 | bool b = getbit(key, 28); 55 | for (size_t i = 0; i < 55; ++i) 56 | setbit(key, i, getbit(key, i + 1)); 57 | setbit(key, 27, a); 58 | setbit(key, 55, b); 59 | }; 60 | 61 | uint8_t key_p[7] = { 0 }; 62 | 63 | for (size_t i = 0; i < 56; ++i) 64 | setbit(key_p, i, getbit(key, pc1[i] - 1)); 65 | 66 | std::array, 16> subkeys; 67 | 68 | 69 | for (size_t i = 0; i < 16; ++i) { 70 | key_shift(key_p); 71 | if (i != 0 && i != 1 && i != 8 && i != 15) key_shift(key_p); 72 | for (size_t j = 0; j < 48; ++j) 73 | setbit(&subkeys[i][0], j, getbit(key_p, pc2[j] - 1)); 74 | } 75 | 76 | 77 | return subkeys; 78 | } 79 | 80 | inline uint32_t f_function(const uint32_t rn_1, const std::array& key_n) { 81 | constexpr size_t E[] = { 32, 1, 2, 3, 4, 5, 82 | 4, 5, 6, 7, 8, 9, 83 | 8, 9, 10, 11, 12, 13, 84 | 12, 13, 14, 15, 16, 17, 85 | 16, 17, 18, 19, 20, 21, 86 | 20, 21, 22, 23, 24, 25, 87 | 24, 25, 26, 27, 28, 29, 88 | 28, 29, 30, 31, 32, 1 }; 89 | constexpr size_t S[8][64] = { 90 | { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 91 | 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 92 | 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 93 | 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 }, 94 | { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 95 | 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 96 | 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 97 | 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 }, 98 | { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 99 | 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 100 | 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 101 | 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 }, 102 | { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 103 | 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 104 | 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 105 | 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 }, 106 | { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 107 | 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 108 | 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 109 | 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 }, 110 | { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 111 | 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 112 | 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 113 | 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 }, 114 | { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 115 | 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 116 | 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 117 | 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}, 118 | { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 119 | 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 120 | 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 121 | 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 } 122 | }; 123 | 124 | uint8_t e[6]; 125 | for (size_t i = 0; i < 48; ++i) 126 | setbit(e, i, getbit(&rn_1, E[i] - 1)); 127 | 128 | for (size_t i = 0; i < 6; ++i) 129 | e[i] ^= key_n[i]; 130 | 131 | uint32_t val = 0; 132 | 133 | for (size_t i = 0; i < 8; ++i) { 134 | uint8_t Sbox_value = S[i][(getbit(e, 6 * i + 0)) << 5 | 135 | (getbit(e, 6 * i + 5)) << 4 | 136 | (getbit(e, 6 * i + 1)) << 3 | 137 | (getbit(e, 6 * i + 2)) << 2 | 138 | (getbit(e, 6 * i + 3)) << 1 | 139 | (getbit(e, 6 * i + 4)) << 0 140 | ]; 141 | setbit(&val, i * 4 + 0, getbit(&Sbox_value, 4)); 142 | setbit(&val, i * 4 + 1, getbit(&Sbox_value, 5)); 143 | setbit(&val, i * 4 + 2, getbit(&Sbox_value, 6)); 144 | setbit(&val, i * 4 + 3, getbit(&Sbox_value, 7)); 145 | } 146 | 147 | constexpr size_t P[32] = { 16, 7, 20, 21, 29, 12, 28, 17, 148 | 1, 15, 23, 26, 5, 18, 31, 10, 149 | 2, 8, 24, 14, 32, 27, 3, 9, 150 | 19, 13, 30, 6, 22, 11, 4, 25 }; 151 | uint32_t p_val; 152 | for (size_t i = 0; i < 32; ++i) 153 | setbit(&p_val, i, getbit(&val, P[i] - 1)); 154 | 155 | return p_val; 156 | } 157 | 158 | // plain is 64 bits, cipher is 64 bits 159 | void des_cfb_iteration(const uint8_t* plain, const std::array, 16>& key, uint8_t* cipher) { 160 | constexpr size_t IP[64] = { 58, 50, 42, 34, 26, 18, 10, 2, 161 | 60, 52, 44, 36, 28, 20, 12, 4, 162 | 62, 54, 46, 38, 30, 22, 14, 6, 163 | 64, 56, 48, 40, 32, 24, 16, 8, 164 | 57, 49, 41, 33, 25, 17, 9, 1, 165 | 59, 51, 43, 35, 27, 19, 11, 3, 166 | 61, 53, 45, 37, 29, 21, 13, 5, 167 | 63, 55, 47, 39, 31, 23, 15, 7 }; 168 | // plain text after ip 169 | uint8_t ip[8]; 170 | for (size_t i = 0; i < 64; ++i) 171 | setbit(ip, i, getbit(plain, IP[i] - 1)); 172 | 173 | uint32_t ln, rn, ln_1, rn_1; 174 | ln_1 = ip[0] << 0 | ip[1] << 8 | ip[2] << 16 | ip[3] << 24; 175 | rn_1 = ip[4] << 0 | ip[5] << 8 | ip[6] << 16 | ip[7] << 24; 176 | 177 | for (size_t i = 0; i < 16; ++i) { 178 | ln = rn_1; 179 | rn = ln_1 ^ f_function(rn_1, key[i]); 180 | 181 | ln_1 = ln; 182 | rn_1 = rn; 183 | } 184 | 185 | constexpr size_t IP_i[64] = { 40, 8, 48, 16, 56, 24, 64, 32, 186 | 39, 7, 47, 15, 55, 23, 63, 31, 187 | 38, 6, 46, 14, 54, 22, 62, 30, 188 | 37, 5, 45, 13, 53, 21, 61, 29, 189 | 36, 4, 44, 12, 52, 20, 60, 28, 190 | 35, 3, 43, 11, 51, 19, 59, 27, 191 | 34, 2, 42, 10, 50, 18, 58, 26, 192 | 33, 1, 41, 9, 49, 17, 57, 25 }; 193 | uint64_t rnln = uint64_t(ln) << 32 | rn; 194 | uint64_t ip_i_rnln; 195 | for (size_t i = 0; i < 64; ++i) 196 | setbit(&ip_i_rnln, i, getbit(&rnln, IP_i[i] - 1)); 197 | 198 | cipher[0] = ip_i_rnln >> 0; 199 | cipher[1] = ip_i_rnln >> 8; 200 | cipher[2] = ip_i_rnln >> 16; 201 | cipher[3] = ip_i_rnln >> 24; 202 | cipher[4] = ip_i_rnln >> 32; 203 | cipher[5] = ip_i_rnln >> 40; 204 | cipher[6] = ip_i_rnln >> 48; 205 | cipher[7] = ip_i_rnln >> 56; 206 | } 207 | 208 | 209 | void des_cfb(const void* plain, const size_t length, const void* key, const void* IV, void* cipher) { 210 | uint8_t* plain_ = (uint8_t*)plain; 211 | const uint8_t* key_ = (const uint8_t*)key; 212 | uint8_t* cipher_ = (uint8_t*)cipher; 213 | 214 | uint8_t buffer[8]; 215 | memcpy(buffer, IV, 8); 216 | 217 | auto subkeys = generateSubkeys(key_); 218 | 219 | for (size_t i = 0; i < length; ++i) { 220 | des_cfb_iteration(buffer, subkeys, cipher_ + i); 221 | cipher_[i] ^= plain_[i]; 222 | for (size_t i = 0; i < 7; ++i) 223 | buffer[i] = buffer[i + 1]; 224 | buffer[7] = cipher_[i]; 225 | } 226 | 227 | } 228 | 229 | int main(int argc, char** argv) { 230 | if (argc == 1) return 0; 231 | 232 | std::ifstream fin(argv[1]); 233 | 234 | fin.seekg(0, std::ios::end); 235 | std::string buffer; 236 | buffer.reserve(fin.tellg()); 237 | fin.seekg(0, std::ios::beg); 238 | 239 | 240 | buffer.assign((std::istreambuf_iterator(fin)), 241 | std::istreambuf_iterator()); 242 | 243 | fin.close(); 244 | 245 | unsigned char key[8] = { 0 }; 246 | unsigned char IV[8] = { 0 }; 247 | 248 | if (argc == 3) { 249 | fin.open(argv[2]); 250 | fin.seekg(0, std::ios::beg); 251 | char buffer[3] = { 0 }; 252 | for (size_t i = 0; i < 8; ++i) { 253 | fin.read(buffer, 2); 254 | key[i] = std::stoi(buffer, 0, 16); 255 | } 256 | fin.close(); 257 | } 258 | 259 | 260 | std::vector cipher(buffer.length() + 8, 0); 261 | des_cfb(buffer.data(), buffer.length(), key, IV, &cipher[0]); 262 | 263 | for (size_t i = 0; i < buffer.length(); ++i) 264 | printf("%02x", int(cipher[i]) & 0xff); 265 | printf("\n"); 266 | 267 | } 268 | 269 | -------------------------------------------------------------------------------- /src/des_ofb.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: des_ofb.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 15, 2015 12 | * Time: 21:58:29 13 | * Description: DES, Output Feedback Block(in 8 bit) Mode(CFB) 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | inline void setbit(void* ptr, size_t i, bool val) { 24 | if (val) 25 | ((uint8_t*)ptr)[i / 8] |= '\x01' << (7 - i % 8); 26 | else 27 | ((uint8_t*)ptr)[i / 8] &= ~('\x01' << (7 - i % 8)); 28 | } 29 | 30 | inline bool getbit(const void* ptr, size_t i) { 31 | return (((uint8_t*)ptr)[i / 8] & ('\x01' << (7 - i % 8)))? 1: 0; 32 | } 33 | 34 | 35 | // key is 64 bits 36 | std::array, 16> generateSubkeys(const uint8_t key[]) { 37 | constexpr size_t pc1[56] = { 57, 49, 41, 33, 25, 17, 9, 38 | 1, 58, 50, 42, 34, 26, 18, 39 | 10, 2, 59, 51, 43, 35, 27, 40 | 19, 11, 3, 60, 52, 44, 36, 41 | 63, 55, 47, 39, 31, 23, 15, 42 | 7, 62, 54, 46, 38, 30, 22, 43 | 14, 6, 61, 53, 45, 37, 29, 44 | 21, 13, 5, 28, 20, 12, 4 }; 45 | constexpr size_t pc2[48] = { 14, 17, 11, 24, 1, 5, 3, 28, 46 | 15, 6, 21, 10, 23, 19, 12, 4, 47 | 26, 8, 16, 7, 27, 20, 13, 2, 48 | 41, 52, 31, 37, 47, 55, 30, 40, 49 | 51, 45, 33, 48, 44, 49, 39, 56, 50 | 34, 53, 46, 42, 50, 36, 29, 32 }; 51 | // left shift both half-keys 1 bit 52 | auto key_shift = [](uint8_t key[])->void { 53 | bool a = getbit(key, 0); 54 | bool b = getbit(key, 28); 55 | for (size_t i = 0; i < 55; ++i) 56 | setbit(key, i, getbit(key, i + 1)); 57 | setbit(key, 27, a); 58 | setbit(key, 55, b); 59 | }; 60 | 61 | uint8_t key_p[7] = { 0 }; 62 | 63 | for (size_t i = 0; i < 56; ++i) 64 | setbit(key_p, i, getbit(key, pc1[i] - 1)); 65 | 66 | std::array, 16> subkeys; 67 | 68 | 69 | for (size_t i = 0; i < 16; ++i) { 70 | key_shift(key_p); 71 | if (i != 0 && i != 1 && i != 8 && i != 15) key_shift(key_p); 72 | for (size_t j = 0; j < 48; ++j) 73 | setbit(&subkeys[i][0], j, getbit(key_p, pc2[j] - 1)); 74 | } 75 | 76 | 77 | return subkeys; 78 | } 79 | 80 | inline uint32_t f_function(const uint32_t rn_1, const std::array& key_n) { 81 | constexpr size_t E[] = { 32, 1, 2, 3, 4, 5, 82 | 4, 5, 6, 7, 8, 9, 83 | 8, 9, 10, 11, 12, 13, 84 | 12, 13, 14, 15, 16, 17, 85 | 16, 17, 18, 19, 20, 21, 86 | 20, 21, 22, 23, 24, 25, 87 | 24, 25, 26, 27, 28, 29, 88 | 28, 29, 30, 31, 32, 1 }; 89 | constexpr size_t S[8][64] = { 90 | { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 91 | 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 92 | 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 93 | 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 }, 94 | { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 95 | 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 96 | 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 97 | 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 }, 98 | { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 99 | 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 100 | 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 101 | 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 }, 102 | { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 103 | 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 104 | 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 105 | 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 }, 106 | { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 107 | 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 108 | 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 109 | 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 }, 110 | { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 111 | 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 112 | 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 113 | 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 }, 114 | { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 115 | 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 116 | 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 117 | 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}, 118 | { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 119 | 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 120 | 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 121 | 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 } 122 | }; 123 | 124 | uint8_t e[6]; 125 | for (size_t i = 0; i < 48; ++i) 126 | setbit(e, i, getbit(&rn_1, E[i] - 1)); 127 | 128 | for (size_t i = 0; i < 6; ++i) 129 | e[i] ^= key_n[i]; 130 | 131 | uint32_t val = 0; 132 | 133 | for (size_t i = 0; i < 8; ++i) { 134 | uint8_t Sbox_value = S[i][(getbit(e, 6 * i + 0)) << 5 | 135 | (getbit(e, 6 * i + 5)) << 4 | 136 | (getbit(e, 6 * i + 1)) << 3 | 137 | (getbit(e, 6 * i + 2)) << 2 | 138 | (getbit(e, 6 * i + 3)) << 1 | 139 | (getbit(e, 6 * i + 4)) << 0 140 | ]; 141 | setbit(&val, i * 4 + 0, getbit(&Sbox_value, 4)); 142 | setbit(&val, i * 4 + 1, getbit(&Sbox_value, 5)); 143 | setbit(&val, i * 4 + 2, getbit(&Sbox_value, 6)); 144 | setbit(&val, i * 4 + 3, getbit(&Sbox_value, 7)); 145 | } 146 | 147 | constexpr size_t P[32] = { 16, 7, 20, 21, 29, 12, 28, 17, 148 | 1, 15, 23, 26, 5, 18, 31, 10, 149 | 2, 8, 24, 14, 32, 27, 3, 9, 150 | 19, 13, 30, 6, 22, 11, 4, 25 }; 151 | uint32_t p_val; 152 | for (size_t i = 0; i < 32; ++i) 153 | setbit(&p_val, i, getbit(&val, P[i] - 1)); 154 | 155 | return p_val; 156 | } 157 | 158 | // plain is 64 bits, cipher is 64 bits 159 | void des_ofb_iteration(const uint8_t* plain, const std::array, 16>& key, uint8_t* cipher) { 160 | constexpr size_t IP[64] = { 58, 50, 42, 34, 26, 18, 10, 2, 161 | 60, 52, 44, 36, 28, 20, 12, 4, 162 | 62, 54, 46, 38, 30, 22, 14, 6, 163 | 64, 56, 48, 40, 32, 24, 16, 8, 164 | 57, 49, 41, 33, 25, 17, 9, 1, 165 | 59, 51, 43, 35, 27, 19, 11, 3, 166 | 61, 53, 45, 37, 29, 21, 13, 5, 167 | 63, 55, 47, 39, 31, 23, 15, 7 }; 168 | // plain text after ip 169 | uint8_t ip[8]; 170 | for (size_t i = 0; i < 64; ++i) 171 | setbit(ip, i, getbit(plain, IP[i] - 1)); 172 | 173 | uint32_t ln, rn, ln_1, rn_1; 174 | ln_1 = ip[0] << 0 | ip[1] << 8 | ip[2] << 16 | ip[3] << 24; 175 | rn_1 = ip[4] << 0 | ip[5] << 8 | ip[6] << 16 | ip[7] << 24; 176 | 177 | for (size_t i = 0; i < 16; ++i) { 178 | ln = rn_1; 179 | rn = ln_1 ^ f_function(rn_1, key[i]); 180 | 181 | ln_1 = ln; 182 | rn_1 = rn; 183 | } 184 | 185 | constexpr size_t IP_i[64] = { 40, 8, 48, 16, 56, 24, 64, 32, 186 | 39, 7, 47, 15, 55, 23, 63, 31, 187 | 38, 6, 46, 14, 54, 22, 62, 30, 188 | 37, 5, 45, 13, 53, 21, 61, 29, 189 | 36, 4, 44, 12, 52, 20, 60, 28, 190 | 35, 3, 43, 11, 51, 19, 59, 27, 191 | 34, 2, 42, 10, 50, 18, 58, 26, 192 | 33, 1, 41, 9, 49, 17, 57, 25 }; 193 | uint64_t rnln = uint64_t(ln) << 32 | rn; 194 | uint64_t ip_i_rnln; 195 | for (size_t i = 0; i < 64; ++i) 196 | setbit(&ip_i_rnln, i, getbit(&rnln, IP_i[i] - 1)); 197 | 198 | cipher[0] = ip_i_rnln >> 0; 199 | cipher[1] = ip_i_rnln >> 8; 200 | cipher[2] = ip_i_rnln >> 16; 201 | cipher[3] = ip_i_rnln >> 24; 202 | cipher[4] = ip_i_rnln >> 32; 203 | cipher[5] = ip_i_rnln >> 40; 204 | cipher[6] = ip_i_rnln >> 48; 205 | cipher[7] = ip_i_rnln >> 56; 206 | } 207 | 208 | 209 | void des_ofb(const void* plain, const size_t length, const void* key, const void* IV, void* cipher) { 210 | uint8_t* plain_ = (uint8_t*)plain; 211 | const uint8_t* key_ = (const uint8_t*)key; 212 | uint8_t* cipher_ = (uint8_t*)cipher; 213 | 214 | uint8_t buffer[8]; 215 | memcpy(buffer, IV, 8); 216 | 217 | auto subkeys = generateSubkeys(key_); 218 | 219 | for (size_t i = 0; i < length; ++i) { 220 | des_ofb_iteration(buffer, subkeys, cipher_ + i); 221 | for (size_t i = 0; i < 7; ++i) 222 | buffer[i] = buffer[i + 1]; 223 | buffer[7] = cipher_[i]; 224 | cipher_[i] ^= plain_[i]; 225 | } 226 | 227 | } 228 | 229 | int main(int argc, char** argv) { 230 | if (argc == 1) return 0; 231 | 232 | std::ifstream fin(argv[1]); 233 | 234 | fin.seekg(0, std::ios::end); 235 | std::string buffer; 236 | buffer.reserve(fin.tellg()); 237 | fin.seekg(0, std::ios::beg); 238 | 239 | 240 | buffer.assign((std::istreambuf_iterator(fin)), 241 | std::istreambuf_iterator()); 242 | 243 | fin.close(); 244 | 245 | unsigned char key[8] = { 0 }; 246 | unsigned char IV[8] = { 0 }; 247 | 248 | if (argc == 3) { 249 | fin.open(argv[2]); 250 | fin.seekg(0, std::ios::beg); 251 | char buffer[3] = { 0 }; 252 | for (size_t i = 0; i < 8; ++i) { 253 | fin.read(buffer, 2); 254 | key[i] = std::stoi(buffer, 0, 16); 255 | } 256 | fin.close(); 257 | } 258 | 259 | 260 | std::vector cipher(buffer.length() + 8, 0); 261 | des_ofb(buffer.data(), buffer.length(), key, IV, &cipher[0]); 262 | 263 | for (size_t i = 0; i < buffer.length(); ++i) 264 | printf("%02x", int(cipher[i]) & 0xff); 265 | printf("\n"); 266 | 267 | } 268 | 269 | -------------------------------------------------------------------------------- /src/des_cbc.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: des_cbc.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 15, 2015 12 | * Time: 21:09:32 13 | * Description: DES, Cipher Block Chaining Mode(CBC) 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | inline void setbit(void* ptr, size_t i, bool val) { 24 | if (val) 25 | ((uint8_t*)ptr)[i / 8] |= '\x01' << (7 - i % 8); 26 | else 27 | ((uint8_t*)ptr)[i / 8] &= ~('\x01' << (7 - i % 8)); 28 | } 29 | 30 | inline bool getbit(const void* ptr, size_t i) { 31 | return (((uint8_t*)ptr)[i / 8] & ('\x01' << (7 - i % 8)))? 1: 0; 32 | } 33 | 34 | 35 | // key is 64 bits 36 | std::array, 16> generateSubkeys(const uint8_t key[]) { 37 | constexpr size_t pc1[56] = { 57, 49, 41, 33, 25, 17, 9, 38 | 1, 58, 50, 42, 34, 26, 18, 39 | 10, 2, 59, 51, 43, 35, 27, 40 | 19, 11, 3, 60, 52, 44, 36, 41 | 63, 55, 47, 39, 31, 23, 15, 42 | 7, 62, 54, 46, 38, 30, 22, 43 | 14, 6, 61, 53, 45, 37, 29, 44 | 21, 13, 5, 28, 20, 12, 4 }; 45 | constexpr size_t pc2[48] = { 14, 17, 11, 24, 1, 5, 3, 28, 46 | 15, 6, 21, 10, 23, 19, 12, 4, 47 | 26, 8, 16, 7, 27, 20, 13, 2, 48 | 41, 52, 31, 37, 47, 55, 30, 40, 49 | 51, 45, 33, 48, 44, 49, 39, 56, 50 | 34, 53, 46, 42, 50, 36, 29, 32 }; 51 | // left shift both half-keys 1 bit 52 | auto key_shift = [](uint8_t key[])->void { 53 | bool a = getbit(key, 0); 54 | bool b = getbit(key, 28); 55 | for (size_t i = 0; i < 55; ++i) 56 | setbit(key, i, getbit(key, i + 1)); 57 | setbit(key, 27, a); 58 | setbit(key, 55, b); 59 | }; 60 | 61 | uint8_t key_p[7] = { 0 }; 62 | 63 | for (size_t i = 0; i < 56; ++i) 64 | setbit(key_p, i, getbit(key, pc1[i] - 1)); 65 | 66 | std::array, 16> subkeys; 67 | 68 | 69 | for (size_t i = 0; i < 16; ++i) { 70 | key_shift(key_p); 71 | if (i != 0 && i != 1 && i != 8 && i != 15) key_shift(key_p); 72 | for (size_t j = 0; j < 48; ++j) 73 | setbit(&subkeys[i][0], j, getbit(key_p, pc2[j] - 1)); 74 | } 75 | 76 | 77 | return subkeys; 78 | } 79 | 80 | inline uint32_t f_function(const uint32_t rn_1, const std::array& key_n) { 81 | constexpr size_t E[] = { 32, 1, 2, 3, 4, 5, 82 | 4, 5, 6, 7, 8, 9, 83 | 8, 9, 10, 11, 12, 13, 84 | 12, 13, 14, 15, 16, 17, 85 | 16, 17, 18, 19, 20, 21, 86 | 20, 21, 22, 23, 24, 25, 87 | 24, 25, 26, 27, 28, 29, 88 | 28, 29, 30, 31, 32, 1 }; 89 | constexpr size_t S[8][64] = { 90 | { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 91 | 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 92 | 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 93 | 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 }, 94 | { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 95 | 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 96 | 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 97 | 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 }, 98 | { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 99 | 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 100 | 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 101 | 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 }, 102 | { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 103 | 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 104 | 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 105 | 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 }, 106 | { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 107 | 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 108 | 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 109 | 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 }, 110 | { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 111 | 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 112 | 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 113 | 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 }, 114 | { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 115 | 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 116 | 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 117 | 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}, 118 | { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 119 | 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 120 | 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 121 | 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 } 122 | }; 123 | 124 | uint8_t e[6]; 125 | for (size_t i = 0; i < 48; ++i) 126 | setbit(e, i, getbit(&rn_1, E[i] - 1)); 127 | 128 | for (size_t i = 0; i < 6; ++i) 129 | e[i] ^= key_n[i]; 130 | 131 | uint32_t val = 0; 132 | 133 | for (size_t i = 0; i < 8; ++i) { 134 | uint8_t Sbox_value = S[i][(getbit(e, 6 * i + 0)) << 5 | 135 | (getbit(e, 6 * i + 5)) << 4 | 136 | (getbit(e, 6 * i + 1)) << 3 | 137 | (getbit(e, 6 * i + 2)) << 2 | 138 | (getbit(e, 6 * i + 3)) << 1 | 139 | (getbit(e, 6 * i + 4)) << 0 140 | ]; 141 | setbit(&val, i * 4 + 0, getbit(&Sbox_value, 4)); 142 | setbit(&val, i * 4 + 1, getbit(&Sbox_value, 5)); 143 | setbit(&val, i * 4 + 2, getbit(&Sbox_value, 6)); 144 | setbit(&val, i * 4 + 3, getbit(&Sbox_value, 7)); 145 | } 146 | 147 | constexpr size_t P[32] = { 16, 7, 20, 21, 29, 12, 28, 17, 148 | 1, 15, 23, 26, 5, 18, 31, 10, 149 | 2, 8, 24, 14, 32, 27, 3, 9, 150 | 19, 13, 30, 6, 22, 11, 4, 25 }; 151 | uint32_t p_val; 152 | for (size_t i = 0; i < 32; ++i) 153 | setbit(&p_val, i, getbit(&val, P[i] - 1)); 154 | 155 | return p_val; 156 | } 157 | 158 | // plain is 64 bits, cipher is 64 bits 159 | void des_cbc_iteration(const uint8_t* plain, const std::array, 16>& key, uint8_t* cipher) { 160 | constexpr size_t IP[64] = { 58, 50, 42, 34, 26, 18, 10, 2, 161 | 60, 52, 44, 36, 28, 20, 12, 4, 162 | 62, 54, 46, 38, 30, 22, 14, 6, 163 | 64, 56, 48, 40, 32, 24, 16, 8, 164 | 57, 49, 41, 33, 25, 17, 9, 1, 165 | 59, 51, 43, 35, 27, 19, 11, 3, 166 | 61, 53, 45, 37, 29, 21, 13, 5, 167 | 63, 55, 47, 39, 31, 23, 15, 7 }; 168 | // plain text after ip 169 | uint8_t ip[8]; 170 | for (size_t i = 0; i < 64; ++i) 171 | setbit(ip, i, getbit(plain, IP[i] - 1)); 172 | 173 | uint32_t ln, rn, ln_1, rn_1; 174 | ln_1 = ip[0] << 0 | ip[1] << 8 | ip[2] << 16 | ip[3] << 24; 175 | rn_1 = ip[4] << 0 | ip[5] << 8 | ip[6] << 16 | ip[7] << 24; 176 | 177 | for (size_t i = 0; i < 16; ++i) { 178 | ln = rn_1; 179 | rn = ln_1 ^ f_function(rn_1, key[i]); 180 | 181 | ln_1 = ln; 182 | rn_1 = rn; 183 | } 184 | 185 | constexpr size_t IP_i[64] = { 40, 8, 48, 16, 56, 24, 64, 32, 186 | 39, 7, 47, 15, 55, 23, 63, 31, 187 | 38, 6, 46, 14, 54, 22, 62, 30, 188 | 37, 5, 45, 13, 53, 21, 61, 29, 189 | 36, 4, 44, 12, 52, 20, 60, 28, 190 | 35, 3, 43, 11, 51, 19, 59, 27, 191 | 34, 2, 42, 10, 50, 18, 58, 26, 192 | 33, 1, 41, 9, 49, 17, 57, 25 }; 193 | uint64_t rnln = uint64_t(ln) << 32 | rn; 194 | uint64_t ip_i_rnln; 195 | for (size_t i = 0; i < 64; ++i) 196 | setbit(&ip_i_rnln, i, getbit(&rnln, IP_i[i] - 1)); 197 | 198 | cipher[0] = ip_i_rnln >> 0; 199 | cipher[1] = ip_i_rnln >> 8; 200 | cipher[2] = ip_i_rnln >> 16; 201 | cipher[3] = ip_i_rnln >> 24; 202 | cipher[4] = ip_i_rnln >> 32; 203 | cipher[5] = ip_i_rnln >> 40; 204 | cipher[6] = ip_i_rnln >> 48; 205 | cipher[7] = ip_i_rnln >> 56; 206 | } 207 | 208 | 209 | void des_cbc(const void* plain, const size_t length, const void* key, const void* IV, void* cipher) { 210 | uint8_t* plain_ = (uint8_t*)plain; 211 | const uint8_t* key_ = (const uint8_t*)key; 212 | uint8_t* cipher_ = (uint8_t*)cipher; 213 | 214 | uint8_t buffer[8]; 215 | memcpy(buffer, IV, 8); 216 | 217 | auto subkeys = generateSubkeys(key_); 218 | for (size_t i = 0; i < length / 8; ++i) { 219 | for (size_t j = 0; j < 8; ++j) 220 | buffer[j] ^= plain_[8 * i + j]; 221 | des_cbc_iteration(buffer, subkeys, cipher_ + 8 * i); 222 | memcpy(buffer, cipher_ + 8 * i, 8); 223 | } 224 | 225 | } 226 | 227 | int main(int argc, char** argv) { 228 | if (argc == 1) return 0; 229 | 230 | std::ifstream fin(argv[1]); 231 | 232 | fin.seekg(0, std::ios::end); 233 | std::string buffer; 234 | size_t len = fin.tellg(); 235 | buffer.reserve(len); 236 | fin.seekg(0, std::ios::beg); 237 | 238 | if (len % 8) { 239 | printf("Length of plain text should be multiple of 8 bytes. \n"); 240 | return 0; 241 | } 242 | 243 | buffer.assign((std::istreambuf_iterator(fin)), 244 | std::istreambuf_iterator()); 245 | 246 | fin.close(); 247 | 248 | unsigned char key[8] = { 0 }; 249 | unsigned char IV[8] = { 0 }; 250 | 251 | if (argc == 3) { 252 | fin.open(argv[2]); 253 | fin.seekg(0, std::ios::beg); 254 | char buffer[3] = { 0 }; 255 | for (size_t i = 0; i < 8; ++i) { 256 | fin.read(buffer, 2); 257 | key[i] = std::stoi(buffer, 0, 16); 258 | } 259 | fin.close(); 260 | } 261 | 262 | 263 | std::vector cipher(buffer.length(), 0); 264 | des_cbc(buffer.data(), buffer.length(), key, IV, &cipher[0]); 265 | 266 | for (size_t i = 0; i < buffer.length(); ++i) 267 | printf("%02x", int(cipher[i]) & 0xff); 268 | printf("\n"); 269 | 270 | } 271 | 272 | -------------------------------------------------------------------------------- /src/des_ctr.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: des_ctr.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 15, 2015 12 | * Time: 22:05:10 13 | * Description: DES, Counter Mode(CFB) 14 | *****************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | inline void setbit(void* ptr, size_t i, bool val) { 24 | if (val) 25 | ((uint8_t*)ptr)[i / 8] |= '\x01' << (7 - i % 8); 26 | else 27 | ((uint8_t*)ptr)[i / 8] &= ~('\x01' << (7 - i % 8)); 28 | } 29 | 30 | inline bool getbit(const void* ptr, size_t i) { 31 | return (((uint8_t*)ptr)[i / 8] & ('\x01' << (7 - i % 8)))? 1: 0; 32 | } 33 | 34 | 35 | // key is 64 bits 36 | std::array, 16> generateSubkeys(const uint8_t key[]) { 37 | constexpr size_t pc1[56] = { 57, 49, 41, 33, 25, 17, 9, 38 | 1, 58, 50, 42, 34, 26, 18, 39 | 10, 2, 59, 51, 43, 35, 27, 40 | 19, 11, 3, 60, 52, 44, 36, 41 | 63, 55, 47, 39, 31, 23, 15, 42 | 7, 62, 54, 46, 38, 30, 22, 43 | 14, 6, 61, 53, 45, 37, 29, 44 | 21, 13, 5, 28, 20, 12, 4 }; 45 | constexpr size_t pc2[48] = { 14, 17, 11, 24, 1, 5, 3, 28, 46 | 15, 6, 21, 10, 23, 19, 12, 4, 47 | 26, 8, 16, 7, 27, 20, 13, 2, 48 | 41, 52, 31, 37, 47, 55, 30, 40, 49 | 51, 45, 33, 48, 44, 49, 39, 56, 50 | 34, 53, 46, 42, 50, 36, 29, 32 }; 51 | // left shift both half-keys 1 bit 52 | auto key_shift = [](uint8_t key[])->void { 53 | bool a = getbit(key, 0); 54 | bool b = getbit(key, 28); 55 | for (size_t i = 0; i < 55; ++i) 56 | setbit(key, i, getbit(key, i + 1)); 57 | setbit(key, 27, a); 58 | setbit(key, 55, b); 59 | }; 60 | 61 | uint8_t key_p[7] = { 0 }; 62 | 63 | for (size_t i = 0; i < 56; ++i) 64 | setbit(key_p, i, getbit(key, pc1[i] - 1)); 65 | 66 | std::array, 16> subkeys; 67 | 68 | 69 | for (size_t i = 0; i < 16; ++i) { 70 | key_shift(key_p); 71 | if (i != 0 && i != 1 && i != 8 && i != 15) key_shift(key_p); 72 | for (size_t j = 0; j < 48; ++j) 73 | setbit(&subkeys[i][0], j, getbit(key_p, pc2[j] - 1)); 74 | } 75 | 76 | 77 | return subkeys; 78 | } 79 | 80 | inline uint32_t f_function(const uint32_t rn_1, const std::array& key_n) { 81 | constexpr size_t E[] = { 32, 1, 2, 3, 4, 5, 82 | 4, 5, 6, 7, 8, 9, 83 | 8, 9, 10, 11, 12, 13, 84 | 12, 13, 14, 15, 16, 17, 85 | 16, 17, 18, 19, 20, 21, 86 | 20, 21, 22, 23, 24, 25, 87 | 24, 25, 26, 27, 28, 29, 88 | 28, 29, 30, 31, 32, 1 }; 89 | constexpr size_t S[8][64] = { 90 | { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 91 | 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 92 | 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 93 | 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 }, 94 | { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 95 | 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 96 | 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 97 | 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 }, 98 | { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 99 | 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 100 | 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 101 | 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 }, 102 | { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 103 | 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 104 | 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 105 | 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 }, 106 | { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 107 | 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 108 | 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 109 | 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 }, 110 | { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 111 | 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 112 | 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 113 | 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 }, 114 | { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 115 | 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 116 | 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 117 | 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}, 118 | { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 119 | 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 120 | 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 121 | 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 } 122 | }; 123 | 124 | uint8_t e[6]; 125 | for (size_t i = 0; i < 48; ++i) 126 | setbit(e, i, getbit(&rn_1, E[i] - 1)); 127 | 128 | for (size_t i = 0; i < 6; ++i) 129 | e[i] ^= key_n[i]; 130 | 131 | uint32_t val = 0; 132 | 133 | for (size_t i = 0; i < 8; ++i) { 134 | uint8_t Sbox_value = S[i][(getbit(e, 6 * i + 0)) << 5 | 135 | (getbit(e, 6 * i + 5)) << 4 | 136 | (getbit(e, 6 * i + 1)) << 3 | 137 | (getbit(e, 6 * i + 2)) << 2 | 138 | (getbit(e, 6 * i + 3)) << 1 | 139 | (getbit(e, 6 * i + 4)) << 0 140 | ]; 141 | setbit(&val, i * 4 + 0, getbit(&Sbox_value, 4)); 142 | setbit(&val, i * 4 + 1, getbit(&Sbox_value, 5)); 143 | setbit(&val, i * 4 + 2, getbit(&Sbox_value, 6)); 144 | setbit(&val, i * 4 + 3, getbit(&Sbox_value, 7)); 145 | } 146 | 147 | constexpr size_t P[32] = { 16, 7, 20, 21, 29, 12, 28, 17, 148 | 1, 15, 23, 26, 5, 18, 31, 10, 149 | 2, 8, 24, 14, 32, 27, 3, 9, 150 | 19, 13, 30, 6, 22, 11, 4, 25 }; 151 | uint32_t p_val; 152 | for (size_t i = 0; i < 32; ++i) 153 | setbit(&p_val, i, getbit(&val, P[i] - 1)); 154 | 155 | return p_val; 156 | } 157 | 158 | // plain is 64 bits, cipher is 64 bits 159 | void des_ctr_iteration(const uint8_t* plain, const std::array, 16>& key, uint8_t* cipher) { 160 | constexpr size_t IP[64] = { 58, 50, 42, 34, 26, 18, 10, 2, 161 | 60, 52, 44, 36, 28, 20, 12, 4, 162 | 62, 54, 46, 38, 30, 22, 14, 6, 163 | 64, 56, 48, 40, 32, 24, 16, 8, 164 | 57, 49, 41, 33, 25, 17, 9, 1, 165 | 59, 51, 43, 35, 27, 19, 11, 3, 166 | 61, 53, 45, 37, 29, 21, 13, 5, 167 | 63, 55, 47, 39, 31, 23, 15, 7 }; 168 | // plain text after ip 169 | uint8_t ip[8]; 170 | for (size_t i = 0; i < 64; ++i) 171 | setbit(ip, i, getbit(plain, IP[i] - 1)); 172 | 173 | uint32_t ln, rn, ln_1, rn_1; 174 | ln_1 = ip[0] << 0 | ip[1] << 8 | ip[2] << 16 | ip[3] << 24; 175 | rn_1 = ip[4] << 0 | ip[5] << 8 | ip[6] << 16 | ip[7] << 24; 176 | 177 | for (size_t i = 0; i < 16; ++i) { 178 | ln = rn_1; 179 | rn = ln_1 ^ f_function(rn_1, key[i]); 180 | 181 | ln_1 = ln; 182 | rn_1 = rn; 183 | } 184 | 185 | constexpr size_t IP_i[64] = { 40, 8, 48, 16, 56, 24, 64, 32, 186 | 39, 7, 47, 15, 55, 23, 63, 31, 187 | 38, 6, 46, 14, 54, 22, 62, 30, 188 | 37, 5, 45, 13, 53, 21, 61, 29, 189 | 36, 4, 44, 12, 52, 20, 60, 28, 190 | 35, 3, 43, 11, 51, 19, 59, 27, 191 | 34, 2, 42, 10, 50, 18, 58, 26, 192 | 33, 1, 41, 9, 49, 17, 57, 25 }; 193 | uint64_t rnln = uint64_t(ln) << 32 | rn; 194 | uint64_t ip_i_rnln; 195 | for (size_t i = 0; i < 64; ++i) 196 | setbit(&ip_i_rnln, i, getbit(&rnln, IP_i[i] - 1)); 197 | 198 | cipher[0] = ip_i_rnln >> 0; 199 | cipher[1] = ip_i_rnln >> 8; 200 | cipher[2] = ip_i_rnln >> 16; 201 | cipher[3] = ip_i_rnln >> 24; 202 | cipher[4] = ip_i_rnln >> 32; 203 | cipher[5] = ip_i_rnln >> 40; 204 | cipher[6] = ip_i_rnln >> 48; 205 | cipher[7] = ip_i_rnln >> 56; 206 | } 207 | 208 | 209 | void des_ctr(const void* plain, const size_t length, const void* key, const void* IV, void* cipher) { 210 | uint8_t* plain_ = (uint8_t*)plain; 211 | const uint8_t* key_ = (const uint8_t*)key; 212 | uint8_t* cipher_ = (uint8_t*)cipher; 213 | 214 | uint8_t buffer[8]; 215 | 216 | uint8_t counter[8] = { 0 }; 217 | uint64_t* ctr = (uint64_t*)counter; 218 | 219 | auto subkeys = generateSubkeys(key_); 220 | 221 | for (size_t i = 0; i < length; ++i) { 222 | // any lossless operation is ok 223 | // we use XOR here 224 | memcpy(buffer, IV, 8); 225 | for (size_t j = 0; j < 8; ++j) 226 | buffer[j] ^= counter[7 - j]; 227 | 228 | des_ctr_iteration(buffer, subkeys, cipher_ + i); 229 | 230 | ++(*ctr); 231 | 232 | cipher_[i] ^= plain_[i]; 233 | } 234 | 235 | } 236 | 237 | int main(int argc, char** argv) { 238 | if (argc == 1) return 0; 239 | 240 | std::ifstream fin(argv[1]); 241 | 242 | fin.seekg(0, std::ios::end); 243 | std::string buffer; 244 | buffer.reserve(fin.tellg()); 245 | fin.seekg(0, std::ios::beg); 246 | 247 | 248 | buffer.assign((std::istreambuf_iterator(fin)), 249 | std::istreambuf_iterator()); 250 | 251 | fin.close(); 252 | 253 | unsigned char key[8] = { 0 }; 254 | unsigned char IV[8] = { 0 }; 255 | 256 | if (argc == 3) { 257 | fin.open(argv[2]); 258 | fin.seekg(0, std::ios::beg); 259 | char buffer[3] = { 0 }; 260 | for (size_t i = 0; i < 8; ++i) { 261 | fin.read(buffer, 2); 262 | key[i] = std::stoi(buffer, 0, 16); 263 | } 264 | fin.close(); 265 | } 266 | 267 | 268 | std::vector cipher(buffer.length() + 8, 0); 269 | des_ctr(buffer.data(), buffer.length(), key, IV, &cipher[0]); 270 | 271 | for (size_t i = 0; i < buffer.length(); ++i) 272 | printf("%02x", int(cipher[i]) & 0xff); 273 | printf("\n"); 274 | 275 | } 276 | 277 | -------------------------------------------------------------------------------- /src/aes_gcm.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2015 Jamis Hoo 3 | * Distributed under the MIT license 4 | * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) 5 | * 6 | * Project: 7 | * Filename: aes_gcm.cc 8 | * Version: 1.0 9 | * Author: Jamis Hoo 10 | * E-mail: hoojamis@gmail.com 11 | * Date: May 17, 2015 12 | * Time: 16:25:47 13 | * Description: AES (128 bit) GCM 14 | * block size 16 bytes, PKCS7 padding 15 | * IV: 12 bytes (explicitly given) concatenate with counter (4 bytes) 16 | * range of counter is [1, UINT_MAX] 17 | *****************************************************************************/ 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | inline uint8_t gmult(uint8_t a, uint8_t b) { 26 | uint8_t p = 0, hbs = 0; 27 | 28 | for (size_t i = 0; i < 8; i++) { 29 | if (b & 1) 30 | p ^= a; 31 | 32 | hbs = a & 0x80; 33 | a <<= 1; 34 | if (hbs) a ^= 0x1b; // 0000 0001 0001 1011 35 | b >>= 1; 36 | } 37 | 38 | return (uint8_t)p; 39 | } 40 | 41 | constexpr uint8_t SubBytes[256] = { 42 | 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 43 | 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 44 | 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 45 | 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 46 | 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 47 | 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 48 | 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 49 | 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 50 | 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 51 | 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 52 | 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 53 | 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 54 | 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 55 | 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 56 | 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 57 | 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 58 | }; 59 | 60 | // key: initial key: 16 bytes 61 | // keys : 44 * 4 bytes 62 | void keyExpansion(const uint8_t key[], uint8_t keys[]) { 63 | constexpr uint8_t RCON[10][4] = { 64 | { 0x01, 0x00, 0x00, 0x00 }, 65 | { 0x02, 0x00, 0x00, 0x00 }, 66 | { 0x04, 0x00, 0x00, 0x00 }, 67 | { 0x08, 0x00, 0x00, 0x00 }, 68 | { 0x10, 0x00, 0x00, 0x00 }, 69 | { 0x20, 0x00, 0x00, 0x00 }, 70 | { 0x40, 0x00, 0x00, 0x00 }, 71 | { 0x80, 0x00, 0x00, 0x00 }, 72 | { 0x1b, 0x00, 0x00, 0x00 }, 73 | { 0x36, 0x00, 0x00, 0x00 } 74 | }; 75 | 76 | 77 | memcpy(keys, key, 4 * 4); 78 | 79 | for (size_t i = 4; i < 44; ++i) { 80 | uint8_t tmp[4] = { keys[4 * (i - 1) + 0], keys[4 * (i - 1) + 1], 81 | keys[4 * (i - 1) + 2], keys[4 * (i - 1) + 3] }; 82 | if (i % 4 == 0) { 83 | // rotate left one byte 84 | uint8_t temp = tmp[0]; 85 | tmp[0] = tmp[1], tmp[1] = tmp[2], tmp[2] = tmp[3], tmp[3] = temp; 86 | // SubBytes 87 | tmp[0] = SubBytes[tmp[0]]; 88 | tmp[1] = SubBytes[tmp[1]]; 89 | tmp[2] = SubBytes[tmp[2]]; 90 | tmp[3] = SubBytes[tmp[3]]; 91 | // XOR round constants 92 | tmp[0] ^= RCON[i / 4 - 1][0], tmp[1] ^= RCON[i / 4 - 1][1], 93 | tmp[2] ^= RCON[i / 4 - 1][2], tmp[3] ^= RCON[i / 4 - 1][3]; 94 | } 95 | keys[4 * i + 0] = tmp[0], keys[4 * i + 1] = tmp[1], 96 | keys[4 * i + 2] = tmp[2], keys[4 * i + 3] = tmp[3]; 97 | keys[4 * i + 0] ^= keys[4 * (i - 4) + 0], 98 | keys[4 * i + 1] ^= keys[4 * (i - 4) + 1], 99 | keys[4 * i + 2] ^= keys[4 * (i - 4) + 2], 100 | keys[4 * i + 3] ^= keys[4 * (i - 4) + 3]; 101 | } 102 | } 103 | 104 | 105 | inline void subBytes(uint8_t state[]) { 106 | for (size_t i = 0; i < 16; ++i) 107 | state[i] = SubBytes[state[i]]; 108 | } 109 | 110 | inline void shiftRows(uint8_t state[]) { 111 | uint8_t tmp = state[1]; 112 | state[1] = state[5]; 113 | state[5] = state[9]; 114 | state[9] = state[13]; 115 | state[13] = tmp; 116 | 117 | tmp = state[2]; 118 | state[2] = state[10]; 119 | state[10] = tmp; 120 | tmp = state[6]; 121 | state[6] = state[14]; 122 | state[14] = tmp; 123 | 124 | tmp = state[3]; 125 | state[3] = state[15]; 126 | state[15] = state[11]; 127 | state[11] = state[7]; 128 | state[7] = tmp; 129 | } 130 | 131 | inline void mixColumns(uint8_t state[]) { 132 | uint8_t tmp[4]; 133 | for (size_t i = 0; i < 4; ++i) { 134 | tmp[0] = gmult(2, state[4 * i + 0]) ^ 135 | gmult(3, state[4 * i + 1]) ^ 136 | gmult(1, state[4 * i + 2]) ^ 137 | gmult(1, state[4 * i + 3]); 138 | tmp[1] = gmult(1, state[4 * i + 0]) ^ 139 | gmult(2, state[4 * i + 1]) ^ 140 | gmult(3, state[4 * i + 2]) ^ 141 | gmult(1, state[4 * i + 3]); 142 | tmp[2] = gmult(1, state[4 * i + 0]) ^ 143 | gmult(1, state[4 * i + 1]) ^ 144 | gmult(2, state[4 * i + 2]) ^ 145 | gmult(3, state[4 * i + 3]); 146 | tmp[3] = gmult(3, state[4 * i + 0]) ^ 147 | gmult(1, state[4 * i + 1]) ^ 148 | gmult(1, state[4 * i + 2]) ^ 149 | gmult(2, state[4 * i + 3]); 150 | state[4 * i + 0] = tmp[0], state[4 * i + 1] = tmp[1], 151 | state[4 * i + 2] = tmp[2], state[4 * i + 3] = tmp[3]; 152 | } 153 | } 154 | 155 | inline void addRoundKey(uint8_t state[], const uint8_t word[]) { 156 | for (size_t i = 0; i < 16; ++i) 157 | state[i] ^= word[i]; 158 | } 159 | 160 | // in: 16 bytes 161 | // out: 16 bytes 162 | // key: 44 * 4 bytes 163 | void aesIteration(const uint8_t in[], uint8_t out[], const uint8_t key[]) { 164 | uint8_t* state = out; 165 | memcpy(state, in, 16); 166 | 167 | // add round key 168 | addRoundKey(state, key); 169 | 170 | for (size_t round = 0; round < 9; ++round) { 171 | subBytes(state); 172 | shiftRows(state); 173 | mixColumns(state); 174 | addRoundKey(state, key + 16 * round + 16); 175 | } 176 | subBytes(state); 177 | shiftRows(state); 178 | addRoundKey(state, key + 16 * 10); 179 | } 180 | 181 | // X: 16 bytes 182 | // Y: 16 bytes 183 | // out: 16 bytes 184 | void galois_multiply(const uint8_t X[], const uint8_t Y[], uint8_t out[]) { 185 | uint8_t V[16]; 186 | memcpy(V, Y, 16); 187 | uint8_t Z[16] = { 0 }; 188 | 189 | for (size_t i = 0; i < 16; ++i) { 190 | for (size_t j = 0; j < 8; ++j) { 191 | if (X[i] & 1 << (7 - j)) 192 | for (size_t k = 0; k < 16; ++k) Z[k] ^= V[k]; 193 | 194 | if (V[15] & 1) { 195 | for (size_t k = 0; k < 16; ++k) { 196 | if (k && V[15 - k] & 1) 197 | V[16 - k] |= 0x80; 198 | V[15 - k] >>= 1; 199 | } 200 | 201 | V[0] ^= 0xe1; 202 | } else { 203 | for (size_t k = 0; k < 16; ++k) { 204 | if (k && V[15 - k] & 1) 205 | V[16 - k] |= 0x80; 206 | V[15 - k] >>= 1; 207 | } 208 | } 209 | } 210 | } 211 | 212 | memcpy(out, Z, 16); 213 | } 214 | 215 | // in: len bytes 216 | // hash_key: 16 bytes 217 | // out: ??? bytes 218 | void gHash(const uint8_t in[], const size_t len, const uint8_t hash_key[], uint8_t out[]) { 219 | memset(out, 0x00, 16); 220 | for (size_t i = 0; i < len / 16; ++i) { 221 | uint8_t tmp[16]; 222 | for (size_t j = 0; j < 16; ++j) 223 | tmp[j] = out[j] ^ in[i * 16 + j]; 224 | galois_multiply(tmp, hash_key, out); 225 | } 226 | } 227 | 228 | // plain: plain_len bytes 229 | // key: 16 bytes 230 | // IV: 12 bytes 231 | // add: add_len bytes 232 | // tag: 16 bytes 233 | void aes_gcm(const void* plain, const size_t plain_len, 234 | const void* key, const void* IV, 235 | const void* add, const size_t add_len, 236 | void* cipher, void* tag) { 237 | const uint8_t* plain_text = (const uint8_t*)(plain); 238 | const uint8_t* key_ = (const uint8_t*)(key); 239 | const uint8_t* IV_ = (const uint8_t*)(IV); 240 | uint8_t* cipher_text = (uint8_t*)(cipher); 241 | uint8_t* tag_ = (uint8_t*)(tag); 242 | 243 | uint8_t keys[44 * 4]; 244 | keyExpansion((uint8_t*)(key), keys); 245 | 246 | uint8_t counter[16] = { IV_[ 0], IV_[ 1], IV_[ 2], IV_[ 3], 247 | IV_[ 4], IV_[ 5], IV_[ 6], IV_[ 7], 248 | IV_[ 8], IV_[ 9], IV_[10], IV_[11], 249 | 0, 0, 0, 1 }; 250 | // counter mode AES 251 | { 252 | uint8_t CB[16]; 253 | uint8_t encrypt_CB[16]; 254 | // why initialize to 1? 255 | uint32_t ctr = 1; 256 | memcpy(CB, counter, 16); 257 | 258 | for (size_t i = 0; i < plain_len / 16; ++i) { 259 | ++ctr; 260 | if (ctr == 0) ctr = 1; 261 | CB[12] = ctr >> 24; 262 | CB[13] = ctr >> 16; 263 | CB[14] = ctr >> 8; 264 | CB[15] = ctr; 265 | 266 | aesIteration(CB, encrypt_CB, keys); 267 | 268 | for (size_t j = 0; j < 16; ++j) 269 | cipher_text[i * 16 + j] = encrypt_CB[j] ^ plain_text[i * 16 + j]; 270 | } 271 | } 272 | 273 | uint8_t* add_cipher = new uint8_t[add_len + plain_len + 16]; 274 | memcpy(add_cipher, add, add_len); 275 | memcpy(add_cipher + add_len, cipher_text, plain_len); 276 | uint64_t len_in_bit = add_len * 8; 277 | add_cipher[add_len + plain_len + 0] = len_in_bit >> 56; 278 | add_cipher[add_len + plain_len + 1] = len_in_bit >> 48; 279 | add_cipher[add_len + plain_len + 2] = len_in_bit >> 40; 280 | add_cipher[add_len + plain_len + 3] = len_in_bit >> 32; 281 | add_cipher[add_len + plain_len + 4] = len_in_bit >> 24; 282 | add_cipher[add_len + plain_len + 5] = len_in_bit >> 16; 283 | add_cipher[add_len + plain_len + 6] = len_in_bit >> 8; 284 | add_cipher[add_len + plain_len + 7] = len_in_bit >> 0; 285 | len_in_bit = plain_len * 8; 286 | add_cipher[add_len + plain_len + 8] = len_in_bit >> 56; 287 | add_cipher[add_len + plain_len + 9] = len_in_bit >> 48; 288 | add_cipher[add_len + plain_len + 10] = len_in_bit >> 40; 289 | add_cipher[add_len + plain_len + 11] = len_in_bit >> 32; 290 | add_cipher[add_len + plain_len + 12] = len_in_bit >> 24; 291 | add_cipher[add_len + plain_len + 13] = len_in_bit >> 16; 292 | add_cipher[add_len + plain_len + 14] = len_in_bit >> 8; 293 | add_cipher[add_len + plain_len + 15] = len_in_bit >> 0; 294 | 295 | 296 | uint8_t zero_data[16] = { 0 }; 297 | uint8_t zero_data_cipher[16]; 298 | aesIteration(zero_data, zero_data_cipher, keys); 299 | 300 | uint8_t Y[16]; 301 | gHash(add_cipher, add_len + plain_len + 16, zero_data_cipher, Y); 302 | 303 | uint8_t en_counter[16]; 304 | aesIteration(counter, en_counter, keys); 305 | 306 | for (size_t i = 0; i < 16; ++i) 307 | tag_[i] = en_counter[i] ^ Y[i]; 308 | } 309 | 310 | 311 | int main(int argc, char** argv) { 312 | { 313 | /* 314 | const unsigned char key[16]={0x98,0xff,0xf6,0x7e,0x64,0xe4,0x6b,0xe5,0xee,0x2e,0x05,0xcc,0x9a,0xf6,0xd0,0x12}; 315 | const unsigned char IV[12] ={0x2d,0xfb,0x42,0x9a,0x48,0x69,0x7c,0x34,0x00,0x6d,0xa8,0x86}; 316 | 317 | const unsigned char plaintext[3*16]={0x29,0xb9,0x1b,0x4a,0x68,0xa9,0x9f,0x97,0xc4,0x1c,0x75,0x08,0xf1,0x7a,0x5c,0x7a, 318 | 0x7a,0xfc,0x9e,0x1a,0xca,0x83,0xe1,0x29,0xb0,0x85,0xbd,0x63,0x7f,0xf6,0x7c,0x01, 319 | 0x29,0xb9,0x1b,0x4a,0x68,0xa9,0x9f,0x97,0xc4,0x1c,0x75,0x08,0xf1,0x7a,0x5c,0x7a}; 320 | 321 | const unsigned char add_data[3*16]={0xa0,0xca,0x58,0x61,0xc0,0x22,0x6c,0x5b,0x5a,0x65,0x14,0xc8,0x2b,0x77,0x81,0x5a, 322 | 0x9e,0x0e,0xb3,0x59,0xd0,0xd4,0x6d,0x03,0x33,0xc3,0xf2,0xba,0xe1,0x4d,0xa0,0xc4, 323 | 0x03,0x30,0xc0,0x02,0x16,0xb4,0xaa,0x64,0xb7,0xc1,0xed,0xb8,0x71,0xc3,0x28,0xf6}; 324 | unsigned char ciphertext[4096]; 325 | unsigned char tag[4096]; 326 | 327 | aes_gcm(plaintext, 48, key, IV, add_data, 48, ciphertext, tag); 328 | 329 | for (size_t i = 0; i < 16; ++i) printf("%02x ", tag[i]); printf("\n"); 330 | 331 | //tag 332 | //{0x9e,0x27,0xe2,0x10,0xd6,0xe1,0xef,0x0f,0x18,0xde,0x98,0xf4,0xc3,0xd0,0xf9,0x68}, 333 | */ 334 | } 335 | if (argc == 1) return 0; 336 | 337 | std::ifstream fin(argv[1]); 338 | 339 | fin.seekg(0, std::ios::end); 340 | std::string buffer; 341 | size_t len = fin.tellg(); 342 | fin.seekg(0, std::ios::beg); 343 | 344 | uint8_t pad = 0; 345 | if (len % 16) { 346 | pad = 16 - len % 16; 347 | len = len / 16 * 16 + 16; 348 | } 349 | 350 | buffer.reserve(len); 351 | 352 | buffer.assign((std::istreambuf_iterator(fin)), 353 | std::istreambuf_iterator()); 354 | // PKCS7 padding 355 | for (size_t i = 0; i < pad; ++i) 356 | buffer += pad; 357 | 358 | assert(buffer.length() == len); 359 | 360 | fin.close(); 361 | 362 | // 128 bit key size 363 | unsigned char key[16] = { 0 }; 364 | 365 | if (argc == 3) { 366 | fin.open(argv[2]); 367 | fin.seekg(0, std::ios::beg); 368 | char buffer[3] = { 0 }; 369 | for (size_t i = 0; i < 16; ++i) { 370 | fin.read(buffer, 2); 371 | key[i] = std::stoi(buffer, 0, 16); 372 | } 373 | fin.close(); 374 | } 375 | 376 | unsigned char IV[12] = { 0 }; 377 | unsigned char add_data[0]; 378 | unsigned char tag[16]; 379 | 380 | std::vector cipher(buffer.length(), 0); 381 | aes_gcm(buffer.data(), buffer.length(), key, IV, add_data, 0, &cipher[0], tag); 382 | 383 | for (size_t i = 0; i < buffer.length(); ++i) 384 | printf("%02x", int(cipher[i]) & 0xff); 385 | printf("\n\n"); 386 | 387 | for (size_t i = 0; i < 16; ++i) 388 | printf("%02x", tag[i]); 389 | printf("\n"); 390 | 391 | } 392 | 393 | --------------------------------------------------------------------------------