IT WAS ALL IN HIS HEAD

This commit is contained in:
malloc 2018-03-21 17:07:30 -05:00
parent 11f993100a
commit 336c40d809
6 changed files with 206 additions and 23 deletions

View file

@ -5,18 +5,20 @@ static const uint32_t bcrypt_ciphertext[6] = {
0x64657253, 0x63727944, 0x6f756274
};
std::string sosc::cgc::bcrypt_hash(const std::string& input) {
std::string salt = csprng::next_bytes(16),
input_t = input.substr(0, 72);
std::string sosc::cgc::bcrypt_hash_raw
(const std::string& input, const std::string& salt, uint32_t cost)
{
std::string salt_t = salt.substr(0, 16),
input_t = input.substr(0, 72);
uint32_t ctext[6];
std::memcpy(ctext, bcrypt_ciphertext, 6 * sizeof(uint32_t));
Blowfish bfish;
bfish.SetEksKey(salt, input);
for(int i = 0; i < BCRYPT_COST; ++i) {
bfish.SetKey(input.c_str(), input.length());
bfish.SetKey(salt.c_str(), salt.length());
bfish.SetEksKey(salt_t, input_t);
for(uint32_t i = 0; i < 1 << (cost % 32); ++i) {
bfish.SetKey(input_t.c_str(), input_t.length());
bfish.SetKey(salt_t.c_str(), salt_t.length());
}
for(int i = 0; i < 64; ++i)
@ -33,9 +35,47 @@ std::string sosc::cgc::bcrypt_hash(const std::string& input) {
std::stringstream stream;
stream << "$2b$"
<< (BCRYPT_COST < 10 ? "0" : "") << BCRYPT_COST
<< "$" << base64_encode(salt, true)
<< (cost < 10 ? "0" : "") << cost
<< "$" << base64_encode(salt_t, true)
<< base64_encode(ct_hash, true);
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;
}

View file

@ -7,13 +7,17 @@
#include "base64.hpp"
#include "bfish.hpp"
#include "../utils/csprng.hpp"
#include "../utils/string.hpp"
#define BCRYPT_COST 10
namespace sosc {
namespace cgc {
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

View file

@ -25,7 +25,8 @@ private:
uint32_t parr[18];
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);
};
}}

View file

@ -10,6 +10,7 @@
#include "crypto/bfish.hpp"
#include "utils/csprng.hpp"
#include "crypto/bcrypt.hpp"
#include "utils/bigint.hpp"
int main(int argc, char **argv) {
//auto sock = sosc::TcpClient();
@ -43,8 +44,12 @@ int main(int argc, char **argv) {
uint32_t teest = sosc::csprng::next<uint32_t>();
std::cout << std::hex << teest;*/
std::string hash = sosc::cgc::bcrypt_hash("test pwd");
std::cout << hash;
/*std::string hash = sosc::cgc::bcrypt_hash("test pwd");
std::cout << hash << std::endl;
std::cout << sosc::cgc::bcrypt_check("test pwd", hash);*/
sosc::BigUInt bi;
bi.Parse("abcdef0", 10);
return 0;
}

View file

@ -1,2 +1,102 @@
#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;
}

View file

@ -5,25 +5,58 @@
#include <string>
#include <vector>
#include <cstdint>
#include "csprng.hpp"
namespace sosc {
class BigInteger {
class BigUInt {
public:
BigInteger();
BigInteger(std::string hex_str, int byte_count = -1);
BigUInt();
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();
}
static std::tuple<BigInteger, BigInteger> DivideWithRemainder
(const BigInteger& num, const BigInteger& denom);
static BigInteger ModPow
(const BigInteger& base, const BigInteger& exp, const BigInteger& mod);
bool IsZero() const;
bool IsOne() const;
bool IsEven() const;
bool IsProbablePrime() const;
static std::tuple<BigUInt, BigUInt> DivideWithRemainder
(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;
inline operator std::string () const {
return this->ToString();