IT WAS ALL IN HIS HEAD
This commit is contained in:
parent
11f993100a
commit
336c40d809
6 changed files with 206 additions and 23 deletions
|
@ -5,18 +5,20 @@ static const uint32_t bcrypt_ciphertext[6] = {
|
||||||
0x64657253, 0x63727944, 0x6f756274
|
0x64657253, 0x63727944, 0x6f756274
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string sosc::cgc::bcrypt_hash(const std::string& input) {
|
std::string sosc::cgc::bcrypt_hash_raw
|
||||||
std::string salt = csprng::next_bytes(16),
|
(const std::string& input, const std::string& salt, uint32_t cost)
|
||||||
input_t = input.substr(0, 72);
|
{
|
||||||
|
std::string salt_t = salt.substr(0, 16),
|
||||||
|
input_t = input.substr(0, 72);
|
||||||
|
|
||||||
uint32_t ctext[6];
|
uint32_t ctext[6];
|
||||||
std::memcpy(ctext, bcrypt_ciphertext, 6 * sizeof(uint32_t));
|
std::memcpy(ctext, bcrypt_ciphertext, 6 * sizeof(uint32_t));
|
||||||
|
|
||||||
Blowfish bfish;
|
Blowfish bfish;
|
||||||
bfish.SetEksKey(salt, input);
|
bfish.SetEksKey(salt_t, input_t);
|
||||||
for(int i = 0; i < BCRYPT_COST; ++i) {
|
for(uint32_t i = 0; i < 1 << (cost % 32); ++i) {
|
||||||
bfish.SetKey(input.c_str(), input.length());
|
bfish.SetKey(input_t.c_str(), input_t.length());
|
||||||
bfish.SetKey(salt.c_str(), salt.length());
|
bfish.SetKey(salt_t.c_str(), salt_t.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < 64; ++i)
|
for(int i = 0; i < 64; ++i)
|
||||||
|
@ -33,9 +35,47 @@ std::string sosc::cgc::bcrypt_hash(const std::string& input) {
|
||||||
|
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
stream << "$2b$"
|
stream << "$2b$"
|
||||||
<< (BCRYPT_COST < 10 ? "0" : "") << BCRYPT_COST
|
<< (cost < 10 ? "0" : "") << cost
|
||||||
<< "$" << base64_encode(salt, true)
|
<< "$" << base64_encode(salt_t, true)
|
||||||
<< base64_encode(ct_hash, true);
|
<< base64_encode(ct_hash, true);
|
||||||
|
|
||||||
return stream.str();
|
return stream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string sosc::cgc::bcrypt_hash(const std::string& input) {
|
||||||
|
return bcrypt_hash_raw(input, sosc::csprng::next_bytes(16), BCRYPT_COST);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sosc::cgc::bcrypt_check
|
||||||
|
(const std::string& input, const std::string& hash)
|
||||||
|
{
|
||||||
|
if(hash.length() != 60 && !str::starts(hash, "$2b$"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto parts = str::split(hash, '$');
|
||||||
|
if(parts.size() != 4)
|
||||||
|
return false;
|
||||||
|
parts.erase(parts.begin());
|
||||||
|
|
||||||
|
if(parts[1].length() != 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int cost;
|
||||||
|
try {
|
||||||
|
cost = std::stoi(parts[1], 0, 10);
|
||||||
|
} catch(...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string salt = parts[2].substr(0, 22),
|
||||||
|
input_t = input.substr(0, 72),
|
||||||
|
hash_chk = bcrypt_hash_raw(input_t, base64_decode(salt, true), cost);
|
||||||
|
|
||||||
|
// timing safe compare DO NOT OPTIMIZE
|
||||||
|
bool success = true;
|
||||||
|
for(int i = 0; i < hash.length(); ++i)
|
||||||
|
if(hash[i] != hash_chk[i])
|
||||||
|
success = false;
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
|
@ -7,13 +7,17 @@
|
||||||
#include "base64.hpp"
|
#include "base64.hpp"
|
||||||
#include "bfish.hpp"
|
#include "bfish.hpp"
|
||||||
#include "../utils/csprng.hpp"
|
#include "../utils/csprng.hpp"
|
||||||
|
#include "../utils/string.hpp"
|
||||||
|
|
||||||
#define BCRYPT_COST 10
|
#define BCRYPT_COST 10
|
||||||
|
|
||||||
namespace sosc {
|
namespace sosc {
|
||||||
namespace cgc {
|
namespace cgc {
|
||||||
std::string bcrypt_hash(const std::string& input);
|
std::string bcrypt_hash(const std::string& input);
|
||||||
bool bcrypt_check(std::string input, std::string hash);
|
std::string bcrypt_hash_raw
|
||||||
|
(const std::string& input, const std::string& salt, uint32_t cost);
|
||||||
|
|
||||||
|
bool bcrypt_check(const std::string& input, const std::string& hash);
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,7 +25,8 @@ private:
|
||||||
uint32_t parr[18];
|
uint32_t parr[18];
|
||||||
uint32_t sbox[4][256];
|
uint32_t sbox[4][256];
|
||||||
|
|
||||||
friend std::string sosc::cgc::bcrypt_hash(const std::string&);
|
friend std::string sosc::cgc::bcrypt_hash_raw
|
||||||
|
(const std::string& input, const std::string& salt, uint32_t cost);
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "crypto/bfish.hpp"
|
#include "crypto/bfish.hpp"
|
||||||
#include "utils/csprng.hpp"
|
#include "utils/csprng.hpp"
|
||||||
#include "crypto/bcrypt.hpp"
|
#include "crypto/bcrypt.hpp"
|
||||||
|
#include "utils/bigint.hpp"
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
//auto sock = sosc::TcpClient();
|
//auto sock = sosc::TcpClient();
|
||||||
|
@ -43,8 +44,12 @@ int main(int argc, char **argv) {
|
||||||
uint32_t teest = sosc::csprng::next<uint32_t>();
|
uint32_t teest = sosc::csprng::next<uint32_t>();
|
||||||
std::cout << std::hex << teest;*/
|
std::cout << std::hex << teest;*/
|
||||||
|
|
||||||
std::string hash = sosc::cgc::bcrypt_hash("test pwd");
|
/*std::string hash = sosc::cgc::bcrypt_hash("test pwd");
|
||||||
std::cout << hash;
|
std::cout << hash << std::endl;
|
||||||
|
std::cout << sosc::cgc::bcrypt_check("test pwd", hash);*/
|
||||||
|
|
||||||
|
sosc::BigUInt bi;
|
||||||
|
bi.Parse("abcdef0", 10);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,102 @@
|
||||||
#include "bigint.hpp"
|
#include "bigint.hpp"
|
||||||
|
|
||||||
|
static bool is_hex_char(char c) {
|
||||||
|
return ((c >= 'a') && (c <= 'f'))
|
||||||
|
|| ((c >= 'A') && (c <= 'F'))
|
||||||
|
|| ((c >= '0') && (c <= '9'));
|
||||||
|
}
|
||||||
|
|
||||||
|
sosc::BigUInt::BigUInt() {
|
||||||
|
this->value = { 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
sosc::BigUInt::BigUInt(std::string hex_str, int byte_count) {
|
||||||
|
this->Parse(hex_str, byte_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sosc::BigUInt::Parse(std::string hex_str, int byte_count) {
|
||||||
|
if(hex_str.length() == 0)
|
||||||
|
hex_str = "00";
|
||||||
|
if(hex_str.length() % 2 != 0)
|
||||||
|
hex_str.insert(hex_str.begin(), '0');
|
||||||
|
|
||||||
|
int str_byte_count = hex_str.length() / 2;
|
||||||
|
byte_count = std::max(byte_count, str_byte_count);
|
||||||
|
|
||||||
|
this->value = std::vector<uint8_t>(byte_count, 0);
|
||||||
|
for(int i = 0; i < hex_str.length(); i += 2) {
|
||||||
|
if(!is_hex_char(hex_str[i]) || !is_hex_char(hex_str[i + 1]))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this->value[str_byte_count - (i / 2) - 1]
|
||||||
|
= std::stoi(hex_str.substr(i, 2), 0, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sosc::BigUInt::Random(int byte_count) {
|
||||||
|
this->value = std::vector<uint8_t>(byte_count, 0);
|
||||||
|
std::string random_str = csprng::next_bytes(byte_count);
|
||||||
|
for(int i = 0; i < byte_count; ++i)
|
||||||
|
this->value[i] = random_str[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void sosc::BigUInt::RandomPrime(int byte_count) {
|
||||||
|
do {
|
||||||
|
this->Random(byte_count);
|
||||||
|
this->value[0] |= 0x01;
|
||||||
|
this->value[byte_count - 1] |= 0x80;
|
||||||
|
} while(!this->IsProbablePrime());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sosc::BigUInt::IsProbablePrime() const {
|
||||||
|
// TODO rabin-miller
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<sosc::BigUInt, sosc::BigUInt> sosc::BigUInt::DivideWithRemainder
|
||||||
|
(const BigUInt& num, const BigUInt& denom)
|
||||||
|
{
|
||||||
|
if(num.IsZero())
|
||||||
|
return std::make_tuple(BigUInt(), BigUInt());
|
||||||
|
if(denom.IsZero())
|
||||||
|
throw "BigUInt division by zero";
|
||||||
|
if(denom.IsOne())
|
||||||
|
return std::make_tuple(num, BigUInt());
|
||||||
|
if(denom > num)
|
||||||
|
return std::make_tuple(BigUInt(), num);
|
||||||
|
|
||||||
|
BigUInt quotient, remainder;
|
||||||
|
for(uint64_t i = num.ByteCount() * 8 - 1;; --i) {
|
||||||
|
remainder = remainder << 1;
|
||||||
|
remainder.SetBit(0, num.GetBit(i));
|
||||||
|
|
||||||
|
if(remainder >= denom) {
|
||||||
|
remainder -= denom;
|
||||||
|
quotient.SetBit(i, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(i == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_tuple(quotient, remainder);
|
||||||
|
}
|
||||||
|
|
||||||
|
sosc::BigUInt sosc::BigUInt::ModPow
|
||||||
|
(const BigUInt& base, const BigUInt& exp, const BigUInt& mod)
|
||||||
|
{
|
||||||
|
BigUInt accum("1");
|
||||||
|
BigUInt x = exp;
|
||||||
|
BigUInt bpow = base;
|
||||||
|
|
||||||
|
while(!x.IsZero()) {
|
||||||
|
if(!x.IsEven())
|
||||||
|
accum = (accum * bpow) % mod;
|
||||||
|
|
||||||
|
x = x >> 1;
|
||||||
|
bpow = (bpow * bpow) % mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
return accum;
|
||||||
|
}
|
||||||
|
|
|
@ -5,24 +5,57 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include "csprng.hpp"
|
||||||
|
|
||||||
namespace sosc {
|
namespace sosc {
|
||||||
class BigInteger {
|
class BigUInt {
|
||||||
public:
|
public:
|
||||||
BigInteger();
|
BigUInt();
|
||||||
BigInteger(std::string hex_str, int byte_count = -1);
|
BigUInt(std::string hex_str, int byte_count = -1);
|
||||||
|
bool Parse(std::string hex_str, int byte_count = -1);
|
||||||
|
void Random(int byte_count);
|
||||||
|
void RandomPrime(int byte_count);
|
||||||
|
|
||||||
inline size_t ByteCount() {
|
inline size_t ByteCount() const {
|
||||||
return value.size();
|
return value.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::tuple<BigInteger, BigInteger> DivideWithRemainder
|
bool IsZero() const;
|
||||||
(const BigInteger& num, const BigInteger& denom);
|
bool IsOne() const;
|
||||||
|
bool IsEven() const;
|
||||||
|
bool IsProbablePrime() const;
|
||||||
|
|
||||||
static BigInteger ModPow
|
static std::tuple<BigUInt, BigUInt> DivideWithRemainder
|
||||||
(const BigInteger& base, const BigInteger& exp, const BigInteger& mod);
|
(const BigUInt& num, const BigUInt& denom);
|
||||||
|
|
||||||
|
static BigUInt ModPow
|
||||||
|
(const BigUInt& base, const BigUInt& exp, const BigUInt& mod);
|
||||||
|
|
||||||
|
void SetBit(uint64_t bit, bool value);
|
||||||
|
bool GetBit(uint64_t bit) const;
|
||||||
|
|
||||||
|
BigUInt& operator + (const BigUInt& rhs) const;
|
||||||
|
BigUInt& operator += (const BigUInt& rhs);
|
||||||
|
|
||||||
|
BigUInt& operator - (const BigUInt& rhs) const;
|
||||||
|
BigUInt& operator -= (const BigUInt& rhs);
|
||||||
|
|
||||||
|
BigUInt& operator * (const BigUInt& rhs) const;
|
||||||
|
BigUInt& operator *= (const BigUInt& rhs);
|
||||||
|
|
||||||
|
BigUInt& operator / (const BigUInt& rhs) const;
|
||||||
|
BigUInt& operator /= (const BigUInt& rhs);
|
||||||
|
|
||||||
|
BigUInt& operator % (const BigUInt& rhs) const;
|
||||||
|
|
||||||
|
bool operator == (const BigUInt& rhs) const;
|
||||||
|
bool operator > (const BigUInt& rhs) const;
|
||||||
|
bool operator >= (const BigUInt& rhs) const;
|
||||||
|
bool operator < (const BigUInt& rhs) const;
|
||||||
|
bool operator <= (const BigUInt& rhs) const;
|
||||||
|
|
||||||
|
BigUInt operator >> (const uint64_t& rhs) const;
|
||||||
|
BigUInt operator << (const uint64_t& rhs) const;
|
||||||
|
|
||||||
std::string ToString() const;
|
std::string ToString() const;
|
||||||
inline operator std::string () const {
|
inline operator std::string () const {
|
||||||
|
|
Loading…
Reference in a new issue