Botan  1.11.15
src/lib/passhash/bcrypt/bcrypt.cpp
Go to the documentation of this file.
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 }