How to read an image to a string for encrypting Crypto++ - encryption

I need to read a file as binary data, then be able encrypt and decrypt it. I am testing speeds of different algorithms in Crypto++. Up until now, I have been using getline to read text files.
int main( int argc, char* argv[] ) {
string plaintext, ciphertext, encoded, recovered, sample_files_path, data_file, line_contents, file_size;
ifstream initial_file_contents ( "1MB.txt");
if (initial_file_contents.is_open()) {
plaintext = "";
while ( getline( initial_file_contents, line_contents ) ) {
plaintext = plaintext + line_contents;
plaintext.push_back('\n');
initial_file_contents.close();
}
} else {
cout << "Unable to open file" << endl;
}
/*BLOWFISH ALGORITHM*/
AutoSeededRandomPool blowfish_prng; // This class seeds itself using an operating system provided RNG
SecByteBlock blowfish_key(Blowfish::DEFAULT_KEYLENGTH); // Generate a random key
blowfish_prng.GenerateBlock(blowfish_key, blowfish_key.size()); // Generate a random initialization vector
byte blowfish_iv[Blowfish::BLOCKSIZE];
blowfish_prng.GenerateBlock(blowfish_iv, sizeof(blowfish_iv));
// Encrypts the plaintext
e.SetKeyWithIV( blowfish_key, blowfish_key.size(), blowfish_iv, sizeof(blowfish_iv) );
ciphertext.clear();
StringSource ss1(plaintext, true, new AuthenticatedEncryptionFilter( e, new StringSink( ciphertext ) ) );
// Decrypts the test
EAX< Blowfish >::Decryption d;
d.SetKeyWithIV( blowfish_key, blowfish_key.size(), blowfish_iv, sizeof(blowfish_iv) );
recovered.clear();
StringSource ss2(ciphertext, true, new AuthenticatedDecryptionFilter( d, new StringSink( recovered ), AuthenticatedDecryptionFilter::THROW_EXCEPTION ) );
return 0;
}
I have seen other articles like Reading an image file in C/C++ and Read a binary file (jpg) to a string using c++ , but I am unsure how to do it. I feel like http://www.cplusplus.com/reference/istream/istream/read/ might be a good example, but I am still unsure how to implement it. Can someone show me how to read in a file such as a .jpg file, and store it as a string so I can encrypt it?
If I had a file named image.jpg, how would I read it in to be in a string variable like plaintext?

Use a FileSource and FileSink. It avoids reading the data into an intermediate object like a string, but its probably a little more efficient under some cases.
AutoSeededRandomPool prng;
SecByteBlock key(Blowfish::DEFAULT_KEYLENGTH);
prng.GenerateBlock( key, key.size() );
byte iv[ Blowfish::BLOCKSIZE ];
prng.GenerateBlock( iv, sizeof(iv) );
string ofilename = "puppy-and-teddy-orig.jpg";
string efilename = "puppy-and-teddy.enc";
string rfilename = "puppy-and-teddy-recovered.jpg";
try {
/*********************************\
\*********************************/
EAX< Blowfish >::Encryption e1;
e1.SetKeyWithIV(key, key.size(), iv, sizeof(iv));
FileSource fs1(ofilename.c_str(), true,
new AuthenticatedEncryptionFilter(e1,
new FileSink(efilename.c_str())
) );
/*********************************\
\*********************************/
EAX< Blowfish >::Decryption d2;
d2.SetKeyWithIV( key, key.size(), iv, sizeof(iv) );
FileSource fs2(efilename.c_str(), true,
new AuthenticatedDecryptionFilter( d2,
new FileSink( rfilename.c_str() ),
AuthenticatedDecryptionFilter::THROW_EXCEPTION
) );
} catch (const Exception& ex) {
cerr << ex.what() << endl;
}
Here's the image:
Here's the encrypted image under a hex editor:
Running it produces no difference between the original and recovered images:
$ ./cryptopp-test.exe
$ diff puppy-and-teddy-orig.jpg puppy-and-teddy-recovered.jpg
$
If you really want to read it into a string, here are the relevant changes:
std::ifstream ifile("puppy-and-teddy-orig.jpg", ios::binary);
std::ifstream::pos_type size = ifile.seekg(0, std::ios_base::end).tellg();
ifile.seekg(0, std::ios_base::beg);
string temp;
temp.resize(size);
ifile.read((char*)temp.data(), temp.size());
/*********************************\
\*********************************/
EAX< Blowfish >::Encryption e1;
e1.SetKeyWithIV(key, key.size(), iv, sizeof(iv));
StringSource ss1(temp, true,
new AuthenticatedEncryptionFilter( e1,
new FileSink(efilename.c_str())
) );
/*********************************\
\*********************************/
EAX< Blowfish >::Decryption d2;
d2.SetKeyWithIV( key, key.size(), iv, sizeof(iv) );
FileSource fs2(efilename.c_str(), true,
new AuthenticatedDecryptionFilter(d2,
new FileSink(rfilename.c_str()),
AuthenticatedDecryptionFilter::THROW_EXCEPTION
) );

Related

Implement PBEWithHmacSHA256AndAES_256 with openSSL 1.1.1 and/or Windows crypt functions

I have an implementation of password based encryption in Java. It formerly used PBEWithMD5AndDES and was later changed to use PBEWithHmacSHA256AndAES_256. The significant code looks like this:
//String cipherAlgorithm = "PBEWithMD5AndDES";
String cipherAlgorithm = "PBEWithHmacSHA256AndAES_256";
PBEKeySpec pbeKeySpec = new PBEKeySpec(passPhrase, salt, iterationCount);
SecretKey secretKey = SecretKeyFactory.getInstance(cipherAlgorithm).generateSecret(pbeKeySpec);
AlgorithmParameterSpec paramSpec = iv == null ?
new PBEParameterSpec(data.salt, iterationCount) :
new PBEParameterSpec(data.salt, iterationCount, new IvParameterSpec(iv));
cipher = Cipher.getInstance(cipherAlgorithm);
if (encrypt) {
cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec);
} else {
cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec);
}
...
byte[] enc = cipher.doFinal(utf8);
I have also an implementation with openSSL (and with Windows crypt functions) for the old algorithm. Now I try to extend this to the new algorithm.
The old code using the openSSL implementation looks like this:
unsigned char iv[8];
unsigned char key[8];
memset(iv, '\0', sizeof(iv));
memset(key, '\0', sizeof(key));
int rc = EVP_BytesToKey(EVP_des_cbc(), EVP_md5(),
salt,
apasswd, alen, iterationCount,
key, iv);
if (rc != sizeof(key))
throw ...
EVP_CIPHER_CTX *ectx;
ectx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(ectx);
if (!EVP_CipherInit_ex(ectx, EVP_des_cbc(), NULL, key, iv, encrypt ? 1 : 0))
throw ...
if (!EVP_CipherUpdate(ectx, ebuf, &ebuflen, (unsigned char *)abuf, abuflen))
throw ...
if (ebuflen > (int)abufsize)
throw ...
...
if (!EVP_CipherFinal_ex(ectx, ebuf, &ebuflen))
throw ...
...
EVP_CIPHER_CTX_free(ectx);
I was not successful to get this working. I tried already the following:
Replace EVP_des_cbc() with EVP_aes_256_cbc() and EVP_md5() : EVP_sha256()
Use PKCS5_PBKDF2_HMAC instead of EVP_BytesToKey (with iv and key sizes adapted to 16 and32)
PKCS5_PBKDF2_HMAC(apasswd, alen, salt, sizeof(salt),
iterationCount, EVP_sha256(),
sizeof(key), key);
But the decryption of data encrypted with the Java implementation fails (EVP_CipherFinal_ex returns an error, so the key seems wrong).
Unfortunately I did not find any information about how PBEWithHmacSHA256AndAES_256 is implemented in Java.
Could anyone point me to more information about this or has anyone successfully implemented similar things (with openSSL or Windows API) and have some hints about this?
I finally got it working, so I can answer the question myself now.
For openSSL, the key can be generated from the passphrase with:
int rc = PKCS5_PBKDF2_HMAC((const char *)passPhrase, pLen, salt,
sizeof(salt), iterationCount, EVP_sha256(),
sizeof(key), key);
For Windows, the key can be generated with:
NTSTATUS status;
BYTE key[32];
BCRYPT_ALG_HANDLE handle;
status = BCryptOpenAlgorithmProvider(&handle,
BCRYPT_SHA256_ALGORITHM, NULL,
BCRYPT_ALG_HANDLE_HMAC_FLAG);
status = BCryptDeriveKeyPBKDF2(handle, (BYTE*)passPhrase, sizeof(passPhrase),
salt, sizeof(salt), iterationCount, key, 32, 0);

decrypt AES input on Flutter, when on web use cryptoJS AES

On web, I'm using CryptoJS for decrypto JS:
CryptoJS.AES.decrypt(inputBase64, key).toString(CryptoJS.enc.Utf8);
Example:
input: "tzfwnxVwE/qNoaWRRfqLp11ZyhB4UtKO+0/Lvv5B7eE="
key: "20190225165436_15230006321670000_15510884759030000"
On flutter I can't find any library to decrypt with a key of any length.
I know "For AES, NIST selected three members of the Rijndael family, each with a block size of 128 bits, but three different key lengths: 128, 192 and 256 bits.
"
But I don't know how to convert any length key to 128 bit format?
import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';
import 'package:crypto/crypto.dart';
import 'package:tuple/tuple.dart';
import 'package:encrypt/encrypt.dart' as encrypt;
String encryptAESCryptoJS(String plainText, String passphrase) {
try {
final salt = genRandomWithNonZero(8);
var keyndIV = deriveKeyAndIV(passphrase, salt);
final key = encrypt.Key(keyndIV.item1);
final iv = encrypt.IV(keyndIV.item2);
final encrypter = encrypt.Encrypter(
encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: "PKCS7"));
final encrypted = encrypter.encrypt(plainText, iv: iv);
Uint8List encryptedBytesWithSalt = Uint8List.fromList(
createUint8ListFromString("Salted__") + salt + encrypted.bytes);
return base64.encode(encryptedBytesWithSalt);
} catch (error) {
throw error;
}
}
String decryptAESCryptoJS(String encrypted, String passphrase) {
try {
Uint8List encryptedBytesWithSalt = base64.decode(encrypted);
Uint8List encryptedBytes =
encryptedBytesWithSalt.sublist(16, encryptedBytesWithSalt.length);
final salt = encryptedBytesWithSalt.sublist(8, 16);
var keyndIV = deriveKeyAndIV(passphrase, salt);
final key = encrypt.Key(keyndIV.item1);
final iv = encrypt.IV(keyndIV.item2);
final encrypter = encrypt.Encrypter(
encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: "PKCS7"));
final decrypted =
encrypter.decrypt64(base64.encode(encryptedBytes), iv: iv);
return decrypted;
} catch (error) {
throw error;
}
}
Tuple2<Uint8List, Uint8List> deriveKeyAndIV(String passphrase, Uint8List salt) {
var password = createUint8ListFromString(passphrase);
Uint8List concatenatedHashes = Uint8List(0);
Uint8List currentHash = Uint8List(0);
bool enoughBytesForKey = false;
Uint8List preHash = Uint8List(0);
while (!enoughBytesForKey) {
int preHashLength = currentHash.length + password.length + salt.length;
if (currentHash.length > 0)
preHash = Uint8List.fromList(
currentHash + password + salt);
else
preHash = Uint8List.fromList(
password + salt);
currentHash = md5.convert(preHash).bytes;
concatenatedHashes = Uint8List.fromList(concatenatedHashes + currentHash);
if (concatenatedHashes.length >= 48) enoughBytesForKey = true;
}
var keyBtyes = concatenatedHashes.sublist(0, 32);
var ivBtyes = concatenatedHashes.sublist(32, 48);
return new Tuple2(keyBtyes, ivBtyes);
}
Uint8List createUint8ListFromString(String s) {
var ret = new Uint8List(s.length);
for (var i = 0; i < s.length; i++) {
ret[i] = s.codeUnitAt(i);
}
return ret;
}
Uint8List genRandomWithNonZero(int seedLength) {
final random = Random.secure();
const int randomMax = 245;
final Uint8List uint8list = Uint8List(seedLength);
for (int i=0; i < seedLength; i++) {
uint8list[i] = random.nextInt(randomMax)+1;
}
return uint8list;
}
Usage
import 'package:app/utils/cryptojs_aes_encryption_helper.dart';
String plainText = 'PlainText is Me';
var encrypted = encryptAESCryptoJS(plainText, "password");
var decrypted = decryptAESCryptoJS(encrypted, "password");
When you pass CryptoJS a string as the key it treats it as a passphrase and generates the key from it using a key derivation function - in this case PBKDF2. It generates a 256 bit key and a 128 bit initialization vector (IV). It then uses those for the encryption/decryption. You also need to find out what chaining method CryptoJS uses (probably cipher block chaining (CBC)) and what padding method it uses (to make sure that the plain text is a round number of 128 bit blocks - probably PKCS#7).
CryptoJS has this "works out of the box" mode, but it isn't particularly clear what it's doing under the hood - you'd need to read the source code or scour the documentation.
When trying to inter-operate between two systems/languages it's best if you remain in charge of things, rather than letting one end make arbitrary decisions. That way you can make sure that you have the settings the same at each end.
So, you might choose to:
Use PBKDF2 to generate a 128 bit key and 128 bit IV from the string
passphrase - with, say, 9999 rounds
Use PKCS#7 padding
Use AES in CBC mode
The pointycastle package supports all the above in Dart. It looks like CryptoJS supports all of those too.
Start with a passphrase and make sure you can generate the same key and IV in JS and Dart. Then move onto creating the ciphers.
Remember, too, never to encrypt two messages with the same key/IV pair. Use a message sequence number, for example, to slightly change the IV for each message.
Sample encrypt using nodejs script:
var key = CryptoJS.PBKDF2("123456", "123456", {
keySize: 256 / 32
});
var iv = CryptoJS.PBKDF2("123456", "123456", {
keySize: 128 / 32
});
var encrypted = CryptoJS.AES.encrypt('my message', key, { iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString();
decript using dart
import 'package:encrypt/encrypt.dart' as aes;
import 'package:crypto/crypto.dart';
import 'package:hex/hex.dart';
import 'package:password_hash/pbkdf2.dart';
void main(List<String> arguments) {
String encrypted = 'HbsmGAigiIWmU3MNZAf8+w==';
final generator = PBKDF2(hashAlgorithm: sha1);
final key = aes.Key.fromBase16(HEX.encode(generator.generateKey("123456", "123456", 1, 32)));
final iv = aes.IV.fromBase16(HEX.encode(generator.generateKey("123456", "123456", 1, 16)));
final encrypter = aes.Encrypter(aes.AES(key, mode: aes.AESMode.cbc, padding: 'PKCS7'));
final decrypted = encrypter.decrypt64(encrypted, iv:iv);
print(decrypted);
}

encrypt using ase256 gives different output in python and nodejs

I am trying to encrypt a string "1" using key = "secret_key" and text "11869021012". Earlier I had written this in nodejs. now I want to port this to python. but here surprisingly both are giving different outputs.
var crypto = require('crypto');
function getBytes (str) {
let bytes = [], char;
str = encodeURI(str);
while (str.length) {
char = str.slice(0, 1);
str = str.slice(1);
if ('%' !== char) {
bytes.push(char.charCodeAt(0));
} else {
char = str.slice(0, 2);
str = str.slice(2);
bytes.push(parseInt(char, 16));
}
}
return bytes;
};
function getIV (str, bytes){
iv = getBytes(str);
if(!bytes) bytes = 16;
for(let i=iv.length;i<bytes;i++) {
iv.push(0);
}
return Buffer.from(iv);
};
function getKey (pwd){
pwd = Buffer.from(getBytes(pwd), 'utf-8');
let hash = crypto.createHash('sha256');
pwd = hash.update(pwd).digest();
return pwd;
};
function createCipherIV (algorithm, input_key, iv_input, text){
let iv = getIV(iv_input);
let key = getKey(input_key);
let cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(text)
encrypted += cipher.final('base64');
return encrypted;
}
output = createCipherIV('aes256', 'secret_key', '11869021012', '1')
console.log(output)
This produces the output:
s6LMaE/YRT6y8vr2SehLKw==
python code:
# AES 256 encryption/decryption using pycrypto library
import base64
import hashlib
from Crypto.Cipher import AES
from Crypto import Random
BLOCK_SIZE = 16
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
unpad = lambda s: s[:-ord(s[len(s) - 1:])]
password = "secret_key"
def encrypt(raw, password):
private_key = hashlib.sha256(bytearray(password, "utf-8")).digest()
raw = pad(raw)
iv = b'11869021012\x00\x00\x00\x00\x00'
cleartext = bytearray(raw, 'utf-8')
cipher = AES.new(private_key, AES.MODE_CBC, iv)
return base64.b64encode(iv + cipher.encrypt(cleartext))
# First let us encrypt secret message
encrypted = encrypt("1", password)
print(encrypted)
This produces the output:
MTE4NjkwMjEwMTIAAAAAALOizGhP2EU+svL69knoSys=
I have used aes256 algorithm here for encrypting message.
Clearly they are very close, but node seems to be padding the output with some extra bytes. Any ideas how I can get the two to interoperate?
First, in a secure crypto system, you should expect the output to be different every time you encrypt, even using the same code. That fact that yours doesn't indicates it's an insecure cipher. Typically this is done by adding a random IV.
Your IV is "11869021012", which is horrible (because it's not random, and not even 16 bytes), but it does seem you're using it the same way in both, so that's fine.
Your password is the SHA-256 of a string, which is a horrible way to create a key, but still, you seem to be doing it the same way in both cases, so that's fine.
Your problem is that the Python code emits the IV followed by the cipher text. Your JS code does not emit the IV; it only emits the cipher text. So you probably meant this in the Python:
return base64.b64encode(cipher.encrypt(cleartext))
Or you need to rework the JavaScript to glue together the IV and the cipher text before Base64 encoding.

Crypto++ exception : "ciphertext length is not a multiple of block size"

I've been trying to encrypt/decrypt a byte array with Crypto++ using AES encryption but I got this exception :
StreamTransformationFilter: ciphertext length is not a multiple of block size
The thing is that I'm using PKCS padding so this shouldn't happen.
This is the function I'm having trouble with. Could anyone tell me what exactly I am doing wrong ?
void QtAES256::decrypt(const QByteArray& cryptedArray, QByteArray& decryptedArray) const
{
CBC_Mode<AES>::Decryption cbcDecryption(reinterpret_cast<const byte*>(m_Key.constData()),
m_Key.length(),
reinterpret_cast<const byte*>(m_IV.constData()));
byte decryptedResult[MAXSIZE];
ArraySink* arraySink = new ArraySink(decryptedResult, MAXSIZE);
StreamTransformationFilter stfDecryptor(cbcDecryption,
arraySink,
StreamTransformationFilter::PKCS_PADDING);
stfDecryptor.Put(reinterpret_cast<const byte*>(cryptedArray.constData()), cryptedArray.length());
try
{
stfDecryptor.MessageEnd();
}
catch(InvalidCiphertext &e)
{
qDebug() << e.what();
}
decryptedArray = QByteArray(reinterpret_cast<const char*>(decryptedResult), arraySink->TotalPutLength());
delete arraySink;
}

encrypt ASP(Rijndael), Descrypt in php

I have a code in ASP, but I dont know encrypt in php and compare the password encrypted.
My library is:
using System.Security.Cryptography;
// Encrypt a string into a string using a password
// Uses Encrypt(byte[], byte[], byte[])
public string Encrypt(string clearText, string Password)
{
// First we need to turn the input string into a byte array.
byte[] clearBytes = System.Text.Encoding.Unicode.GetBytes(clearText);
// Then, we need to turn the password into Key and IV
// We are using salt to make it harder to guess our key using a dictionary attack -
// trying to guess a password by enumerating all possible words.
PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password,
new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
// Now get the key/IV and do the encryption using the function that accepts byte arrays.
// Using PasswordDeriveBytes object we are first getting 32 bytes for the Key
// (the default Rijndael key length is 256bit = 32bytes) and then 16 bytes for the IV.
// IV should always be the block size, which is by default 16 bytes (128 bit) for Rijndael.
// If you are using DES/TripleDES/RC2 the block size is 8 bytes and so should be the IV size.
// You can also read KeySize/BlockSize properties off the algorithm to find out the sizes.
byte[] encryptedData = Encrypt(clearBytes, pdb.GetBytes(32), pdb.GetBytes(16));
// Now we need to turn the resulting byte array into a string.
// A common mistake would be to use an Encoding class for that. It does not work
// because not all byte values can be represented by characters.
// We are going to be using Base64 encoding that is designed exactly for what we are
// trying to do.
return Convert.ToBase64String(encryptedData);
}
and php code is:
function fnEncrypt($Word, $key){
$iv = mcrypt_create_iv( mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND );
if (strlen($iv_base64 = rtrim(base64_encode($iv), '=')) != 22) return false;
$encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $Word . md5($Word), MCRYPT_MODE_CBC, $iv));
return $iv_base64 . $encrypted;
}
or I tried use this code in php:
function Encrypt($pass, $salt){
$derived = PBKDF1($pass, $salt, 100, 32);
$key = bin2hex(substr($derived, 0, 32));
$iv = bin2hex(substr($derived, 32, 16));
return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $pass, MCRYPT_MODE_CBC, $iv);
}
function PBKDF1($pass, $salt, $count, $dklen)
{
$t = sha1($pass.$salt);
for($i=1; $i <= $count; $i++)
{
$t = sha1($t);
}
$t = substr($t,0,$dklen-1);
return $t;
}
but not working, I hope I can help.
Excuse me for my bad english

Resources