Botan
1.11.15
|
00001 /* 00002 * Bcrypt Password Hashing 00003 * (C) 2010 Jack Lloyd 00004 * 00005 * Botan is released under the Simplified BSD License (see license.txt) 00006 */ 00007 00008 #include <botan/bcrypt.h> 00009 #include <botan/loadstor.h> 00010 #include <botan/blowfish.h> 00011 #include <botan/base64.h> 00012 00013 namespace Botan { 00014 00015 namespace { 00016 00017 std::string bcrypt_base64_encode(const byte input[], size_t length) 00018 { 00019 // Bcrypt uses a non-standard base64 alphabet 00020 const byte OPENBSD_BASE64_SUB[256] = { 00021 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00022 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00023 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00024 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x38, 0x80, 0x80, 0x80, 0x39, 00025 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x80, 0x80, 00026 0x80, 0x80, 0x80, 0x80, 0x80, 0x2E, 0x2F, 0x41, 0x42, 0x43, 0x44, 0x45, 00027 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 00028 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x80, 0x80, 0x80, 0x80, 0x80, 00029 0x80, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 00030 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 00031 0x76, 0x77, 0x78, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00032 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00033 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00034 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00035 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00036 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00037 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00038 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00039 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00040 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00041 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00042 0x80, 0x80, 0x80, 0x80 00043 }; 00044 00045 std::string b64 = base64_encode(input, length); 00046 00047 while(b64.size() && b64[b64.size()-1] == '=') 00048 b64 = b64.substr(0, b64.size() - 1); 00049 00050 for(size_t i = 0; i != b64.size(); ++i) 00051 b64[i] = OPENBSD_BASE64_SUB[static_cast<byte>(b64[i])]; 00052 00053 return b64; 00054 } 00055 00056 std::vector<byte> bcrypt_base64_decode(std::string input) 00057 { 00058 const byte OPENBSD_BASE64_SUB[256] = { 00059 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00060 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00061 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00062 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x41, 0x42, 00063 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F, 0x80, 0x80, 00064 0x80, 0x80, 0x80, 0x80, 0x80, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 00065 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 00066 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x80, 0x80, 0x80, 0x80, 0x80, 00067 0x80, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 00068 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 00069 0x7A, 0x30, 0x31, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00070 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00071 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00072 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00073 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00074 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00075 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00076 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00077 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00078 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00079 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 00080 0x80, 0x80, 0x80, 0x80 00081 }; 00082 00083 for(size_t i = 0; i != input.size(); ++i) 00084 input[i] = OPENBSD_BASE64_SUB[static_cast<byte>(input[i])]; 00085 00086 return unlock(base64_decode(input)); 00087 } 00088 00089 std::string make_bcrypt(const std::string& pass, 00090 const std::vector<byte>& salt, 00091 u16bit work_factor) 00092 { 00093 const byte magic[24] = { 00094 0x4F, 0x72, 0x70, 0x68, 0x65, 0x61, 0x6E, 0x42, 00095 0x65, 0x68, 0x6F, 0x6C, 0x64, 0x65, 0x72, 0x53, 00096 0x63, 0x72, 0x79, 0x44, 0x6F, 0x75, 0x62, 0x74 00097 }; 00098 00099 std::vector<byte> ctext(magic, magic + sizeof(magic)); 00100 00101 Blowfish blowfish; 00102 00103 // Include the trailing NULL byte 00104 blowfish.eks_key_schedule(reinterpret_cast<const byte*>(pass.c_str()), 00105 pass.length() + 1, 00106 &salt[0], 00107 work_factor); 00108 00109 for(size_t i = 0; i != 64; ++i) 00110 blowfish.encrypt_n(&ctext[0], &ctext[0], 3); 00111 00112 std::string salt_b64 = bcrypt_base64_encode(&salt[0], salt.size()); 00113 00114 std::string work_factor_str = std::to_string(work_factor); 00115 if(work_factor_str.length() == 1) 00116 work_factor_str = "0" + work_factor_str; 00117 00118 return "$2a$" + work_factor_str + 00119 "$" + salt_b64.substr(0, 22) + 00120 bcrypt_base64_encode(&ctext[0], ctext.size() - 1); 00121 } 00122 00123 } 00124 00125 std::string generate_bcrypt(const std::string& pass, 00126 RandomNumberGenerator& rng, 00127 u16bit work_factor) 00128 { 00129 return make_bcrypt(pass, unlock(rng.random_vec(16)), work_factor); 00130 } 00131 00132 bool check_bcrypt(const std::string& pass, const std::string& hash) 00133 { 00134 if(hash.size() != 60 || 00135 hash[0] != '$' || hash[1] != '2' || hash[2] != 'a' || 00136 hash[3] != '$' || hash[6] != '$') 00137 { 00138 return false; 00139 } 00140 00141 const u16bit workfactor = to_u32bit(hash.substr(4, 2)); 00142 00143 const std::vector<byte> salt = bcrypt_base64_decode(hash.substr(7, 22)); 00144 if(salt.size() != 16) 00145 return false; 00146 00147 const std::string compare = make_bcrypt(pass, salt, workfactor); 00148 00149 return same_mem(hash.data(), compare.data(), compare.size()); 00150 } 00151 00152 }