├── .gitignore ├── README.md ├── base64_lib ├── CMakeLists.txt ├── README.md ├── bulid │ └── run.sh ├── include │ └── base64.h ├── src │ ├── CMakeLists.txt │ └── base64.cpp └── test │ ├── demo │ ├── demo.cpp │ └── makefile ├── crc32_lib ├── crc32.cpp ├── demo └── makefile ├── des_lib ├── CMakeLists.txt ├── README.md ├── bulid │ └── run.sh ├── include │ └── des.h ├── src │ ├── CMakeLists.txt │ └── des.cpp └── test │ ├── demo.cpp │ └── makefile ├── documents ├── Feistel密码结构学习.md ├── 从FIPS 197中理解AES算法.md ├── 从FIPS 46-3中理解DES算法.md ├── 从RFC1321中理解MD5算法.md ├── 从RFC2040中理解RC5算法.md ├── 从RFC3174中理解SHA1算法.md ├── 从RFC4648中理解Base64算法.md ├── 从RFC6229中理解RC4算法.md ├── 从RFC6234中理解SHA2-256算法.md ├── 探讨关于Base64算法的魔改方式.md ├── 探讨关于CRC32算法的魔改方式.md ├── 探讨关于MD5算法的魔改方式.md ├── 探讨关于RC4算法的魔改方式.md ├── 探讨关于SHA1算法的魔改方式.md ├── 探讨关于SHA256算法的魔改方式.md └── 理解CRC32算法.md ├── md5_lib ├── CMakeLists.txt ├── README.md ├── bulid │ └── run.sh ├── include │ └── md5.h ├── rfc1321.txt ├── src │ ├── CMakeLists.txt │ └── md5.cpp └── test │ ├── demo │ ├── demo.cpp │ └── makefile ├── rc5_lib ├── CMakeLists.txt ├── README.md ├── bulid │ └── run.sh ├── include │ └── rc5.h ├── rfc1321.txt ├── src │ ├── CMakeLists.txt │ └── rc5.cpp └── test │ ├── demo │ ├── demo.cpp │ └── makefile ├── sha1_lib ├── CMakeLists.txt ├── README.md ├── bulid │ └── run.sh ├── include │ └── sha1.h ├── rfc3174.txt ├── src │ ├── CMakeLists.txt │ └── sha1.cpp └── test │ ├── demo │ ├── demo.cpp │ └── makefile └── sha256_lib ├── CMakeLists.txt ├── README.md ├── bulid └── run.sh ├── include └── sha256.h ├── rfc6234.txt ├── src ├── CMakeLists.txt └── sha256.cpp └── test ├── demo ├── demo.cpp └── makefile /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.swp 3 | *~ 4 | *.a 5 | *.so 6 | *.exe 7 | build/ 8 | test/demo 9 | .vscode -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dirty_algorithm 2 | >该项目的主旨是对移动安全领域常见算法的学习以及魔改方式、逆向分析方式的探究 3 | 4 | - 一、算法学习 5 | - 编码格式 6 | - [从RFC4648中理解Base64算法](https://github.com/tcc0lin/dirty_algorithm/blob/main/documents/%E4%BB%8ERFC4648%E4%B8%AD%E7%90%86%E8%A7%A3Base64%E7%AE%97%E6%B3%95.md) 7 | - c++实现参考base64_lib 8 | 9 | - 校验码 10 | - [理解CRC32算法](https://github.com/tcc0lin/dirty_algorithm/blob/main/documents/%E7%90%86%E8%A7%A3CRC32%E7%AE%97%E6%B3%95.md) 11 | - c++实现参考crc32_lib 12 | 13 | - 哈希加密 14 | - [从RFC1321中理解MD5算法](https://github.com/tcc0lin/dirty_algorithm/blob/main/documents/%E4%BB%8ERFC1321%E4%B8%AD%E7%90%86%E8%A7%A3MD5%E7%AE%97%E6%B3%95.md) 15 | - c++实现参考md5_lib 16 | 17 | - [从RFC3174中理解SHA1算法](https://github.com/tcc0lin/dirty_algorithm/blob/main/documents/%E4%BB%8ERFC3174%E4%B8%AD%E7%90%86%E8%A7%A3SHA1%E7%AE%97%E6%B3%95.md) 18 | - c++实现参考sha1_lib 19 | 20 | - [从RFC6234中理解SHA2-256算法](https://github.com/tcc0lin/dirty_algorithm/blob/main/documents/%E4%BB%8ERFC6234%E4%B8%AD%E7%90%86%E8%A7%A3SHA2-256%E7%AE%97%E6%B3%95.md) 21 | - c++实现参考sha256_lib 22 | - 对称加密 23 | - 分组加密 24 | - [从FIPS 46-3中理解DES算法](https://github.com/tcc0lin/dirty_algorithm/blob/main/documents/%E4%BB%8EFIPS%2046-3%E4%B8%AD%E7%90%86%E8%A7%A3DES%E7%AE%97%E6%B3%95.md) 25 | - c++实现参考des_lib 26 | 27 | - [从RFC2040中理解RC5算法](https://github.com/tcc0lin/dirty_algorithm/blob/main/documents/%E4%BB%8ERFC2040%E4%B8%AD%E7%90%86%E8%A7%A3RC5%E7%AE%97%E6%B3%95.md) 28 | - c++实现参考rc5_lib 29 | - 流加密 30 | - [从RFC6229中理解RC4算法](https://github.com/tcc0lin/dirty_algorithm/blob/main/documents/%E4%BB%8ERFC6229%E4%B8%AD%E7%90%86%E8%A7%A3RC4%E7%AE%97%E6%B3%95.md) 31 | - c++实现参考rc4_lib 32 | 33 | - 二、魔改思路 34 | - [探讨关于Base64算法的魔改方式](https://github.com/tcc0lin/dirty_algorithm/blob/main/documents/%E6%8E%A2%E8%AE%A8%E5%85%B3%E4%BA%8EBase64%E7%AE%97%E6%B3%95%E7%9A%84%E9%AD%94%E6%94%B9%E6%96%B9%E5%BC%8F.md) 35 | - [探讨关于MD5算法的魔改方式](https://github.com/tcc0lin/dirty_algorithm/blob/main/documents/%E6%8E%A2%E8%AE%A8%E5%85%B3%E4%BA%8EMD5%E7%AE%97%E6%B3%95%E7%9A%84%E9%AD%94%E6%94%B9%E6%96%B9%E5%BC%8F.md) 36 | - [探讨关于SHA1算法的魔改方式](https://github.com/tcc0lin/dirty_algorithm/blob/main/documents/%E6%8E%A2%E8%AE%A8%E5%85%B3%E4%BA%8ESHA1%E7%AE%97%E6%B3%95%E7%9A%84%E9%AD%94%E6%94%B9%E6%96%B9%E5%BC%8F.md) 37 | 38 | - [探讨关于SHA256算法的魔改方式](https://github.com/tcc0lin/dirty_algorithm/blob/main/documents/%E6%8E%A2%E8%AE%A8%E5%85%B3%E4%BA%8ESHA256%E7%AE%97%E6%B3%95%E7%9A%84%E9%AD%94%E6%94%B9%E6%96%B9%E5%BC%8F.md) 39 | 40 | - [探讨关于RC4算法的魔改方式](https://github.com/tcc0lin/dirty_algorithm/blob/main/documents/%E6%8E%A2%E8%AE%A8%E5%85%B3%E4%BA%8ERC4%E7%AE%97%E6%B3%95%E7%9A%84%E9%AD%94%E6%94%B9%E6%96%B9%E5%BC%8F.md) 41 | 42 | - [探讨关于CRC32算法的魔改方式](https://github.com/tcc0lin/dirty_algorithm/blob/main/documents/%E6%8E%A2%E8%AE%A8%E5%85%B3%E4%BA%8ECRC32%E7%AE%97%E6%B3%95%E7%9A%84%E9%AD%94%E6%94%B9%E6%96%B9%E5%BC%8F.md) 43 | -------------------------------------------------------------------------------- /base64_lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | add_subdirectory(src) 4 | -------------------------------------------------------------------------------- /base64_lib/README.md: -------------------------------------------------------------------------------- 1 | 基于c++实现的base64算法库 2 | 3 | ## 使用说明 4 | 5 | 基于`cmake`编译,切换到`build`目录,执行脚本`./run.sh`即可在`lib`目录生成静态库`libbase64.a` 6 | 7 | 使用时只需要引入对应的头文件,然后就可以调用`base64`函数了。 8 | ```cpp 9 | #include "base64.h" 10 | 11 | base64_encode(string) 12 | ``` 13 | 14 | ## 测试 15 | 切换到`test`目录下,执行`make`命令生成`demo`的可执行程序 16 | 17 | ```bash 18 | > ./demo encode lin 19 | base64_encode of 'lin': bGlu 20 | > ./demo decode bGlu 21 | base64_decode of 'bGlu': lin 22 | ``` -------------------------------------------------------------------------------- /base64_lib/bulid/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -f ./run.sh ../run.sh; 4 | rm -rf *; 5 | cp -f ../run.sh ./run.sh; 6 | rm -f ../run.sh; 7 | cmake ../; 8 | make; 9 | make install; 10 | cp -f ./run.sh ../run.sh; 11 | rm -rf *; 12 | cp -f ../run.sh ./run.sh; 13 | rm -f ../run.sh; -------------------------------------------------------------------------------- /base64_lib/include/base64.h: -------------------------------------------------------------------------------- 1 | // 2 | // base64 encoding and decoding with C++. 3 | // Version: 2.rc.09 (release candidate) 4 | // 5 | 6 | #ifndef BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A 7 | #define BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A 8 | 9 | #include 10 | 11 | #if __cplusplus >= 201703L 12 | #include 13 | #endif // __cplusplus >= 201703L 14 | 15 | std::string base64_encode (std::string const& s, bool url = false); 16 | std::string base64_encode_pem (std::string const& s); 17 | std::string base64_encode_mime(std::string const& s); 18 | 19 | std::string base64_decode(std::string const& s, bool remove_linebreaks = false); 20 | std::string base64_encode(unsigned char const*, size_t len, bool url = false); 21 | 22 | #if __cplusplus >= 201703L 23 | // 24 | // Interface with std::string_view rather than const std::string& 25 | // Requires C++17 26 | // Provided by Yannic Bonenberger (https://github.com/Yannic) 27 | // 28 | std::string base64_encode (std::string_view s, bool url = false); 29 | std::string base64_encode_pem (std::string_view s); 30 | std::string base64_encode_mime(std::string_view s); 31 | 32 | std::string base64_decode(std::string_view s, bool remove_linebreaks = false); 33 | #endif // __cplusplus >= 201703L 34 | 35 | #endif /* BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A */ -------------------------------------------------------------------------------- /base64_lib/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | SET(CMAKE_CXX_FLAGS " -g -Wall -o2") 2 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 3 | SET(base64_lib_path ${PROJECT_SOURCE_DIR}/lib) 4 | SET(base64_src_path ${PROJECT_SOURCE_DIR}/src) 5 | 6 | INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include) 7 | 8 | AUX_SOURCE_DIRECTORY(${base64_src_path} X_SRC) 9 | ADD_LIBRARY(base64 STATIC ${X_SRC}) 10 | 11 | SET_TARGET_PROPERTIES(base64 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${base64_lib_path}") 12 | -------------------------------------------------------------------------------- /base64_lib/src/base64.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | base64.cpp and base64.h 3 | 4 | base64 encoding and decoding with C++. 5 | More information at 6 | https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp 7 | 8 | Version: 2.rc.09 (release candidate) 9 | 10 | Copyright (C) 2004-2017, 2020-2022 René Nyffenegger 11 | 12 | This source code is provided 'as-is', without any express or implied 13 | warranty. In no event will the author be held liable for any damages 14 | arising from the use of this software. 15 | 16 | Permission is granted to anyone to use this software for any purpose, 17 | including commercial applications, and to alter it and redistribute it 18 | freely, subject to the following restrictions: 19 | 20 | 1. The origin of this source code must not be misrepresented; you must not 21 | claim that you wrote the original source code. If you use this source code 22 | in a product, an acknowledgment in the product documentation would be 23 | appreciated but is not required. 24 | 25 | 2. Altered source versions must be plainly marked as such, and must not be 26 | misrepresented as being the original source code. 27 | 28 | 3. This notice may not be removed or altered from any source distribution. 29 | 30 | René Nyffenegger rene.nyffenegger@adp-gmbh.ch 31 | 32 | */ 33 | 34 | #include "base64.h" 35 | 36 | #include 37 | #include 38 | 39 | // 40 | // Depending on the url parameter in base64_chars, one of 41 | // two sets of base64 characters needs to be chosen. 42 | // They differ in their last two characters. 43 | // 44 | static const char* base64_chars[2] = { 45 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 46 | "abcdefghijklmnopqrstuvwxyz" 47 | "0123456789" 48 | "+/", 49 | 50 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 51 | "abcdefghijklmnopqrstuvwxyz" 52 | "0123456789" 53 | "-_"}; 54 | 55 | static unsigned int pos_of_char(const unsigned char chr) { 56 | // 57 | // Return the position of chr within base64_encode() 58 | // 59 | 60 | if (chr >= 'A' && chr <= 'Z') return chr - 'A'; 61 | else if (chr >= 'a' && chr <= 'z') return chr - 'a' + ('Z' - 'A') + 1; 62 | else if (chr >= '0' && chr <= '9') return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2; 63 | else if (chr == '+' || chr == '-') return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters ( 64 | else if (chr == '/' || chr == '_') return 63; // Ditto for '/' and '_' 65 | else 66 | // 67 | // 2020-10-23: Throw std::exception rather than const char* 68 | //(Pablo Martin-Gomez, https://github.com/Bouska) 69 | // 70 | throw std::runtime_error("Input is not valid base64-encoded data."); 71 | } 72 | 73 | static std::string insert_linebreaks(std::string str, size_t distance) { 74 | // 75 | // Provided by https://github.com/JomaCorpFX, adapted by me. 76 | // 77 | if (!str.length()) { 78 | return ""; 79 | } 80 | 81 | size_t pos = distance; 82 | 83 | while (pos < str.size()) { 84 | str.insert(pos, "\n"); 85 | pos += distance + 1; 86 | } 87 | 88 | return str; 89 | } 90 | 91 | template 92 | static std::string encode_with_line_breaks(String s) { 93 | return insert_linebreaks(base64_encode(s, false), line_length); 94 | } 95 | 96 | template 97 | static std::string encode_pem(String s) { 98 | return encode_with_line_breaks(s); 99 | } 100 | 101 | template 102 | static std::string encode_mime(String s) { 103 | return encode_with_line_breaks(s); 104 | } 105 | 106 | template 107 | static std::string encode(String s, bool url) { 108 | return base64_encode(reinterpret_cast(s.data()), s.length(), url); 109 | } 110 | 111 | std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len, bool url) { 112 | 113 | size_t len_encoded = (in_len +2) / 3 * 4; 114 | 115 | unsigned char trailing_char = url ? '.' : '='; 116 | 117 | // 118 | // Choose set of base64 characters. They differ 119 | // for the last two positions, depending on the url 120 | // parameter. 121 | // A bool (as is the parameter url) is guaranteed 122 | // to evaluate to either 0 or 1 in C++ therefore, 123 | // the correct character set is chosen by subscripting 124 | // base64_chars with url. 125 | // 126 | const char* base64_chars_ = base64_chars[url]; 127 | 128 | std::string ret; 129 | ret.reserve(len_encoded); 130 | 131 | unsigned int pos = 0; 132 | 133 | while (pos < in_len) { 134 | //第一个字符处理 135 | ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]); 136 | if (pos+1 < in_len) { 137 | //第二个字符处理 138 | ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]); 139 | if (pos+2 < in_len) { 140 | //第三、四个字符处理 141 | ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]); 142 | ret.push_back(base64_chars_[ bytes_to_encode[pos + 2] & 0x3f]); 143 | } 144 | else { 145 | //剩余字符为2的处理 146 | ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]); 147 | ret.push_back(trailing_char); 148 | } 149 | } 150 | else { 151 | //剩余字符为1的处理 152 | ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]); 153 | ret.push_back(trailing_char); 154 | ret.push_back(trailing_char); 155 | } 156 | //每三个字符为一组 157 | pos += 3; 158 | } 159 | 160 | 161 | return ret; 162 | } 163 | 164 | template 165 | static std::string decode(String const& encoded_string, bool remove_linebreaks) { 166 | // 167 | // decode(…) is templated so that it can be used with String = const std::string& 168 | // or std::string_view (requires at least C++17) 169 | // 170 | 171 | if (encoded_string.empty()) return std::string(); 172 | 173 | if (remove_linebreaks) { 174 | 175 | std::string copy(encoded_string); 176 | 177 | copy.erase(std::remove(copy.begin(), copy.end(), '\n'), copy.end()); 178 | 179 | return base64_decode(copy, false); 180 | } 181 | 182 | size_t length_of_string = encoded_string.length(); 183 | size_t pos = 0; 184 | 185 | // 186 | // The approximate length (bytes) of the decoded string might be one or 187 | // two bytes smaller, depending on the amount of trailing equal signs 188 | // in the encoded string. This approximation is needed to reserve 189 | // enough space in the string to be returned. 190 | // 191 | size_t approx_length_of_decoded_string = length_of_string / 4 * 3; 192 | std::string ret; 193 | ret.reserve(approx_length_of_decoded_string); 194 | 195 | while (pos < length_of_string) { 196 | // 197 | // Iterate over encoded input string in chunks. The size of all 198 | // chunks except the last one is 4 bytes. 199 | // 200 | // The last chunk might be padded with equal signs or dots 201 | // in order to make it 4 bytes in size as well, but this 202 | // is not required as per RFC 2045. 203 | // 204 | // All chunks except the last one produce three output bytes. 205 | // 206 | // The last chunk produces at least one and up to three bytes. 207 | // 208 | 209 | size_t pos_of_char_1 = pos_of_char(encoded_string.at(pos+1) ); 210 | 211 | // 212 | // Emit the first output byte that is produced in each chunk: 213 | // 214 | ret.push_back(static_cast( ( (pos_of_char(encoded_string.at(pos+0)) ) << 2 ) + ( (pos_of_char_1 & 0x30 ) >> 4))); 215 | 216 | if ( ( pos + 2 < length_of_string ) && // Check for data that is not padded with equal signs (which is allowed by RFC 2045) 217 | encoded_string.at(pos+2) != '=' && 218 | encoded_string.at(pos+2) != '.' // accept URL-safe base 64 strings, too, so check for '.' also. 219 | ) 220 | { 221 | // 222 | // Emit a chunk's second byte (which might not be produced in the last chunk). 223 | // 224 | unsigned int pos_of_char_2 = pos_of_char(encoded_string.at(pos+2) ); 225 | ret.push_back(static_cast( (( pos_of_char_1 & 0x0f) << 4) + (( pos_of_char_2 & 0x3c) >> 2))); 226 | 227 | if ( ( pos + 3 < length_of_string ) && 228 | encoded_string.at(pos+3) != '=' && 229 | encoded_string.at(pos+3) != '.' 230 | ) 231 | { 232 | // 233 | // Emit a chunk's third byte (which might not be produced in the last chunk). 234 | // 235 | ret.push_back(static_cast( ( (pos_of_char_2 & 0x03 ) << 6 ) + pos_of_char(encoded_string.at(pos+3)) )); 236 | } 237 | } 238 | 239 | pos += 4; 240 | } 241 | 242 | return ret; 243 | } 244 | 245 | std::string base64_decode(std::string const& s, bool remove_linebreaks) { 246 | return decode(s, remove_linebreaks); 247 | } 248 | 249 | std::string base64_encode(std::string const& s, bool url) { 250 | return encode(s, url); 251 | } 252 | 253 | std::string base64_encode_pem (std::string const& s) { 254 | return encode_pem(s); 255 | } 256 | 257 | std::string base64_encode_mime(std::string const& s) { 258 | return encode_mime(s); 259 | } 260 | 261 | #if __cplusplus >= 201703L 262 | // 263 | // Interface with std::string_view rather than const std::string& 264 | // Requires C++17 265 | // Provided by Yannic Bonenberger (https://github.com/Yannic) 266 | // 267 | 268 | std::string base64_encode(std::string_view s, bool url) { 269 | return encode(s, url); 270 | } 271 | 272 | std::string base64_encode_pem(std::string_view s) { 273 | return encode_pem(s); 274 | } 275 | 276 | std::string base64_encode_mime(std::string_view s) { 277 | return encode_mime(s); 278 | } 279 | 280 | std::string base64_decode(std::string_view s, bool remove_linebreaks) { 281 | return decode(s, remove_linebreaks); 282 | } 283 | 284 | #endif // __cplusplus >= 201703L -------------------------------------------------------------------------------- /base64_lib/test/demo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcc0lin/dirty_algorithm/50c8276dcd65b5a8e23f78cf83e87df41d414358/base64_lib/test/demo -------------------------------------------------------------------------------- /base64_lib/test/demo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "base64.h" 3 | using namespace std; 4 | 5 | int main(int argc, char *argv[]) { 6 | if (argc != 3) { 7 | cout << "usage: ./demo encode/decode string" << endl; 8 | } else { 9 | if (!strcmp(argv[1],"encode")){ 10 | cout << "base64_encode of '" << argv[2] << "': " << base64_encode(argv[2]) << endl; 11 | }else{ 12 | cout << "base64_decode of '" << argv[2] << "': " << base64_decode(argv[2]) << endl; 13 | } 14 | } 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /base64_lib/test/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | g++ demo.cpp -I../include/ -L../lib ../lib/libbase64.a -o demo 3 | clean: 4 | rm demo -------------------------------------------------------------------------------- /crc32_lib/crc32.cpp: -------------------------------------------------------------------------------- 1 | // CRC32.cpp : Defines the entry point for the console application. 2 | // 3 | #include 4 | 5 | using namespace std; 6 | 7 | unsigned int uiCRC32_Table[256]; 8 | 9 | 10 | int make_crc32_table() 11 | { 12 | uint32_t c; 13 | int i = 0; 14 | int bit = 0; 15 | 16 | for(i = 0; i < 256; i++) 17 | { 18 | c = (uint32_t)i; 19 | 20 | for(bit = 0; bit < 8; bit++) 21 | { 22 | if(c&1) 23 | { 24 | c = (c >> 1)^(0xEDB88320); 25 | } 26 | else 27 | { 28 | c = c >> 1; 29 | } 30 | 31 | } 32 | uiCRC32_Table[i] = c; 33 | } 34 | } 35 | 36 | unsigned int crc32(void *pData, size_t iLen) 37 | { 38 | make_crc32_table(); 39 | unsigned int uiCRC32 = 0xFFFFFFFF; 40 | unsigned char *pszData = (unsigned char*)pData; 41 | 42 | for (size_t i = 0; i> 8) & 0x00FFFFFF) ^ uiCRC32_Table[(uiCRC32 ^ (unsigned int)*pszData++) & 0xFF]; 44 | 45 | return (uiCRC32 ^ 0xFFFFFFFF); 46 | } 47 | 48 | int main() 49 | { 50 | char* teststr = "Simple Test String!"; 51 | unsigned int Hash = crc32(teststr, strlen(teststr)); 52 | 53 | cout << "0x" << uppercase << hex << Hash; 54 | } -------------------------------------------------------------------------------- /crc32_lib/demo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcc0lin/dirty_algorithm/50c8276dcd65b5a8e23f78cf83e87df41d414358/crc32_lib/demo -------------------------------------------------------------------------------- /crc32_lib/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | g++ crc32.cpp -o demo 3 | clean: 4 | rm demo -------------------------------------------------------------------------------- /des_lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | add_subdirectory(src) 4 | -------------------------------------------------------------------------------- /des_lib/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcc0lin/dirty_algorithm/50c8276dcd65b5a8e23f78cf83e87df41d414358/des_lib/README.md -------------------------------------------------------------------------------- /des_lib/bulid/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -f ./run.sh ../run.sh; 4 | rm -rf *; 5 | cp -f ../run.sh ./run.sh; 6 | rm -f ../run.sh; 7 | cmake ../; 8 | make; 9 | make install; 10 | cp -f ./run.sh ../run.sh; 11 | rm -rf *; 12 | cp -f ../run.sh ./run.sh; 13 | rm -f ../run.sh; -------------------------------------------------------------------------------- /des_lib/include/des.h: -------------------------------------------------------------------------------- 1 | #ifndef DES_H_ 2 | #define DES_H_ 3 | #include 4 | using namespace std; 5 | 6 | class DES_Encryption{ 7 | public: 8 | void encrypt(string plain_txt, string key); 9 | }; 10 | #endif /* DES_H_ */ 11 | -------------------------------------------------------------------------------- /des_lib/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | SET(CMAKE_CXX_FLAGS " -g -Wall -o2") 2 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 3 | SET(des_lib_path ${PROJECT_SOURCE_DIR}/lib) 4 | SET(des_src_path ${PROJECT_SOURCE_DIR}/src) 5 | 6 | INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include) 7 | 8 | AUX_SOURCE_DIRECTORY(${des_src_path} X_SRC) 9 | ADD_LIBRARY(des STATIC ${X_SRC}) 10 | 11 | SET_TARGET_PROPERTIES(des PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${des_lib_path}") 12 | -------------------------------------------------------------------------------- /des_lib/src/des.cpp: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------- 2 | // Project 1 - Encryption and Decryption program 3 | // Class: 4 | // Description: 5 | // Author: Date: <10/3/2018> 6 | //-------------------------------------------------------------- 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | 15 | string Bin_to_Hex(string s); 16 | string Hex_to_Bin(string s); 17 | string Dec_to_Bin(int n); 18 | 19 | class DES_Encryption 20 | { 21 | 22 | // constants regarding the keys 23 | 24 | const int pc_1[56] = { 57 ,49 ,41 ,33 ,25 ,17 ,9 , 25 | 1 ,58 ,50 ,42 ,34 ,26 ,18 , 26 | 10 ,2 ,59 ,51 ,43 ,35 ,27 , 27 | 19 ,11 ,3 ,60 ,52 ,44 ,36 , 28 | 63 ,55 ,47 ,39 ,31 ,23 ,15 , 29 | 7 ,62 ,54 ,46 ,38 ,30 ,22 , 30 | 14 ,6 ,61 ,53 ,45 ,37 ,29 , 31 | 21 ,13 ,5 ,28 ,20 ,12 ,4 }; 32 | 33 | int num_leftShift[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; // number of bits to shift for each iteration 34 | 35 | const int pc_2[48] = { 14 ,17 ,11 ,24 ,1 ,5 , 36 | 3 ,28 ,15 ,6 ,21 ,10 , 37 | 23 ,19 ,12 ,4 ,26 ,8 , 38 | 16 ,7 ,27 ,20 ,13 ,2 , 39 | 41 ,52 ,31 ,37 ,47 ,55 , 40 | 30 ,40 ,51 ,45 ,33 ,48 , 41 | 44 ,49 ,39 ,56 ,34 ,53 , 42 | 46 ,42 ,50 ,36 ,29 ,32 }; 43 | 44 | // constants regarding the plain text 45 | 46 | const int IP_t[64] = { 58 ,50 ,42 ,34 ,26 ,18 ,10 ,2 , // intital permutation table 47 | 60 ,52 ,44 ,36 ,28 ,20 ,12 ,4 , 48 | 62 ,54 ,46 ,38 ,30 ,22 ,14 ,6 , 49 | 64 ,56 ,48 ,40 ,32 ,24 ,16 ,8 , 50 | 57 ,49 ,41 ,33 ,25 ,17 ,9 ,1 , 51 | 59 ,51 ,43 ,35 ,27 ,19 ,11 ,3 , 52 | 61 ,53 ,45 ,37 ,29 ,21 ,13 ,5 , 53 | 63 ,55 ,47 ,39 ,31 ,23 ,15 ,7 }; 54 | 55 | const int E_t[48] = { 32 ,1 ,2 ,3 ,4 ,5 , // expantion table 56 | 4 ,5 ,6 ,7 ,8 ,9 , 57 | 8 ,9 ,10 ,11 ,12 ,13 , 58 | 12 ,13 ,14 ,15 ,16 ,17 , 59 | 16 ,17 ,18 ,19 ,20 ,21 , 60 | 20 ,21 ,22 ,23 ,24 ,25 , 61 | 24 ,25 ,26 ,27 ,28 ,29 , 62 | 28 ,29 ,30 ,31 ,32 ,1 }; 63 | 64 | int S[8][4][16] = { // S-box 65 | { 66 | { 14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7 }, 67 | { 0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8 }, 68 | { 4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0 }, 69 | { 15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13 } 70 | }, 71 | { 72 | { 15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10 }, 73 | { 3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5 }, 74 | { 0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15 }, 75 | { 13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9 } 76 | }, 77 | { 78 | { 10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8 }, 79 | { 13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1 }, 80 | { 13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7 }, 81 | { 1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12 } 82 | }, 83 | { 84 | { 7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15 }, 85 | { 13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9 }, 86 | { 10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4 }, 87 | { 3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14 } 88 | }, 89 | { 90 | { 2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9 }, 91 | { 14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6 }, 92 | { 4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14 }, 93 | { 11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3 } 94 | }, 95 | { 96 | { 12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11 }, 97 | { 10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8 }, 98 | { 9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6 }, 99 | { 4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13 } 100 | }, 101 | { 102 | { 4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1 }, 103 | { 13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6 }, 104 | { 1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2 }, 105 | { 6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12 } 106 | }, 107 | { 108 | { 13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7 }, 109 | { 1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2 }, 110 | { 7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8 }, 111 | { 2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11 } 112 | } 113 | }; 114 | 115 | const int P[32] = { 16 ,7 ,20 ,21 , 116 | 29 ,12 ,28 ,17 , 117 | 1 ,15 ,23 ,26 , 118 | 5 ,18 ,31 ,10 , 119 | 2 ,8 ,24 ,14 , 120 | 32 ,27 ,3 ,9 , 121 | 19 ,13 ,30 ,6 , 122 | 22 ,11 ,4 ,25 }; 123 | 124 | const int P_1[64] = { 40 ,8 ,48 ,16 ,56 ,24 ,64 ,32 , 125 | 39 ,7 ,47 ,15 ,55 ,23 ,63 ,31 , 126 | 38 ,6 ,46 ,14 ,54 ,22 ,62 ,30 , 127 | 37 ,5 ,45 ,13 ,53 ,21 ,61 ,29 , 128 | 36 ,4 ,44 ,12 ,52 ,20 ,60 ,28 , 129 | 35 ,3 ,43 ,11 ,51 ,19 ,59 ,27 , 130 | 34 ,2 ,42 ,10 ,50 ,18 ,58 ,26 , 131 | 33 ,1 ,41 ,9 ,49 ,17 ,57 ,25 }; 132 | 133 | 134 | // some functions 135 | 136 | string shift_bit(string s, int n) 137 | { 138 | string k = ""; 139 | 140 | for (int i = n; i < s.size(); i++) 141 | k += s[i]; 142 | 143 | for (int i = 0; i < n; i++) 144 | k += s[i]; 145 | 146 | return k; 147 | } 148 | 149 | 150 | void expand_R(string r, string r32) // expanding according to expantion table E_t 151 | { 152 | r = ""; 153 | for (int j = 0; j < 48; j++) 154 | { 155 | r += r32[E_t[j] - 1]; 156 | } 157 | } 158 | 159 | 160 | string xor_add(string s1, string s2) 161 | { 162 | string result = ""; 163 | for (int j = 0; j < s1.size(); j++) { 164 | if (s1[j] != s2[j]) result += '1'; 165 | else result += '0'; 166 | } 167 | return result; 168 | } 169 | 170 | string get_element_from_box(string s, int k) 171 | { 172 | int dec1 = 0, dec2 = 0, pwr = 0; 173 | dec1 = (int)(s[0] - '0') * 2 + (int)(s[5] - '0'); 174 | for (int i = s.size() - 2; i >= 1; i--) 175 | { 176 | dec2 += (int)(s[i] - '0') * pow(2, pwr++); 177 | } 178 | 179 | return Dec_to_Bin(S[k][dec1][dec2]); 180 | } 181 | 182 | 183 | public: 184 | 185 | void encrypt(string plain_txt, string key) 186 | { 187 | // making sub-keys 188 | 189 | string key_64 = Hex_to_Bin(key); 190 | 191 | 192 | 193 | string key_56 = ""; 194 | string key_firstHalf = "", key_secondHalf = ""; 195 | 196 | for (int i = 0; i < 56; i++) 197 | key_56 += key_64[pc_1[i] - 1]; 198 | 199 | for (int i = 0; i < 28; i++) 200 | key_firstHalf += key_56[i]; 201 | 202 | for (int i = 28; i < 56; i++) { 203 | key_secondHalf += key_56[i]; 204 | } 205 | 206 | string L_key[16], R_key[16]; 207 | 208 | L_key[0] = shift_bit(key_firstHalf, num_leftShift[0]); // shifting the bits according to num_leftSifht 209 | R_key[0] = shift_bit(key_secondHalf, num_leftShift[0]); 210 | 211 | for (int i = 1; i < 16; i++) 212 | { 213 | L_key[i] = shift_bit(L_key[i - 1], num_leftShift[i]); 214 | R_key[i] = shift_bit(R_key[i - 1], num_leftShift[i]); 215 | } 216 | 217 | 218 | 219 | string key_48[16], keys_56[16]; 220 | 221 | for (int i = 0; i < 16; i++) 222 | { 223 | keys_56[i] = L_key[i] + R_key[i]; // making 56 bits keys 224 | } 225 | for (int i = 0; i < 16; i++) 226 | { 227 | key_48[i] = ""; 228 | for (int j = 0; j < 48; j++) 229 | key_48[i] += keys_56[i][pc_2[j] - 1]; // making 48 bits keys 230 | } 231 | 232 | // working on the plain text 233 | 234 | string plain_txt_64 = Hex_to_Bin(plain_txt); // transforming key from 16-bits hex to 64-bits bin 235 | 236 | string IP = ""; // permuted key 237 | 238 | for (int i = 0; i < 64; i++) 239 | IP += plain_txt_64[IP_t[i] - 1]; 240 | 241 | string L = "", R = ""; 242 | 243 | for (int i = 0; i < 32; i++) 244 | L += IP[i]; 245 | 246 | for (int i = 32; i < 64; i++) 247 | R += IP[i]; 248 | 249 | string L_32[16], R_32[16]; 250 | string R_xor_K[16]; 251 | string R_48[16]; // making R_32 48 bits so that we can xor it with key_48 (wich is 48 bits) 252 | string S_R[16], s[16][8]; 253 | string s_1[16]; 254 | string P_R[16]; 255 | 256 | R_48[0] = ""; 257 | for (int j = 0; j < 48; j++) 258 | R_48[0] += R[E_t[j] - 1]; 259 | 260 | R_xor_K[0] = xor_add(R_48[0], key_48[0]); // fill the R_xor_K array 261 | 262 | for (int j = 0; j <48; j += 6) // dividing each value of R_xor_K to 8 string contaning 6 char each 263 | for (int k = j; k < j + 6; k++) 264 | s[0][j / 6] += R_xor_K[0][k]; 265 | 266 | s_1[0] = ""; 267 | for (int j = 0; j < 8; j++) 268 | s_1[0] += get_element_from_box(s[0][j], j); 269 | 270 | for (int j = 0; j < 32; j++) 271 | P_R[0] += s_1[0][P[j] - 1]; 272 | 273 | L_32[0] = R; 274 | R_32[0] = ""; 275 | R_32[0] = xor_add(P_R[0], L); 276 | 277 | for (int i = 1; i < 16; i++) 278 | 279 | { 280 | L_32[i] = R_32[i - 1]; 281 | R_48[i] = ""; 282 | for (int j = 0; j < 48; j++) 283 | R_48[i] += R_32[i - 1][E_t[j] - 1]; 284 | 285 | R_xor_K[i] = xor_add(R_48[i], key_48[i]); // fill the R_xor_K 286 | 287 | for (int j = 0; j <48; j += 6) // dividing each value of R_xor_K to 8 string contaning 6 char each 288 | for (int k = j; k < j + 6; k++) 289 | s[i][j / 6] += R_xor_K[i][k]; 290 | 291 | s_1[i] = ""; 292 | for (int j = 0; j < 8; j++) 293 | s_1[i] += get_element_from_box(s[i][j], j); 294 | 295 | for (int j = 0; j < 32; j++) 296 | P_R[i] += s_1[i][P[j] - 1]; 297 | 298 | L_32[i] = R_32[i - 1]; 299 | R_32[i] = ""; 300 | R_32[i] = xor_add(P_R[i], L_32[i - 1]); 301 | 302 | } 303 | 304 | string encrypted_bin = "", RL; 305 | 306 | RL = R_32[15] + L_32[15]; 307 | 308 | for (int i = 0; i < 64; i++) 309 | encrypted_bin += RL[P_1[i] - 1]; 310 | 311 | cout << Bin_to_Hex(encrypted_bin) << endl; 312 | 313 | } 314 | 315 | 316 | }; 317 | 318 | 319 | string Bin_to_Hex(string s) 320 | { 321 | string hex = ""; 322 | for (int i = 0; i < s.size(); i += 4) 323 | { 324 | string k = ""; 325 | for (int j = i; j < i + 4; j++) 326 | k += s[j]; 327 | if (k == "0000") 328 | hex += '0'; 329 | else if (k == "0001") 330 | hex += '1'; 331 | else if (k == "0010") 332 | hex += '2'; 333 | else if (k == "0011") 334 | hex += '3'; 335 | else if (k == "0100") 336 | hex += '4'; 337 | else if (k == "0101") 338 | hex += '5'; 339 | else if (k == "0110") 340 | hex += '6'; 341 | else if (k == "0111") 342 | hex += '7'; 343 | else if (k == "1000") 344 | hex += '8'; 345 | else if (k == "1001") 346 | hex += '9'; 347 | else if (k == "1010") 348 | hex += 'A'; 349 | else if (k == "1011") 350 | hex += 'B'; 351 | else if (k == "1100") 352 | hex += 'C'; 353 | else if (k == "1101") 354 | hex += 'D'; 355 | else if (k == "1110") 356 | hex += 'E'; 357 | else if (k == "1111") 358 | hex += 'F'; 359 | } 360 | return hex; 361 | } 362 | 363 | string Hex_to_Bin(string s) 364 | { 365 | string bin = ""; 366 | for (int i = 0; i < s.size(); i++) 367 | { 368 | switch (s[i]) 369 | { 370 | case '0': bin += "0000"; break; 371 | case '1': bin += "0001"; break; 372 | case '2': bin += "0010"; break; 373 | case '3': bin += "0011"; break; 374 | case '4': bin += "0100"; break; 375 | case '5': bin += "0101"; break; 376 | case '6': bin += "0110"; break; 377 | case '7': bin += "0111"; break; 378 | case '8': bin += "1000"; break; 379 | case '9': bin += "1001"; break; 380 | case 'A': 381 | case 'a': bin += "1010"; break; 382 | case 'B': 383 | case 'b': bin += "1011"; break; 384 | case 'C': 385 | case 'c': bin += "1100"; break; 386 | case 'D': 387 | case 'd': bin += "1101"; break; 388 | case 'E': 389 | case 'e': bin += "1110"; break; 390 | case 'F': 391 | case 'f': bin += "1111"; break; 392 | 393 | } 394 | } 395 | return bin; 396 | } 397 | 398 | string Dec_to_Bin(int n) 399 | { 400 | string bin = ""; 401 | while (n > 0) 402 | { 403 | bin = (char)(n % 2 + '0') + bin; 404 | n /= 2; 405 | } 406 | while (bin.size() < 4) 407 | bin = '0' + bin; 408 | return bin; 409 | } -------------------------------------------------------------------------------- /des_lib/test/demo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "des.h" 3 | using namespace std; 4 | 5 | int main(int argc, char *argv[]) { 6 | DES_Encryption DES; 7 | 8 | bool is_valid; 9 | string plain_txt, key; 10 | plain_txt = "1234567812345678"; 11 | key = "1234567812345678"; 12 | DES.encrypt(plain_txt,key); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /des_lib/test/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | g++ demo.cpp -I../include/ -L../lib ../lib/libdes.a -o demo 3 | clean: 4 | rm demo -------------------------------------------------------------------------------- /documents/Feistel密码结构学习.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcc0lin/dirty_algorithm/50c8276dcd65b5a8e23f78cf83e87df41d414358/documents/Feistel密码结构学习.md -------------------------------------------------------------------------------- /documents/从FIPS 197中理解AES算法.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcc0lin/dirty_algorithm/50c8276dcd65b5a8e23f78cf83e87df41d414358/documents/从FIPS 197中理解AES算法.md -------------------------------------------------------------------------------- /documents/从FIPS 46-3中理解DES算法.md: -------------------------------------------------------------------------------- 1 | DES是一种对称密钥的块加密算法。”对称密钥”,是因为加密、解密用的密钥是一样的(这不同于RSA等非对称密钥体系)。“块加密”,是因为这种算法把明文划分为很多个等长的块(block),对每个块进行加密,最后以某种手段拼在一起。“块加密”亦称“分组加密”。 2 | 3 | 1973年,NSA向社会征集满足安全要求的加密算法。1973-1974年,IBM研发了DES加密算法。1974年,NSA开始了第二次征集,此后DES在1976年成为美国联邦标准。 4 | 5 | ### 一、DES概述 6 | 7 | DES的功能是:给定一个64位的明文和一个64位的密钥,输出一个64位的密文。这个密文可以用相同的密钥解密。所谓“64位的密钥”,其实里面只有54位在起作用。剩余的位可以直接丢弃,或者当作奇偶校验位。 8 | 9 | 虽然DES一次只能加密8个字节,但我们只需要把明文划分成每8个字节一组的块,就可以实现任意长度明文的加密。如果明文长度不是8个字节的倍数,还得进行填充。现在流行的填充方式是PKCS7/PKCS5,都是很简单的思路,用于把任意长度的文本填充成8字节的倍数长,也能方便地恢复原文,这里不再赘述。此外,独立地对每个块加密,最后直接拼起来是不行的(这种方式称为“电子密码本”,ECB模式。它会导致明文中重复的块,加密结果也重复,这对于图片之类的数据来说几乎是致命的)。因为不涵盖在算法流程中,因此对有关DES输入输出的处理后续再讲。 10 | 11 | DES有一个非常不平凡的性质——加密与解密算法几乎一模一样。这大大简化了软件和硬件的设计。和加密算法的区别是,给它加上一行(倒转子密钥的顺序),就是一个解密算法了。 12 | 13 | 在这篇文章中,我们只关注一个核心任务——如何把64位的明文,用64位的密钥,加密成64位的密文,并执行解密。 14 | 15 | ### 二、DES算法框架 16 | DES算法是在Feistel Network(费斯妥网络)的基础上执行的。以下是DES算法的流程图: 17 | 18 | ![](https://img-blog.csdnimg.cn/2352967361874f29a156bf17c0c91d9d.png) 19 | 20 | 可以看到,整个算法可以看成是两个部分 21 | - 密钥调度计算(右边基于给定密钥生成子密钥的过程) 22 | 23 | 所谓密钥调度,就是从一把64位的主密钥,得到16把48位的子密钥,然后把这些子密钥参与到后续16轮迭代加密中。那么,如何从一把主密钥得到16把子密钥呢? 24 | 25 | 1. 首先是从64位的主密钥中通过选择置换1选取特定的56位,其余的位就作为检验位,不参与后续计算。于是我们现在手上有了一个56位的密钥 26 | 27 | 2. 接着把它分成左、右两个半密钥C0、D0,它们都是28位的密钥 28 | 29 | 3. 然后对C0和D0进行16轮的迭代,每轮迭代都包括以下步骤: 30 | - 左、右两个半密钥Cn、Dn都左旋(也就是循环左移。整个数组往左移,左边弹出去了的东西补到最右边去)一定位数得到Cn+1、Dn+1,这个左移的位数也是指定的。有些轮次是1位,有些轮次是2位 31 | - 把左、右半密钥拼起来成为Kn+1,再通过选择置换2得到Kn,就得到了这一轮生成的子密钥。这个置换是从56位的数组里面选取指定的48位。所以现在每一轮都可以生成一个48位的子密钥。(注意,步骤3并不改变左右半密钥)。 32 | 4. 最后,经过16轮迭代之后,就生成了16个48位的子密钥,这些子密钥被用于加密和解密数据 33 | 34 | 5. 解密过程中,除了子密钥输出的顺序相反外,密钥调度的过程与加密完全相同 35 | - 迭代加密(左边的16轮迭代加密的过程) 36 | 迭代加密就是由具体数据参与的主流程的加密逻辑,具体逻辑是 37 | 38 | 1. 输入的明文(64bit)做一个置换(IP置换)。仍然得到64bit的数组(位数不等会导致信息丢失) 39 | 40 | 2. 同样基于Feistel Network的概念将数据拆分成左右两个半数据,各32bit 41 | 42 | 3. 每轮迭代都是接收一组L、R,返回L'、R',作为下一轮迭代的 L, R . 迭代过程如下: 43 | ``` 44 | L' = R 45 | R' = L⊕F(R,subkey) 46 | ``` 47 | 关键在于F函数,也称为轮(Round)函数,是整个算法的核心,用于以子密钥加密32bit的信息 48 | 49 | 4. 步骤3执行16轮,每轮分别更新L、R值 50 | 51 | 5. 将最终得到的L、R值进行合并,再做一次置换(FP置换),即可得到密文 52 | 53 | 以上就是DES算法的大致过程,文中也提到,加解密的唯一区别就在于子密钥的顺序不同 54 | 55 | #### 1 密钥调度计算 56 | 57 | 详细来看看DES如何通过给定的主密钥而生成16把子密钥的,图示如下: 58 | ![](https://img-blog.csdnimg.cn/156aca10b8774ebb916dc0c8420d2f0e.png) 59 | 60 | 首先,采用“选择置换1 (PC-1)”,从64位key里面选出56位。这一步属于encode,对信息安全没有帮助。PC-1方法如下: 61 | ```c 62 | const int pc_1[56] = { 57 ,49 ,41 ,33 ,25 ,17 ,9 , 63 | 1 ,58 ,50 ,42 ,34 ,26 ,18 , 64 | 10 ,2 ,59 ,51 ,43 ,35 ,27 , 65 | 19 ,11 ,3 ,60 ,52 ,44 ,36 , 66 | 63 ,55 ,47 ,39 ,31 ,23 ,15 , 67 | 7 ,62 ,54 ,46 ,38 ,30 ,22 , 68 | 14 ,6 ,61 ,53 ,45 ,37 ,29 , 69 | 21 ,13 ,5 ,28 ,20 ,12 ,4 }; 70 | string key_56 = ""; 71 | for (int i = 0; i < 56; i++) 72 | key_56 += key_64[pc_1[i] - 1]; 73 | ``` 74 | 经过PC-1之后,我们有了左、右两个半密钥,长度都是28位。接下来,我们每一轮把左、右半密钥左旋几位,再调用PC-2方法来造子密钥。框架如下: 75 | ```c 76 | int num_leftShift[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; 77 | L_key[0] = shift_bit(key_firstHalf, num_leftShift[0]); 78 | R_key[0] = shift_bit(key_secondHalf, num_leftShift[0]); 79 | for (int i = 1; i < 16; i++) 80 | { 81 | L_key[i] = shift_bit(L_key[i - 1], num_leftShift[i]); 82 | R_key[i] = shift_bit(R_key[i - 1], num_leftShift[i]); 83 | } 84 | for (int i = 0; i < 16; i++) 85 | { 86 | keys_56[i] = L_key[i] + R_key[i]; // making 56 bits keys 87 | } 88 | ``` 89 | 其中, shift_bit是循环左移,实现如下: 90 | ```c 91 | string shift_bit(string s, int n) 92 | { 93 | string k = ""; 94 | 95 | for (int i = n; i < s.size(); i++) 96 | k += s[i]; 97 | 98 | for (int i = 0; i < n; i++) 99 | k += s[i]; 100 | 101 | return k; 102 | } 103 | ``` 104 | PC-2又是一个简单置换,用于从左右半密钥拼起来的56位密钥中,选取48位作为一个子密钥。实现如下: 105 | ```c 106 | const int pc_2[48] = { 14 ,17 ,11 ,24 ,1 ,5 , 107 | 3 ,28 ,15 ,6 ,21 ,10 , 108 | 23 ,19 ,12 ,4 ,26 ,8 , 109 | 16 ,7 ,27 ,20 ,13 ,2 , 110 | 41 ,52 ,31 ,37 ,47 ,55 , 111 | 30 ,40 ,51 ,45 ,33 ,48 , 112 | 44 ,49 ,39 ,56 ,34 ,53 , 113 | 46 ,42 ,50 ,36 ,29 ,32 }; 114 | for (int i = 0; i < 16; i++) 115 | { 116 | key_48[i] = ""; 117 | for (int j = 0; j < 48; j++) 118 | key_48[i] += keys_56[i][pc_2[j] - 1]; // making 48 bits keys 119 | } 120 | ``` 121 | 这样,我们就实现了密钥调度算法。基于主密钥而得到的16个48位的子密钥。不难看出,整个密钥调度的过程都是对主密钥的encode。生成这么多子密钥的目的,是使得加密迭代变得更加复杂、难以分析 122 | #### 2 迭代加密 123 | ![](https://img-blog.csdnimg.cn/e77861a56532490d9ccfb2e9d309b2c1.png) 124 | 加密迭代的过程已经描述过。先把信息进行一次初始置换(IP置换);再进行16轮迭代;最后再给(R+L)这个数组来一次最终置换(FP置换),即可输出作为密文 125 | ```c 126 | const int IP_t[64] = { 58 ,50 ,42 ,34 ,26 ,18 ,10 ,2 , 127 | 60 ,52 ,44 ,36 ,28 ,20 ,12 ,4 , 128 | 62 ,54 ,46 ,38 ,30 ,22 ,14 ,6 , 129 | 64 ,56 ,48 ,40 ,32 ,24 ,16 ,8 , 130 | 57 ,49 ,41 ,33 ,25 ,17 ,9 ,1 , 131 | 59 ,51 ,43 ,35 ,27 ,19 ,11 ,3 , 132 | 61 ,53 ,45 ,37 ,29 ,21 ,13 ,5 , 133 | 63 ,55 ,47 ,39 ,31 ,23 ,15 ,7 }; 134 | 135 | string IP = ""; // permuted key 136 | for (int i = 0; i < 64; i++) 137 | IP += plain_txt_64[IP_t[i] - 1]; 138 | ``` 139 | DES的安全性在很大程度上取决于F函数,也就是轮函数。那么Feistel函数是干了什么事呢?来看下面一张流程图: 140 | ![](https://img-blog.csdnimg.cn/43043d18f1cd4aafbbfb81d4f5242c46.png) 141 | 142 | 一个32-bit的块,经过一个扩张(Expand函数),变成48位,然后与子密钥异或。得到的48-bit的结果分为8组,每一组是6-bit的数据,丢进对应的S盒,输出4-bit的信息。把这些输出收集起来,一共是4*8=32位,做一次置换(P置换),得到32-bit的结果。这与输进来的32-bit信息是等长度的。 143 | 144 | Expand算法是指定的 145 | ```c 146 | const int E_t[48] = { 32 ,1 ,2 ,3 ,4 ,5 , // expantion table 147 | 4 ,5 ,6 ,7 ,8 ,9 , 148 | 8 ,9 ,10 ,11 ,12 ,13 , 149 | 12 ,13 ,14 ,15 ,16 ,17 , 150 | 16 ,17 ,18 ,19 ,20 ,21 , 151 | 20 ,21 ,22 ,23 ,24 ,25 , 152 | 24 ,25 ,26 ,27 ,28 ,29 , 153 | 28 ,29 ,30 ,31 ,32 ,1 }; 154 | R_48[0] = ""; 155 | for (int j = 0; j < 48; j++) 156 | R_48[0] += R[E_t[j] - 1]; 157 | 158 | string xor_add(string s1, string s2) 159 | { 160 | string result = ""; 161 | for (int j = 0; j < s1.size(); j++) { 162 | if (s1[j] != s2[j]) result += '1'; 163 | else result += '0'; 164 | } 165 | return result; 166 | } 167 | 168 | R_xor_K[0] = xor_add(R_48[0], key_48[0]); 169 | ``` 170 | 分成8组分别进入S盒处理 171 | ```c 172 | for (int j = 0; j <48; j += 6) // dividing each value of R_xor_K to 8 string contaning 6 char each 173 | for (int k = j; k < j + 6; k++) 174 | s[0][j / 6] += R_xor_K[0][k]; 175 | 176 | s_1[0] = ""; 177 | for (int j = 0; j < 8; j++) 178 | s_1[0] += get_element_from_box(s[0][j], j); 179 | ``` 180 | S盒构成如下 181 | ```c 182 | int S[8][4][16] = { // S-box 183 | { 184 | { 14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7 }, 185 | { 0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8 }, 186 | { 4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0 }, 187 | { 15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13 } 188 | }, 189 | { 190 | { 15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10 }, 191 | { 3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5 }, 192 | { 0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15 }, 193 | { 13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9 } 194 | }, 195 | { 196 | { 10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8 }, 197 | { 13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1 }, 198 | { 13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7 }, 199 | { 1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12 } 200 | }, 201 | { 202 | { 7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15 }, 203 | { 13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9 }, 204 | { 10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4 }, 205 | { 3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14 } 206 | }, 207 | { 208 | { 2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9 }, 209 | { 14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6 }, 210 | { 4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14 }, 211 | { 11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3 } 212 | }, 213 | { 214 | { 12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11 }, 215 | { 10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8 }, 216 | { 9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6 }, 217 | { 4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13 } 218 | }, 219 | { 220 | { 4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1 }, 221 | { 13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6 }, 222 | { 1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2 }, 223 | { 6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12 } 224 | }, 225 | { 226 | { 13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7 }, 227 | { 1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2 }, 228 | { 7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8 }, 229 | { 2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11 } 230 | } 231 | }; 232 | 233 | string get_element_from_box(string s, int k) 234 | { 235 | int dec1 = 0, dec2 = 0, pwr = 0; 236 | dec1 = (int)(s[0] - '0') * 2 + (int)(s[5] - '0'); 237 | for (int i = s.size() - 2; i >= 1; i--) 238 | { 239 | dec2 += (int)(s[i] - '0') * pow(2, pwr++); 240 | } 241 | 242 | return Dec_to_Bin(S[k][dec1][dec2]); 243 | } 244 | ``` 245 | S盒变换的逻辑参考: 246 | ![](https://img-blog.csdnimg.cn/c2514656eb6c432493a1722664ce2cb4.png) 247 | ``` 248 | 现在我们假设第二组是 101100 ,来看它在 S盒变换之后会得到什么结果 249 | 由于这是第二组,故查询 S2 表。 250 | 它的首位、末尾是 10 ,故查询第三行(1yyyy0行)。 251 | 它的中间 4 位是 0110 ,查表知结果是 13. 252 | 把 13 转为二进制,得到 1101 ,于是这就是输出 253 | ``` 254 | 最后得到的32位结果还需要经过一个P置换 255 | ```c 256 | const int P[32] = { 16 ,7 ,20 ,21 , 257 | 29 ,12 ,28 ,17 , 258 | 1 ,15 ,23 ,26 , 259 | 5 ,18 ,31 ,10 , 260 | 2 ,8 ,24 ,14 , 261 | 32 ,27 ,3 ,9 , 262 | 19 ,13 ,30 ,6 , 263 | 22 ,11 ,4 ,25 }; 264 | for (int j = 0; j < 32; j++) 265 | P_R[0] += s_1[0][P[j] - 1]; 266 | ``` 267 | 268 | 269 | 270 | ### 三、理解 271 | DES也算是第一代的公认的对称加密的标准算法,核心在于F函数的概念与实现。当然DES算法主体流程还是依赖于固定64位的输入输出,而到了实际使用上还存在有不同的工作方式以及安全性问题,这些问题还等到后续继续补充 -------------------------------------------------------------------------------- /documents/从RFC1321中理解MD5算法.md: -------------------------------------------------------------------------------- 1 | ### 一、前置知识点 2 | MD5算法的输入是任意长度的信息,而输出是固定的长度为128位的信息,也就是固定大小为16字节的数组(byte=8bit) 3 | ### 二、算法流程 4 | 根据上面所说,MD5算法的输入是任意长度的信息,长度可以是0,也可以不是8的倍数,针对任意长度的输入,就需要通过下面的五个步骤来计算出它的MD5值 5 | #### 1 补位 6 | 输入可以是不定长的信息,但是实际上转化到算法逻辑中时又需要根据定长的信息来计算,因此,首先需要做的就是补位操作,方法如下: 7 | 将二进制数据对512进行取模,如果有余数不等于448,则将余数补足到448的长度,补足的规则是先补1,后面全补0,相当于N*512+448的长度,N为一个非负整数(也包括0) 8 | 9 | 例如 10 | ``` 11 | # 以长度20解释 12 | 1001001001 #长度为10 13 | 10010010011000000000 #先补1后补0 14 | ``` 15 | #### 2 记录信息长度 16 | 上一步将最后的余数补充到448,距离512还相差64,这64位二进制就是用来记录信息的长度的,当然,如果信息长度超过64位,则取低64位。经过以上这两步的处理,整个输入信息的长度已经被扩充成N\*512+448+64=(N+1)\*512,即长度恰好是512的整数倍。这样做的原因是为满足后面处理中对信息长度的要求 17 | #### 3 初始化变量 18 | 这一步引入MD5算法中第一个关键点---初始常量(可以叫幻数、魔数或者IV),这些参数以小端字节序来表示,会参与到后续的计算,也会直接影响最终的计算结果。 19 | ``` 20 | word A: 01 23 45 67 21 | word B: 89 ab cd ef 22 | word C: fe dc ba 98 23 | word D: 76 54 32 10 24 | ``` 25 | 每一个变量给出的数值是高字节存于内存低地址,低字节存于内存高地址,即小端字节序。在程序中变量A、B、C、D的值分别为0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476 26 | #### 4 处理分组数据 27 | 在前两步我们将数据处理成了N*512的分组形式,下面再对每个分组进行二次分组成16份,也就是16\*32=512,每个子分组是32bit的数据 28 | 29 | 每个分组的计算流程都是一样的,简单来说如下:默认初始变量有a、b、c、d四个变量,首先以第三步的四个变量分别对其赋值,也就是 30 | ``` 31 | A = a 32 | B = b 33 | C = c 34 | D = d 35 | ``` 36 | 之后开始四轮的循环计算,每轮有16次操作,分别对应一个非线性函数以及子分组、常量,每次操作都会计算出a、b、c、d其中一个变量的新值作替换,这样经过四轮计算之后,a、b、c、d的值也就更新了一遍,后续的其他分组也是如此操作 37 | 38 | 下面具体讲下其中的逻辑: 39 | 40 | 首先是MD5算法中第二个关键点---非线性函数,分别是 41 | ```c 42 | F(X,Y,Z) = XY v not(X) Z 43 | G(X,Y,Z) = XZ v Y not(Z) 44 | H(X,Y,Z) = X xor Y xor Z 45 | I(X,Y,Z) = Y xor (X v not(Z)) 46 | 47 | // c++实现 F, G, H and I are basic MD5 functions. 48 | inline MD5::uint4 MD5::F(uint4 x, uint4 y, uint4 z) { 49 | return (x & y) | (~x & z); 50 | } 51 | 52 | inline MD5::uint4 MD5::G(uint4 x, uint4 y, uint4 z) { 53 | return (x & z) | (y & ~z); 54 | } 55 | 56 | inline MD5::uint4 MD5::H(uint4 x, uint4 y, uint4 z) { 57 | return x ^ y ^ z; 58 | } 59 | 60 | inline MD5::uint4 MD5::I(uint4 x, uint4 y, uint4 z) { 61 | return y ^ (x | ~z); 62 | } 63 | ``` 64 | 每轮中都会使用其中一个函数来进行计算,因此函数的逻辑也直接决定最终的结果,具体使用到的地方如下 65 | ```c 66 | // rotate_left rotates x left n bits. 67 | inline MD5::uint4 MD5::rotate_left(uint4 x, int n) { 68 | return (x << n) | (x >> (32 - n)); 69 | } 70 | 71 | // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. 72 | // Rotation is separate from addition to prevent recomputation. 73 | inline void MD5::FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { 74 | a = rotate_left(a + F(b, c, d) + x + ac, s) + b; 75 | } 76 | 77 | inline void MD5::GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { 78 | a = rotate_left(a + G(b, c, d) + x + ac, s) + b; 79 | } 80 | 81 | inline void MD5::HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { 82 | a = rotate_left(a + H(b, c, d) + x + ac, s) + b; 83 | } 84 | 85 | inline void MD5::II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { 86 | a = rotate_left(a + I(b, c, d) + x + ac, s) + b; 87 | } 88 | ``` 89 | 四个函数格式相似,不同的只是引用到刚才所说的非线性函数 90 | 91 | 讲到主逻辑之前还需要提到MD5算法中第三个关键点---T常量表 92 | 93 | 它的计算方式也比较简单,之前说到计算会有4\*16=64次,因此也就需要64个常量,公式如 94 | ``` 95 | 4294967296*abs(sin(i)) 96 | ``` 97 | 其中i是取值从1到64,而4294967296=2的32次方,最后计算可得出T常量表如 98 | ```c 99 | unsigned int T[64] = { 100 | 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 101 | 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 102 | 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 103 | 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 104 | 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 105 | 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 106 | 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 107 | 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 108 | }; 109 | ``` 110 | 还有第四个关键点---转换常量 111 | ```c 112 | unsigned int S1[4] = {7, 12, 17, 22}; 113 | unsigned int S2[4] = {5, 9, 14, 20}; 114 | unsigned int S3[4] = {4, 11, 16, 23}; 115 | unsigned int S4[4] = {6, 10, 15, 21}; 116 | ``` 117 | 参与到非线性函数中循环左移的操作 118 | 主逻辑 119 | ```c 120 | /* Round 1 */ 121 | FF(a, b, c, d, x[0], S1[0], T[0]); /* 1 */ 122 | FF(d, a, b, c, x[1], S1[1], T[1]); /* 2 */ 123 | FF(c, d, a, b, x[2], S1[2], T[2]); /* 3 */ 124 | FF(b, c, d, a, x[3], S1[3], T[3]); /* 4 */ 125 | FF(a, b, c, d, x[4], S1[0], T[4]); /* 5 */ 126 | FF(d, a, b, c, x[5], S1[1], T[5]); /* 6 */ 127 | FF(c, d, a, b, x[6], S1[2], T[6]); /* 7 */ 128 | FF(b, c, d, a, x[7], S1[3], T[7]); /* 8 */ 129 | FF(a, b, c, d, x[8], S1[0], T[8]); /* 9 */ 130 | FF(d, a, b, c, x[9], S1[1], T[9]); /* 10 */ 131 | FF(c, d, a, b, x[10], S1[2], T[10]); /* 11 */ 132 | FF(b, c, d, a, x[11], S1[3], T[11]); /* 12 */ 133 | FF(a, b, c, d, x[12], S1[0], T[12]); /* 13 */ 134 | FF(d, a, b, c, x[13], S1[1], T[13]); /* 14 */ 135 | FF(c, d, a, b, x[14], S1[2], T[14]); /* 15 */ 136 | FF(b, c, d, a, x[15], S1[3], T[15]); /* 16 */ 137 | 138 | /* Round 2 */ 139 | GG(a, b, c, d, x[1], S2[0], T[16]); /* 17 */ 140 | GG(d, a, b, c, x[6], S2[1], T[17]); /* 18 */ 141 | GG(c, d, a, b, x[11], S2[2], T[18]); /* 19 */ 142 | GG(b, c, d, a, x[0], S2[3], T[19]); /* 20 */ 143 | GG(a, b, c, d, x[5], S2[0], T[20]); /* 21 */ 144 | GG(d, a, b, c, x[10], S2[1], T[21]); /* 22 */ 145 | GG(c, d, a, b, x[15], S2[2], T[22]); /* 23 */ 146 | GG(b, c, d, a, x[4], S2[3], T[23]); /* 24 */ 147 | GG(a, b, c, d, x[9], S2[0], T[24]); /* 25 */ 148 | GG(d, a, b, c, x[14], S2[1], T[25]); /* 26 */ 149 | GG(c, d, a, b, x[3], S2[2], T[26]); /* 27 */ 150 | GG(b, c, d, a, x[8], S2[3], T[27]); /* 28 */ 151 | GG(a, b, c, d, x[13], S2[0], T[28]); /* 29 */ 152 | GG(d, a, b, c, x[2], S2[1], T[29]); /* 30 */ 153 | GG(c, d, a, b, x[7], S2[2], T[30]); /* 31 */ 154 | GG(b, c, d, a, x[12], S2[3], T[31]); /* 32 */ 155 | 156 | /* Round 3 */ 157 | HH(a, b, c, d, x[5], S3[0], T[32]); /* 33 */ 158 | HH(d, a, b, c, x[8], S3[1], T[33]); /* 34 */ 159 | HH(c, d, a, b, x[11], S3[2], T[34]); /* 35 */ 160 | HH(b, c, d, a, x[14], S3[3], T[35]); /* 36 */ 161 | HH(a, b, c, d, x[1], S3[0], T[36]); /* 37 */ 162 | HH(d, a, b, c, x[4], S3[1], T[37]); /* 38 */ 163 | HH(c, d, a, b, x[7], S3[2], T[38]); /* 39 */ 164 | HH(b, c, d, a, x[10], S3[3], T[39]); /* 40 */ 165 | HH(a, b, c, d, x[13], S3[0], T[40]); /* 41 */ 166 | HH(d, a, b, c, x[0], S3[1], T[41]); /* 42 */ 167 | HH(c, d, a, b, x[3], S3[2], T[42]); /* 43 */ 168 | HH(b, c, d, a, x[6], S3[3], T[43]); /* 44 */ 169 | HH(a, b, c, d, x[9], S3[0], T[44]); /* 45 */ 170 | HH(d, a, b, c, x[12], S3[1], T[45]); /* 46 */ 171 | HH(c, d, a, b, x[15], S3[2], T[46]); /* 47 */ 172 | HH(b, c, d, a, x[2], S3[3], T[47]); /* 48 */ 173 | 174 | /* Round 4 */ 175 | II(a, b, c, d, x[0], S4[0], T[48]); /* 49 */ 176 | II(d, a, b, c, x[7], S4[1], T[49]); /* 50 */ 177 | II(c, d, a, b, x[14], S4[2], T[50]); /* 51 */ 178 | II(b, c, d, a, x[5], S4[3], T[51]); /* 52 */ 179 | II(a, b, c, d, x[12], S4[0], T[52]); /* 53 */ 180 | II(d, a, b, c, x[3], S4[1], T[53]); /* 54 */ 181 | II(c, d, a, b, x[10], S4[2], T[54]); /* 55 */ 182 | II(b, c, d, a, x[1], S4[3], T[55]); /* 56 */ 183 | II(a, b, c, d, x[8], S4[0], T[56]); /* 57 */ 184 | II(d, a, b, c, x[15], S4[1], T[57]); /* 58 */ 185 | II(c, d, a, b, x[6], S4[2], T[58]); /* 59 */ 186 | II(b, c, d, a, x[13], S4[3], T[59]); /* 60 */ 187 | II(a, b, c, d, x[4], S4[0], T[60]); /* 61 */ 188 | II(d, a, b, c, x[11], S4[1], T[61]); /* 62 */ 189 | II(c, d, a, b, x[2], S4[2], T[62]); /* 63 */ 190 | II(b, c, d, a, x[9], S4[3], T[63]); /* 64 */ 191 | ``` 192 | 最终只需要将得到的a、b、c、d重新赋值再作为初始变量传递给下一分组计算即可 193 | #### 5 输出结果 194 | 在经过分组计算后能够得到A、B、C、D,从低位字节A开始,高位字节D结束 195 | 196 | ### 总结 197 | 综合上面所讲到的MD5算法原理,可以看出MD5还是比较简单易懂的,与最终结果相关的正如上面所讲到的有四个关键点,理解它们的含义以及作用在后续我们对MD5算法进行魔改的时候是很有帮助的 198 | -------------------------------------------------------------------------------- /documents/从RFC2040中理解RC5算法.md: -------------------------------------------------------------------------------- 1 | ### 一、RC5算法概述 2 | 作为同样是由Rivest推出的算法,RC5算法与RC4算法是完全不同的,一个明显的特征是RC5采用的是基于Feistel对称结构的分组加密算法 3 | 4 | 和许多加密方法不同,RC5支持可变的块大小(32、64或128比特),密钥长度(0至2040位)和加密轮数(0~255)。最初建议选择的参数是64位的块大小,128位的密钥和12轮加密 5 | 6 | RC5的一个关键特征是使用基于数据的置换。RC5的其中一个目标是促进对于这类作为原始密码的操作的研究和评估。RC5也包括一些的取模加法和逻辑异或(XOR)运算。加密结构是基于Feistel来完成的,虽然结构简单,但密钥的生成算法更复杂。密钥扩展使用了e和黄金比例代入一个单向函数,将所得值作为“袖子里是空的”数字(即无任何来源依据的魔法数字)。算法的诱人的简洁性和基于数据的置换的特性,让RC5吸引了众多密码研究人员将其作为研究对象。 RC5通常被记为RC5-w/r/b,w=字的大小(以bit为单位),r=加密轮数,b=密钥的字节数。这样,RC5-32/16/16表示为RC5的块长为64位(注:RC5使用两个字块)、16轮加密和16字节密钥。Ron Rivest推荐的最低安全版本为RC5-32/16/16 7 | 8 | ### 二、RC5算法框架 9 | 10 | 为了便于理解RC5算法,假设输入明文块的长度为64位,其他块长的操作原理是一样的 11 | 12 | 在一次性初始操作中,输入明文块分成两个32位块A和B,前两个子密钥(稍后会介绍如何生成)S[0]和S[1]分别加进A和B,分别产生C和D,表示一次性操作结束 13 | 14 | 接着进行各轮计算,每轮完成以下操作: 15 | 1. 位异或运算 16 | 2. 循环左移 17 | 3. 对C和D增加下一个子密钥,先是加法运算,然后将结果用2^32求模 18 | 19 | ![](https://img-blog.csdnimg.cn/7b5f352052a04136a9c9f4043357bd12.png) 20 | 21 | #### 1 初始化操作 22 | 第一步的初始化计算可以看成是RC4融合了DES的做法,融合了RC4的密钥计算和DES的Feistel的一个对称结构运用 23 | 24 | 首先会将明文分为两个等长的A和B,接着是第一个子密钥S[0]与A相加,第二个子密钥S[1]与B相加 25 | 26 | #### 2 子密钥的计算 27 | 子密钥的计算可以分成生成和混合两步,预计要产生2r+2个子密钥,每个密钥长度为w位 28 | - 生成 29 | 30 | 这一步使用两个常量P和Q。生成的子密钥数组称为S,第一个子密钥为S[0]用P值初始化。每个后续子密钥(S[1],S[2],…)根据前面的子密钥和常量Q求出,用2^32求模,这个过程要进行2(r+1)-1次,其中r位轮数 31 | 32 | ```c 33 | // Set magic constants 34 | rc5_p = 0xb7e15163; 35 | rc5_q = 0x9e3779b9; 36 | 37 | // Cleaning user key 38 | for(int i=0; i 3*c 52 | for(a=b=i=j=k=0; k<3*RC5_T; k++, i=(i+1)%RC5_T, j=(j+1)%RC5_C) 53 | { 54 | a = rc5_s[i] = RC5_ROTL(rc5_s[i]+(a+b),3); 55 | b = l[j] = RC5_ROTL(l[j]+(a+b),(a+b)); 56 | } 57 | ``` 58 | 59 | 混合之后得到了新的长度为(2 * r) + 2的密钥组,需要注意的是,代码中提到了P和Q两个变量,其实是根据以下的公式而得来的 60 | ``` 61 | Pw = Odd((e-2)*2^32) 62 | Qw = Odd((Φ-2)*2^32) 63 | ``` 64 | e表示自然对数的底 65 | Φ表示黄金分割比率 66 | Odd(x)表示最接近x的奇整数 67 | #### 3 轮计算 68 | ```c 69 | RC5_TWORD i; 70 | RC5_TWORD a=pt[0]+rc5_s[0]; 71 | RC5_TWORD b=pt[1]+rc5_s[1]; 72 | 73 | for(i=1; i<=RC5_R; i++) 74 | { 75 | a = RC5_ROTL(a^b, b)+rc5_s[2*i]; 76 | b = RC5_ROTL(b^a, a)+rc5_s[2*i+1]; 77 | } 78 | 79 | ct[0] = a; 80 | ct[1] = b; 81 | ``` 82 | ### 三、理解 -------------------------------------------------------------------------------- /documents/从RFC3174中理解SHA1算法.md: -------------------------------------------------------------------------------- 1 | ### 一、前置知识点 2 | 总体上来说,SHA1算法和MD5算法很类似(因为它们都属于是针对于信息摘要的哈希算法),大体的算法流程也是基本相同,可以回忆下MD5算法的五个步骤,可以说SHA1是升级版本的MD5。不同点从直观上看,SHA1返回的信息长度是160位(20个字节),而MD5则是128位(16个字节),因此相较于MD5算法来说会更加安全一些(不过也仅仅是一些而已) 3 | ### 二、算法流程 4 | 算法流程就不多做介绍,和MD5算法类似,同样需要通过五个步骤来完成 5 | #### 1 补位 6 | 基本一样,不做额外说明 7 | #### 2 记录信息长度 8 | 同上 9 | #### 3 初始化变量 10 | 这一步开始有不同了,SHA1算法也同样有初始变量,与MD5不同的是,MD5最终是依靠初始变量组合起来的16个字节的结果,而SHA1结果为20个字节,因此也在初始变量中多了4个字节,定义如下 11 | ``` 12 | uint32_t H0 = 0x67452301; // 0x01, 0x23, 0x45, 0x67 13 | uint32_t H1 = 0xEFCDAB89; // 0x89, 0xAB, 0xCD, 0xEF 14 | uint32_t H2 = 0x98BADCFE; // 0xFE, 0xDC, 0xBA, 0x98 15 | uint32_t H3 = 0x10325476; // 0x76, 0x54, 0x32, 0x10 16 | uint32_t H4 = 0xC3D2E1F0; // 0xF0, 0xE1, 0xD2, 0xC3 17 | ``` 18 | 初始化变量的个数和结果有直接关系,因为结果是由初始化变量组合在一起的 19 | #### 4 处理分组数据 20 | 这一步大体结构一样,但是处理的方式有点不同 21 | 22 | 分组方式不说了,同样是将数据处理成了N*512的分组形式,下面再对每个分组进行二次分组成16份,也就是16\*32=512,每个子分组是32bit的数据,着重讲讲和MD5算法的不同点 23 | 24 | 相比于MD5的四轮计算,SHA1也会涉及到四轮计算,每轮则增加到20次,一共是80次非线性函数计算,对于每轮使用的数据和MD5也是有区别的,MD5处理每次分组的数据就是把数据分成16组,每轮使用的都是这16组数据,而SHA1则不一样,只有前16组使用的是拆分的数据,从16-80则根据公式得到新的数据 25 | ```c 26 | /* a. Divide M(i) into 16 words W(0), W(1), ..., W(15), where W(0) is the left - most word. */ 27 | for (t = 0; t <= 15; t++) 28 | { 29 | W[t] = M[t]; 30 | } 31 | 32 | /* b. For t = 16 to 79 let 33 | W(t) = S^1(W(t-3) XOR W(t-8) XOR W(t-14) XOR W(t-16)). */ 34 | for (t = 16; t <= 79; t++) 35 | { 36 | W[t] = MoveLeft(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); 37 | } 38 | ``` 39 | 40 | 首先先看看四个非线性函数参考(二、四轮其实是一样的) 41 | ```c 42 | /* f(X, Y, Z) */ 43 | /* [0, 19] */ 44 | static uint32_t Ch(uint32_t X, uint32_t Y, uint32_t Z) 45 | { 46 | return (X & Y) ^ ((~X) & Z); 47 | } 48 | /* [20, 39] */ /* [60, 79] */ 49 | static uint32_t Parity(uint32_t X, uint32_t Y, uint32_t Z) 50 | { 51 | return X ^ Y ^ Z; 52 | } 53 | /* [40, 59] */ 54 | static uint32_t Maj(uint32_t X, uint32_t Y, uint32_t Z) 55 | { 56 | return (X & Y) ^ (X & Z) ^ (Y & Z); 57 | } 58 | ``` 59 | 接着是每次计算所会涉及到的常量K,还记得在MD5中有个常量表T表,T表是根据公式计算得来的64个常量,而K就是直接给好的 60 | ``` 61 | K(t) = 5A827999 ( 0 <= t <= 19) 62 | 63 | K(t) = 6ED9EBA1 (20 <= t <= 39) 64 | 65 | K(t) = 8F1BBCDC (40 <= t <= 59) 66 | 67 | K(t) = CA62C1D6 (60 <= t <= 79) 68 | ``` 69 | 文档也给的很干脆,每轮一个固定常量 70 | 71 | 下面该讲到具体的处理了,MD5算法每次计算改变的只是一个变量的值,但是SHA1每次计算则会改变五个变量的值 72 | ```c 73 | uint32_t temp = MoveLeft(A, 5) + Ch(B, C, D) + E + W[t] + K[0]; 74 | E = D; 75 | D = C; 76 | C = MoveLeft(B, 30); 77 | B = A; 78 | A = temp; 79 | ``` 80 | 最终只需要将得到的a、b、c、d重新赋值再作为初始变量传递给下一分组计算即可 81 | #### 5 输出结果 82 | 在经过分组计算后能够得到A、B、C、D、E,从低位字节A开始,高位字节E结束 83 | 84 | ### 总结 85 | 文中每个步骤都在对比MD5和SHA1的异同,可以看出,虽然结果上SHA1只是多了4个字节,但是在细节上还是有很大的提升,算法整体上更复杂了,变化也更多了,下面总体归纳下两个算法的异同 86 | 87 | | 算法 | MD5 | SHA1 | 88 | | ---- | ---- |---- | 89 | | 分组数据处理 | 使用同一套16组数据 | 基于16组数据的基础上变化得到额外64组数据 | 90 | | 初始化常量 | 4个 | 5个 | 91 | |非线性函数 | 4个 | 4个 | 92 | | 常量表 | T常量表分配给64次计算,各不相同 | K表分配给80次计算,每20次使用同一个常量 | 93 | |常量变化 | 每次计算重新给一个常量赋值 |每次计算所有常量全部发生变化| 94 | 95 | -------------------------------------------------------------------------------- /documents/从RFC4648中理解Base64算法.md: -------------------------------------------------------------------------------- 1 | ### 一、前置知识点 2 | Base64算法是一种编码算法,它是采用常见的64个字符来表示做数据映射的表,分别是A-Z、a-z、+、/。 3 | 4 | 64对应的二进制是0b111111,也就是 5 | ``` 6 | 2^6 = 64 7 | ``` 8 | 换句话说,6个bit就能表示一个字符,而正常的字节对应的8bit,要把正常字符和编码后的字符串联起来的话那么就需要找出它们的最小公倍数,以最小公倍数所代表的长度来划分,那么8和6的公倍数是24,也就可以这么理解,3个正常字符实际上对应的是4个编码字符,举例说明下 9 | ``` 10 | lin的正常二进制编码 11 | 01101100|01101001|01101110 12 | 13 | 变成base64的编码 14 | 011011|000110|100101|101110 15 | 16 | # 正常来说8bit组成一个字节,所以划分成base64的编码之后还需要在前面补两个0变成正常的8bit 17 | 18 | 变成十进制 19 | 27|6|37|46 20 | 21 | 获取映射表 22 | bGlu 23 | ``` 24 | 这样就得到了最终的编码,所以就可以理解正常字符中每三个字符会对应编码后的四个字符,如果按长度3来切分存在余数的话(例如1、2),就使用0来做填充,而填充的输出通常用=来表示,所以一般都能看到在base64编码后的字符存在=的情况,这样就表示字符长度非3的倍数(一般余数为1的话就是两个=) 25 | ### 二、算法流程 26 | #### 1 分组并获取映射 27 | 获取输入字符的长度,每3个字符为一组来进行处理 28 | 29 | 第一个字符的处理:获取字符的二进制前6位,并获取对应的映射 30 | ```c 31 | ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]); 32 | ``` 33 | 第二个字符的处理:第一个字符还剩余两位,取出低位2个bit,同时左移四位并取出第二个字符的前4个bit 34 | ```c 35 | ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]); 36 | ``` 37 | 第三个字符的处理:第二个字符的后4个bit还没取出,取出并取第三个字符的前2个bit 38 | ```c 39 | ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]); 40 | ``` 41 | 第四个字符的处理:直接取出剩余的低六位即可 42 | ``` 43 | ret.push_back(base64_chars_[ bytes_to_encode[pos + 2] & 0x3f]); 44 | ``` 45 | #### 3 尾端处理 46 | 剩余两个字符的情况 47 | ```c 48 | ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]); 49 | ret.push_back(trailing_char); 50 | ``` 51 | 剩余一个字符的情况 52 | ```c 53 | ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]); 54 | ret.push_back(trailing_char); 55 | ret.push_back(trailing_char); 56 | ``` 57 | ### 三、解码算法流程 58 | 解码流程就可以当做编码流程的逆向过程,将每个编码根据映射表转化成索引->二进制,再组合起来即可 59 | ### 总结 60 | 综合上面所讲到的MD5算法原理,可以看出Base64还是比较简单易懂的,与最终结果相关的正如上面所讲到的有一个关键点,理解它们的含义以及作用在后续我们对Base64算法进行魔改的时候是很有帮助的 61 | -------------------------------------------------------------------------------- /documents/从RFC6229中理解RC4算法.md: -------------------------------------------------------------------------------- 1 | ### 一、RC4概述 2 | RC4是在1987年提出,和DES算法一样。是一种对称加密算法,也就是说使用的密钥为单钥(或称为私钥)。但不同于DES算法的是。RC4不是对明文进行分组处理,而是通过字节流的方式依次加密明文中的每个字节,同样的,解密的时候也是依次对密文中的每个字节进行解密。 3 | 4 | RC4算法的一个特点是可变密钥,可变范围在1~256字节,也就是8位~2048位 5 | ### 二、RC4算法框架 6 | 7 | RC4算法简单、易于描述,主要使用一个S表来生成密钥流,分为密钥调度算法(KSA)和伪随机数生成算法(PRGA)两个步骤。其中KSA使用原始密钥生成S表,PRGA利用S表来产生密钥流序列。 8 | 9 | 上面已经说过了,原始密钥K是可变的,而加密单位的话以一个字节为准。 10 | 11 | #### 1 密钥调度算法(Key Scheduling Algorithm,KSA) 12 | 13 | 密钥调度算法的作用是,利用原始密钥K来生成S表 14 | 15 | 这里的密钥K的长度为1~256字节。S表类似于一个数组,其大小为256,表示为S[0]~S[255],其中每个S表单元可以存放一个字节(8位) 16 | 17 | S表的生成分为初始化和置换两部分: 18 | - 初始化 19 | 20 | - 首先对S表的每个单元依照编号从0~255依次填充(二进制序列)。即S[0]=0;S[1]=1;......S[255]=255 21 | - 接着建立一个临时数组T,称为T表,其大小与S表相同。使用原始密钥K对T表进行填充。如果K的长度等于256,则直接将K赋值给T表。如果K的长度小于256,则T表剩余的部分继续使用密钥K循环填充,直到填满为止。假设密钥K=123,T表长度为7,则T表=1231231 22 | 23 | 用代码来描述的话如下 24 | ```c 25 | unsigned char S[256]; //状态向量S表 26 | unsigned char T[256]; //临时向量T表 27 | vector K; 28 | int keylen; //密钥长度,keylen个字节,取值范围为1-256 29 | for(int i = 0; i < 256; i++)//对S表、T表的每个单元进行填充 30 | { 31 | //填充S表 32 | S[i] = i; 33 | //填充T表,使用密钥K循环填充,keylen为密钥K的长度 34 | T[i] = K[i % keylen]; 35 | } 36 | ``` 37 | - 置换 38 | 39 | 置换过程就是根据一定的规则,对S表中的单元交换位置,交换的规则为: 40 | 41 | 初始化一个变量j=0,然后对于S表的第i个单元,计算得j=(j+S[i]+T[i])mod256,括号中的j为上一次计算得出的j值 42 | 43 | 每次计算出j后,交换S[i]和S[j]的值 44 | 45 | 以上的代码如下: 46 | ```c 47 | int j=0; 48 | for(int i=0;i<256;++i){ 49 | j=(j+S[i]+T[i])%256; 50 | //cout<<"j="<>> 2**0.5-1 13 | 0.41421356237309515 14 | 15 | 0.41421356237309515=6*16^-1+a*16^-2+0&16^-3··· 16 | ``` 17 | 于是, 质数2的平方根的小数部分取前32位就对应0x6a09e667,据此类推,初始化常量的值就是 18 | ```c 19 | m_state[0] = 0x6a09e667; 20 | m_state[1] = 0xbb67ae85; 21 | m_state[2] = 0x3c6ef372; 22 | m_state[3] = 0xa54ff53a; 23 | m_state[4] = 0x510e527f; 24 | m_state[5] = 0x9b05688c; 25 | m_state[6] = 0x1f83d9ab; 26 | m_state[7] = 0x5be0cd19; 27 | ``` 28 | #### 4 处理分组数据 29 | 还是同样的套路,输入的数据被分成每512位一组,而512位的数据又被拆分成每32位一小组,一共是16个小组,SHA256的循环轮次和MD5是相同的,但是SHA256和SHA1一样,除了初始的16组是原始的以外,剩余的组都通过额外的公式来计算得来 30 | 31 | 根据文档 32 | ``` 33 | For t = 0 to 15 34 | Wt = M(i)t 35 | For t = 16 to 63 36 | Wt = SSIG1(W(t-2)) + W(t-7) + SSIG0(w(t-15)) + W(t-16) 37 | ``` 38 | c++实现 39 | ```c 40 | for (uint8_t i = 0, j = 0; i < 16; i++, j += 4) { // Split data in 32 bit blocks for the 16 first words 41 | m[i] = (m_data[j] << 24) | (m_data[j + 1] << 16) | (m_data[j + 2] << 8) | (m_data[j + 3]); 42 | } 43 | 44 | for (uint8_t k = 16 ; k < 64; k++) { // Remaining 48 blocks 45 | m[k] = SHA256::sig1(m[k - 2]) + m[k - 7] + SHA256::sig0(m[k - 15]) + m[k - 16]; 46 | } 47 | 48 | uint32_t SHA256::sig0(uint32_t x) { 49 | return SHA256::rotr(x, 7) ^ SHA256::rotr(x, 18) ^ (x >> 3); 50 | } 51 | 52 | uint32_t SHA256::sig1(uint32_t x) { 53 | return SHA256::rotr(x, 17) ^ SHA256::rotr(x, 19) ^ (x >> 10); 54 | } 55 | ``` 56 | 针对64轮次每轮同样有常量,而SHA256的常量计算方式如下(取自自然数中前面64个素数的立方根的小数部分的前32位) 57 | ```c 58 | unsigned int K[64] = { 59 | 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5, 60 | 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, 61 | 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3, 62 | 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, 63 | 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc, 64 | 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, 65 | 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7, 66 | 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, 67 | 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13, 68 | 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, 69 | 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3, 70 | 0xd192e819,0xd6990624,0xf40e3585,0x106aa070, 71 | 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5, 72 | 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, 73 | 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208, 74 | 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 75 | }; 76 | ``` 77 | 看下主处理流程 78 | ``` 79 | 3. Perform the main hash computation: 80 | For t = 0 to 63 81 | T1 = h + BSIG1(e) + CH(e,f,g) + Kt + Wt 82 | T2 = BSIG0(a) + MAJ(a,b,c) 83 | h = g 84 | g = f 85 | f = e 86 | e = d + T1 87 | d = c 88 | c = b 89 | b = a 90 | a = T1 + T2 91 | ``` 92 | 出现T1、T2两个中间变量,涉及到了4个函数 93 | ``` 94 | CH( x, y, z) = (x AND y) XOR ( (NOT x) AND z) 95 | 96 | MAJ( x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z) 97 | 98 | BSIG0(x) = ROTR^2(x) XOR ROTR^13(x) XOR ROTR^22(x) 99 | 100 | BSIG1(x) = ROTR^6(x) XOR ROTR^11(x) XOR ROTR^25(x) 101 | ``` 102 | c++来实现 103 | ```c 104 | maj = SHA256::majority(state[0], state[1], state[2]); 105 | xorA = SHA256::rotr(state[0], 2) ^ SHA256::rotr(state[0], 13) ^ SHA256::rotr(state[0], 22); 106 | 107 | ch = choose(state[4], state[5], state[6]); 108 | 109 | xorE = SHA256::rotr(state[4], 6) ^ SHA256::rotr(state[4], 11) ^ SHA256::rotr(state[4], 25); 110 | 111 | sum = m[i] + K[i] + state[7] + ch + xorE; 112 | newA = xorA + maj + sum; 113 | newE = state[3] + sum; 114 | 115 | state[7] = state[6]; 116 | state[6] = state[5]; 117 | state[5] = state[4]; 118 | state[4] = newE; 119 | state[3] = state[2]; 120 | state[2] = state[1]; 121 | state[1] = state[0]; 122 | state[0] = newA; 123 | ``` 124 | 最终只需要将得到的8个变量重新赋值再作为初始变量传递给下一分组计算即可 125 | #### 5 输出结果 126 | 在经过分组计算后能够得到A、B、C、D、E、F、G、H,从低位字节A开始,高位字节E结束 127 | 128 | ### 总结 129 | 在了解了MD5、SHA1算法之后再来看SHA2-256算法的话,很明显能发现SHA2-256结合了前两个算法,包括MD5的每轮次的不同常量以及SHA1的数据分组方式以及每轮次计算方式,并且来降低了计算的轮次,引入更多的空间来替换计算时间效率的提升 -------------------------------------------------------------------------------- /documents/探讨关于Base64算法的魔改方式.md: -------------------------------------------------------------------------------- 1 | - 写法 2 | - 算法常量 3 | - 编码表 4 | - 算法流程 -------------------------------------------------------------------------------- /documents/探讨关于CRC32算法的魔改方式.md: -------------------------------------------------------------------------------- 1 | - 写法 2 | - 函数名 3 | - 算法常量 4 | - CRC码表 5 | - 多项式的二进制 6 | - 算法流程 7 | - CRC码表生成方式 -------------------------------------------------------------------------------- /documents/探讨关于MD5算法的魔改方式.md: -------------------------------------------------------------------------------- 1 | - 写法 2 | - 函数名 3 | - 常量初始化方式 4 | - 算法常量 5 | - IV 6 | - 转换变量 7 | - T常量表 8 | - 算法流程 9 | - 非线性函数 -------------------------------------------------------------------------------- /documents/探讨关于RC4算法的魔改方式.md: -------------------------------------------------------------------------------- 1 | - 写法 2 | - 算法常量 3 | - S盒长度、值 4 | - 算法流程 5 | - 数据交换 6 | - 流数据异或 -------------------------------------------------------------------------------- /documents/探讨关于SHA1算法的魔改方式.md: -------------------------------------------------------------------------------- 1 | - 写法 2 | - 函数名 3 | - 常量初始化方式 4 | - 算法常量 5 | - IV 6 | - K常量表 7 | - 算法流程 8 | - 分组数据变化的步函数 9 | - 非线性函数 10 | - 每次计算时初始化变量赋值方式 -------------------------------------------------------------------------------- /documents/探讨关于SHA256算法的魔改方式.md: -------------------------------------------------------------------------------- 1 | - 写法 2 | - 函数名 3 | - 常量初始化方式 4 | - 算法常量 5 | - IV 6 | - K常量表 7 | - 算法流程 8 | - 分组数据变化的步函数 9 | - 非线性函数 10 | - 每次计算时初始化变量赋值方式 -------------------------------------------------------------------------------- /documents/理解CRC32算法.md: -------------------------------------------------------------------------------- 1 | ### 一、CRC算法概述 2 | >循环冗余校验(Cyclic Redundancy Check, CRC)是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检测或校验数据传输或者保存后可能出现的错误。它是利用除法及余数的原理来作错误侦测的。 --–维基百科 3 | 4 | 在对信息的处理过程中,我们可以将要被处理的数据块M看成一个n阶的二进制多项式,其形式如下 5 | 6 | $M=a_{n-1}x^{n-1}+a_{n-2}x^{n-2}+a_{n-3}x^{n-3}+......+a_1x^1+a_0$ 7 | 8 | CRC校验就是基于这种多项式进行的运算,以GF(2)(The integers modulo 2)多项式算术为数学基础,即(模-2)除法的余数运算(其实说白了就是异或Xor),使用的除数不同,CRC的类型也就不一样。CRC传输实际上就是在长度为 k 的数据后面添加供差错检测(Frame Check Sequence) 用的 r 位冗余码(Redundant code 没错CRC里面的R就是这个),使原数据构成 n = k + r 位并发送出去, 此方式又叫(n, k)码。可以证明存在一个最高次幂为n-k=r的多项式G(x), 根据G(x)可以生成k位信息的校验码,而 G(x) 叫做这个CRC码的生成多项式( Poly )。而根据 k 值的不同,就形成了不同的CRC码的生成多项式,以下为各种常用的多项表达式: 9 | 10 | $crc-4=x^4+x+1$ 11 | 12 | $crc-8=x^8+x^5+x^4+1$ 13 | 14 | $crc-32=x^32+x^26+x^2+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+1$ 15 | 16 | 这些多项表达式的值便是(模-2)除法的除数,这里选取CRC-32多项式(即为对应除数)格式,通过取余做操,获取CRC检验码 17 | 18 | ### 二、CRC32算法框架 19 | 20 | CRC32校验计算框架如下: 21 | 1. 选择一个生成多项式G(x) 22 | 2. 假设该生成多项式G(x)的二进制数有k位,在发送的数据帧B(x)(设为m位)后加k-1个0,得到新二进制串H(x),H(x)位数应该为m+k-1。 23 | 3. H(x)“模2除法”除以G(x),所得到的余数(记为F(x))就是原数据帧的CRC校验码,又称FCS(帧校验序列)。注意,F(x)的位数只能比G(x)少一位,0不能省略。 24 | 4. 将F(x)附加到B(x)后面,组成新帧N(x),然后发送到接收端。 25 | 5. 接收端将N(x)以“模2除法”除以G(x),如果没有余数,则表明没有出错(因为在发送端发送数据帧之前就已附加了一个数,做了去余处理(也就已经能整除了),所以结果应该没有余数。如果有余数,则表明该帧在传输过程中出现了差错)。 26 | 27 | #### 1 多项式选择 28 | 如上面所示,常见CRC标准如下 29 | ![](https://img-blog.csdnimg.cn/a943fbdeea9246759cea3eb045ed47ea.jpeg) 30 | 通常多项式也会使用二进制来表示,计算方式是x的最高幂次对应二进制数的最高位,以下各位对应多项式的各幂次,有此幂次项对应1,无此幂次项对应0。可以看出:x的最高幂次为R,转换成对应的二进制数有R+1位 31 | #### 2 模2除法 32 | CRC校验是基于多项式进行的运算,其加减法运算以2为模GF(2) ,加减时不进(借)位,实际上与逻辑异或(XOR)运算是一致, XOR是将参加运算的两个数据,按二进制位进行“异或”运算。 33 | 34 | 异或运算规则(^)规则如下: 35 | ``` 36 | 0^0=0; 0^1=1; 1^0=1; 1^1=0; 37 | ``` 38 | 即:参加运算的两个对象,如果两个相应位为“异”(值不同),则该位结果为1,否则为0。 39 | #### 3 计算示例 40 | 以$G(x)=x^4+x^3+1$为例,设原数据为10110011 41 | 1. $G(x)=x^4+x^3+1$, 二进制比特串为11001。(在X的n次方不为0处2的n次方的位=1) 42 | 2. 因为校验码4位,所以10110011后面需加4个0,得到101100110000,用“模2除法” (即逻辑亦或^) 即可得出结果: 43 | ![](https://img-blog.csdnimg.cn/7309a55599bc4dc3909da0960e829dc3.png) 44 | 3. 即CRC^101100110000得到101100110100,并发送到接收端 45 | 4. 接收端收到101100110100后除以11001(以“模2除法”方式去除),余数为0则无差错 46 | #### 4 CRC的实现方式 47 | 一般来说CRC有多种实现方式,通常有直接生成法和查表法两种 48 | 49 | 直接生成法 适用于CRC次幂较小的格式,当CRC次幂逐渐增高时,因为其复杂的XOR逻辑运算会拖累系统运行速度,不再建议使用直接生成法,取而代之的是查表法——将数据块M 的一部分提前运算好,并将结果存入数组中,系统开始执行运算时,相当于省去了之前的操作,直接从类似中间的位置开始计算,所以会提高效率 50 | 51 | 生成CRC码表的方式如下: 52 | ```c 53 | int make_crc32_table() 54 | { 55 | uint32_t c; 56 | int i = 0; 57 | int bit = 0; 58 | 59 | for(i = 0; i < 256; i++) 60 | { 61 | c = (uint32_t)i; 62 | 63 | for(bit = 0; bit < 8; bit++) 64 | { 65 | if(c&1) 66 | { 67 | c = (c >> 1)^(0xEDB88320); 68 | } 69 | else 70 | { 71 | c = c >> 1; 72 | } 73 | 74 | } 75 | uiCRC32_Table[i] = c; 76 | } 77 | } 78 | ``` 79 | ### 三、思考 80 | 如上面所理解的那样,CRC算法关键在于码表,但是码表也分动态生成和静态表,若是动态生成表,则应留意生成多项式,若是静态表,则会在数据段留下整个表 -------------------------------------------------------------------------------- /md5_lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | add_subdirectory(src) 4 | -------------------------------------------------------------------------------- /md5_lib/README.md: -------------------------------------------------------------------------------- 1 | 基于c++实现的MD5算法库 2 | 3 | ## 使用说明 4 | 5 | 基于`cmake`编译,切换到`build`目录,执行脚本`./run.sh`即可在`lib`目录生成静态库`libmd5.a` 6 | 7 | 使用时只需要引入对应的头文件,然后就可以调用`md5`函数了。 8 | ```cpp 9 | #include "md5.h" 10 | 11 | md5(string) 12 | ``` 13 | 14 | ## 测试 15 | 切换到`test`目录下,执行`make`命令生成`demo`的可执行程序 16 | 17 | ```bash 18 | > echo -n "tcc0lin" | md5 19 | edf2ef5bfb48ca2b5f0d69a9bd47ac53 20 | > ./demo "tcc0lin" 21 | md5 of 'tcc0lin': edf2ef5bfb48ca2b5f0d69a9bd47ac53 22 | ``` -------------------------------------------------------------------------------- /md5_lib/bulid/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -f ./run.sh ../run.sh; 4 | rm -rf *; 5 | cp -f ../run.sh ./run.sh; 6 | rm -f ../run.sh; 7 | cmake ../; 8 | make; 9 | make install; 10 | cp -f ./run.sh ../run.sh; 11 | rm -rf *; 12 | cp -f ../run.sh ./run.sh; 13 | rm -f ../run.sh; -------------------------------------------------------------------------------- /md5_lib/include/md5.h: -------------------------------------------------------------------------------- 1 | #ifndef MD5_H_ 2 | #define MD5_H_ 3 | 4 | /* MD5 5 | converted to C++ class by Frank Thilo (thilo@unix-ag.org) 6 | for bzflag (http://www.bzflag.org) 7 | 8 | based on: 9 | 10 | md5.h and md5.c 11 | reference implementation of RFC 1321 12 | 13 | Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All 14 | rights reserved. 15 | 16 | License to copy and use this software is granted provided that it 17 | is identified as the "RSA Data Security, Inc. MD5 Message-Digest 18 | Algorithm" in all material mentioning or referencing this software 19 | or this function. 20 | 21 | License is also granted to make and use derivative works provided 22 | that such works are identified as "derived from the RSA Data 23 | Security, Inc. MD5 Message-Digest Algorithm" in all material 24 | mentioning or referencing the derived work. 25 | 26 | RSA Data Security, Inc. makes no representations concerning either 27 | the merchantability of this software or the suitability of this 28 | software for any particular purpose. It is provided "as is" 29 | without express or implied warranty of any kind. 30 | 31 | These notices must be retained in any copies of any part of this 32 | documentation and/or software. 33 | 34 | */ 35 | 36 | #include 37 | #include 38 | 39 | // a small class for calculating MD5 hashes of strings or byte arrays 40 | // it is not meant to be fast or secure 41 | // 42 | // usage: 1) feed it blocks of uchars with update() 43 | // 2) finalize() 44 | // 3) get hexdigest() string 45 | // or 46 | // MD5(std::string).hexdigest() 47 | // 48 | // assumes that char is 8 bit and int is 32 bit 49 | class MD5 { 50 | public: 51 | typedef unsigned int size_type; // must be 32bit 52 | 53 | MD5(); 54 | MD5(const std::string& text); 55 | void update(const unsigned char *buf, size_type length); 56 | void update(const char *buf, size_type length); 57 | MD5& finalize(); 58 | std::string hexdigest() const; 59 | friend std::ostream& operator<<(std::ostream&, MD5 md5); 60 | 61 | private: 62 | void init(); 63 | typedef unsigned char uint1; // 8bit 64 | typedef unsigned int uint4; // 32bit 65 | enum { 66 | blocksize = 64 67 | }; // VC6 won't eat a const static int here 68 | 69 | void transform(const uint1 block[blocksize]); 70 | static void decode(uint4 output[], const uint1 input[], size_type len); 71 | static void encode(uint1 output[], const uint4 input[], size_type len); 72 | 73 | bool finalized; 74 | uint1 buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk 75 | uint4 count[2]; // 64bit counter for number of bits (lo, hi) 76 | uint1 digest[16]; // the result 77 | 78 | //MD5算法中最关键的常量以及函数 79 | /* 80 | load magic initialization constants. 81 | */ 82 | unsigned state[4] = { 83 | 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 84 | }; 85 | /* 86 | * T denotes the integer part of the i-th element of the function: 87 | * T[i] = 4294967296 * abs(sin(i)), where i is in radians. 88 | */ 89 | unsigned int T[64] = { 90 | 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 91 | 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 92 | 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 93 | 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 94 | 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 95 | 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 96 | 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 97 | 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 98 | }; 99 | /* 100 | * Constants for the MD5 Transform routine as defined in RFC 1321 101 | */ 102 | unsigned int S1[4] = {7, 12, 17, 22}; 103 | unsigned int S2[4] = {5, 9, 14, 20}; 104 | unsigned int S3[4] = {4, 11, 16, 23}; 105 | unsigned int S4[4] = {6, 10, 15, 21}; 106 | /* 107 | low level logic operations 108 | */ 109 | static inline uint4 F(uint4 x, uint4 y, uint4 z); 110 | static inline uint4 G(uint4 x, uint4 y, uint4 z); 111 | static inline uint4 H(uint4 x, uint4 y, uint4 z); 112 | static inline uint4 I(uint4 x, uint4 y, uint4 z); 113 | static inline uint4 rotate_left(uint4 x, int n); 114 | static inline void FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); 115 | static inline void GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); 116 | static inline void HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); 117 | static inline void II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); 118 | }; 119 | 120 | std::string md5(const std::string str); 121 | 122 | #endif /* MD5_H_ */ 123 | -------------------------------------------------------------------------------- /md5_lib/rfc1321.txt: -------------------------------------------------------------------------------- 1 | Network Working Group R. Rivest 2 | Request for Comments: 1321 MIT Laboratory for Computer Science 3 | and RSA Data Security, Inc. 4 | April 1992 5 | 6 | The MD5 Message-Digest Algorithm 7 | 8 | Status of this Memo 9 | 10 | This memo provides information for the Internet community. It does 11 | not specify an Internet standard. Distribution of this memo is 12 | unlimited. 13 | 14 | Acknowlegements 15 | 16 | We would like to thank Don Coppersmith, Burt Kaliski, Ralph Merkle, 17 | David Chaum, and Noam Nisan for numerous helpful comments and 18 | suggestions. 19 | 20 | Table of Contents 21 | 22 | 1. Executive Summary 1 23 | 2. Terminology and Notation 2 24 | 3. MD5 Algorithm Description 3 25 | 4. Summary 6 26 | 5. Differences Between MD4 and MD5 6 27 | References 7 28 | APPENDIX A - Reference Implementation 7 29 | Security Considerations 21 30 | Author's Address 21 31 | 32 | 1. Executive Summary 33 | 34 | This document describes the MD5 message-digest algorithm. The 35 | algorithm takes as input a message of arbitrary length and produces 36 | as output a 128-bit "fingerprint" or "message digest" of the input. 37 | It is conjectured that it is computationally infeasible to produce 38 | two messages having the same message digest, or to produce any 39 | message having a given prespecified target message digest. The MD5 40 | algorithm is intended for digital signature applications, where a 41 | large file must be "compressed" in a secure manner before being 42 | encrypted with a private (secret) key under a public-key cryptosystem 43 | such as RSA. 44 | 45 | The MD5 algorithm is designed to be quite fast on 32-bit machines. In 46 | addition, the MD5 algorithm does not require any large substitution 47 | tables; the algorithm can be coded quite compactly. 48 | 49 | The MD5 algorithm is an extension of the MD4 message-digest algorithm 50 | 1,2]. MD5 is slightly slower than MD4, but is more "conservative" in 51 | design. MD5 was designed because it was felt that MD4 was perhaps 52 | being adopted for use more quickly than justified by the existing 53 | critical review; because MD4 was designed to be exceptionally fast, 54 | it is "at the edge" in terms of risking successful cryptanalytic 55 | attack. MD5 backs off a bit, giving up a little in speed for a much 56 | greater likelihood of ultimate security. It incorporates some 57 | suggestions made by various reviewers, and contains additional 58 | optimizations. The MD5 algorithm is being placed in the public domain 59 | for review and possible adoption as a standard. 60 | 61 | For OSI-based applications, MD5's object identifier is 62 | 63 | md5 OBJECT IDENTIFIER ::= 64 | iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5} 65 | 66 | In the X.509 type AlgorithmIdentifier [3], the parameters for MD5 67 | should have type NULL. 68 | 69 | 2. Terminology and Notation 70 | 71 | In this document a "word" is a 32-bit quantity and a "byte" is an 72 | eight-bit quantity. A sequence of bits can be interpreted in a 73 | natural manner as a sequence of bytes, where each consecutive group 74 | of eight bits is interpreted as a byte with the high-order (most 75 | significant) bit of each byte listed first. Similarly, a sequence of 76 | bytes can be interpreted as a sequence of 32-bit words, where each 77 | consecutive group of four bytes is interpreted as a word with the 78 | low-order (least significant) byte given first. 79 | 80 | Let x_i denote "x sub i". If the subscript is an expression, we 81 | surround it in braces, as in x_{i+1}. Similarly, we use ^ for 82 | superscripts (exponentiation), so that x^i denotes x to the i-th 83 | power. 84 | 85 | Let the symbol "+" denote addition of words (i.e., modulo-2^32 86 | addition). Let X <<< s denote the 32-bit value obtained by circularly 87 | shifting (rotating) X left by s bit positions. Let not(X) denote the 88 | bit-wise complement of X, and let X v Y denote the bit-wise OR of X 89 | and Y. Let X xor Y denote the bit-wise XOR of X and Y, and let XY 90 | denote the bit-wise AND of X and Y. 91 | 92 | 3. MD5 Algorithm Description 93 | 94 | We begin by supposing that we have a b-bit message as input, and that 95 | we wish to find its message digest. Here b is an arbitrary 96 | nonnegative integer; b may be zero, it need not be a multiple of 97 | eight, and it may be arbitrarily large. We imagine the bits of the 98 | message written down as follows: 99 | 100 | m_0 m_1 ... m_{b-1} 101 | 102 | The following five steps are performed to compute the message digest 103 | of the message. 104 | 105 | 3.1 Step 1. Append Padding Bits 106 | 107 | The message is "padded" (extended) so that its length (in bits) is 108 | congruent to 448, modulo 512. That is, the message is extended so 109 | that it is just 64 bits shy of being a multiple of 512 bits long. 110 | Padding is always performed, even if the length of the message is 111 | already congruent to 448, modulo 512. 112 | 113 | Padding is performed as follows: a single "1" bit is appended to the 114 | message, and then "0" bits are appended so that the length in bits of 115 | the padded message becomes congruent to 448, modulo 512. In all, at 116 | least one bit and at most 512 bits are appended. 117 | 118 | 3.2 Step 2. Append Length 119 | 120 | A 64-bit representation of b (the length of the message before the 121 | padding bits were added) is appended to the result of the previous 122 | step. In the unlikely event that b is greater than 2^64, then only 123 | the low-order 64 bits of b are used. (These bits are appended as two 124 | 32-bit words and appended low-order word first in accordance with the 125 | previous conventions.) 126 | 127 | At this point the resulting message (after padding with bits and with 128 | b) has a length that is an exact multiple of 512 bits. Equivalently, 129 | this message has a length that is an exact multiple of 16 (32-bit) 130 | words. Let M[0 ... N-1] denote the words of the resulting message, 131 | where N is a multiple of 16. 132 | 133 | 3.3 Step 3. Initialize MD Buffer 134 | 135 | A four-word buffer (A,B,C,D) is used to compute the message digest. 136 | Here each of A, B, C, D is a 32-bit register. These registers are 137 | initialized to the following values in hexadecimal, low-order bytes 138 | first): 139 | 140 | word A: 01 23 45 67 141 | word B: 89 ab cd ef 142 | word C: fe dc ba 98 143 | word D: 76 54 32 10 144 | 145 | 3.4 Step 4. Process Message in 16-Word Blocks 146 | 147 | We first define four auxiliary functions that each take as input 148 | three 32-bit words and produce as output one 32-bit word. 149 | 150 | F(X,Y,Z) = XY v not(X) Z 151 | G(X,Y,Z) = XZ v Y not(Z) 152 | H(X,Y,Z) = X xor Y xor Z 153 | I(X,Y,Z) = Y xor (X v not(Z)) 154 | 155 | In each bit position F acts as a conditional: if X then Y else Z. 156 | The function F could have been defined using + instead of v since XY 157 | and not(X)Z will never have 1's in the same bit position.) It is 158 | interesting to note that if the bits of X, Y, and Z are independent 159 | and unbiased, the each bit of F(X,Y,Z) will be independent and 160 | unbiased. 161 | 162 | The functions G, H, and I are similar to the function F, in that they 163 | act in "bitwise parallel" to produce their output from the bits of X, 164 | Y, and Z, in such a manner that if the corresponding bits of X, Y, 165 | and Z are independent and unbiased, then each bit of G(X,Y,Z), 166 | H(X,Y,Z), and I(X,Y,Z) will be independent and unbiased. Note that 167 | the function H is the bit-wise "xor" or "parity" function of its 168 | inputs. 169 | 170 | This step uses a 64-element table T[1 ... 64] constructed from the 171 | sine function. Let T[i] denote the i-th element of the table, which 172 | is equal to the integer part of 4294967296 times abs(sin(i)), where i 173 | is in radians. The elements of the table are given in the appendix. 174 | 175 | Do the following: 176 | 177 | /* Process each 16-word block. */ 178 | For i = 0 to N/16-1 do 179 | 180 | /* Copy block i into X. */ 181 | For j = 0 to 15 do 182 | Set X[j] to M[i*16+j]. 183 | end /* of loop on j */ 184 | 185 | /* Save A as AA, B as BB, C as CC, and D as DD. */ 186 | AA = A 187 | BB = B 188 | CC = C 189 | DD = D 190 | 191 | /* Round 1. */ 192 | /* Let [abcd k s i] denote the operation 193 | a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ 194 | /* Do the following 16 operations. */ 195 | [ABCD 0 7 1] [DABC 1 12 2] [CDAB 2 17 3] [BCDA 3 22 4] 196 | [ABCD 4 7 5] [DABC 5 12 6] [CDAB 6 17 7] [BCDA 7 22 8] 197 | [ABCD 8 7 9] [DABC 9 12 10] [CDAB 10 17 11] [BCDA 11 22 12] 198 | [ABCD 12 7 13] [DABC 13 12 14] [CDAB 14 17 15] [BCDA 15 22 16] 199 | 200 | /* Round 2. */ 201 | /* Let [abcd k s i] denote the operation 202 | a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ 203 | /* Do the following 16 operations. */ 204 | [ABCD 1 5 17] [DABC 6 9 18] [CDAB 11 14 19] [BCDA 0 20 20] 205 | [ABCD 5 5 21] [DABC 10 9 22] [CDAB 15 14 23] [BCDA 4 20 24] 206 | [ABCD 9 5 25] [DABC 14 9 26] [CDAB 3 14 27] [BCDA 8 20 28] 207 | [ABCD 13 5 29] [DABC 2 9 30] [CDAB 7 14 31] [BCDA 12 20 32] 208 | 209 | /* Round 3. */ 210 | /* Let [abcd k s t] denote the operation 211 | a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ 212 | /* Do the following 16 operations. */ 213 | [ABCD 5 4 33] [DABC 8 11 34] [CDAB 11 16 35] [BCDA 14 23 36] 214 | [ABCD 1 4 37] [DABC 4 11 38] [CDAB 7 16 39] [BCDA 10 23 40] 215 | [ABCD 13 4 41] [DABC 0 11 42] [CDAB 3 16 43] [BCDA 6 23 44] 216 | [ABCD 9 4 45] [DABC 12 11 46] [CDAB 15 16 47] [BCDA 2 23 48] 217 | 218 | /* Round 4. */ 219 | /* Let [abcd k s t] denote the operation 220 | a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ 221 | /* Do the following 16 operations. */ 222 | [ABCD 0 6 49] [DABC 7 10 50] [CDAB 14 15 51] [BCDA 5 21 52] 223 | [ABCD 12 6 53] [DABC 3 10 54] [CDAB 10 15 55] [BCDA 1 21 56] 224 | [ABCD 8 6 57] [DABC 15 10 58] [CDAB 6 15 59] [BCDA 13 21 60] 225 | [ABCD 4 6 61] [DABC 11 10 62] [CDAB 2 15 63] [BCDA 9 21 64] 226 | 227 | /* Then perform the following additions. (That is increment each 228 | of the four registers by the value it had before this block 229 | was started.) */ 230 | A = A + AA 231 | B = B + BB 232 | C = C + CC 233 | D = D + DD 234 | 235 | end /* of loop on i */ 236 | 237 | 3.5 Step 5. Output 238 | 239 | The message digest produced as output is A, B, C, D. That is, we 240 | begin with the low-order byte of A, and end with the high-order byte 241 | of D. 242 | 243 | This completes the description of MD5. A reference implementation in 244 | C is given in the appendix. 245 | 246 | 4. Summary 247 | 248 | The MD5 message-digest algorithm is simple to implement, and provides 249 | a "fingerprint" or message digest of a message of arbitrary length. 250 | It is conjectured that the difficulty of coming up with two messages 251 | having the same message digest is on the order of 2^64 operations, 252 | and that the difficulty of coming up with any message having a given 253 | message digest is on the order of 2^128 operations. The MD5 algorithm 254 | has been carefully scrutinized for weaknesses. It is, however, a 255 | relatively new algorithm and further security analysis is of course 256 | justified, as is the case with any new proposal of this sort. 257 | 258 | 5. Differences Between MD4 and MD5 259 | 260 | The following are the differences between MD4 and MD5: 261 | 262 | 1. A fourth round has been added. 263 | 264 | 2. Each step now has a unique additive constant. 265 | 266 | 3. The function g in round 2 was changed from (XY v XZ v YZ) to 267 | (XZ v Y not(Z)) to make g less symmetric. 268 | 269 | 4. Each step now adds in the result of the previous step. This 270 | promotes a faster "avalanche effect". 271 | 272 | 5. The order in which input words are accessed in rounds 2 and 273 | 3 is changed, to make these patterns less like each other. 274 | 275 | 6. The shift amounts in each round have been approximately 276 | optimized, to yield a faster "avalanche effect." The shifts in 277 | different rounds are distinct. 278 | 279 | References 280 | 281 | [1] Rivest, R., "The MD4 Message Digest Algorithm", RFC 1320, MIT and 282 | RSA Data Security, Inc., April 1992. 283 | 284 | [2] Rivest, R., "The MD4 message digest algorithm", in A.J. Menezes 285 | and S.A. Vanstone, editors, Advances in Cryptology - CRYPTO '90 286 | Proceedings, pages 303-311, Springer-Verlag, 1991. 287 | 288 | [3] CCITT Recommendation X.509 (1988), "The Directory - 289 | Authentication Framework." 290 | 291 | APPENDIX A - Reference Implementation 292 | 293 | This appendix contains the following files taken from RSAREF: A 294 | Cryptographic Toolkit for Privacy-Enhanced Mail: 295 | 296 | global.h -- global header file 297 | 298 | md5.h -- header file for MD5 299 | 300 | md5c.c -- source code for MD5 301 | 302 | For more information on RSAREF, send email to . 303 | 304 | The appendix also includes the following file: 305 | 306 | mddriver.c -- test driver for MD2, MD4 and MD5 307 | 308 | The driver compiles for MD5 by default but can compile for MD2 or MD4 309 | if the symbol MD is defined on the C compiler command line as 2 or 4. 310 | 311 | The implementation is portable and should work on many different 312 | plaforms. However, it is not difficult to optimize the implementation 313 | on particular platforms, an exercise left to the reader. For example, 314 | on "little-endian" platforms where the lowest-addressed byte in a 32- 315 | bit word is the least significant and there are no alignment 316 | restrictions, the call to Decode in MD5Transform can be replaced with 317 | a typecast. 318 | 319 | A.1 global.h 320 | 321 | /* GLOBAL.H - RSAREF types and constants 322 | */ 323 | 324 | /* PROTOTYPES should be set to one if and only if the compiler supports 325 | function argument prototyping. 326 | The following makes PROTOTYPES default to 0 if it has not already 327 | been defined with C compiler flags. 328 | */ 329 | #ifndef PROTOTYPES 330 | #define PROTOTYPES 0 331 | #endif 332 | 333 | /* POINTER defines a generic pointer type */ 334 | typedef unsigned char *POINTER; 335 | 336 | /* UINT2 defines a two byte word */ 337 | typedef unsigned short int UINT2; 338 | 339 | /* UINT4 defines a four byte word */ 340 | typedef unsigned long int UINT4; 341 | 342 | /* PROTO_LIST is defined depending on how PROTOTYPES is defined above. 343 | If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it 344 | returns an empty list. 345 | */ 346 | #if PROTOTYPES 347 | #define PROTO_LIST(list) list 348 | #else 349 | #define PROTO_LIST(list) () 350 | #endif 351 | 352 | A.2 md5.h 353 | 354 | /* MD5.H - header file for MD5C.C 355 | */ 356 | 357 | /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All 358 | rights reserved. 359 | 360 | License to copy and use this software is granted provided that it 361 | is identified as the "RSA Data Security, Inc. MD5 Message-Digest 362 | Algorithm" in all material mentioning or referencing this software 363 | or this function. 364 | 365 | License is also granted to make and use derivative works provided 366 | that such works are identified as "derived from the RSA Data 367 | Security, Inc. MD5 Message-Digest Algorithm" in all material 368 | mentioning or referencing the derived work. 369 | 370 | RSA Data Security, Inc. makes no representations concerning either 371 | the merchantability of this software or the suitability of this 372 | software for any particular purpose. It is provided "as is" 373 | without express or implied warranty of any kind. 374 | 375 | These notices must be retained in any copies of any part of this 376 | documentation and/or software. 377 | */ 378 | 379 | /* MD5 context. */ 380 | typedef struct { 381 | UINT4 state[4]; /* state (ABCD) */ 382 | UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ 383 | unsigned char buffer[64]; /* input buffer */ 384 | } MD5_CTX; 385 | 386 | void MD5Init PROTO_LIST ((MD5_CTX *)); 387 | void MD5Update PROTO_LIST 388 | ((MD5_CTX *, unsigned char *, unsigned int)); 389 | void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); 390 | 391 | A.3 md5c.c 392 | 393 | /* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm 394 | */ 395 | 396 | /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All 397 | rights reserved. 398 | 399 | License to copy and use this software is granted provided that it 400 | is identified as the "RSA Data Security, Inc. MD5 Message-Digest 401 | Algorithm" in all material mentioning or referencing this software 402 | or this function. 403 | 404 | License is also granted to make and use derivative works provided 405 | that such works are identified as "derived from the RSA Data 406 | Security, Inc. MD5 Message-Digest Algorithm" in all material 407 | mentioning or referencing the derived work. 408 | 409 | RSA Data Security, Inc. makes no representations concerning either 410 | the merchantability of this software or the suitability of this 411 | software for any particular purpose. It is provided "as is" 412 | without express or implied warranty of any kind. 413 | 414 | These notices must be retained in any copies of any part of this 415 | documentation and/or software. 416 | */ 417 | 418 | #include "global.h" 419 | #include "md5.h" 420 | 421 | /* Constants for MD5Transform routine. 422 | */ 423 | 424 | #define S11 7 425 | #define S12 12 426 | #define S13 17 427 | #define S14 22 428 | #define S21 5 429 | #define S22 9 430 | #define S23 14 431 | #define S24 20 432 | #define S31 4 433 | #define S32 11 434 | #define S33 16 435 | #define S34 23 436 | #define S41 6 437 | #define S42 10 438 | #define S43 15 439 | #define S44 21 440 | 441 | static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); 442 | static void Encode PROTO_LIST 443 | ((unsigned char *, UINT4 *, unsigned int)); 444 | static void Decode PROTO_LIST 445 | ((UINT4 *, unsigned char *, unsigned int)); 446 | static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); 447 | static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); 448 | 449 | static unsigned char PADDING[64] = { 450 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 451 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 452 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 453 | }; 454 | 455 | /* F, G, H and I are basic MD5 functions. 456 | */ 457 | #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) 458 | #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) 459 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 460 | #define I(x, y, z) ((y) ^ ((x) | (~z))) 461 | 462 | /* ROTATE_LEFT rotates x left n bits. 463 | */ 464 | #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) 465 | 466 | /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. 467 | Rotation is separate from addition to prevent recomputation. 468 | */ 469 | #define FF(a, b, c, d, x, s, ac) { \ 470 | (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ 471 | (a) = ROTATE_LEFT ((a), (s)); \ 472 | (a) += (b); \ 473 | } 474 | #define GG(a, b, c, d, x, s, ac) { \ 475 | (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ 476 | (a) = ROTATE_LEFT ((a), (s)); \ 477 | (a) += (b); \ 478 | } 479 | #define HH(a, b, c, d, x, s, ac) { \ 480 | (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ 481 | (a) = ROTATE_LEFT ((a), (s)); \ 482 | (a) += (b); \ 483 | } 484 | #define II(a, b, c, d, x, s, ac) { \ 485 | (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ 486 | (a) = ROTATE_LEFT ((a), (s)); \ 487 | (a) += (b); \ 488 | } 489 | 490 | /* MD5 initialization. Begins an MD5 operation, writing a new context. 491 | */ 492 | void MD5Init (context) 493 | MD5_CTX *context; /* context */ 494 | { 495 | context->count[0] = context->count[1] = 0; 496 | /* Load magic initialization constants. 497 | */ 498 | context->state[0] = 0x67452301; 499 | context->state[1] = 0xefcdab89; 500 | context->state[2] = 0x98badcfe; 501 | context->state[3] = 0x10325476; 502 | } 503 | 504 | /* MD5 block update operation. Continues an MD5 message-digest 505 | operation, processing another message block, and updating the 506 | context. 507 | */ 508 | void MD5Update (context, input, inputLen) 509 | MD5_CTX *context; /* context */ 510 | unsigned char *input; /* input block */ 511 | unsigned int inputLen; /* length of input block */ 512 | { 513 | unsigned int i, index, partLen; 514 | 515 | /* Compute number of bytes mod 64 */ 516 | index = (unsigned int)((context->count[0] >> 3) & 0x3F); 517 | 518 | /* Update number of bits */ 519 | if ((context->count[0] += ((UINT4)inputLen << 3)) 520 | < ((UINT4)inputLen << 3)) 521 | context->count[1]++; 522 | context->count[1] += ((UINT4)inputLen >> 29); 523 | 524 | partLen = 64 - index; 525 | 526 | /* Transform as many times as possible. 527 | */ 528 | if (inputLen >= partLen) { 529 | MD5_memcpy 530 | ((POINTER)&context->buffer[index], (POINTER)input, partLen); 531 | MD5Transform (context->state, context->buffer); 532 | 533 | for (i = partLen; i + 63 < inputLen; i += 64) 534 | MD5Transform (context->state, &input[i]); 535 | 536 | index = 0; 537 | } 538 | else 539 | i = 0; 540 | 541 | /* Buffer remaining input */ 542 | MD5_memcpy 543 | ((POINTER)&context->buffer[index], (POINTER)&input[i], 544 | inputLen-i); 545 | } 546 | 547 | /* MD5 finalization. Ends an MD5 message-digest operation, writing the 548 | the message digest and zeroizing the context. 549 | */ 550 | void MD5Final (digest, context) 551 | unsigned char digest[16]; /* message digest */ 552 | MD5_CTX *context; /* context */ 553 | { 554 | unsigned char bits[8]; 555 | unsigned int index, padLen; 556 | 557 | /* Save number of bits */ 558 | Encode (bits, context->count, 8); 559 | 560 | /* Pad out to 56 mod 64. 561 | */ 562 | index = (unsigned int)((context->count[0] >> 3) & 0x3f); 563 | padLen = (index < 56) ? (56 - index) : (120 - index); 564 | MD5Update (context, PADDING, padLen); 565 | 566 | /* Append length (before padding) */ 567 | MD5Update (context, bits, 8); 568 | 569 | /* Store state in digest */ 570 | Encode (digest, context->state, 16); 571 | 572 | /* Zeroize sensitive information. 573 | */ 574 | MD5_memset ((POINTER)context, 0, sizeof (*context)); 575 | } 576 | 577 | /* MD5 basic transformation. Transforms state based on block. 578 | */ 579 | static void MD5Transform (state, block) 580 | UINT4 state[4]; 581 | unsigned char block[64]; 582 | { 583 | UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; 584 | 585 | Decode (x, block, 64); 586 | 587 | /* Round 1 */ 588 | FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ 589 | FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ 590 | FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ 591 | FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ 592 | FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ 593 | FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ 594 | FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ 595 | FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ 596 | FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ 597 | FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ 598 | FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ 599 | FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ 600 | FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ 601 | FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ 602 | FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ 603 | FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ 604 | 605 | /* Round 2 */ 606 | GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ 607 | GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ 608 | GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ 609 | GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ 610 | GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ 611 | GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ 612 | GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ 613 | GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ 614 | GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ 615 | GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ 616 | GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ 617 | GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ 618 | GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ 619 | GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ 620 | GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ 621 | GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ 622 | 623 | /* Round 3 */ 624 | HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ 625 | HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ 626 | HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ 627 | HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ 628 | HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ 629 | HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ 630 | HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ 631 | HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ 632 | HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ 633 | HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ 634 | HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ 635 | HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ 636 | HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ 637 | HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ 638 | HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ 639 | HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ 640 | 641 | /* Round 4 */ 642 | II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ 643 | II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ 644 | II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ 645 | II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ 646 | II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ 647 | II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ 648 | II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ 649 | II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ 650 | II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ 651 | II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ 652 | II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ 653 | II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ 654 | II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ 655 | II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ 656 | II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ 657 | II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ 658 | 659 | state[0] += a; 660 | state[1] += b; 661 | state[2] += c; 662 | state[3] += d; 663 | 664 | /* Zeroize sensitive information. 665 | */ 666 | MD5_memset ((POINTER)x, 0, sizeof (x)); 667 | } 668 | 669 | /* Encodes input (UINT4) into output (unsigned char). Assumes len is 670 | a multiple of 4. 671 | */ 672 | static void Encode (output, input, len) 673 | unsigned char *output; 674 | UINT4 *input; 675 | unsigned int len; 676 | { 677 | unsigned int i, j; 678 | 679 | for (i = 0, j = 0; j < len; i++, j += 4) { 680 | output[j] = (unsigned char)(input[i] & 0xff); 681 | output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); 682 | output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); 683 | output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); 684 | } 685 | } 686 | 687 | /* Decodes input (unsigned char) into output (UINT4). Assumes len is 688 | a multiple of 4. 689 | */ 690 | static void Decode (output, input, len) 691 | UINT4 *output; 692 | unsigned char *input; 693 | unsigned int len; 694 | { 695 | unsigned int i, j; 696 | 697 | for (i = 0, j = 0; j < len; i++, j += 4) 698 | output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | 699 | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); 700 | } 701 | 702 | /* Note: Replace "for loop" with standard memcpy if possible. 703 | */ 704 | 705 | static void MD5_memcpy (output, input, len) 706 | POINTER output; 707 | POINTER input; 708 | unsigned int len; 709 | { 710 | unsigned int i; 711 | 712 | for (i = 0; i < len; i++) 713 | 714 | output[i] = input[i]; 715 | } 716 | 717 | /* Note: Replace "for loop" with standard memset if possible. 718 | */ 719 | static void MD5_memset (output, value, len) 720 | POINTER output; 721 | int value; 722 | unsigned int len; 723 | { 724 | unsigned int i; 725 | 726 | for (i = 0; i < len; i++) 727 | ((char *)output)[i] = (char)value; 728 | } 729 | 730 | A.4 mddriver.c 731 | 732 | /* MDDRIVER.C - test driver for MD2, MD4 and MD5 733 | */ 734 | 735 | /* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All 736 | rights reserved. 737 | 738 | RSA Data Security, Inc. makes no representations concerning either 739 | the merchantability of this software or the suitability of this 740 | software for any particular purpose. It is provided "as is" 741 | without express or implied warranty of any kind. 742 | 743 | These notices must be retained in any copies of any part of this 744 | documentation and/or software. 745 | */ 746 | 747 | /* The following makes MD default to MD5 if it has not already been 748 | defined with C compiler flags. 749 | */ 750 | #ifndef MD 751 | #define MD MD5 752 | #endif 753 | 754 | #include 755 | #include 756 | #include 757 | #include "global.h" 758 | #if MD == 2 759 | #include "md2.h" 760 | #endif 761 | #if MD == 4 762 | #include "md4.h" 763 | #endif 764 | #if MD == 5 765 | #include "md5.h" 766 | #endif 767 | 768 | /* Length of test block, number of test blocks. 769 | */ 770 | #define TEST_BLOCK_LEN 1000 771 | #define TEST_BLOCK_COUNT 1000 772 | 773 | static void MDString PROTO_LIST ((char *)); 774 | static void MDTimeTrial PROTO_LIST ((void)); 775 | static void MDTestSuite PROTO_LIST ((void)); 776 | static void MDFile PROTO_LIST ((char *)); 777 | static void MDFilter PROTO_LIST ((void)); 778 | static void MDPrint PROTO_LIST ((unsigned char [16])); 779 | 780 | #if MD == 2 781 | #define MD_CTX MD2_CTX 782 | #define MDInit MD2Init 783 | #define MDUpdate MD2Update 784 | #define MDFinal MD2Final 785 | #endif 786 | #if MD == 4 787 | #define MD_CTX MD4_CTX 788 | #define MDInit MD4Init 789 | #define MDUpdate MD4Update 790 | #define MDFinal MD4Final 791 | #endif 792 | #if MD == 5 793 | #define MD_CTX MD5_CTX 794 | #define MDInit MD5Init 795 | #define MDUpdate MD5Update 796 | #define MDFinal MD5Final 797 | #endif 798 | 799 | /* Main driver. 800 | 801 | Arguments (may be any combination): 802 | -sstring - digests string 803 | -t - runs time trial 804 | -x - runs test script 805 | filename - digests file 806 | (none) - digests standard input 807 | */ 808 | int main (argc, argv) 809 | int argc; 810 | char *argv[]; 811 | { 812 | int i; 813 | 814 | if (argc > 1) 815 | for (i = 1; i < argc; i++) 816 | if (argv[i][0] == '-' && argv[i][1] == 's') 817 | MDString (argv[i] + 2); 818 | else if (strcmp (argv[i], "-t") == 0) 819 | MDTimeTrial (); 820 | else if (strcmp (argv[i], "-x") == 0) 821 | MDTestSuite (); 822 | else 823 | MDFile (argv[i]); 824 | else 825 | MDFilter (); 826 | 827 | return (0); 828 | } 829 | 830 | /* Digests a string and prints the result. 831 | */ 832 | static void MDString (string) 833 | char *string; 834 | { 835 | MD_CTX context; 836 | unsigned char digest[16]; 837 | unsigned int len = strlen (string); 838 | 839 | MDInit (&context); 840 | MDUpdate (&context, string, len); 841 | MDFinal (digest, &context); 842 | 843 | printf ("MD%d (\"%s\") = ", MD, string); 844 | MDPrint (digest); 845 | printf ("\n"); 846 | } 847 | 848 | /* Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte 849 | blocks. 850 | */ 851 | static void MDTimeTrial () 852 | { 853 | MD_CTX context; 854 | time_t endTime, startTime; 855 | unsigned char block[TEST_BLOCK_LEN], digest[16]; 856 | unsigned int i; 857 | 858 | printf 859 | ("MD%d time trial. Digesting %d %d-byte blocks ...", MD, 860 | TEST_BLOCK_LEN, TEST_BLOCK_COUNT); 861 | 862 | /* Initialize block */ 863 | for (i = 0; i < TEST_BLOCK_LEN; i++) 864 | block[i] = (unsigned char)(i & 0xff); 865 | 866 | /* Start timer */ 867 | time (&startTime); 868 | 869 | /* Digest blocks */ 870 | MDInit (&context); 871 | for (i = 0; i < TEST_BLOCK_COUNT; i++) 872 | MDUpdate (&context, block, TEST_BLOCK_LEN); 873 | MDFinal (digest, &context); 874 | 875 | /* Stop timer */ 876 | time (&endTime); 877 | 878 | printf (" done\n"); 879 | printf ("Digest = "); 880 | MDPrint (digest); 881 | printf ("\nTime = %ld seconds\n", (long)(endTime-startTime)); 882 | printf 883 | ("Speed = %ld bytes/second\n", 884 | (long)TEST_BLOCK_LEN * (long)TEST_BLOCK_COUNT/(endTime-startTime)); 885 | } 886 | 887 | /* Digests a reference suite of strings and prints the results. 888 | */ 889 | static void MDTestSuite () 890 | { 891 | printf ("MD%d test suite:\n", MD); 892 | 893 | MDString (""); 894 | MDString ("a"); 895 | MDString ("abc"); 896 | MDString ("message digest"); 897 | MDString ("abcdefghijklmnopqrstuvwxyz"); 898 | MDString 899 | ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); 900 | MDString 901 | ("1234567890123456789012345678901234567890\ 902 | 1234567890123456789012345678901234567890"); 903 | } 904 | 905 | /* Digests a file and prints the result. 906 | */ 907 | static void MDFile (filename) 908 | char *filename; 909 | { 910 | FILE *file; 911 | MD_CTX context; 912 | int len; 913 | unsigned char buffer[1024], digest[16]; 914 | 915 | if ((file = fopen (filename, "rb")) == NULL) 916 | printf ("%s can't be opened\n", filename); 917 | 918 | else { 919 | MDInit (&context); 920 | while (len = fread (buffer, 1, 1024, file)) 921 | MDUpdate (&context, buffer, len); 922 | MDFinal (digest, &context); 923 | 924 | fclose (file); 925 | 926 | printf ("MD%d (%s) = ", MD, filename); 927 | MDPrint (digest); 928 | printf ("\n"); 929 | } 930 | } 931 | 932 | /* Digests the standard input and prints the result. 933 | */ 934 | static void MDFilter () 935 | { 936 | MD_CTX context; 937 | int len; 938 | unsigned char buffer[16], digest[16]; 939 | 940 | MDInit (&context); 941 | while (len = fread (buffer, 1, 16, stdin)) 942 | MDUpdate (&context, buffer, len); 943 | MDFinal (digest, &context); 944 | 945 | MDPrint (digest); 946 | printf ("\n"); 947 | } 948 | 949 | /* Prints a message digest in hexadecimal. 950 | */ 951 | static void MDPrint (digest) 952 | unsigned char digest[16]; 953 | { 954 | unsigned int i; 955 | 956 | for (i = 0; i < 16; i++) 957 | printf ("%02x", digest[i]); 958 | } 959 | 960 | A.5 Test suite 961 | 962 | The MD5 test suite (driver option "-x") should print the following 963 | results: 964 | 965 | MD5 test suite: 966 | MD5 ("") = d41d8cd98f00b204e9800998ecf8427e 967 | MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661 968 | MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72 969 | MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0 970 | MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b 971 | MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = 972 | d174ab98d277d9f5a5611c2c9f419d9f 973 | MD5 ("123456789012345678901234567890123456789012345678901234567890123456 974 | 78901234567890") = 57edf4a22be3c955ac49da2e2107b67a 975 | 976 | Security Considerations 977 | 978 | The level of security discussed in this memo is considered to be 979 | sufficient for implementing very high security hybrid digital- 980 | signature schemes based on MD5 and a public-key cryptosystem. 981 | 982 | Author's Address 983 | 984 | Ronald L. Rivest 985 | Massachusetts Institute of Technology 986 | Laboratory for Computer Science 987 | NE43-324 988 | 545 Technology Square 989 | Cambridge, MA 02139-1986 990 | 991 | Phone: (617) 253-5880 992 | EMail: rivest@theory.lcs.mit.edu 993 | -------------------------------------------------------------------------------- /md5_lib/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | SET(CMAKE_CXX_FLAGS " -g -Wall -o2") 2 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 3 | SET(md5_lib_path ${PROJECT_SOURCE_DIR}/lib) 4 | SET(md5_src_path ${PROJECT_SOURCE_DIR}/src) 5 | 6 | INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include) 7 | 8 | AUX_SOURCE_DIRECTORY(${md5_src_path} X_SRC) 9 | ADD_LIBRARY(md5 STATIC ${X_SRC}) 10 | 11 | SET_TARGET_PROPERTIES(md5 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${md5_lib_path}") 12 | -------------------------------------------------------------------------------- /md5_lib/src/md5.cpp: -------------------------------------------------------------------------------- 1 | /* MD5 2 | converted to C++ class by Frank Thilo (thilo@unix-ag.org) 3 | for bzflag (http://www.bzflag.org) 4 | 5 | based on: 6 | 7 | md5.h and md5.c 8 | reference implemantion of RFC 1321 9 | 10 | Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All 11 | rights reserved. 12 | 13 | License to copy and use this software is granted provided that it 14 | is identified as the "RSA Data Security, Inc. MD5 Message-Digest 15 | Algorithm" in all material mentioning or referencing this software 16 | or this function. 17 | 18 | License is also granted to make and use derivative works provided 19 | that such works are identified as "derived from the RSA Data 20 | Security, Inc. MD5 Message-Digest Algorithm" in all material 21 | mentioning or referencing the derived work. 22 | 23 | RSA Data Security, Inc. makes no representations concerning either 24 | the merchantability of this software or the suitability of this 25 | software for any particular purpose. It is provided "as is" 26 | without express or implied warranty of any kind. 27 | 28 | These notices must be retained in any copies of any part of this 29 | documentation and/or software. 30 | 31 | */ 32 | 33 | /* interface header */ 34 | #include "md5.h" 35 | 36 | /* system implementation headers */ 37 | #include 38 | 39 | /////////////////////////////////////////////// 40 | 41 | // F, G, H and I are basic MD5 functions. 42 | inline MD5::uint4 MD5::F(uint4 x, uint4 y, uint4 z) { 43 | return (x & y) | (~x & z); 44 | } 45 | 46 | inline MD5::uint4 MD5::G(uint4 x, uint4 y, uint4 z) { 47 | return (x & z) | (y & ~z); 48 | } 49 | 50 | inline MD5::uint4 MD5::H(uint4 x, uint4 y, uint4 z) { 51 | return x ^ y ^ z; 52 | } 53 | 54 | inline MD5::uint4 MD5::I(uint4 x, uint4 y, uint4 z) { 55 | return y ^ (x | ~z); 56 | } 57 | 58 | // rotate_left rotates x left n bits. 59 | inline MD5::uint4 MD5::rotate_left(uint4 x, int n) { 60 | return (x << n) | (x >> (32 - n)); 61 | } 62 | 63 | // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. 64 | // Rotation is separate from addition to prevent recomputation. 65 | inline void MD5::FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { 66 | a = rotate_left(a + F(b, c, d) + x + ac, s) + b; 67 | } 68 | 69 | inline void MD5::GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { 70 | a = rotate_left(a + G(b, c, d) + x + ac, s) + b; 71 | } 72 | 73 | inline void MD5::HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { 74 | a = rotate_left(a + H(b, c, d) + x + ac, s) + b; 75 | } 76 | 77 | inline void MD5::II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { 78 | a = rotate_left(a + I(b, c, d) + x + ac, s) + b; 79 | } 80 | 81 | ////////////////////////////////////////////// 82 | 83 | // default ctor, just initailize 84 | MD5::MD5() { 85 | init(); 86 | } 87 | 88 | ////////////////////////////////////////////// 89 | 90 | // nifty shortcut ctor, compute MD5 for string and finalize it right away 91 | MD5::MD5(const std::string &text) { 92 | init(); 93 | update(text.c_str(), text.length()); 94 | finalize(); 95 | } 96 | 97 | ////////////////////////////// 98 | 99 | void MD5::init() { 100 | finalized = false; 101 | 102 | count[0] = 0; 103 | count[1] = 0; 104 | } 105 | 106 | ////////////////////////////// 107 | 108 | // decodes input (unsigned char) into output (uint4). Assumes len is a multiple of 4. 109 | void MD5::decode(uint4 output[], const uint1 input[], size_type len) { 110 | for (unsigned int i = 0, j = 0; j < len; i++, j += 4) 111 | output[i] = ((uint4) input[j]) | (((uint4) input[j + 1]) << 8) | (((uint4) input[j + 2]) << 16) 112 | | (((uint4) input[j + 3]) << 24); 113 | } 114 | 115 | ////////////////////////////// 116 | 117 | // encodes input (uint4) into output (unsigned char). Assumes len is 118 | // a multiple of 4. 119 | void MD5::encode(uint1 output[], const uint4 input[], size_type len) { 120 | for (size_type i = 0, j = 0; j < len; i++, j += 4) { 121 | output[j] = input[i] & 0xff; 122 | output[j + 1] = (input[i] >> 8) & 0xff; 123 | output[j + 2] = (input[i] >> 16) & 0xff; 124 | output[j + 3] = (input[i] >> 24) & 0xff; 125 | } 126 | } 127 | 128 | ////////////////////////////// 129 | 130 | // apply MD5 algo on a block 131 | void MD5::transform(const uint1 block[blocksize]) { 132 | uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; 133 | decode(x, block, blocksize); 134 | 135 | /* Round 1 */ 136 | FF(a, b, c, d, x[0], S1[0], T[0]); /* 1 */ 137 | FF(d, a, b, c, x[1], S1[1], T[1]); /* 2 */ 138 | FF(c, d, a, b, x[2], S1[2], T[2]); /* 3 */ 139 | FF(b, c, d, a, x[3], S1[3], T[3]); /* 4 */ 140 | FF(a, b, c, d, x[4], S1[0], T[4]); /* 5 */ 141 | FF(d, a, b, c, x[5], S1[1], T[5]); /* 6 */ 142 | FF(c, d, a, b, x[6], S1[2], T[6]); /* 7 */ 143 | FF(b, c, d, a, x[7], S1[3], T[7]); /* 8 */ 144 | FF(a, b, c, d, x[8], S1[0], T[8]); /* 9 */ 145 | FF(d, a, b, c, x[9], S1[1], T[9]); /* 10 */ 146 | FF(c, d, a, b, x[10], S1[2], T[10]); /* 11 */ 147 | FF(b, c, d, a, x[11], S1[3], T[11]); /* 12 */ 148 | FF(a, b, c, d, x[12], S1[0], T[12]); /* 13 */ 149 | FF(d, a, b, c, x[13], S1[1], T[13]); /* 14 */ 150 | FF(c, d, a, b, x[14], S1[2], T[14]); /* 15 */ 151 | FF(b, c, d, a, x[15], S1[3], T[15]); /* 16 */ 152 | 153 | /* Round 2 */ 154 | GG(a, b, c, d, x[1], S2[0], T[16]); /* 17 */ 155 | GG(d, a, b, c, x[6], S2[1], T[17]); /* 18 */ 156 | GG(c, d, a, b, x[11], S2[2], T[18]); /* 19 */ 157 | GG(b, c, d, a, x[0], S2[3], T[19]); /* 20 */ 158 | GG(a, b, c, d, x[5], S2[0], T[20]); /* 21 */ 159 | GG(d, a, b, c, x[10], S2[1], T[21]); /* 22 */ 160 | GG(c, d, a, b, x[15], S2[2], T[22]); /* 23 */ 161 | GG(b, c, d, a, x[4], S2[3], T[23]); /* 24 */ 162 | GG(a, b, c, d, x[9], S2[0], T[24]); /* 25 */ 163 | GG(d, a, b, c, x[14], S2[1], T[25]); /* 26 */ 164 | GG(c, d, a, b, x[3], S2[2], T[26]); /* 27 */ 165 | GG(b, c, d, a, x[8], S2[3], T[27]); /* 28 */ 166 | GG(a, b, c, d, x[13], S2[0], T[28]); /* 29 */ 167 | GG(d, a, b, c, x[2], S2[1], T[29]); /* 30 */ 168 | GG(c, d, a, b, x[7], S2[2], T[30]); /* 31 */ 169 | GG(b, c, d, a, x[12], S2[3], T[31]); /* 32 */ 170 | 171 | /* Round 3 */ 172 | HH(a, b, c, d, x[5], S3[0], T[32]); /* 33 */ 173 | HH(d, a, b, c, x[8], S3[1], T[33]); /* 34 */ 174 | HH(c, d, a, b, x[11], S3[2], T[34]); /* 35 */ 175 | HH(b, c, d, a, x[14], S3[3], T[35]); /* 36 */ 176 | HH(a, b, c, d, x[1], S3[0], T[36]); /* 37 */ 177 | HH(d, a, b, c, x[4], S3[1], T[37]); /* 38 */ 178 | HH(c, d, a, b, x[7], S3[2], T[38]); /* 39 */ 179 | HH(b, c, d, a, x[10], S3[3], T[39]); /* 40 */ 180 | HH(a, b, c, d, x[13], S3[0], T[40]); /* 41 */ 181 | HH(d, a, b, c, x[0], S3[1], T[41]); /* 42 */ 182 | HH(c, d, a, b, x[3], S3[2], T[42]); /* 43 */ 183 | HH(b, c, d, a, x[6], S3[3], T[43]); /* 44 */ 184 | HH(a, b, c, d, x[9], S3[0], T[44]); /* 45 */ 185 | HH(d, a, b, c, x[12], S3[1], T[45]); /* 46 */ 186 | HH(c, d, a, b, x[15], S3[2], T[46]); /* 47 */ 187 | HH(b, c, d, a, x[2], S3[3], T[47]); /* 48 */ 188 | 189 | /* Round 4 */ 190 | II(a, b, c, d, x[0], S4[0], T[48]); /* 49 */ 191 | II(d, a, b, c, x[7], S4[1], T[49]); /* 50 */ 192 | II(c, d, a, b, x[14], S4[2], T[50]); /* 51 */ 193 | II(b, c, d, a, x[5], S4[3], T[51]); /* 52 */ 194 | II(a, b, c, d, x[12], S4[0], T[52]); /* 53 */ 195 | II(d, a, b, c, x[3], S4[1], T[53]); /* 54 */ 196 | II(c, d, a, b, x[10], S4[2], T[54]); /* 55 */ 197 | II(b, c, d, a, x[1], S4[3], T[55]); /* 56 */ 198 | II(a, b, c, d, x[8], S4[0], T[56]); /* 57 */ 199 | II(d, a, b, c, x[15], S4[1], T[57]); /* 58 */ 200 | II(c, d, a, b, x[6], S4[2], T[58]); /* 59 */ 201 | II(b, c, d, a, x[13], S4[3], T[59]); /* 60 */ 202 | II(a, b, c, d, x[4], S4[0], T[60]); /* 61 */ 203 | II(d, a, b, c, x[11], S4[1], T[61]); /* 62 */ 204 | II(c, d, a, b, x[2], S4[2], T[62]); /* 63 */ 205 | II(b, c, d, a, x[9], S4[3], T[63]); /* 64 */ 206 | 207 | state[0] += a; 208 | state[1] += b; 209 | state[2] += c; 210 | state[3] += d; 211 | 212 | // Zeroize sensitive information. 213 | memset(x, 0, sizeof x); 214 | } 215 | 216 | ////////////////////////////// 217 | 218 | // MD5 block update operation. Continues an MD5 message-digest 219 | // operation, processing another message block 220 | void MD5::update(const unsigned char input[], size_type length) { 221 | // compute number of bytes mod 64 222 | size_type index = count[0] / 8 % blocksize; 223 | 224 | // Update number of bits 225 | if ((count[0] += (length << 3)) < (length << 3)) { 226 | count[1]++; 227 | } 228 | 229 | count[1] += (length >> 29); 230 | 231 | // number of bytes we need to fill in buffer 232 | size_type firstpart = 64 - index; 233 | 234 | size_type i; 235 | 236 | // transform as many times as possible. 237 | if (length >= firstpart) { 238 | // fill buffer first, transform 239 | memcpy(&buffer[index], input, firstpart); 240 | transform(buffer); 241 | 242 | // transform chunks of blocksize (64 bytes) 243 | for (i = firstpart; i + blocksize <= length; i += blocksize) { 244 | transform(&input[i]); 245 | } 246 | 247 | index = 0; 248 | } else 249 | i = 0; 250 | 251 | // buffer remaining input 252 | memcpy(&buffer[index], &input[i], length - i); 253 | } 254 | 255 | ////////////////////////////// 256 | 257 | // for convenience provide a verson with signed char 258 | void MD5::update(const char input[], size_type length) { 259 | update((const unsigned char*) input, length); 260 | } 261 | 262 | ////////////////////////////// 263 | 264 | // MD5 finalization. Ends an MD5 message-digest operation, writing the 265 | // the message digest and zeroizing the context. 266 | MD5& MD5::finalize() { 267 | static unsigned char padding[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 268 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 269 | 0, 0, 0 }; 270 | 271 | if (!finalized) { 272 | // Save number of bits 273 | unsigned char bits[8]; 274 | encode(bits, count, 8); 275 | 276 | // pad out to 56 mod 64. 277 | size_type index = count[0] / 8 % 64; 278 | size_type padLen = (index < 56) ? (56 - index) : (120 - index); 279 | update(padding, padLen); 280 | 281 | // Append length (before padding) 282 | update(bits, 8); 283 | 284 | // Store state in digest 285 | encode(digest, state, 16); 286 | 287 | // Zeroize sensitive information. 288 | memset(buffer, 0, sizeof buffer); 289 | memset(count, 0, sizeof count); 290 | 291 | finalized = true; 292 | } 293 | 294 | return *this; 295 | } 296 | 297 | ////////////////////////////// 298 | 299 | // return hex representation of digest as string 300 | std::string MD5::hexdigest() const { 301 | if (!finalized) { 302 | return ""; 303 | } 304 | 305 | char buf[33]; 306 | for (int i = 0; i < 16; i++) { 307 | snprintf(buf + i * 2, sizeof(buf) - i * 2, "%02x", digest[i]); 308 | } 309 | 310 | return std::string(buf); 311 | } 312 | 313 | ////////////////////////////// 314 | 315 | std::ostream& operator<<(std::ostream& out, MD5 md5) { 316 | return out << md5.hexdigest(); 317 | } 318 | 319 | ////////////////////////////// 320 | 321 | std::string md5(const std::string str) { 322 | MD5 md5 = MD5(str); 323 | return md5.hexdigest(); 324 | } 325 | -------------------------------------------------------------------------------- /md5_lib/test/demo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcc0lin/dirty_algorithm/50c8276dcd65b5a8e23f78cf83e87df41d414358/md5_lib/test/demo -------------------------------------------------------------------------------- /md5_lib/test/demo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "md5.h" 3 | using namespace std; 4 | 5 | int main(int argc, char *argv[]) { 6 | if (argc != 2) { 7 | cout << "usage: ./demo string" << endl; 8 | } else { 9 | cout << "md5 of '" << argv[1] << "': " << md5(argv[1]) << endl; 10 | } 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /md5_lib/test/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | g++ demo.cpp -I../include/ -L../lib ../lib/libmd5.a -o demo 3 | clean: 4 | rm demo -------------------------------------------------------------------------------- /rc5_lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | add_subdirectory(src) 4 | -------------------------------------------------------------------------------- /rc5_lib/README.md: -------------------------------------------------------------------------------- 1 | 基于c++实现的MD5算法库 2 | 3 | ## 使用说明 4 | 5 | 基于`cmake`编译,切换到`build`目录,执行脚本`./run.sh`即可在`lib`目录生成静态库`libmd5.a` 6 | 7 | 使用时只需要引入对应的头文件,然后就可以调用`md5`函数了。 8 | ```cpp 9 | #include "md5.h" 10 | 11 | md5(string) 12 | ``` 13 | 14 | ## 测试 15 | 切换到`test`目录下,执行`make`命令生成`demo`的可执行程序 16 | 17 | ```bash 18 | > echo -n "tcc0lin" | md5 19 | edf2ef5bfb48ca2b5f0d69a9bd47ac53 20 | > ./demo "tcc0lin" 21 | md5 of 'tcc0lin': edf2ef5bfb48ca2b5f0d69a9bd47ac53 22 | ``` -------------------------------------------------------------------------------- /rc5_lib/bulid/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -f ./run.sh ../run.sh; 4 | rm -rf *; 5 | cp -f ../run.sh ./run.sh; 6 | rm -f ../run.sh; 7 | cmake ../; 8 | make; 9 | make install; 10 | cp -f ./run.sh ../run.sh; 11 | rm -rf *; 12 | cp -f ../run.sh ./run.sh; 13 | rm -f ../run.sh; -------------------------------------------------------------------------------- /rc5_lib/include/rc5.h: -------------------------------------------------------------------------------- 1 | #ifndef __RC5SIMPLE_H__ 2 | #define __RC5SIMPLE_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | #define RC5_SIMPLE_VERSION "RC5Simple Ver. 1.30 / 11.12.2013" 16 | 17 | #define RC5_FORMAT_VERSION_1 1 18 | #define RC5_FORMAT_VERSION_2 2 19 | #define RC5_FORMAT_VERSION_3 3 20 | #define RC5_FORMAT_VERSION_CURRENT RC5_FORMAT_VERSION_3 21 | 22 | #define RC5_SIMPLE_SIGNATURE "RC5SIMP" // Strong 7 bytes 23 | 24 | // For detect 32 or 64 architecture, this code checked LONG_BIT definition. 25 | // In *NIX GCC this definition is present. 26 | // In Windows is uncertain. 27 | // Try, if need, set this definition at this place. 28 | // Sample: 29 | // #define LONG_BIT 64 30 | 31 | // If undestand enviroments 32 | #ifndef LONG_BIT 33 | 34 | typedef unsigned long int RC5_TWORD; 35 | #define RC5_ARCHITECTURE 32 36 | 37 | #else 38 | // Else definition LONG_BIT is presents 39 | 40 | #if LONG_BIT==32 41 | typedef unsigned long int RC5_TWORD; 42 | #define RC5_ARCHITECTURE 32 43 | #endif 44 | 45 | #if LONG_BIT==64 46 | typedef unsigned int RC5_TWORD; 47 | #define RC5_ARCHITECTURE 64 48 | #endif 49 | 50 | #endif 51 | 52 | #ifndef RC5_ARCHITECTURE 53 | #error CAN NOT DETECT MICROPROCESSOR ARCHITECTURE 54 | #endif 55 | 56 | 57 | #define RC5_W 32 // word size in bits 58 | #define RC5_R 12 // number of rounds 59 | #define RC5_B 16 // number of bytes in key 60 | #define RC5_C 4 // number words in key = ceil(8*b/rc5_w) 61 | #define RC5_T 26 // size of table S = 2*(r+1) words 62 | 63 | #define RC5_WORDS_IN_BLOCK 2 // words in block 64 | #define RC5_BLOCK_LEN (RC5_W*RC5_WORDS_IN_BLOCK/8) // block size in bytes 65 | #define RC5_WORD_LEN (RC5_W/8) // word size in bytes 66 | 67 | // Rotation operators. x must be unsigned, to get logical right shift 68 | #define RC5_ROTL(x,y) (((x)<<(y&(RC5_W-1))) | ((x)>>(RC5_W-(y&(RC5_W-1))))) 69 | #define RC5_ROTR(x,y) (((x)>>(y&(RC5_W-1))) | ((x)<<(RC5_W-(y&(RC5_W-1))))) 70 | 71 | #define RC5_MODE_ENCODE 0 72 | #define RC5_MODE_DECODE 1 73 | 74 | #define RC5_ERROR_CODE_1 1 // Bad RC5 key length 75 | #define RC5_ERROR_CODE_2 2 // Can't read input file 76 | #define RC5_ERROR_CODE_3 3 // Input file is empty 77 | #define RC5_ERROR_CODE_4 4 // Can't create output file 78 | #define RC5_ERROR_CODE_5 5 // Can't encrypt null data 79 | #define RC5_ERROR_CODE_6 6 // Can't decrypt null data 80 | #define RC5_ERROR_CODE_7 7 // Incorrect data size for decrypt data 81 | 82 | // Debugging log to console 83 | // 0 - disable debug print 84 | // 1 - enable debug print 85 | #define RC5_ENABLE_DEBUG_PRINT 0 86 | 87 | #if RC5_ENABLE_DEBUG_PRINT==1 88 | #define RC5_LOG(X) RC5_LogPrint X 89 | #else 90 | #define RC5_LOG(X) 91 | #endif 92 | 93 | 94 | class RC5Simple 95 | { 96 | 97 | public: 98 | RC5Simple(bool enableRandomInit=false); 99 | virtual ~RC5Simple(); 100 | 101 | const char *RC5_GetVersion(void); 102 | 103 | void RC5_EncryptBlock(RC5_TWORD *pt, RC5_TWORD *ct); 104 | void RC5_DecryptBlock(RC5_TWORD *ct, RC5_TWORD *pt); 105 | void RC5_Setup(unsigned char *key); 106 | 107 | void RC5_SetKey(vector &key); 108 | void RC5_SetFormatVersionForce(unsigned char formatVersion); 109 | void RC5_Encrypt(vector &in, vector &out); 110 | void RC5_Decrypt(vector &in, vector &out); 111 | 112 | void RC5_EncryptFile(unsigned char *in_name, unsigned char *out_name); 113 | void RC5_EncryptFile(const char *in_name, const char *out_name); 114 | 115 | void RC5_DecryptFile(unsigned char *in_name, unsigned char *out_name); 116 | void RC5_DecryptFile(const char *in_name, const char *out_name); 117 | 118 | void RC5_EncDecFile(unsigned char *in_name, unsigned char *out_name, int mode); 119 | 120 | unsigned int RC5_GetErrorCode(); 121 | 122 | private: 123 | 124 | RC5_TWORD rc5_s[RC5_T]; // Expanded key table 125 | RC5_TWORD rc5_p; // Magic constants one 126 | RC5_TWORD rc5_q; // Magic constants two 127 | 128 | unsigned char rc5_key[RC5_B]; 129 | unsigned char rc5_formatVersion; 130 | bool rc5_isSetFormatVersionForce; 131 | 132 | unsigned int errorCode; 133 | 134 | inline unsigned char RC5_GetByteFromWord(RC5_TWORD w, int n); 135 | inline unsigned char RC5_GetByteFromInt(unsigned int l, int n); 136 | inline unsigned int RC5_GetIntFromByte(unsigned char b0, 137 | unsigned char b1, 138 | unsigned char b2, 139 | unsigned char b3); 140 | inline RC5_TWORD RC5_GetWordFromByte(unsigned char b0, 141 | unsigned char b1, 142 | unsigned char b2, 143 | unsigned char b3); 144 | 145 | void RC5_EncDec(vector &in, vector &out, int mode); 146 | 147 | unsigned int RC5_Rand(unsigned int from, unsigned int to); 148 | 149 | void RC5_LogPrint(char *lpszText, ...); 150 | }; 151 | 152 | #endif // __RC5SIMPLE_H__ -------------------------------------------------------------------------------- /rc5_lib/rfc1321.txt: -------------------------------------------------------------------------------- 1 | Network Working Group R. Rivest 2 | Request for Comments: 1321 MIT Laboratory for Computer Science 3 | and RSA Data Security, Inc. 4 | April 1992 5 | 6 | The MD5 Message-Digest Algorithm 7 | 8 | Status of this Memo 9 | 10 | This memo provides information for the Internet community. It does 11 | not specify an Internet standard. Distribution of this memo is 12 | unlimited. 13 | 14 | Acknowlegements 15 | 16 | We would like to thank Don Coppersmith, Burt Kaliski, Ralph Merkle, 17 | David Chaum, and Noam Nisan for numerous helpful comments and 18 | suggestions. 19 | 20 | Table of Contents 21 | 22 | 1. Executive Summary 1 23 | 2. Terminology and Notation 2 24 | 3. MD5 Algorithm Description 3 25 | 4. Summary 6 26 | 5. Differences Between MD4 and MD5 6 27 | References 7 28 | APPENDIX A - Reference Implementation 7 29 | Security Considerations 21 30 | Author's Address 21 31 | 32 | 1. Executive Summary 33 | 34 | This document describes the MD5 message-digest algorithm. The 35 | algorithm takes as input a message of arbitrary length and produces 36 | as output a 128-bit "fingerprint" or "message digest" of the input. 37 | It is conjectured that it is computationally infeasible to produce 38 | two messages having the same message digest, or to produce any 39 | message having a given prespecified target message digest. The MD5 40 | algorithm is intended for digital signature applications, where a 41 | large file must be "compressed" in a secure manner before being 42 | encrypted with a private (secret) key under a public-key cryptosystem 43 | such as RSA. 44 | 45 | The MD5 algorithm is designed to be quite fast on 32-bit machines. In 46 | addition, the MD5 algorithm does not require any large substitution 47 | tables; the algorithm can be coded quite compactly. 48 | 49 | The MD5 algorithm is an extension of the MD4 message-digest algorithm 50 | 1,2]. MD5 is slightly slower than MD4, but is more "conservative" in 51 | design. MD5 was designed because it was felt that MD4 was perhaps 52 | being adopted for use more quickly than justified by the existing 53 | critical review; because MD4 was designed to be exceptionally fast, 54 | it is "at the edge" in terms of risking successful cryptanalytic 55 | attack. MD5 backs off a bit, giving up a little in speed for a much 56 | greater likelihood of ultimate security. It incorporates some 57 | suggestions made by various reviewers, and contains additional 58 | optimizations. The MD5 algorithm is being placed in the public domain 59 | for review and possible adoption as a standard. 60 | 61 | For OSI-based applications, MD5's object identifier is 62 | 63 | md5 OBJECT IDENTIFIER ::= 64 | iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5} 65 | 66 | In the X.509 type AlgorithmIdentifier [3], the parameters for MD5 67 | should have type NULL. 68 | 69 | 2. Terminology and Notation 70 | 71 | In this document a "word" is a 32-bit quantity and a "byte" is an 72 | eight-bit quantity. A sequence of bits can be interpreted in a 73 | natural manner as a sequence of bytes, where each consecutive group 74 | of eight bits is interpreted as a byte with the high-order (most 75 | significant) bit of each byte listed first. Similarly, a sequence of 76 | bytes can be interpreted as a sequence of 32-bit words, where each 77 | consecutive group of four bytes is interpreted as a word with the 78 | low-order (least significant) byte given first. 79 | 80 | Let x_i denote "x sub i". If the subscript is an expression, we 81 | surround it in braces, as in x_{i+1}. Similarly, we use ^ for 82 | superscripts (exponentiation), so that x^i denotes x to the i-th 83 | power. 84 | 85 | Let the symbol "+" denote addition of words (i.e., modulo-2^32 86 | addition). Let X <<< s denote the 32-bit value obtained by circularly 87 | shifting (rotating) X left by s bit positions. Let not(X) denote the 88 | bit-wise complement of X, and let X v Y denote the bit-wise OR of X 89 | and Y. Let X xor Y denote the bit-wise XOR of X and Y, and let XY 90 | denote the bit-wise AND of X and Y. 91 | 92 | 3. MD5 Algorithm Description 93 | 94 | We begin by supposing that we have a b-bit message as input, and that 95 | we wish to find its message digest. Here b is an arbitrary 96 | nonnegative integer; b may be zero, it need not be a multiple of 97 | eight, and it may be arbitrarily large. We imagine the bits of the 98 | message written down as follows: 99 | 100 | m_0 m_1 ... m_{b-1} 101 | 102 | The following five steps are performed to compute the message digest 103 | of the message. 104 | 105 | 3.1 Step 1. Append Padding Bits 106 | 107 | The message is "padded" (extended) so that its length (in bits) is 108 | congruent to 448, modulo 512. That is, the message is extended so 109 | that it is just 64 bits shy of being a multiple of 512 bits long. 110 | Padding is always performed, even if the length of the message is 111 | already congruent to 448, modulo 512. 112 | 113 | Padding is performed as follows: a single "1" bit is appended to the 114 | message, and then "0" bits are appended so that the length in bits of 115 | the padded message becomes congruent to 448, modulo 512. In all, at 116 | least one bit and at most 512 bits are appended. 117 | 118 | 3.2 Step 2. Append Length 119 | 120 | A 64-bit representation of b (the length of the message before the 121 | padding bits were added) is appended to the result of the previous 122 | step. In the unlikely event that b is greater than 2^64, then only 123 | the low-order 64 bits of b are used. (These bits are appended as two 124 | 32-bit words and appended low-order word first in accordance with the 125 | previous conventions.) 126 | 127 | At this point the resulting message (after padding with bits and with 128 | b) has a length that is an exact multiple of 512 bits. Equivalently, 129 | this message has a length that is an exact multiple of 16 (32-bit) 130 | words. Let M[0 ... N-1] denote the words of the resulting message, 131 | where N is a multiple of 16. 132 | 133 | 3.3 Step 3. Initialize MD Buffer 134 | 135 | A four-word buffer (A,B,C,D) is used to compute the message digest. 136 | Here each of A, B, C, D is a 32-bit register. These registers are 137 | initialized to the following values in hexadecimal, low-order bytes 138 | first): 139 | 140 | word A: 01 23 45 67 141 | word B: 89 ab cd ef 142 | word C: fe dc ba 98 143 | word D: 76 54 32 10 144 | 145 | 3.4 Step 4. Process Message in 16-Word Blocks 146 | 147 | We first define four auxiliary functions that each take as input 148 | three 32-bit words and produce as output one 32-bit word. 149 | 150 | F(X,Y,Z) = XY v not(X) Z 151 | G(X,Y,Z) = XZ v Y not(Z) 152 | H(X,Y,Z) = X xor Y xor Z 153 | I(X,Y,Z) = Y xor (X v not(Z)) 154 | 155 | In each bit position F acts as a conditional: if X then Y else Z. 156 | The function F could have been defined using + instead of v since XY 157 | and not(X)Z will never have 1's in the same bit position.) It is 158 | interesting to note that if the bits of X, Y, and Z are independent 159 | and unbiased, the each bit of F(X,Y,Z) will be independent and 160 | unbiased. 161 | 162 | The functions G, H, and I are similar to the function F, in that they 163 | act in "bitwise parallel" to produce their output from the bits of X, 164 | Y, and Z, in such a manner that if the corresponding bits of X, Y, 165 | and Z are independent and unbiased, then each bit of G(X,Y,Z), 166 | H(X,Y,Z), and I(X,Y,Z) will be independent and unbiased. Note that 167 | the function H is the bit-wise "xor" or "parity" function of its 168 | inputs. 169 | 170 | This step uses a 64-element table T[1 ... 64] constructed from the 171 | sine function. Let T[i] denote the i-th element of the table, which 172 | is equal to the integer part of 4294967296 times abs(sin(i)), where i 173 | is in radians. The elements of the table are given in the appendix. 174 | 175 | Do the following: 176 | 177 | /* Process each 16-word block. */ 178 | For i = 0 to N/16-1 do 179 | 180 | /* Copy block i into X. */ 181 | For j = 0 to 15 do 182 | Set X[j] to M[i*16+j]. 183 | end /* of loop on j */ 184 | 185 | /* Save A as AA, B as BB, C as CC, and D as DD. */ 186 | AA = A 187 | BB = B 188 | CC = C 189 | DD = D 190 | 191 | /* Round 1. */ 192 | /* Let [abcd k s i] denote the operation 193 | a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ 194 | /* Do the following 16 operations. */ 195 | [ABCD 0 7 1] [DABC 1 12 2] [CDAB 2 17 3] [BCDA 3 22 4] 196 | [ABCD 4 7 5] [DABC 5 12 6] [CDAB 6 17 7] [BCDA 7 22 8] 197 | [ABCD 8 7 9] [DABC 9 12 10] [CDAB 10 17 11] [BCDA 11 22 12] 198 | [ABCD 12 7 13] [DABC 13 12 14] [CDAB 14 17 15] [BCDA 15 22 16] 199 | 200 | /* Round 2. */ 201 | /* Let [abcd k s i] denote the operation 202 | a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ 203 | /* Do the following 16 operations. */ 204 | [ABCD 1 5 17] [DABC 6 9 18] [CDAB 11 14 19] [BCDA 0 20 20] 205 | [ABCD 5 5 21] [DABC 10 9 22] [CDAB 15 14 23] [BCDA 4 20 24] 206 | [ABCD 9 5 25] [DABC 14 9 26] [CDAB 3 14 27] [BCDA 8 20 28] 207 | [ABCD 13 5 29] [DABC 2 9 30] [CDAB 7 14 31] [BCDA 12 20 32] 208 | 209 | /* Round 3. */ 210 | /* Let [abcd k s t] denote the operation 211 | a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ 212 | /* Do the following 16 operations. */ 213 | [ABCD 5 4 33] [DABC 8 11 34] [CDAB 11 16 35] [BCDA 14 23 36] 214 | [ABCD 1 4 37] [DABC 4 11 38] [CDAB 7 16 39] [BCDA 10 23 40] 215 | [ABCD 13 4 41] [DABC 0 11 42] [CDAB 3 16 43] [BCDA 6 23 44] 216 | [ABCD 9 4 45] [DABC 12 11 46] [CDAB 15 16 47] [BCDA 2 23 48] 217 | 218 | /* Round 4. */ 219 | /* Let [abcd k s t] denote the operation 220 | a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ 221 | /* Do the following 16 operations. */ 222 | [ABCD 0 6 49] [DABC 7 10 50] [CDAB 14 15 51] [BCDA 5 21 52] 223 | [ABCD 12 6 53] [DABC 3 10 54] [CDAB 10 15 55] [BCDA 1 21 56] 224 | [ABCD 8 6 57] [DABC 15 10 58] [CDAB 6 15 59] [BCDA 13 21 60] 225 | [ABCD 4 6 61] [DABC 11 10 62] [CDAB 2 15 63] [BCDA 9 21 64] 226 | 227 | /* Then perform the following additions. (That is increment each 228 | of the four registers by the value it had before this block 229 | was started.) */ 230 | A = A + AA 231 | B = B + BB 232 | C = C + CC 233 | D = D + DD 234 | 235 | end /* of loop on i */ 236 | 237 | 3.5 Step 5. Output 238 | 239 | The message digest produced as output is A, B, C, D. That is, we 240 | begin with the low-order byte of A, and end with the high-order byte 241 | of D. 242 | 243 | This completes the description of MD5. A reference implementation in 244 | C is given in the appendix. 245 | 246 | 4. Summary 247 | 248 | The MD5 message-digest algorithm is simple to implement, and provides 249 | a "fingerprint" or message digest of a message of arbitrary length. 250 | It is conjectured that the difficulty of coming up with two messages 251 | having the same message digest is on the order of 2^64 operations, 252 | and that the difficulty of coming up with any message having a given 253 | message digest is on the order of 2^128 operations. The MD5 algorithm 254 | has been carefully scrutinized for weaknesses. It is, however, a 255 | relatively new algorithm and further security analysis is of course 256 | justified, as is the case with any new proposal of this sort. 257 | 258 | 5. Differences Between MD4 and MD5 259 | 260 | The following are the differences between MD4 and MD5: 261 | 262 | 1. A fourth round has been added. 263 | 264 | 2. Each step now has a unique additive constant. 265 | 266 | 3. The function g in round 2 was changed from (XY v XZ v YZ) to 267 | (XZ v Y not(Z)) to make g less symmetric. 268 | 269 | 4. Each step now adds in the result of the previous step. This 270 | promotes a faster "avalanche effect". 271 | 272 | 5. The order in which input words are accessed in rounds 2 and 273 | 3 is changed, to make these patterns less like each other. 274 | 275 | 6. The shift amounts in each round have been approximately 276 | optimized, to yield a faster "avalanche effect." The shifts in 277 | different rounds are distinct. 278 | 279 | References 280 | 281 | [1] Rivest, R., "The MD4 Message Digest Algorithm", RFC 1320, MIT and 282 | RSA Data Security, Inc., April 1992. 283 | 284 | [2] Rivest, R., "The MD4 message digest algorithm", in A.J. Menezes 285 | and S.A. Vanstone, editors, Advances in Cryptology - CRYPTO '90 286 | Proceedings, pages 303-311, Springer-Verlag, 1991. 287 | 288 | [3] CCITT Recommendation X.509 (1988), "The Directory - 289 | Authentication Framework." 290 | 291 | APPENDIX A - Reference Implementation 292 | 293 | This appendix contains the following files taken from RSAREF: A 294 | Cryptographic Toolkit for Privacy-Enhanced Mail: 295 | 296 | global.h -- global header file 297 | 298 | md5.h -- header file for MD5 299 | 300 | md5c.c -- source code for MD5 301 | 302 | For more information on RSAREF, send email to . 303 | 304 | The appendix also includes the following file: 305 | 306 | mddriver.c -- test driver for MD2, MD4 and MD5 307 | 308 | The driver compiles for MD5 by default but can compile for MD2 or MD4 309 | if the symbol MD is defined on the C compiler command line as 2 or 4. 310 | 311 | The implementation is portable and should work on many different 312 | plaforms. However, it is not difficult to optimize the implementation 313 | on particular platforms, an exercise left to the reader. For example, 314 | on "little-endian" platforms where the lowest-addressed byte in a 32- 315 | bit word is the least significant and there are no alignment 316 | restrictions, the call to Decode in MD5Transform can be replaced with 317 | a typecast. 318 | 319 | A.1 global.h 320 | 321 | /* GLOBAL.H - RSAREF types and constants 322 | */ 323 | 324 | /* PROTOTYPES should be set to one if and only if the compiler supports 325 | function argument prototyping. 326 | The following makes PROTOTYPES default to 0 if it has not already 327 | been defined with C compiler flags. 328 | */ 329 | #ifndef PROTOTYPES 330 | #define PROTOTYPES 0 331 | #endif 332 | 333 | /* POINTER defines a generic pointer type */ 334 | typedef unsigned char *POINTER; 335 | 336 | /* UINT2 defines a two byte word */ 337 | typedef unsigned short int UINT2; 338 | 339 | /* UINT4 defines a four byte word */ 340 | typedef unsigned long int UINT4; 341 | 342 | /* PROTO_LIST is defined depending on how PROTOTYPES is defined above. 343 | If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it 344 | returns an empty list. 345 | */ 346 | #if PROTOTYPES 347 | #define PROTO_LIST(list) list 348 | #else 349 | #define PROTO_LIST(list) () 350 | #endif 351 | 352 | A.2 md5.h 353 | 354 | /* MD5.H - header file for MD5C.C 355 | */ 356 | 357 | /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All 358 | rights reserved. 359 | 360 | License to copy and use this software is granted provided that it 361 | is identified as the "RSA Data Security, Inc. MD5 Message-Digest 362 | Algorithm" in all material mentioning or referencing this software 363 | or this function. 364 | 365 | License is also granted to make and use derivative works provided 366 | that such works are identified as "derived from the RSA Data 367 | Security, Inc. MD5 Message-Digest Algorithm" in all material 368 | mentioning or referencing the derived work. 369 | 370 | RSA Data Security, Inc. makes no representations concerning either 371 | the merchantability of this software or the suitability of this 372 | software for any particular purpose. It is provided "as is" 373 | without express or implied warranty of any kind. 374 | 375 | These notices must be retained in any copies of any part of this 376 | documentation and/or software. 377 | */ 378 | 379 | /* MD5 context. */ 380 | typedef struct { 381 | UINT4 state[4]; /* state (ABCD) */ 382 | UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ 383 | unsigned char buffer[64]; /* input buffer */ 384 | } MD5_CTX; 385 | 386 | void MD5Init PROTO_LIST ((MD5_CTX *)); 387 | void MD5Update PROTO_LIST 388 | ((MD5_CTX *, unsigned char *, unsigned int)); 389 | void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); 390 | 391 | A.3 md5c.c 392 | 393 | /* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm 394 | */ 395 | 396 | /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All 397 | rights reserved. 398 | 399 | License to copy and use this software is granted provided that it 400 | is identified as the "RSA Data Security, Inc. MD5 Message-Digest 401 | Algorithm" in all material mentioning or referencing this software 402 | or this function. 403 | 404 | License is also granted to make and use derivative works provided 405 | that such works are identified as "derived from the RSA Data 406 | Security, Inc. MD5 Message-Digest Algorithm" in all material 407 | mentioning or referencing the derived work. 408 | 409 | RSA Data Security, Inc. makes no representations concerning either 410 | the merchantability of this software or the suitability of this 411 | software for any particular purpose. It is provided "as is" 412 | without express or implied warranty of any kind. 413 | 414 | These notices must be retained in any copies of any part of this 415 | documentation and/or software. 416 | */ 417 | 418 | #include "global.h" 419 | #include "md5.h" 420 | 421 | /* Constants for MD5Transform routine. 422 | */ 423 | 424 | #define S11 7 425 | #define S12 12 426 | #define S13 17 427 | #define S14 22 428 | #define S21 5 429 | #define S22 9 430 | #define S23 14 431 | #define S24 20 432 | #define S31 4 433 | #define S32 11 434 | #define S33 16 435 | #define S34 23 436 | #define S41 6 437 | #define S42 10 438 | #define S43 15 439 | #define S44 21 440 | 441 | static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); 442 | static void Encode PROTO_LIST 443 | ((unsigned char *, UINT4 *, unsigned int)); 444 | static void Decode PROTO_LIST 445 | ((UINT4 *, unsigned char *, unsigned int)); 446 | static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); 447 | static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); 448 | 449 | static unsigned char PADDING[64] = { 450 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 451 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 452 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 453 | }; 454 | 455 | /* F, G, H and I are basic MD5 functions. 456 | */ 457 | #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) 458 | #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) 459 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 460 | #define I(x, y, z) ((y) ^ ((x) | (~z))) 461 | 462 | /* ROTATE_LEFT rotates x left n bits. 463 | */ 464 | #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) 465 | 466 | /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. 467 | Rotation is separate from addition to prevent recomputation. 468 | */ 469 | #define FF(a, b, c, d, x, s, ac) { \ 470 | (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ 471 | (a) = ROTATE_LEFT ((a), (s)); \ 472 | (a) += (b); \ 473 | } 474 | #define GG(a, b, c, d, x, s, ac) { \ 475 | (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ 476 | (a) = ROTATE_LEFT ((a), (s)); \ 477 | (a) += (b); \ 478 | } 479 | #define HH(a, b, c, d, x, s, ac) { \ 480 | (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ 481 | (a) = ROTATE_LEFT ((a), (s)); \ 482 | (a) += (b); \ 483 | } 484 | #define II(a, b, c, d, x, s, ac) { \ 485 | (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ 486 | (a) = ROTATE_LEFT ((a), (s)); \ 487 | (a) += (b); \ 488 | } 489 | 490 | /* MD5 initialization. Begins an MD5 operation, writing a new context. 491 | */ 492 | void MD5Init (context) 493 | MD5_CTX *context; /* context */ 494 | { 495 | context->count[0] = context->count[1] = 0; 496 | /* Load magic initialization constants. 497 | */ 498 | context->state[0] = 0x67452301; 499 | context->state[1] = 0xefcdab89; 500 | context->state[2] = 0x98badcfe; 501 | context->state[3] = 0x10325476; 502 | } 503 | 504 | /* MD5 block update operation. Continues an MD5 message-digest 505 | operation, processing another message block, and updating the 506 | context. 507 | */ 508 | void MD5Update (context, input, inputLen) 509 | MD5_CTX *context; /* context */ 510 | unsigned char *input; /* input block */ 511 | unsigned int inputLen; /* length of input block */ 512 | { 513 | unsigned int i, index, partLen; 514 | 515 | /* Compute number of bytes mod 64 */ 516 | index = (unsigned int)((context->count[0] >> 3) & 0x3F); 517 | 518 | /* Update number of bits */ 519 | if ((context->count[0] += ((UINT4)inputLen << 3)) 520 | < ((UINT4)inputLen << 3)) 521 | context->count[1]++; 522 | context->count[1] += ((UINT4)inputLen >> 29); 523 | 524 | partLen = 64 - index; 525 | 526 | /* Transform as many times as possible. 527 | */ 528 | if (inputLen >= partLen) { 529 | MD5_memcpy 530 | ((POINTER)&context->buffer[index], (POINTER)input, partLen); 531 | MD5Transform (context->state, context->buffer); 532 | 533 | for (i = partLen; i + 63 < inputLen; i += 64) 534 | MD5Transform (context->state, &input[i]); 535 | 536 | index = 0; 537 | } 538 | else 539 | i = 0; 540 | 541 | /* Buffer remaining input */ 542 | MD5_memcpy 543 | ((POINTER)&context->buffer[index], (POINTER)&input[i], 544 | inputLen-i); 545 | } 546 | 547 | /* MD5 finalization. Ends an MD5 message-digest operation, writing the 548 | the message digest and zeroizing the context. 549 | */ 550 | void MD5Final (digest, context) 551 | unsigned char digest[16]; /* message digest */ 552 | MD5_CTX *context; /* context */ 553 | { 554 | unsigned char bits[8]; 555 | unsigned int index, padLen; 556 | 557 | /* Save number of bits */ 558 | Encode (bits, context->count, 8); 559 | 560 | /* Pad out to 56 mod 64. 561 | */ 562 | index = (unsigned int)((context->count[0] >> 3) & 0x3f); 563 | padLen = (index < 56) ? (56 - index) : (120 - index); 564 | MD5Update (context, PADDING, padLen); 565 | 566 | /* Append length (before padding) */ 567 | MD5Update (context, bits, 8); 568 | 569 | /* Store state in digest */ 570 | Encode (digest, context->state, 16); 571 | 572 | /* Zeroize sensitive information. 573 | */ 574 | MD5_memset ((POINTER)context, 0, sizeof (*context)); 575 | } 576 | 577 | /* MD5 basic transformation. Transforms state based on block. 578 | */ 579 | static void MD5Transform (state, block) 580 | UINT4 state[4]; 581 | unsigned char block[64]; 582 | { 583 | UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; 584 | 585 | Decode (x, block, 64); 586 | 587 | /* Round 1 */ 588 | FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ 589 | FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ 590 | FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ 591 | FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ 592 | FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ 593 | FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ 594 | FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ 595 | FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ 596 | FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ 597 | FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ 598 | FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ 599 | FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ 600 | FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ 601 | FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ 602 | FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ 603 | FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ 604 | 605 | /* Round 2 */ 606 | GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ 607 | GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ 608 | GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ 609 | GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ 610 | GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ 611 | GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ 612 | GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ 613 | GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ 614 | GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ 615 | GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ 616 | GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ 617 | GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ 618 | GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ 619 | GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ 620 | GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ 621 | GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ 622 | 623 | /* Round 3 */ 624 | HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ 625 | HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ 626 | HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ 627 | HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ 628 | HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ 629 | HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ 630 | HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ 631 | HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ 632 | HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ 633 | HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ 634 | HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ 635 | HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ 636 | HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ 637 | HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ 638 | HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ 639 | HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ 640 | 641 | /* Round 4 */ 642 | II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ 643 | II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ 644 | II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ 645 | II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ 646 | II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ 647 | II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ 648 | II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ 649 | II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ 650 | II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ 651 | II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ 652 | II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ 653 | II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ 654 | II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ 655 | II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ 656 | II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ 657 | II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ 658 | 659 | state[0] += a; 660 | state[1] += b; 661 | state[2] += c; 662 | state[3] += d; 663 | 664 | /* Zeroize sensitive information. 665 | */ 666 | MD5_memset ((POINTER)x, 0, sizeof (x)); 667 | } 668 | 669 | /* Encodes input (UINT4) into output (unsigned char). Assumes len is 670 | a multiple of 4. 671 | */ 672 | static void Encode (output, input, len) 673 | unsigned char *output; 674 | UINT4 *input; 675 | unsigned int len; 676 | { 677 | unsigned int i, j; 678 | 679 | for (i = 0, j = 0; j < len; i++, j += 4) { 680 | output[j] = (unsigned char)(input[i] & 0xff); 681 | output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); 682 | output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); 683 | output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); 684 | } 685 | } 686 | 687 | /* Decodes input (unsigned char) into output (UINT4). Assumes len is 688 | a multiple of 4. 689 | */ 690 | static void Decode (output, input, len) 691 | UINT4 *output; 692 | unsigned char *input; 693 | unsigned int len; 694 | { 695 | unsigned int i, j; 696 | 697 | for (i = 0, j = 0; j < len; i++, j += 4) 698 | output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | 699 | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); 700 | } 701 | 702 | /* Note: Replace "for loop" with standard memcpy if possible. 703 | */ 704 | 705 | static void MD5_memcpy (output, input, len) 706 | POINTER output; 707 | POINTER input; 708 | unsigned int len; 709 | { 710 | unsigned int i; 711 | 712 | for (i = 0; i < len; i++) 713 | 714 | output[i] = input[i]; 715 | } 716 | 717 | /* Note: Replace "for loop" with standard memset if possible. 718 | */ 719 | static void MD5_memset (output, value, len) 720 | POINTER output; 721 | int value; 722 | unsigned int len; 723 | { 724 | unsigned int i; 725 | 726 | for (i = 0; i < len; i++) 727 | ((char *)output)[i] = (char)value; 728 | } 729 | 730 | A.4 mddriver.c 731 | 732 | /* MDDRIVER.C - test driver for MD2, MD4 and MD5 733 | */ 734 | 735 | /* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All 736 | rights reserved. 737 | 738 | RSA Data Security, Inc. makes no representations concerning either 739 | the merchantability of this software or the suitability of this 740 | software for any particular purpose. It is provided "as is" 741 | without express or implied warranty of any kind. 742 | 743 | These notices must be retained in any copies of any part of this 744 | documentation and/or software. 745 | */ 746 | 747 | /* The following makes MD default to MD5 if it has not already been 748 | defined with C compiler flags. 749 | */ 750 | #ifndef MD 751 | #define MD MD5 752 | #endif 753 | 754 | #include 755 | #include 756 | #include 757 | #include "global.h" 758 | #if MD == 2 759 | #include "md2.h" 760 | #endif 761 | #if MD == 4 762 | #include "md4.h" 763 | #endif 764 | #if MD == 5 765 | #include "md5.h" 766 | #endif 767 | 768 | /* Length of test block, number of test blocks. 769 | */ 770 | #define TEST_BLOCK_LEN 1000 771 | #define TEST_BLOCK_COUNT 1000 772 | 773 | static void MDString PROTO_LIST ((char *)); 774 | static void MDTimeTrial PROTO_LIST ((void)); 775 | static void MDTestSuite PROTO_LIST ((void)); 776 | static void MDFile PROTO_LIST ((char *)); 777 | static void MDFilter PROTO_LIST ((void)); 778 | static void MDPrint PROTO_LIST ((unsigned char [16])); 779 | 780 | #if MD == 2 781 | #define MD_CTX MD2_CTX 782 | #define MDInit MD2Init 783 | #define MDUpdate MD2Update 784 | #define MDFinal MD2Final 785 | #endif 786 | #if MD == 4 787 | #define MD_CTX MD4_CTX 788 | #define MDInit MD4Init 789 | #define MDUpdate MD4Update 790 | #define MDFinal MD4Final 791 | #endif 792 | #if MD == 5 793 | #define MD_CTX MD5_CTX 794 | #define MDInit MD5Init 795 | #define MDUpdate MD5Update 796 | #define MDFinal MD5Final 797 | #endif 798 | 799 | /* Main driver. 800 | 801 | Arguments (may be any combination): 802 | -sstring - digests string 803 | -t - runs time trial 804 | -x - runs test script 805 | filename - digests file 806 | (none) - digests standard input 807 | */ 808 | int main (argc, argv) 809 | int argc; 810 | char *argv[]; 811 | { 812 | int i; 813 | 814 | if (argc > 1) 815 | for (i = 1; i < argc; i++) 816 | if (argv[i][0] == '-' && argv[i][1] == 's') 817 | MDString (argv[i] + 2); 818 | else if (strcmp (argv[i], "-t") == 0) 819 | MDTimeTrial (); 820 | else if (strcmp (argv[i], "-x") == 0) 821 | MDTestSuite (); 822 | else 823 | MDFile (argv[i]); 824 | else 825 | MDFilter (); 826 | 827 | return (0); 828 | } 829 | 830 | /* Digests a string and prints the result. 831 | */ 832 | static void MDString (string) 833 | char *string; 834 | { 835 | MD_CTX context; 836 | unsigned char digest[16]; 837 | unsigned int len = strlen (string); 838 | 839 | MDInit (&context); 840 | MDUpdate (&context, string, len); 841 | MDFinal (digest, &context); 842 | 843 | printf ("MD%d (\"%s\") = ", MD, string); 844 | MDPrint (digest); 845 | printf ("\n"); 846 | } 847 | 848 | /* Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte 849 | blocks. 850 | */ 851 | static void MDTimeTrial () 852 | { 853 | MD_CTX context; 854 | time_t endTime, startTime; 855 | unsigned char block[TEST_BLOCK_LEN], digest[16]; 856 | unsigned int i; 857 | 858 | printf 859 | ("MD%d time trial. Digesting %d %d-byte blocks ...", MD, 860 | TEST_BLOCK_LEN, TEST_BLOCK_COUNT); 861 | 862 | /* Initialize block */ 863 | for (i = 0; i < TEST_BLOCK_LEN; i++) 864 | block[i] = (unsigned char)(i & 0xff); 865 | 866 | /* Start timer */ 867 | time (&startTime); 868 | 869 | /* Digest blocks */ 870 | MDInit (&context); 871 | for (i = 0; i < TEST_BLOCK_COUNT; i++) 872 | MDUpdate (&context, block, TEST_BLOCK_LEN); 873 | MDFinal (digest, &context); 874 | 875 | /* Stop timer */ 876 | time (&endTime); 877 | 878 | printf (" done\n"); 879 | printf ("Digest = "); 880 | MDPrint (digest); 881 | printf ("\nTime = %ld seconds\n", (long)(endTime-startTime)); 882 | printf 883 | ("Speed = %ld bytes/second\n", 884 | (long)TEST_BLOCK_LEN * (long)TEST_BLOCK_COUNT/(endTime-startTime)); 885 | } 886 | 887 | /* Digests a reference suite of strings and prints the results. 888 | */ 889 | static void MDTestSuite () 890 | { 891 | printf ("MD%d test suite:\n", MD); 892 | 893 | MDString (""); 894 | MDString ("a"); 895 | MDString ("abc"); 896 | MDString ("message digest"); 897 | MDString ("abcdefghijklmnopqrstuvwxyz"); 898 | MDString 899 | ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); 900 | MDString 901 | ("1234567890123456789012345678901234567890\ 902 | 1234567890123456789012345678901234567890"); 903 | } 904 | 905 | /* Digests a file and prints the result. 906 | */ 907 | static void MDFile (filename) 908 | char *filename; 909 | { 910 | FILE *file; 911 | MD_CTX context; 912 | int len; 913 | unsigned char buffer[1024], digest[16]; 914 | 915 | if ((file = fopen (filename, "rb")) == NULL) 916 | printf ("%s can't be opened\n", filename); 917 | 918 | else { 919 | MDInit (&context); 920 | while (len = fread (buffer, 1, 1024, file)) 921 | MDUpdate (&context, buffer, len); 922 | MDFinal (digest, &context); 923 | 924 | fclose (file); 925 | 926 | printf ("MD%d (%s) = ", MD, filename); 927 | MDPrint (digest); 928 | printf ("\n"); 929 | } 930 | } 931 | 932 | /* Digests the standard input and prints the result. 933 | */ 934 | static void MDFilter () 935 | { 936 | MD_CTX context; 937 | int len; 938 | unsigned char buffer[16], digest[16]; 939 | 940 | MDInit (&context); 941 | while (len = fread (buffer, 1, 16, stdin)) 942 | MDUpdate (&context, buffer, len); 943 | MDFinal (digest, &context); 944 | 945 | MDPrint (digest); 946 | printf ("\n"); 947 | } 948 | 949 | /* Prints a message digest in hexadecimal. 950 | */ 951 | static void MDPrint (digest) 952 | unsigned char digest[16]; 953 | { 954 | unsigned int i; 955 | 956 | for (i = 0; i < 16; i++) 957 | printf ("%02x", digest[i]); 958 | } 959 | 960 | A.5 Test suite 961 | 962 | The MD5 test suite (driver option "-x") should print the following 963 | results: 964 | 965 | MD5 test suite: 966 | MD5 ("") = d41d8cd98f00b204e9800998ecf8427e 967 | MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661 968 | MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72 969 | MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0 970 | MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b 971 | MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = 972 | d174ab98d277d9f5a5611c2c9f419d9f 973 | MD5 ("123456789012345678901234567890123456789012345678901234567890123456 974 | 78901234567890") = 57edf4a22be3c955ac49da2e2107b67a 975 | 976 | Security Considerations 977 | 978 | The level of security discussed in this memo is considered to be 979 | sufficient for implementing very high security hybrid digital- 980 | signature schemes based on MD5 and a public-key cryptosystem. 981 | 982 | Author's Address 983 | 984 | Ronald L. Rivest 985 | Massachusetts Institute of Technology 986 | Laboratory for Computer Science 987 | NE43-324 988 | 545 Technology Square 989 | Cambridge, MA 02139-1986 990 | 991 | Phone: (617) 253-5880 992 | EMail: rivest@theory.lcs.mit.edu 993 | -------------------------------------------------------------------------------- /rc5_lib/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | SET(CMAKE_CXX_FLAGS " -g -Wall -o2") 2 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 3 | SET(rc5_lib_path ${PROJECT_SOURCE_DIR}/lib) 4 | SET(rc5_src_path ${PROJECT_SOURCE_DIR}/src) 5 | 6 | INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include) 7 | 8 | AUX_SOURCE_DIRECTORY(${rc5_src_path} X_SRC) 9 | ADD_LIBRARY(rc5 STATIC ${X_SRC}) 10 | 11 | SET_TARGET_PROPERTIES(rc5 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${rc5_lib_path}") 12 | -------------------------------------------------------------------------------- /rc5_lib/src/rc5.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | RC5Simple C++ library 3 | 4 | The easy implementation of RC5 32/12/16 algorythm 5 | with user fiendly interface. 6 | 7 | Copyright 2011 Sergey M. Stepanov 8 | 9 | Contact: xintrea@gmail.com, www.webhamster.ru 10 | 11 | License: GPL v.3 and BSD 12 | 13 | Volgodonsk, 2011-2013 14 | */ 15 | 16 | #include "rc5.h" 17 | 18 | 19 | // 1.15 - Первая публичная версия 20 | 21 | // 1.16 - Основана на версии 1.15 22 | // - Исправлены предупреждения о сравнении знакового и беззнакового 23 | // числа в методах 24 | // RC5_Setup() и 25 | // RC5_EncDecFile() 26 | // возникающие при строгих опциях компилятора 27 | // - В прототип конструктора добавлен аргумент enableRandomInit, 28 | // который по-умолчанию равен false. Это необходимо для того, 29 | // чтобы пользователь мог управлять инициализацией генератора 30 | // случайных чисел. Если в основной программе сделана инициализация, 31 | // то инициализация в данном классе не требуется, 32 | // и по-умолчанию теперь отключена 33 | 34 | // 1.17 - 1.19 - Промежуточные отладочные версии 35 | 36 | // 1.20 - Основана на версии 1.19 37 | // - Изменена реализация механизма сцепления блоков шифротекста с упрощенного, 38 | // предложенного в Reference implementation of RC5-32/12/16 in C 39 | // RSA Data Security, Inc, 1995 на полный CBC, описанный в Wikipedia 40 | // http://ru.wikipedia.org/wiki/Режим_сцепления_блоков_шифротекста 41 | // - Скорость шифрации/дешифрации данных увеличена в 2,5 раз 42 | // - Добавлен каталог /doc. В нем размещено описание формата данных 43 | // и HOWTO по использованию библиотеки RC5Simple 44 | 45 | // 1.21 - Основана на версии 1.20 46 | // - Внесены исправления, позволяющие добиться павильной работы на 47 | // 64-х битовых архитектурах. Протестировано на Cent OS x86_64, Intel 64 48 | 49 | // 1.22 - Основана на версии 1.21 50 | // - Удалена проверка на невозможность работы под x86_64 51 | // и сообщение об ошибке в конструкторе 52 | // - Подтверждена работа блоков шифрования и дешифровки на 53 | // миропроцессорах AMD 54 | 55 | // 1.23 - Основана на версии 1.22 56 | // - Исправлен код, приводящий к появлению предупреждений 57 | // в релиз режиме компиляции в методе RC5_SetKey() 58 | // - В заголовочном файле исправлена сбившаяся кодировка в определениях 59 | // разрядности микропроцессора, получившаяся вследствие копирования 60 | // из окна терминала виртуальной машины с другой кодировкой 61 | 62 | // 1.27 - Основана на версиях 1.24 - 1.26 63 | // - Сделана поддержка форматов хранения данных. 64 | // Формат 1 - это первый формат, использующийся вплоть до версии 1.23 65 | // Формат 2 - это новый формат с усиленным форматом шифрования 66 | // - В формате 2 (и всех последующих) присутсвует сигнатура RC5SIMP 67 | // после которой следует один байт версии формата данных 68 | // - По умолчанию идет шифрация в формат 2 69 | // - В формате 2, помимо вектора инициализации, добавлен дополнительный 70 | // блок случайных данных, размещаемый в шифрованном тексте. Данная 71 | // мера предотвращает атаку при наличии нескольких образцов шифрованного 72 | // текста по заранее известному началу открытого текста. Пользоваться 73 | // устаревшей версией формата 1 строго не рекомендуется 74 | // - Сделана возможность принудительного выбора формата шифрации/дешифрации 75 | // для сохранения совместимости с предыдущей версией. Выбор формата 76 | // осуществляется функцией 77 | // void RC5_SetFormatVersionForce(unsigned char formatVersion); 78 | // - Добавлено несколько дополнительных отладочных сообщений 79 | 80 | // 1.28 - Основана на версии 1.27 81 | // - Проведены тесты упаковки-распаковки форматов 1 и 2 82 | // - Прописаны правильные смещения для корректной распаковки формата 1 83 | // - Добавлено свойство, хранящее последнюю ошибку 84 | // - Добавлен метод получения последней ошибки RC5_GetErrorCode() 85 | // - Вывод сообщения в консоль при возникновении ошибки заменен запоминанием 86 | // кода последней ошибки 87 | // - В заголовочном файле прописаны коды ошибок RC5_ERROR_CODE_X и 88 | // их описания 89 | 90 | // 1.29 - Основана на версии 1.28 91 | // - Внесены исправления для правильной компиляции под Windows, в которой 92 | // отсутсвует предустановленное определение LONG_BIT. Теперь, в случае 93 | // отсутсвия данного определения, компиляция произвдится на 32-х битную 94 | // платформу 95 | 96 | // 1.30 - Основана на версии 1.29 97 | // - Добавлен формат 3. В предыдущем формате 2 обнаружено 98 | // необоснованное занижение количества первичных случайных данных 99 | // на половину длинны ключа шифрования. В формате 3 первичные 100 | // случайные данные имеют полную ширину ключа шифрования 101 | // - По умолчанию идет шифрация в формат 3 102 | // - В метод RC5_Encrypt добавлена установка кода ошибки при попытке 103 | // зашифровать пустые данные 104 | // - В метод RC5_Decrypt добавлена установка кода ошибки при попытке 105 | // расшифровать пустые данные 106 | // - В метод RC5_Decrypt добавлена установка кода ошибки при попытке 107 | // расшифровать данные с некорректной длинной 108 | // - В методах расшифровки проставлены правильные константы для 109 | // смещений данных в разных форматах хранения 110 | // - Произведена проверка через valgrind упаковки/распаковки в каждом 111 | // из форматов. Везде имеем отчет 112 | // ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 113 | // - Фиксация номера версии 114 | // - Пройдены тесты шифрации/дешифрации данных на совместимость 115 | // с предыдущими версиями 116 | // - Пройдены тесты по интеграции и работе в рамках MyTetra 117 | // - Удалена информация об отвлекающих факторах 118 | // - Финальный коммит, присвоение тега версии 119 | 120 | 121 | RC5Simple::RC5Simple(bool enableRandomInit) 122 | { 123 | // Set magic constants 124 | rc5_p = 0xb7e15163; 125 | rc5_q = 0x9e3779b9; 126 | 127 | // Cleaning user key 128 | for(int i=0; i0; i--) 196 | { 197 | b = RC5_ROTR(b-rc5_s[2*i+1], a)^a; 198 | a = RC5_ROTR(a-rc5_s[2*i], b)^b; 199 | } 200 | 201 | pt[1] = b-rc5_s[1]; 202 | pt[0] = a-rc5_s[0]; 203 | } 204 | 205 | 206 | // Setup secret key 207 | // Parameters: 208 | // key - secret input key[RC5_B] 209 | void RC5Simple::RC5_Setup(unsigned char *key) 210 | { 211 | RC5_LOG(( "RC5_Setup, set key to: " )); 212 | for(int i=0; i 3*c 240 | for(a=b=i=j=k=0; k<3*RC5_T; k++, i=(i+1)%RC5_T, j=(j+1)%RC5_C) 241 | { 242 | a = rc5_s[i] = RC5_ROTL(rc5_s[i]+(a+b),3); 243 | b = l[j] = RC5_ROTL(l[j]+(a+b),(a+b)); 244 | } 245 | 246 | RC5_LOG(( "RC5_Setup, mix rc5_s[]: " )); 247 | for(int i=0; i &key) 255 | { 256 | if(key.size()!=RC5_B) 257 | { 258 | errorCode=RC5_ERROR_CODE_1; 259 | return; 260 | } 261 | 262 | for(int i=0; i &in, vector &out) 269 | { 270 | // Clear output vector 271 | out.clear(); 272 | 273 | // No crypt null data 274 | if(in.size()==0) 275 | { 276 | errorCode=RC5_ERROR_CODE_5; 277 | return; 278 | } 279 | 280 | 281 | // Save input data size 282 | unsigned int clean_data_size=in.size(); 283 | RC5_LOG(( "Input data size: %d\n", clean_data_size )); 284 | 285 | 286 | // IV block 287 | unsigned char iv[RC5_BLOCK_LEN]; 288 | for(int i=0; i0) 316 | for(unsigned int n=1; n<=firsRandomDataBlocks; n++) 317 | { 318 | in.insert( in.begin(), RC5_BLOCK_LEN, 0); 319 | for(int i=0; i0) 329 | { 330 | // Add random data to end for align to block size 331 | for(int i=0; i<(RC5_BLOCK_LEN-last_unalign_len); i++) 332 | { 333 | RC5_LOG(( "Add byte: %d\n", i )); 334 | in.push_back( (unsigned char)RC5_Rand(0, 0xFF) ); 335 | } 336 | } 337 | 338 | #if RC5_ENABLE_DEBUG_PRINT==1 339 | RC5_LOG(( "Data size after crypt setup: %d\n", in.size() )); 340 | RC5_LOG(( "Plain byte after crypt setup: " )); 341 | for(int i=0; i=RC5_FORMAT_VERSION_2) 369 | { 370 | out.resize(in.size()+RC5_BLOCK_LEN*2, 0); 371 | 372 | // Signature bytes in header 373 | const char *signature=RC5_SIMPLE_SIGNATURE; 374 | for(int i=0; i<(RC5_BLOCK_LEN-1); i++) 375 | out[i]=signature[i]; 376 | 377 | // Format version byte in header 378 | if(rc5_isSetFormatVersionForce) 379 | out[RC5_BLOCK_LEN-1]=rc5_formatVersion; 380 | else 381 | out[RC5_BLOCK_LEN-1]=RC5_FORMAT_VERSION_CURRENT; 382 | 383 | // Save start IV to second block in output data 384 | for(int i=0; i0) 471 | for(unsigned int n=1; n<=firsRandomDataBlocks; n++) 472 | in.erase(in.begin(), in.begin()+RC5_BLOCK_LEN); 473 | 474 | // Remove from input vector last random byte for aligning 475 | if(in.size()>clean_data_size) 476 | in.erase(in.begin()+clean_data_size, in.end()); 477 | 478 | } 479 | 480 | 481 | // Decrypt data in vector 482 | void RC5Simple::RC5_Decrypt(vector &in, vector &out) 483 | { 484 | RC5_LOG(( "\nDecrypt\n" )); 485 | 486 | RC5_LOG(( "\nInput data size: %d\n", in.size() )); 487 | 488 | // No decrypt null data 489 | if(in.size()==0) 490 | { 491 | errorCode=RC5_ERROR_CODE_6; 492 | return; 493 | } 494 | 495 | 496 | // Detect format version 497 | unsigned int formatVersion=0; 498 | if(rc5_isSetFormatVersionForce==true) 499 | formatVersion=rc5_formatVersion; // If format set force, format not autodetected 500 | else 501 | { 502 | // Signature bytes 503 | const char *signature=RC5_SIMPLE_SIGNATURE; 504 | 505 | // Detect signature 506 | bool isSignatureCorrect=true; 507 | for(int i=0; i<(RC5_BLOCK_LEN-1); i++) 508 | if(in[i]!=signature[i]) 509 | isSignatureCorrect=false; 510 | 511 | // If not detect signature 512 | if(isSignatureCorrect==false) 513 | formatVersion=RC5_FORMAT_VERSION_1; // In first version can't signature 514 | else 515 | { 516 | // Get format version 517 | unsigned char readFormatVersion=in[RC5_BLOCK_LEN-1]; 518 | 519 | // If format version correct 520 | if(readFormatVersion>=RC5_FORMAT_VERSION_2 && readFormatVersion<=RC5_FORMAT_VERSION_CURRENT) 521 | formatVersion=readFormatVersion; 522 | else 523 | formatVersion=RC5_FORMAT_VERSION_1; // If version not correct, may be it format 1 ( probability 0.[hrendesyatih]1 ) 524 | } 525 | } 526 | 527 | 528 | unsigned int ivShift=0; 529 | unsigned int firstDataBlock=0; 530 | unsigned int removeBlocksFromOutput=0; 531 | unsigned int blockWithDataSize=0; 532 | 533 | 534 | if(formatVersion==RC5_FORMAT_VERSION_1) 535 | { 536 | ivShift=0; 537 | firstDataBlock=1; // Start decode from block with index 1 (from block 0 read IV) 538 | removeBlocksFromOutput=1; 539 | blockWithDataSize=1; 540 | } 541 | 542 | if(formatVersion==RC5_FORMAT_VERSION_2) 543 | { 544 | ivShift=RC5_BLOCK_LEN; 545 | firstDataBlock=2; // Start decode from block with index 2 (0 - signature and version, 1 - IV) 546 | removeBlocksFromOutput=2; // Random data block and size data block 547 | blockWithDataSize=3; 548 | } 549 | 550 | if(formatVersion==RC5_FORMAT_VERSION_3) 551 | { 552 | ivShift=RC5_BLOCK_LEN; 553 | firstDataBlock=2; // Start decode from block with index 2 (0 - signature and version, 1 - IV) 554 | removeBlocksFromOutput=3; // Two random data block and size data block 555 | blockWithDataSize=4; 556 | } 557 | 558 | 559 | // Get IV 560 | unsigned char iv[RC5_BLOCK_LEN]; 561 | for(int i=0; i(unsigned int)in.size()) 633 | { 634 | // RC5_LOG(( "Incorrect data size. Decrypt data size: %d, estimate data size: ~%d\n", data_size, in.size() )); 635 | errorCode=RC5_ERROR_CODE_7; 636 | return; 637 | } 638 | } 639 | 640 | #if RC5_ENABLE_DEBUG_PRINT==1 641 | RC5_LOG(( "Pt %.8X, %.8X\n", pt[0], pt[1] )); 642 | RC5_LOG(( "Ct %.8X, %.8X\n", ct[0], ct[1] )); 643 | #endif 644 | 645 | 646 | // Generate next IV for Cipher Block Chaining (CBC) 647 | for(int i=0; idata_size) 671 | out.erase(out.begin()+data_size, out.end()); 672 | } 673 | 674 | 675 | void RC5Simple::RC5_EncryptFile(unsigned char *in_name, unsigned char *out_name) 676 | { 677 | RC5_EncDecFile(in_name, out_name, RC5_MODE_ENCODE); 678 | } 679 | 680 | 681 | void RC5Simple::RC5_EncryptFile(const char *in_name, const char *out_name) 682 | { 683 | RC5_EncDecFile((unsigned char *)in_name, (unsigned char *)out_name, RC5_MODE_ENCODE); 684 | } 685 | 686 | 687 | void RC5Simple::RC5_DecryptFile(unsigned char *in_name, unsigned char *out_name) 688 | { 689 | RC5_EncDecFile(in_name, out_name, RC5_MODE_DECODE); 690 | } 691 | 692 | 693 | void RC5Simple::RC5_DecryptFile(const char *in_name, const char *out_name) 694 | { 695 | RC5_EncDecFile((unsigned char *)in_name, (unsigned char *)out_name, RC5_MODE_DECODE); 696 | } 697 | 698 | 699 | void RC5Simple::RC5_EncDecFile(unsigned char *in_name, unsigned char *out_name, int mode) 700 | { 701 | FILE *in_file; 702 | FILE *out_file; 703 | 704 | if((in_file=fopen( (const char*)in_name, "rb") )==NULL) 705 | { 706 | errorCode=RC5_ERROR_CODE_2; 707 | return; 708 | } 709 | 710 | // Get size of input file 711 | fseek(in_file, 0, SEEK_END); 712 | unsigned int in_file_length=ftell(in_file); 713 | RC5_LOG(( "Input file name: %s, size: %d\n", in_name, in_file_length)); 714 | 715 | if(in_file_length==0) 716 | { 717 | errorCode=RC5_ERROR_CODE_3; 718 | return; 719 | } 720 | 721 | // Return to begin file 722 | fseek(in_file, 0, SEEK_SET); 723 | 724 | // Create data vectors 725 | vector in(in_file_length); 726 | vector out; 727 | 728 | // Fill input data vector 729 | unsigned int byte=0; 730 | while(byte> 8; 769 | break; 770 | case 2: 771 | b=(w & 0x00FF0000) >> 16; 772 | break; 773 | case 3: 774 | b=(w & 0xFF000000) >> 24; 775 | } 776 | 777 | // RC5_LOG(( "GetByteFromWord(%.8X, %d)=%.2X\n", w, n, b )); 778 | 779 | return b; 780 | } 781 | 782 | 783 | inline unsigned char RC5Simple::RC5_GetByteFromInt(unsigned int w, int n) 784 | { 785 | unsigned char b=0; 786 | 787 | switch (n) { 788 | case 0: 789 | b=(w & 0x000000FF); 790 | break; 791 | case 1: 792 | b=(w & 0x0000FF00) >> 8; 793 | break; 794 | case 2: 795 | b=(w & 0x00FF0000) >> 16; 796 | break; 797 | case 3: 798 | b=(w & 0xFF000000) >> 24; 799 | } 800 | 801 | // RC5_LOG(( "GetByteFromWord(%.8X, %d)=%.2X\n", w, n, b )); 802 | 803 | return b; 804 | } 805 | 806 | 807 | inline unsigned int RC5Simple::RC5_GetIntFromByte(unsigned char b0, 808 | unsigned char b1, 809 | unsigned char b2, 810 | unsigned char b3) 811 | { 812 | return b0+ 813 | (b1 << 8)+ 814 | (b2 << 16)+ 815 | (b3 << 24); 816 | } 817 | 818 | 819 | inline RC5_TWORD RC5Simple::RC5_GetWordFromByte(unsigned char b0, 820 | unsigned char b1, 821 | unsigned char b2, 822 | unsigned char b3) 823 | { 824 | return b0+ 825 | (b1 << 8)+ 826 | (b2 << 16)+ 827 | (b3 << 24); 828 | } 829 | 830 | 831 | // Random generator, from - to inclusive 832 | unsigned int RC5Simple::RC5_Rand(unsigned int from, unsigned int to) 833 | { 834 | unsigned int len=to-from+1; 835 | 836 | return (rand()%len)+from; 837 | } 838 | 839 | 840 | unsigned int RC5Simple::RC5_GetErrorCode() 841 | { 842 | return errorCode; 843 | } 844 | 845 | 846 | void RC5Simple::RC5_LogPrint(char *lpszText, ...) 847 | { 848 | va_list argList; 849 | 850 | va_start(argList, lpszText); 851 | 852 | vprintf(lpszText, argList); 853 | 854 | va_end(argList); 855 | 856 | return; 857 | } -------------------------------------------------------------------------------- /rc5_lib/test/demo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcc0lin/dirty_algorithm/50c8276dcd65b5a8e23f78cf83e87df41d414358/rc5_lib/test/demo -------------------------------------------------------------------------------- /rc5_lib/test/demo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | #include "rc5.h" 6 | 7 | 8 | int main() 9 | { 10 | RC5Simple rc5(true); 11 | 12 | printf("RC5-32/12/16 examples\n"); 13 | 14 | printf("Library version: %s\n", rc5.RC5_GetVersion() ); 15 | 16 | // ------------------------------------ 17 | // Byte array encrypt / decrypt example 18 | // ------------------------------------ 19 | 20 | printf("\nByte array encrypt example\n\n"); 21 | 22 | #define DATA_SIZE 100 23 | 24 | // Generate first data 25 | unsigned char data[DATA_SIZE]; 26 | 27 | printf("Plain byte array:\n"); 28 | for(int i=0; i v_key(RC5_B); 48 | for(int i=0; i v_data(DATA_SIZE); 59 | for(int i=0; i v_crypt_data; 64 | 65 | 66 | // Example for force set format version 67 | // rc5.RC5_SetFormatVersionForce(RC5_FORMAT_VERSION_1); 68 | 69 | // Encrypt 70 | rc5.RC5_SetKey(v_key); 71 | rc5.RC5_Encrypt(v_data, v_crypt_data); 72 | 73 | printf("\nEncrypt byte array:\n"); 74 | for(int i=0; i example.txt.encrypt -> example.txt.decrypt\n"); 101 | 102 | // rc5.RC5_SetKey(v_key); 103 | 104 | // rc5.RC5_EncryptFile("example.txt", "example.txt.encrypt"); 105 | 106 | // rc5.RC5_DecryptFile("example.txt.encrypt", "example.txt.decrypt"); 107 | 108 | return 0; 109 | } -------------------------------------------------------------------------------- /rc5_lib/test/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | g++ demo.cpp -I../include/ -L../lib ../lib/librc5.a -o demo 3 | clean: 4 | rm demo -------------------------------------------------------------------------------- /sha1_lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | add_subdirectory(src) 4 | -------------------------------------------------------------------------------- /sha1_lib/README.md: -------------------------------------------------------------------------------- 1 | 基于c++实现的SHA1算法库 2 | 3 | ## 使用说明 4 | 5 | 基于`cmake`编译,切换到`build`目录,执行脚本`./run.sh`即可在`lib`目录生成静态库`libsha1.a` 6 | 7 | 使用时只需要引入对应的头文件,然后就可以调用`SHA1`函数了。 8 | ```cpp 9 | #include "sha1.h" 10 | 11 | unsigned char m[56] = "123"; 12 | unsigned int c[5] = { 0 }; 13 | SHA1(m,c); 14 | for (int j = 0; j <= 4; j++) printf("%08X", c[j]); 15 | ``` 16 | 17 | ## 测试 18 | 切换到`test`目录下,执行`make`命令生成`demo`的可执行程序 -------------------------------------------------------------------------------- /sha1_lib/bulid/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -f ./run.sh ../run.sh; 4 | rm -rf *; 5 | cp -f ../run.sh ./run.sh; 6 | rm -f ../run.sh; 7 | cmake ../; 8 | make; 9 | make install; 10 | cp -f ./run.sh ../run.sh; 11 | rm -rf *; 12 | cp -f ../run.sh ./run.sh; 13 | rm -f ../run.sh; -------------------------------------------------------------------------------- /sha1_lib/include/sha1.h: -------------------------------------------------------------------------------- 1 | #ifndef SHA1_H 2 | #define SHA1_H 3 | 4 | void SHA1(unsigned char *context,unsigned int * cipher); 5 | 6 | #endif -------------------------------------------------------------------------------- /sha1_lib/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | SET(CMAKE_CXX_FLAGS " -g -Wall -o2") 2 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 3 | SET(sha1_lib_path ${PROJECT_SOURCE_DIR}/lib) 4 | SET(sha1_src_path ${PROJECT_SOURCE_DIR}/src) 5 | 6 | INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include) 7 | 8 | AUX_SOURCE_DIRECTORY(${sha1_src_path} X_SRC) 9 | ADD_LIBRARY(sha1 STATIC ${X_SRC}) 10 | 11 | SET_TARGET_PROPERTIES(sha1 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${sha1_lib_path}") 12 | -------------------------------------------------------------------------------- /sha1_lib/src/sha1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #pragma warning(disable:4996) 5 | 6 | //初始化链接变量 7 | unsigned int A = 0x67452301, B = 0xEFCDAB89, C = 0x98BADCFE, D = 0x10325476, E = 0xC3D2E1F0; //第一次迭代的链接变量 8 | 9 | unsigned int K[4] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 }; //循环中用到的常量 10 | unsigned int A0 = 0x67452301, B0 = 0xEFCDAB89, C0 = 0x98BADCFE, D0 = 0x10325476, E0 = 0xC3D2E1F0; 11 | 12 | // 字节转换,将四个字节转换为一个整型 13 | int CharToWord(unsigned char *context, int i) 14 | { 15 | return (((int)context[i] & 0x000000ff) << 24) | (((int)context[i + 1] & 0x000000ff) << 16) | (((int)context[i + 2] & 0x000000ff) << 8) | ((int)context[i + 3] & 0x000000ff); 16 | } 17 | 18 | // 填充补位获得原始明文 19 | void SHA1_fill(unsigned char *plaintext, unsigned int *group, int length) 20 | { 21 | int temp = length / 32, len = length; 22 | while (len > 0) 23 | { 24 | if (len = len / 32) 25 | { 26 | for (int j = 0; j < temp; j++) 27 | { 28 | group[j] = CharToWord(plaintext, 4 * j); 29 | } 30 | } 31 | else 32 | { 33 | plaintext[length / 8] = 0x80; 34 | group[temp] = CharToWord(plaintext, temp * 4); 35 | break; 36 | } 37 | } 38 | group[15] = length; 39 | } 40 | // f函数 41 | unsigned int f(int B, int C, int D, int t) 42 | { 43 | return (t >= 0 && t <= 19) ? ((B&C) | (~B&D)) : ((t >= 20 && t <= 39) ? (B ^ C ^ D) : ((t >= 40 && t <= 59) ? ((B&C) | (B&D) | (C&D)) : ((t >= 60 && t <= 79) ? B ^ C ^ D : 0))); 44 | } 45 | //获得Kr 46 | unsigned int GetK(int r) 47 | { 48 | /* 49 | if (r >= 0&& r <= 19) 50 | { 51 | return K[0]; 52 | }else if (r >= 20 && r <= 39) 53 | { 54 | return K[1]; 55 | }else if (r >= 40 && r <= 59) 56 | { 57 | return K[2]; 58 | }else if (r >= 60 && r <= 79) 59 | { 60 | return K[3]; 61 | } 62 | */ 63 | return (r >= 0 && r <= 19) ? K[0] : ((r >= 20 && r <= 39) ? K[1] : ((r >= 40 && r <= 59) ? K[2] : ((r >= 60 && r <= 79) ? K[3] : 0))); 64 | } 65 | 66 | //获得 Wt 67 | void GetW(unsigned int w[]) 68 | { 69 | /* 70 | for (int i = 16; i < 80; i++) 71 | w[i] = ((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]) << 1) | ((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]) >> 31); 72 | */ 73 | for (int i = 16; i < 80; w[i++] = ((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]) << 1) | ((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]) >> 31)); 74 | } 75 | // 步函数 76 | void StepFunction(unsigned int w[], int t) 77 | { 78 | unsigned int temp = ((A << 5) | (A >> 27)) + f(B, C, D, t) + E + w[t] + GetK(t); 79 | E = D, D = C, C = ((B << 30) | (B >> 2)), B = A, A = temp; 80 | } 81 | // 获得密文 82 | void GetCipher(unsigned int * cipher) 83 | { 84 | cipher[0] = A0 + A; 85 | cipher[1] = B0 + B; 86 | cipher[2] = C0 + C; 87 | cipher[3] = D0 + D; 88 | cipher[4] = E0 + E; 89 | } 90 | 91 | void SHA1(unsigned char *context,unsigned int * cipher) 92 | { 93 | int len = strlen((char*)context) * 8; 94 | unsigned int group[80] = { 0 }; 95 | 96 | SHA1_fill(context, group, len); 97 | GetW(group); 98 | for (int t = 0; t < 80; t++) 99 | { 100 | StepFunction(group, t); 101 | } 102 | 103 | 104 | GetCipher(cipher); 105 | 106 | } -------------------------------------------------------------------------------- /sha1_lib/test/demo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcc0lin/dirty_algorithm/50c8276dcd65b5a8e23f78cf83e87df41d414358/sha1_lib/test/demo -------------------------------------------------------------------------------- /sha1_lib/test/demo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "sha1.h" 3 | using namespace std; 4 | 5 | int main() { 6 | unsigned char m[56] = "123"; 7 | unsigned int c[5] = { 0 }; 8 | SHA1(m,c); 9 | for (int j = 0; j <= 4; j++) printf("%08X", c[j]); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /sha1_lib/test/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | g++ demo.cpp -I../include/ -L../lib ../lib/libsha1.a -o demo 3 | clean: 4 | rm demo -------------------------------------------------------------------------------- /sha256_lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | add_subdirectory(src) 4 | -------------------------------------------------------------------------------- /sha256_lib/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcc0lin/dirty_algorithm/50c8276dcd65b5a8e23f78cf83e87df41d414358/sha256_lib/README.md -------------------------------------------------------------------------------- /sha256_lib/bulid/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -f ./run.sh ../run.sh; 4 | rm -rf *; 5 | cp -f ../run.sh ./run.sh; 6 | rm -f ../run.sh; 7 | cmake ../; 8 | make; 9 | make install; 10 | cp -f ./run.sh ../run.sh; 11 | rm -rf *; 12 | cp -f ../run.sh ./run.sh; 13 | rm -f ../run.sh; -------------------------------------------------------------------------------- /sha256_lib/include/sha256.h: -------------------------------------------------------------------------------- 1 | #ifndef SHA256_H 2 | #define SHA256_H 3 | 4 | #include 5 | #include 6 | 7 | class SHA256 { 8 | 9 | public: 10 | SHA256(); 11 | void update(const uint8_t * data, size_t length); 12 | void update(const std::string &data); 13 | uint8_t * digest(); 14 | 15 | static std::string toString(const uint8_t * digest); 16 | 17 | private: 18 | uint8_t m_data[64]; 19 | uint32_t m_blocklen; 20 | uint64_t m_bitlen; 21 | uint32_t m_state[8]; //A, B, C, D, E, F, G, H 22 | 23 | unsigned int K[64] = { 24 | 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5, 25 | 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, 26 | 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3, 27 | 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, 28 | 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc, 29 | 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, 30 | 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7, 31 | 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, 32 | 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13, 33 | 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, 34 | 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3, 35 | 0xd192e819,0xd6990624,0xf40e3585,0x106aa070, 36 | 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5, 37 | 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, 38 | 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208, 39 | 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 40 | }; 41 | 42 | static uint32_t rotr(uint32_t x, uint32_t n); 43 | static uint32_t choose(uint32_t e, uint32_t f, uint32_t g); 44 | static uint32_t majority(uint32_t a, uint32_t b, uint32_t c); 45 | static uint32_t sig0(uint32_t x); 46 | static uint32_t sig1(uint32_t x); 47 | void transform(); 48 | void pad(); 49 | void revert(uint8_t * hash); 50 | }; 51 | 52 | #endif -------------------------------------------------------------------------------- /sha256_lib/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | SET(CMAKE_CXX_FLAGS " -g -Wall -o2") 2 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 3 | SET(sha256_lib_path ${PROJECT_SOURCE_DIR}/lib) 4 | SET(sha256_src_path ${PROJECT_SOURCE_DIR}/src) 5 | 6 | INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include) 7 | 8 | AUX_SOURCE_DIRECTORY(${sha256_src_path} X_SRC) 9 | ADD_LIBRARY(sha256 STATIC ${X_SRC}) 10 | 11 | SET_TARGET_PROPERTIES(sha256 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${sha256_lib_path}") 12 | -------------------------------------------------------------------------------- /sha256_lib/src/sha256.cpp: -------------------------------------------------------------------------------- 1 | #include "SHA256.h" 2 | #include 3 | #include 4 | #include 5 | 6 | SHA256::SHA256(): m_blocklen(0), m_bitlen(0) { 7 | m_state[0] = 0x6a09e667; 8 | m_state[1] = 0xbb67ae85; 9 | m_state[2] = 0x3c6ef372; 10 | m_state[3] = 0xa54ff53a; 11 | m_state[4] = 0x510e527f; 12 | m_state[5] = 0x9b05688c; 13 | m_state[6] = 0x1f83d9ab; 14 | m_state[7] = 0x5be0cd19; 15 | } 16 | 17 | void SHA256::update(const uint8_t * data, size_t length) { 18 | for (size_t i = 0 ; i < length ; i++) { 19 | m_data[m_blocklen++] = data[i]; 20 | if (m_blocklen == 64) { 21 | transform(); 22 | 23 | // End of the block 24 | m_bitlen += 512; 25 | m_blocklen = 0; 26 | } 27 | } 28 | } 29 | 30 | void SHA256::update(const std::string &data) { 31 | update(reinterpret_cast (data.c_str()), data.size()); 32 | } 33 | 34 | uint8_t * SHA256::digest() { 35 | uint8_t * hash = new uint8_t[32]; 36 | 37 | pad(); 38 | revert(hash); 39 | 40 | return hash; 41 | } 42 | 43 | uint32_t SHA256::rotr(uint32_t x, uint32_t n) { 44 | return (x >> n) | (x << (32 - n)); 45 | } 46 | 47 | uint32_t SHA256::choose(uint32_t e, uint32_t f, uint32_t g) { 48 | return (e & f) ^ (~e & g); 49 | } 50 | 51 | uint32_t SHA256::majority(uint32_t a, uint32_t b, uint32_t c) { 52 | return (a & (b | c)) | (b & c); 53 | } 54 | 55 | uint32_t SHA256::sig0(uint32_t x) { 56 | return SHA256::rotr(x, 7) ^ SHA256::rotr(x, 18) ^ (x >> 3); 57 | } 58 | 59 | uint32_t SHA256::sig1(uint32_t x) { 60 | return SHA256::rotr(x, 17) ^ SHA256::rotr(x, 19) ^ (x >> 10); 61 | } 62 | 63 | void SHA256::transform() { 64 | uint32_t maj, xorA, ch, xorE, sum, newA, newE, m[64]; 65 | uint32_t state[8]; 66 | 67 | for (uint8_t i = 0, j = 0; i < 16; i++, j += 4) { // Split data in 32 bit blocks for the 16 first words 68 | m[i] = (m_data[j] << 24) | (m_data[j + 1] << 16) | (m_data[j + 2] << 8) | (m_data[j + 3]); 69 | } 70 | 71 | for (uint8_t k = 16 ; k < 64; k++) { // Remaining 48 blocks 72 | m[k] = SHA256::sig1(m[k - 2]) + m[k - 7] + SHA256::sig0(m[k - 15]) + m[k - 16]; 73 | } 74 | 75 | for(uint8_t i = 0 ; i < 8 ; i++) { 76 | state[i] = m_state[i]; 77 | } 78 | 79 | for (uint8_t i = 0; i < 64; i++) { 80 | maj = SHA256::majority(state[0], state[1], state[2]); 81 | xorA = SHA256::rotr(state[0], 2) ^ SHA256::rotr(state[0], 13) ^ SHA256::rotr(state[0], 22); 82 | 83 | ch = choose(state[4], state[5], state[6]); 84 | 85 | xorE = SHA256::rotr(state[4], 6) ^ SHA256::rotr(state[4], 11) ^ SHA256::rotr(state[4], 25); 86 | 87 | sum = m[i] + K[i] + state[7] + ch + xorE; 88 | newA = xorA + maj + sum; 89 | newE = state[3] + sum; 90 | 91 | state[7] = state[6]; 92 | state[6] = state[5]; 93 | state[5] = state[4]; 94 | state[4] = newE; 95 | state[3] = state[2]; 96 | state[2] = state[1]; 97 | state[1] = state[0]; 98 | state[0] = newA; 99 | } 100 | 101 | for(uint8_t i = 0 ; i < 8 ; i++) { 102 | m_state[i] += state[i]; 103 | } 104 | } 105 | 106 | void SHA256::pad() { 107 | 108 | uint64_t i = m_blocklen; 109 | uint8_t end = m_blocklen < 56 ? 56 : 64; 110 | 111 | m_data[i++] = 0x80; // Append a bit 1 112 | while (i < end) { 113 | m_data[i++] = 0x00; // Pad with zeros 114 | } 115 | 116 | if(m_blocklen >= 56) { 117 | transform(); 118 | memset(m_data, 0, 56); 119 | } 120 | 121 | // Append to the padding the total message's length in bits and transform. 122 | m_bitlen += m_blocklen * 8; 123 | m_data[63] = m_bitlen; 124 | m_data[62] = m_bitlen >> 8; 125 | m_data[61] = m_bitlen >> 16; 126 | m_data[60] = m_bitlen >> 24; 127 | m_data[59] = m_bitlen >> 32; 128 | m_data[58] = m_bitlen >> 40; 129 | m_data[57] = m_bitlen >> 48; 130 | m_data[56] = m_bitlen >> 56; 131 | transform(); 132 | } 133 | 134 | void SHA256::revert(uint8_t * hash) { 135 | // SHA uses big endian byte ordering 136 | // Revert all bytes 137 | for (uint8_t i = 0 ; i < 4 ; i++) { 138 | for(uint8_t j = 0 ; j < 8 ; j++) { 139 | hash[i + (j * 4)] = (m_state[j] >> (24 - i * 8)) & 0x000000ff; 140 | } 141 | } 142 | } 143 | 144 | std::string SHA256::toString(const uint8_t * digest) { 145 | std::stringstream s; 146 | s << std::setfill('0') << std::hex; 147 | 148 | for(uint8_t i = 0 ; i < 32 ; i++) { 149 | s << std::setw(2) << (unsigned int) digest[i]; 150 | } 151 | 152 | return s.str(); 153 | } -------------------------------------------------------------------------------- /sha256_lib/test/demo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcc0lin/dirty_algorithm/50c8276dcd65b5a8e23f78cf83e87df41d414358/sha256_lib/test/demo -------------------------------------------------------------------------------- /sha256_lib/test/demo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "sha256.h" 3 | using namespace std; 4 | 5 | int main() { 6 | string s = "hello world"; 7 | SHA256 sha; 8 | sha.update(s); 9 | uint8_t * digest = sha.digest(); 10 | 11 | std::cout << SHA256::toString(digest) << std::endl; 12 | delete[] digest; 13 | return 0; 14 | } -------------------------------------------------------------------------------- /sha256_lib/test/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | g++ demo.cpp -I../include/ -L../lib ../lib/libsha256.a -o demo 3 | clean: 4 | rm demo --------------------------------------------------------------------------------