├── CMakeLists.txt ├── LICENSE ├── README.md ├── chenxification ├── CMakeLists.txt ├── chenxify.cpp └── chenxify.h ├── run_test.sh └── test └── md5.c /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required(VERSION 3.3 FATAL_ERROR) 3 | 4 | project(chenxification) 5 | 6 | set(CMAKE_BUILD_TYPE Debug) 7 | set(CMAKE_CXX_STANDARD 14) 8 | 9 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/build") 10 | 11 | list(APPEND CMAKE_PREFIX_PATH "${LLVM_ROOT}/share/llvm/cmake") 12 | 13 | link_directories(/usr/local/lib) 14 | find_package(LLVM 4.0 REQUIRED CONFIG) 15 | 16 | add_definitions(${LLVM_DEFINITIONS}) 17 | 18 | include_directories(${LLVM_INCLUDE_DIRS}) 19 | #include_directories(${CMAKE_SOURCE_DIR}/include) 20 | 21 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 22 | 23 | include(HandleLLVMOptions) 24 | include(AddLLVM) 25 | 26 | add_subdirectory(chenxification) 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | University of Illinois/NCSA 2 | Open Source License 3 | 4 | Copyright (c) 2013 dwuid. All rights reserved. 5 | 6 | 7 | Developed by: dwuid 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. 12 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution. 13 | Neither the names of dwuid, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chenxification 2 | 3 | Exemplary LLVM 4.0 function pass implementing 4 | [Control Flow Flattening](https://pdfs.semanticscholar.org/6125/fa88ab17c8e2879482e10f0028ab3f681524.pdf). 5 | Take note that this is a straight port from a 2013 university assignment and 6 | thus might not make use of the latest LLVM features. 7 | 8 | ## Author 9 | [@dwuid](https://twitter.com/dwuid) 10 | 11 | ## License 12 | ``` 13 | University of Illinois/NCSA 14 | Open Source License 15 | 16 | Copyright (c) 2013 dwuid. All rights reserved. 17 | 18 | 19 | Developed by: dwuid 20 | 21 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 22 | 23 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. 24 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution. 25 | Neither the names of dwuid, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. 28 | ``` 29 | 30 | -------------------------------------------------------------------------------- /chenxification/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_llvm_loadable_module(Chenxification chenxify.cpp chenxify.h) 3 | -------------------------------------------------------------------------------- /chenxification/chenxify.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "chenxify.h" 3 | 4 | #include "llvm/Support/raw_ostream.h" 5 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 6 | 7 | #include 8 | 9 | using namespace std; 10 | using namespace llvm; 11 | 12 | bool Chenxify::runOnFunction(Function &function) { 13 | if(function.size() <= 1) { 14 | return false; 15 | } 16 | 17 | errs() << "Chenxifying "; 18 | errs().write_escaped(function.getName()) << ".\n"; 19 | 20 | auto split_index = get_average_block_length(function); 21 | if(split_index < minimum_split_size) { 22 | split_index = 0; 23 | } 24 | 25 | // FIXME: This does not work yet. ¯\_(ツ)_/¯ 26 | //split_basic_blocks(function, split_index); 27 | 28 | BasicBlock &entry = function.front(); 29 | auto &dominator_pass = getAnalysis(); 30 | 31 | assign_indices(function, entry); 32 | add_control_blocks(function, entry); 33 | connect_control_blocks(function, entry); 34 | 35 | rewrite_branches(function); 36 | replace_uses(function, dominator_pass); 37 | 38 | return true; 39 | } 40 | 41 | void Chenxify::getAnalysisUsage(AnalysisUsage &usage) const { 42 | usage.addRequired(); 43 | } 44 | 45 | size_t Chenxify::get_average_block_length(Function &function) const { 46 | if(!function.size()) { 47 | return 0; 48 | } 49 | 50 | size_t instruction_count = 0; 51 | for(BasicBlock &block : function) { 52 | for(auto i = block.getFirstInsertionPt(), e = block.end(); 53 | i != e; ++i) { 54 | instruction_count += 1; 55 | } 56 | } 57 | 58 | return instruction_count / function.size(); 59 | } 60 | 61 | void Chenxify::split_basic_blocks(Function &function, size_t split_index) { 62 | if(!split_index) { 63 | return; 64 | } 65 | 66 | vector blocks; 67 | for(BasicBlock &block : function) { 68 | blocks.push_back(&block); 69 | } 70 | 71 | for(BasicBlock *block : blocks) { 72 | if(block->size() < 2 * minimum_split_size) { 73 | continue; 74 | } 75 | 76 | auto j = 0u; 77 | for(auto i = block->getFirstInsertionPt(), e = block->end(); 78 | i != e; ++i, ++j) { 79 | if(j == split_index) { 80 | i->dump(); 81 | block->splitBasicBlock(&*i); 82 | } 83 | } 84 | } 85 | } 86 | 87 | void Chenxify::assign_indices(Function &function, BasicBlock &entry) { 88 | branching_blocks_.clear(); 89 | branch_targets_.clear(); 90 | 91 | for(BasicBlock &block : function) { 92 | auto terminator = block.getTerminator(); 93 | if(BranchInst *branch = dyn_cast(terminator)) { 94 | branching_blocks_.push_back(&block); 95 | 96 | if(branch->isUnconditional()) { 97 | branch_targets_.insert(branch->getSuccessor(0)); 98 | } else { 99 | branch_targets_.insert(branch->getSuccessor(0)); 100 | branch_targets_.insert(branch->getSuccessor(1)); 101 | } 102 | } 103 | } 104 | 105 | block_indices_.clear(); 106 | block_indices_[&entry] = 0; 107 | 108 | set random; 109 | uniform_int_distribution distribution; 110 | 111 | while(random.size() != branch_targets_.size()) { 112 | random.insert(distribution(engine_)); 113 | } 114 | 115 | auto block = branch_targets_.begin(); 116 | for(auto i = random.cbegin(), e = random.end(); i != e; ++i, ++block) { 117 | block_indices_[*block] = *i; 118 | } 119 | } 120 | 121 | void Chenxify::add_control_blocks(Function &function, BasicBlock &e) { 122 | auto &context = function.getContext(); 123 | auto int_type = IntegerType::getInt32Ty(context); 124 | 125 | const auto entry = prefix_ + "entry"; 126 | const auto dispatch = prefix_ + "dispatch"; 127 | const auto latch = prefix_ + "latch"; 128 | 129 | block_entry_ = BasicBlock::Create(context, entry, &function, &e); 130 | block_dispatch_ = BasicBlock::Create(context, dispatch, &function, &e); 131 | block_latch_ = BasicBlock::Create(context, latch, &function, &e); 132 | 133 | const auto phi_dispatch = prefix_ + "phi_dispatch"; 134 | const auto phi_latch = prefix_ + "phi_latch"; 135 | 136 | phi_dispatch_ = PHINode::Create(int_type, 0, phi_dispatch, block_dispatch_); 137 | phi_latch_ = PHINode::Create(int_type, 0, phi_latch, block_latch_); 138 | } 139 | 140 | void Chenxify::connect_control_blocks(Function &function, BasicBlock &entry) { 141 | auto &context = function.getContext(); 142 | auto int_type = IntegerType::getInt32Ty(context); 143 | 144 | vip_ = new AllocaInst(int_type, prefix_ + "alloca_vip", block_entry_); 145 | new StoreInst(Constant::getNullValue(int_type), vip_, block_entry_); 146 | 147 | auto load_vip = new LoadInst(vip_, prefix_ + "vip", block_entry_); 148 | 149 | phi_dispatch_->addIncoming(load_vip, block_entry_); 150 | phi_dispatch_->addIncoming(phi_latch_, block_latch_); 151 | 152 | BranchInst::Create(block_dispatch_, block_entry_); 153 | BranchInst::Create(block_dispatch_, block_latch_); 154 | 155 | switch_ = SwitchInst::Create(phi_dispatch_, &entry, 0, block_dispatch_); 156 | 157 | for(BasicBlock *block : branch_targets_) { 158 | auto index = block_indices_[block]; 159 | switch_->addCase(ConstantInt::get(int_type, index), block); 160 | } 161 | } 162 | 163 | void Chenxify::rewrite_branches(Function &function) { 164 | auto &context = function.getContext(); 165 | auto int_type = IntegerType::getInt32Ty(context); 166 | 167 | for(BasicBlock *block : branching_blocks_) { 168 | const string label = prefix_ + "forward"; 169 | 170 | auto terminator = block->getTerminator(); 171 | BranchInst *branch = dyn_cast(terminator); 172 | 173 | if(branch->isUnconditional()) { 174 | auto successor = branch->getSuccessor(0); 175 | successor->removePredecessor(block); 176 | 177 | uint32_t delta = block_indices_[successor] - block_indices_[block]; 178 | auto delta_constant = ConstantInt::get(int_type, delta); 179 | 180 | auto *forward = BinaryOperator::Create(Instruction::Add, 181 | phi_dispatch_, 182 | delta_constant, 183 | label, branch); 184 | 185 | branch->setSuccessor(0, block_latch_); 186 | phi_latch_->addIncoming(forward, block); 187 | continue; 188 | } 189 | 190 | auto successor_t = branch->getSuccessor(0); 191 | auto successor_f = branch->getSuccessor(1); 192 | 193 | successor_t->removePredecessor(block); 194 | successor_f->removePredecessor(block); 195 | 196 | auto block_t = BasicBlock::Create(context, label, &function, block); 197 | auto block_f = BasicBlock::Create(context, label, &function, block); 198 | 199 | uint32_t delta = block_indices_[successor_t] - block_indices_[block]; 200 | auto delta_true = ConstantInt::get(int_type, delta); 201 | 202 | auto *forward_t = BinaryOperator::Create(Instruction::Add, 203 | phi_dispatch_, 204 | delta_true, 205 | label, block_t); 206 | 207 | delta = block_indices_[successor_f] - block_indices_[block]; 208 | auto delta_false = ConstantInt::get(int_type, delta); 209 | 210 | auto *forward_f = BinaryOperator::Create(Instruction::Add, 211 | phi_dispatch_, 212 | delta_false, 213 | label, block_f); 214 | 215 | BranchInst::Create(block_latch_, block_t); 216 | BranchInst::Create(block_latch_, block_f); 217 | 218 | phi_latch_->addIncoming(forward_t, block_t); 219 | phi_latch_->addIncoming(forward_f, block_f); 220 | 221 | branch->setSuccessor(0, block_t); 222 | branch->setSuccessor(1, block_f); 223 | } 224 | } 225 | 226 | void Chenxify::replace_uses(Function &function, 227 | DominatorTreeWrapperPass &dominators) { 228 | dominators.runOnFunction(function); 229 | DominatorTree &dominator_tree = dominators.getDomTree(); 230 | 231 | std::set conflicts; 232 | for(BasicBlock &block : function) { 233 | for(Instruction &instruction : block.getInstList()) { 234 | for(auto i = 0u, e = instruction.getNumOperands(); i != e; ++i) { 235 | Instruction *operand = 236 | dyn_cast(instruction.getOperand(i)); 237 | if(!operand) { 238 | continue; 239 | } 240 | 241 | const Use &use = instruction.getOperandUse(i); 242 | if(!dominator_tree.dominates(operand, use)) { 243 | conflicts.insert(operand); 244 | } 245 | } 246 | } 247 | } 248 | 249 | for(Instruction *operand : conflicts) { 250 | if(isa(operand)) { 251 | operand->removeFromParent(); 252 | operand->insertAfter(block_entry_->getFirstNonPHI()); 253 | continue; 254 | } 255 | 256 | auto type = operand->getType(); 257 | auto initialization = new AllocaInst(type, vip_); 258 | new StoreInst(Constant::getNullValue(type), initialization, vip_); 259 | 260 | auto default_ = new LoadInst(initialization, prefix_ + "default", vip_); 261 | auto phi = PHINode::Create(type, 0, prefix_ + "phi", phi_dispatch_); 262 | 263 | phi->addIncoming(default_, block_entry_); 264 | operand->replaceAllUsesWith(phi); 265 | 266 | auto phi_latch = PHINode::Create(type, 0, prefix_ + "phi_latch", 267 | phi_latch_); 268 | phi_latch->addIncoming(operand, operand->getParent()); 269 | 270 | for(auto i = pred_begin(block_latch_), e = pred_end(block_latch_); 271 | i != e; ++i) { 272 | if(*i != operand->getParent()) { 273 | phi_latch->addIncoming(phi, *i); 274 | } 275 | } 276 | 277 | phi->addIncoming(phi_latch , block_latch_); 278 | } 279 | } 280 | 281 | char Chenxify::ID = 0; 282 | const string Chenxify::prefix_ = "__chenxify_"; 283 | 284 | static RegisterPass _("chenxify", 285 | "Pass to flatten the control flow graph" 286 | " (Chenxification)", false, false); 287 | -------------------------------------------------------------------------------- /chenxification/chenxify.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "llvm/Pass.h" 5 | 6 | #include "llvm/IR/Type.h" 7 | #include "llvm/IR/Constant.h" 8 | #include "llvm/IR/Function.h" 9 | #include "llvm/IR/IRBuilder.h" 10 | #include "llvm/IR/Dominators.h" 11 | #include "llvm/IR/Instructions.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | class Chenxify : public llvm::FunctionPass { 21 | public: 22 | static char ID; 23 | 24 | public: 25 | Chenxify() : FunctionPass(ID), engine_(device_()) { 26 | } 27 | 28 | virtual ~Chenxify() { 29 | } 30 | 31 | virtual bool runOnFunction(llvm::Function &function) override; 32 | virtual void getAnalysisUsage(llvm::AnalysisUsage &usage) const override; 33 | 34 | private: 35 | size_t get_average_block_length(llvm::Function &function) const; 36 | void split_basic_blocks(llvm::Function &function, size_t split_index); 37 | 38 | void assign_indices(llvm::Function &function, llvm::BasicBlock &entry); 39 | void add_control_blocks(llvm::Function &function, llvm::BasicBlock &entry); 40 | void connect_control_blocks(llvm::Function &function, 41 | llvm::BasicBlock &entry); 42 | 43 | void rewrite_branches(llvm::Function &function); 44 | void replace_uses(llvm::Function &function, 45 | llvm::DominatorTreeWrapperPass &dominator_pass); 46 | 47 | private: 48 | const size_t minimum_split_size = 3; 49 | 50 | static const std::string prefix_; 51 | std::random_device device_; 52 | std::default_random_engine engine_; 53 | 54 | std::vector branching_blocks_; 55 | std::set branch_targets_; 56 | 57 | std::map block_indices_; 58 | 59 | llvm::BasicBlock *block_entry_ = nullptr, 60 | *block_dispatch_ = nullptr, 61 | *block_latch_ = nullptr; 62 | 63 | llvm::Instruction *vip_ = nullptr; 64 | llvm::SwitchInst *switch_ = nullptr; 65 | 66 | llvm::PHINode *phi_dispatch_ = nullptr, 67 | *phi_latch_ = nullptr; 68 | }; 69 | -------------------------------------------------------------------------------- /run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | clang ./test/md5.c -o ./test/md5-orig 6 | clang ./test/md5.c -emit-llvm -c -o ./test/md5.bc 7 | 8 | opt -load ./build/chenxification/Chenxification.so \ 9 | -loop-simplify -lowerswitch -reg2mem \ 10 | -chenxify \ 11 | -mem2reg -dot-cfg \ 12 | ./test/md5.bc -o ./test/md5.bc 13 | 14 | clang -O3 ./test/md5.bc -o ./test/md5 15 | 16 | echo "foo" > ./test/foo 17 | 18 | set +e 19 | (cd ./test && diff <(./md5 -x) <(./md5-orig -x) >/dev/null); 20 | 21 | RESULT=$? 22 | if [ $RESULT -eq 0 ]; then 23 | echo -e "\nAll good." 24 | else 25 | echo -e "\nTransformation is NOT semantics-preserving!" 26 | fi 27 | 28 | -------------------------------------------------------------------------------- /test/md5.c: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************** 3 | ** md5.h -- Header file for implementation of MD5 ** 4 | ** RSA Data Security, Inc. MD5 Message Digest Algorithm ** 5 | ** Created: 2/17/90 RLR ** 6 | ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version ** 7 | ** Revised (for MD5): RLR 4/27/91 ** 8 | ** -- G modified to have y&~z instead of y&z ** 9 | ** -- FF, GG, HH modified to add in last register done ** 10 | ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 ** 11 | ** -- distinct additive constant for each step ** 12 | ** -- round 4 added, working mod 7 ** 13 | ********************************************************************** 14 | */ 15 | 16 | /* 17 | ********************************************************************** 18 | ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** 19 | ** ** 20 | ** License to copy and use this software is granted provided that ** 21 | ** it is identified as the "RSA Data Security, Inc. MD5 Message ** 22 | ** Digest Algorithm" in all material mentioning or referencing this ** 23 | ** software or this function. ** 24 | ** ** 25 | ** License is also granted to make and use derivative works ** 26 | ** provided that such works are identified as "derived from the RSA ** 27 | ** Data Security, Inc. MD5 Message Digest Algorithm" in all ** 28 | ** material mentioning or referencing the derived work. ** 29 | ** ** 30 | ** RSA Data Security, Inc. makes no representations concerning ** 31 | ** either the merchantability of this software or the suitability ** 32 | ** of this software for any particular purpose. It is provided "as ** 33 | ** is" without express or implied warranty of any kind. ** 34 | ** ** 35 | ** These notices must be retained in any copies of any part of this ** 36 | ** documentation and/or software. ** 37 | ********************************************************************** 38 | */ 39 | 40 | /* typedef a 32 bit type */ 41 | typedef unsigned long int UINT4; 42 | 43 | /* Data structure for MD5 (Message Digest) computation */ 44 | typedef struct { 45 | UINT4 i[2]; /* number of _bits_ handled mod 2^64 */ 46 | UINT4 buf[4]; /* scratch buffer */ 47 | unsigned char in[64]; /* input buffer */ 48 | unsigned char digest[16]; /* actual digest after MD5Final call */ 49 | } MD5_CTX; 50 | 51 | void MD5Init (); 52 | void MD5Update (); 53 | void MD5Final (); 54 | 55 | /* 56 | ********************************************************************** 57 | ** End of md5.h ** 58 | ******************************* (cut) ******************************** 59 | */ 60 | 61 | /* 62 | ********************************************************************** 63 | ** md5.c ** 64 | ** RSA Data Security, Inc. MD5 Message Digest Algorithm ** 65 | ** Created: 2/17/90 RLR ** 66 | ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version ** 67 | ********************************************************************** 68 | */ 69 | 70 | /* 71 | ********************************************************************** 72 | ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** 73 | ** ** 74 | ** License to copy and use this software is granted provided that ** 75 | ** it is identified as the "RSA Data Security, Inc. MD5 Message ** 76 | ** Digest Algorithm" in all material mentioning or referencing this ** 77 | ** software or this function. ** 78 | ** ** 79 | ** License is also granted to make and use derivative works ** 80 | ** provided that such works are identified as "derived from the RSA ** 81 | ** Data Security, Inc. MD5 Message Digest Algorithm" in all ** 82 | ** material mentioning or referencing the derived work. ** 83 | ** ** 84 | ** RSA Data Security, Inc. makes no representations concerning ** 85 | ** either the merchantability of this software or the suitability ** 86 | ** of this software for any particular purpose. It is provided "as ** 87 | ** is" without express or implied warranty of any kind. ** 88 | ** ** 89 | ** These notices must be retained in any copies of any part of this ** 90 | ** documentation and/or software. ** 91 | ********************************************************************** 92 | */ 93 | 94 | /* -- include the following line if the md5.h header file is separate -- */ 95 | /* #include "md5.h" */ 96 | 97 | /* forward declaration */ 98 | static void Transform (); 99 | 100 | static unsigned char PADDING[64] = { 101 | 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 102 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 103 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 104 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 105 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 106 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 107 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 108 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 109 | }; 110 | 111 | /* F, G and H are basic MD5 functions: selection, majority, parity */ 112 | #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) 113 | #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) 114 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 115 | #define I(x, y, z) ((y) ^ ((x) | (~z))) 116 | 117 | /* ROTATE_LEFT rotates x left n bits */ 118 | #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) 119 | 120 | /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ 121 | /* Rotation is separate from addition to prevent recomputation */ 122 | #define FF(a, b, c, d, x, s, ac) \ 123 | {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ 124 | (a) = ROTATE_LEFT ((a), (s)); \ 125 | (a) += (b); \ 126 | } 127 | #define GG(a, b, c, d, x, s, ac) \ 128 | {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ 129 | (a) = ROTATE_LEFT ((a), (s)); \ 130 | (a) += (b); \ 131 | } 132 | #define HH(a, b, c, d, x, s, ac) \ 133 | {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ 134 | (a) = ROTATE_LEFT ((a), (s)); \ 135 | (a) += (b); \ 136 | } 137 | #define II(a, b, c, d, x, s, ac) \ 138 | {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ 139 | (a) = ROTATE_LEFT ((a), (s)); \ 140 | (a) += (b); \ 141 | } 142 | 143 | void MD5Init (mdContext) 144 | MD5_CTX *mdContext; 145 | { 146 | mdContext->i[0] = mdContext->i[1] = (UINT4)0; 147 | 148 | /* Load magic initialization constants. 149 | */ 150 | mdContext->buf[0] = (UINT4)0x67452301; 151 | mdContext->buf[1] = (UINT4)0xefcdab89; 152 | mdContext->buf[2] = (UINT4)0x98badcfe; 153 | mdContext->buf[3] = (UINT4)0x10325476; 154 | } 155 | 156 | void MD5Update (mdContext, inBuf, inLen) 157 | MD5_CTX *mdContext; 158 | unsigned char *inBuf; 159 | unsigned int inLen; 160 | { 161 | UINT4 in[16]; 162 | int mdi; 163 | unsigned int i, ii; 164 | 165 | /* compute number of bytes mod 64 */ 166 | mdi = (int)((mdContext->i[0] >> 3) & 0x3F); 167 | 168 | /* update number of bits */ 169 | if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) 170 | mdContext->i[1]++; 171 | mdContext->i[0] += ((UINT4)inLen << 3); 172 | mdContext->i[1] += ((UINT4)inLen >> 29); 173 | 174 | while (inLen--) { 175 | /* add new character to buffer, increment mdi */ 176 | mdContext->in[mdi++] = *inBuf++; 177 | 178 | /* transform if necessary */ 179 | if (mdi == 0x40) { 180 | for (i = 0, ii = 0; i < 16; i++, ii += 4) 181 | in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | 182 | (((UINT4)mdContext->in[ii+2]) << 16) | 183 | (((UINT4)mdContext->in[ii+1]) << 8) | 184 | ((UINT4)mdContext->in[ii]); 185 | Transform (mdContext->buf, in); 186 | mdi = 0; 187 | } 188 | } 189 | } 190 | 191 | void MD5Final (mdContext) 192 | MD5_CTX *mdContext; 193 | { 194 | UINT4 in[16]; 195 | int mdi; 196 | unsigned int i, ii; 197 | unsigned int padLen; 198 | 199 | /* save number of bits */ 200 | in[14] = mdContext->i[0]; 201 | in[15] = mdContext->i[1]; 202 | 203 | /* compute number of bytes mod 64 */ 204 | mdi = (int)((mdContext->i[0] >> 3) & 0x3F); 205 | 206 | /* pad out to 56 mod 64 */ 207 | padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); 208 | MD5Update (mdContext, PADDING, padLen); 209 | 210 | /* append length in bits and transform */ 211 | for (i = 0, ii = 0; i < 14; i++, ii += 4) 212 | in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | 213 | (((UINT4)mdContext->in[ii+2]) << 16) | 214 | (((UINT4)mdContext->in[ii+1]) << 8) | 215 | ((UINT4)mdContext->in[ii]); 216 | Transform (mdContext->buf, in); 217 | 218 | /* store buffer in digest */ 219 | for (i = 0, ii = 0; i < 4; i++, ii += 4) { 220 | mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); 221 | mdContext->digest[ii+1] = 222 | (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); 223 | mdContext->digest[ii+2] = 224 | (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); 225 | mdContext->digest[ii+3] = 226 | (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); 227 | } 228 | } 229 | 230 | /* Basic MD5 step. Transform buf based on in. 231 | */ 232 | static void Transform (buf, in) 233 | UINT4 *buf; 234 | UINT4 *in; 235 | { 236 | UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; 237 | 238 | /* Round 1 */ 239 | #define S11 7 240 | #define S12 12 241 | #define S13 17 242 | #define S14 22 243 | FF ( a, b, c, d, in[ 0], S11, 3614090360); /* 1 */ 244 | FF ( d, a, b, c, in[ 1], S12, 3905402710); /* 2 */ 245 | FF ( c, d, a, b, in[ 2], S13, 606105819); /* 3 */ 246 | FF ( b, c, d, a, in[ 3], S14, 3250441966); /* 4 */ 247 | FF ( a, b, c, d, in[ 4], S11, 4118548399); /* 5 */ 248 | FF ( d, a, b, c, in[ 5], S12, 1200080426); /* 6 */ 249 | FF ( c, d, a, b, in[ 6], S13, 2821735955); /* 7 */ 250 | FF ( b, c, d, a, in[ 7], S14, 4249261313); /* 8 */ 251 | FF ( a, b, c, d, in[ 8], S11, 1770035416); /* 9 */ 252 | FF ( d, a, b, c, in[ 9], S12, 2336552879); /* 10 */ 253 | FF ( c, d, a, b, in[10], S13, 4294925233); /* 11 */ 254 | FF ( b, c, d, a, in[11], S14, 2304563134); /* 12 */ 255 | FF ( a, b, c, d, in[12], S11, 1804603682); /* 13 */ 256 | FF ( d, a, b, c, in[13], S12, 4254626195); /* 14 */ 257 | FF ( c, d, a, b, in[14], S13, 2792965006); /* 15 */ 258 | FF ( b, c, d, a, in[15], S14, 1236535329); /* 16 */ 259 | 260 | /* Round 2 */ 261 | #define S21 5 262 | #define S22 9 263 | #define S23 14 264 | #define S24 20 265 | GG ( a, b, c, d, in[ 1], S21, 4129170786); /* 17 */ 266 | GG ( d, a, b, c, in[ 6], S22, 3225465664); /* 18 */ 267 | GG ( c, d, a, b, in[11], S23, 643717713); /* 19 */ 268 | GG ( b, c, d, a, in[ 0], S24, 3921069994); /* 20 */ 269 | GG ( a, b, c, d, in[ 5], S21, 3593408605); /* 21 */ 270 | GG ( d, a, b, c, in[10], S22, 38016083); /* 22 */ 271 | GG ( c, d, a, b, in[15], S23, 3634488961); /* 23 */ 272 | GG ( b, c, d, a, in[ 4], S24, 3889429448); /* 24 */ 273 | GG ( a, b, c, d, in[ 9], S21, 568446438); /* 25 */ 274 | GG ( d, a, b, c, in[14], S22, 3275163606); /* 26 */ 275 | GG ( c, d, a, b, in[ 3], S23, 4107603335); /* 27 */ 276 | GG ( b, c, d, a, in[ 8], S24, 1163531501); /* 28 */ 277 | GG ( a, b, c, d, in[13], S21, 2850285829); /* 29 */ 278 | GG ( d, a, b, c, in[ 2], S22, 4243563512); /* 30 */ 279 | GG ( c, d, a, b, in[ 7], S23, 1735328473); /* 31 */ 280 | GG ( b, c, d, a, in[12], S24, 2368359562); /* 32 */ 281 | 282 | /* Round 3 */ 283 | #define S31 4 284 | #define S32 11 285 | #define S33 16 286 | #define S34 23 287 | HH ( a, b, c, d, in[ 5], S31, 4294588738); /* 33 */ 288 | HH ( d, a, b, c, in[ 8], S32, 2272392833); /* 34 */ 289 | HH ( c, d, a, b, in[11], S33, 1839030562); /* 35 */ 290 | HH ( b, c, d, a, in[14], S34, 4259657740); /* 36 */ 291 | HH ( a, b, c, d, in[ 1], S31, 2763975236); /* 37 */ 292 | HH ( d, a, b, c, in[ 4], S32, 1272893353); /* 38 */ 293 | HH ( c, d, a, b, in[ 7], S33, 4139469664); /* 39 */ 294 | HH ( b, c, d, a, in[10], S34, 3200236656); /* 40 */ 295 | HH ( a, b, c, d, in[13], S31, 681279174); /* 41 */ 296 | HH ( d, a, b, c, in[ 0], S32, 3936430074); /* 42 */ 297 | HH ( c, d, a, b, in[ 3], S33, 3572445317); /* 43 */ 298 | HH ( b, c, d, a, in[ 6], S34, 76029189); /* 44 */ 299 | HH ( a, b, c, d, in[ 9], S31, 3654602809); /* 45 */ 300 | HH ( d, a, b, c, in[12], S32, 3873151461); /* 46 */ 301 | HH ( c, d, a, b, in[15], S33, 530742520); /* 47 */ 302 | HH ( b, c, d, a, in[ 2], S34, 3299628645); /* 48 */ 303 | 304 | /* Round 4 */ 305 | #define S41 6 306 | #define S42 10 307 | #define S43 15 308 | #define S44 21 309 | II ( a, b, c, d, in[ 0], S41, 4096336452); /* 49 */ 310 | II ( d, a, b, c, in[ 7], S42, 1126891415); /* 50 */ 311 | II ( c, d, a, b, in[14], S43, 2878612391); /* 51 */ 312 | II ( b, c, d, a, in[ 5], S44, 4237533241); /* 52 */ 313 | II ( a, b, c, d, in[12], S41, 1700485571); /* 53 */ 314 | II ( d, a, b, c, in[ 3], S42, 2399980690); /* 54 */ 315 | II ( c, d, a, b, in[10], S43, 4293915773); /* 55 */ 316 | II ( b, c, d, a, in[ 1], S44, 2240044497); /* 56 */ 317 | II ( a, b, c, d, in[ 8], S41, 1873313359); /* 57 */ 318 | II ( d, a, b, c, in[15], S42, 4264355552); /* 58 */ 319 | II ( c, d, a, b, in[ 6], S43, 2734768916); /* 59 */ 320 | II ( b, c, d, a, in[13], S44, 1309151649); /* 60 */ 321 | II ( a, b, c, d, in[ 4], S41, 4149444226); /* 61 */ 322 | II ( d, a, b, c, in[11], S42, 3174756917); /* 62 */ 323 | II ( c, d, a, b, in[ 2], S43, 718787259); /* 63 */ 324 | II ( b, c, d, a, in[ 9], S44, 3951481745); /* 64 */ 325 | 326 | buf[0] += a; 327 | buf[1] += b; 328 | buf[2] += c; 329 | buf[3] += d; 330 | } 331 | 332 | /* 333 | ********************************************************************** 334 | ** End of md5.c ** 335 | ******************************* (cut) ******************************** 336 | */ 337 | 338 | /* 339 | ********************************************************************** 340 | ** md5driver.c -- sample routines to test ** 341 | ** RSA Data Security, Inc. MD5 message digest algorithm. ** 342 | ** Created: 2/16/90 RLR ** 343 | ** Updated: 1/91 SRD ** 344 | ********************************************************************** 345 | */ 346 | 347 | /* 348 | ********************************************************************** 349 | ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** 350 | ** ** 351 | ** RSA Data Security, Inc. makes no representations concerning ** 352 | ** either the merchantability of this software or the suitability ** 353 | ** of this software for any particular purpose. It is provided "as ** 354 | ** is" without express or implied warranty of any kind. ** 355 | ** ** 356 | ** These notices must be retained in any copies of any part of this ** 357 | ** documentation and/or software. ** 358 | ********************************************************************** 359 | */ 360 | 361 | #include 362 | #include 363 | #include 364 | #include 365 | /* -- include the following file if the file md5.h is separate -- */ 366 | /* #include "md5.h" */ 367 | 368 | /* Prints message digest buffer in mdContext as 32 hexadecimal digits. 369 | Order is from low-order byte to high-order byte of digest. 370 | Each byte is printed with high-order hexadecimal digit first. 371 | */ 372 | static void MDPrint (mdContext) 373 | MD5_CTX *mdContext; 374 | { 375 | int i; 376 | 377 | for (i = 0; i < 16; i++) 378 | printf ("%02x", mdContext->digest[i]); 379 | } 380 | 381 | /* size of test block */ 382 | #define TEST_BLOCK_SIZE 1000 383 | 384 | /* number of blocks to process */ 385 | #define TEST_BLOCKS 10000 386 | 387 | /* number of test bytes = TEST_BLOCK_SIZE * TEST_BLOCKS */ 388 | static long TEST_BYTES = (long)TEST_BLOCK_SIZE * (long)TEST_BLOCKS; 389 | 390 | /* A time trial routine, to measure the speed of MD5. 391 | Measures wall time required to digest TEST_BLOCKS * TEST_BLOCK_SIZE 392 | characters. 393 | */ 394 | static void MDTimeTrial () 395 | { 396 | MD5_CTX mdContext; 397 | time_t endTime, startTime; 398 | unsigned char data[TEST_BLOCK_SIZE]; 399 | unsigned int i; 400 | 401 | /* initialize test data */ 402 | for (i = 0; i < TEST_BLOCK_SIZE; i++) 403 | data[i] = (unsigned char)(i & 0xFF); 404 | 405 | /* start timer */ 406 | printf ("MD5 time trial. Processing %ld characters...\n", TEST_BYTES); 407 | time (&startTime); 408 | 409 | /* digest data in TEST_BLOCK_SIZE byte blocks */ 410 | MD5Init (&mdContext); 411 | for (i = TEST_BLOCKS; i > 0; i--) 412 | MD5Update (&mdContext, data, TEST_BLOCK_SIZE); 413 | MD5Final (&mdContext); 414 | 415 | /* stop timer, get time difference */ 416 | time (&endTime); 417 | MDPrint (&mdContext); 418 | printf (" is digest of test input.\n"); 419 | printf 420 | ("Seconds to process test input: %ld\n", (long)(endTime-startTime)); 421 | printf 422 | ("Characters processed per second: %ld\n", 423 | TEST_BYTES/(endTime-startTime)); 424 | } 425 | 426 | /* Computes the message digest for string inString. 427 | Prints out message digest, a space, the string (in quotes) and a 428 | carriage return. 429 | */ 430 | static void MDString (inString) 431 | char *inString; 432 | { 433 | MD5_CTX mdContext; 434 | unsigned int len = strlen (inString); 435 | 436 | MD5Init (&mdContext); 437 | MD5Update (&mdContext, (unsigned char*)inString, len); 438 | MD5Final (&mdContext); 439 | MDPrint (&mdContext); 440 | printf (" \"%s\"\n\n", inString); 441 | } 442 | 443 | /* Computes the message digest for a specified file. 444 | Prints out message digest, a space, the file name, and a carriage 445 | return. 446 | */ 447 | static void MDFile (filename) 448 | char *filename; 449 | { 450 | FILE *inFile = fopen (filename, "rb"); 451 | MD5_CTX mdContext; 452 | int bytes; 453 | unsigned char data[1024]; 454 | 455 | if (inFile == NULL) { 456 | printf ("%s can't be opened.\n", filename); 457 | return; 458 | } 459 | 460 | MD5Init (&mdContext); 461 | while ((bytes = fread (data, 1, 1024, inFile)) != 0) 462 | MD5Update (&mdContext, data, bytes); 463 | MD5Final (&mdContext); 464 | MDPrint (&mdContext); 465 | printf (" %s\n", filename); 466 | fclose (inFile); 467 | } 468 | 469 | /* Writes the message digest of the data from stdin onto stdout, 470 | followed by a carriage return. 471 | */ 472 | static void MDFilter () 473 | { 474 | MD5_CTX mdContext; 475 | int bytes; 476 | unsigned char data[16]; 477 | 478 | MD5Init (&mdContext); 479 | while ((bytes = fread (data, 1, 16, stdin)) != 0) 480 | MD5Update (&mdContext, data, bytes); 481 | MD5Final (&mdContext); 482 | MDPrint (&mdContext); 483 | printf ("\n"); 484 | } 485 | 486 | /* Runs a standard suite of test data. 487 | */ 488 | static void MDTestSuite () 489 | { 490 | printf ("MD5 test suite results:\n\n"); 491 | MDString (""); 492 | MDString ("a"); 493 | MDString ("abc"); 494 | MDString ("message digest"); 495 | MDString ("abcdefghijklmnopqrstuvwxyz"); 496 | MDString 497 | ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); 498 | MDString 499 | ("1234567890123456789012345678901234567890\ 500 | 1234567890123456789012345678901234567890"); 501 | /* Contents of file foo are "abc" */ 502 | MDFile ("foo"); 503 | } 504 | 505 | int main (argc, argv) 506 | int argc; 507 | char *argv[]; 508 | { 509 | int i; 510 | 511 | /* For each command line argument in turn: 512 | ** filename -- prints message digest and name of file 513 | ** -sstring -- prints message digest and contents of string 514 | ** -t -- prints time trial statistics for 1M characters 515 | ** -x -- execute a standard suite of test data 516 | ** (no args) -- writes messages digest of stdin onto stdout 517 | */ 518 | if (argc == 1) 519 | MDFilter (); 520 | else 521 | for (i = 1; i < argc; i++) 522 | if (argv[i][0] == '-' && argv[i][1] == 's') 523 | MDString (argv[i] + 2); 524 | else if (strcmp (argv[i], "-t") == 0) 525 | MDTimeTrial (); 526 | else if (strcmp (argv[i], "-x") == 0) 527 | MDTestSuite (); 528 | else MDFile (argv[i]); 529 | } 530 | 531 | /* 532 | ********************************************************************** 533 | ** End of md5driver.c ** 534 | ******************************* (cut) ******************************** 535 | */ 536 | --------------------------------------------------------------------------------