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
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
}}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue