1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
|
#include <cryptopp/aes.h>
#include <cryptopp/hex.h>
#include <cryptopp/modes.h>
#include <cryptopp/osrng.h>
#include <cryptopp/pwdbased.h>
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
using namespace CryptoPP;
const char *SALTfile = "salt.txt";
const char *IVfile = "iv.txt";
const char *RecordsFile = "records.txt";
const char *szErrWrite = "Error writing to output file";
void EncryptUserpass(int iterations, string userpass, string Password)
{
AutoSeededX917RNG<AES> rng;
SecByteBlock iv(AES::BLOCKSIZE);
rng.GenerateBlock(iv,iv.size());
// See NIST SP 800-132 for detailed recommendations on length, generation and
// format of the salt. This test program will just generate a random one. That
// might not be sufficient for every application.
SecByteBlock pwsalt(AES::DEFAULT_KEYLENGTH);
rng.GenerateBlock(pwsalt,pwsalt.size());
SecByteBlock derivedkey(AES::DEFAULT_KEYLENGTH);
cout << endl;
cout << "Password is " << Password << endl;
cout << "Deriving key from password:" << endl;
PKCS5_PBKDF2_HMAC<SHA256> pbkdf;
pbkdf.DeriveKey(
// buffer that holds the derived key
derivedkey, derivedkey.size(),
// purpose byte. unused by this PBKDF implementation.
0x00,
// password bytes. careful to be consistent with encoding...
(byte *) Password.data(), Password.size(),
// salt bytes
pwsalt, pwsalt.size(),
// iteration count. See SP 800-132 for details. You want this as large as you can tolerate.
// make sure to use the same iteration count on both sides...
iterations
);
cout << "Derived key: " << derivedkey.BytePtr() << endl << endl;
string cipherText;
//3
CBC_Mode<AES>::Encryption aesencryption(derivedkey,derivedkey.size(),iv);
// encrypt message using key derived above, storing the hex encoded result into ciphertext
StringSource encryptor(userpass, true, new StreamTransformationFilter(aesencryption, new HexEncoder( new StringSink(cipherText))) );
// hex encode salt and IV for "transport"
string hexsalt, hexiv;
ArraySource saltEncoder(pwsalt,pwsalt.size(), true, new HexEncoder(new StringSink(hexsalt)));
//
ArraySource ivEncoder(iv,iv.size(), true, new HexEncoder(new StringSink(hexiv)));
cout << "Salt: " << hexsalt << endl;
cout << "IV: " << hexiv << endl;
cout << "Ciphertext: " << cipherText << endl;
ofstream out1 (SALTfile);
if ( !out1.is_open() ) {
cout << szErrWrite << endl;
} else {
out1 << hexsalt;
out1.close();
}
ofstream out2 (IVfile);
if ( !out2.is_open() ) {
cout << szErrWrite << endl;
} else {
out2 << hexiv;
out2.close();
}
ofstream out3 (RecordsFile);
if ( !out3.is_open() ) {
cout << szErrWrite << endl;
} else {
out3 << cipherText;
out3.close();
}
}
bool Authenticate(int iterations, string userpass, string Password){
int size;
char *buf;
string hashText;
//Read in the SALT used for the previous userpass
ifstream in1(SALTfile, ios::in | ios::binary | ios::ate);
size = in1.tellg();
buf = new char[size + 1];
buf[size] = 0;
in1.seekg(0, ios::beg);
in1.read(buf, size);
in1.close();
string hexsalt = string(buf);
//Read in the IV used for the previous userpass
ifstream in2(IVfile, ios::in | ios::binary | ios::ate);
size = in2.tellg();
buf = new char[size + 1];
buf[size] = 0;
in2.seekg(0, ios::beg);
in2.read(buf, size);
in2.close();
string hexiv = string(buf);
//Read in the hash used for the previous userpass, this will be compared the to newly entered userpass encrypted with the previous SALT and IV
ifstream in3(RecordsFile, ios::in | ios::binary | ios::ate);
size = in3.tellg();
buf = new char[size + 1];
buf[size] = 0;
in3.seekg(0, ios::beg);
in3.read(buf, size);
in3.close();
string cipherText = string(buf);
cout << endl;
cout << "Salt: " << hexsalt << endl;
cout << "IV: " << hexiv << endl;
cout << "Ciphertext: " << cipherText << endl;
cout << endl;
//Recover the SALT and IV from the hex values in the file,
PKCS5_PBKDF2_HMAC<SHA256> pbkdf;
SecByteBlock recoveredkey(AES::DEFAULT_KEYLENGTH);
SecByteBlock recoveredsalt(AES::DEFAULT_KEYLENGTH);
StringSource saltDecoder(hexsalt,true,new HexDecoder(new ArraySink(recoveredsalt, recoveredsalt.size() ) ) );
pbkdf.DeriveKey(recoveredkey, recoveredkey.size(), 0x00, (byte *) Password.data(), Password.size(), recoveredsalt, recoveredsalt.size(), iterations);
SecByteBlock recoverediv(AES::BLOCKSIZE);
StringSource ivDecoder(hexiv,true,new HexDecoder(new ArraySink(recoverediv, recoverediv.size() ) ) );
//Encrypt the userpass that has been entered, using the SALT and IV stored in the file
SecByteBlock derivedkey(AES::DEFAULT_KEYLENGTH);
//Buffer that holds the derived key, purpose byte (unused), password bytes, salt bytes, iteration count (large as you can tolerate)
pbkdf.DeriveKey(derivedkey, derivedkey.size(), 0x00, (byte *) Password.data(), Password.size(), recoveredsalt, recoveredsalt.size(), iterations);
cout << "Derived key: " << derivedkey.BytePtr() << endl;
cout << "Password: " << (byte *) Password.data() << endl;
cout << "Recovered salt: " << recoveredsalt.BytePtr() << endl;
cout << endl;
//Encrypt the userpass using key derived above, storing the hex encoded result into hashtext
CBC_Mode<AES>::Encryption aesencryption(derivedkey,derivedkey.size(),recoverediv);
StringSource encryptor(userpass, true, new StreamTransformationFilter(aesencryption, new HexEncoder( new StringSink(hashText))) );
cout << "Old hased userpass: " << cipherText << endl;
cout << "New hased userpass: " << hashText << endl;
return (hashText == cipherText);
}
int main()
{
std::string username, password, salt;
std::cout << "Enter username: ";
std::getline(std::cin,username);
std::cout << std::endl << "Enter password: ";
std::getline(std::cin,password);
salt = username + password;
EncryptUserpass(1,salt,password);
Authenticate(1,salt,password);
return 0;
}
|