C++ Des encryption with 16 bytes key - c++

I'm trying to encrypt in DES a text with dynamic length with a 16 bytes key, but there is a problem with the block size of the key and text, i'm using openssl library for DES encryption. How can I use keys with 16 bytes of length.
Here my example:
char * Encrypt( char Key, char *Msg, int size) {
static char* Res;
DES_cblock Key2;
DES_key_schedule schedule;
Res = ( char * ) malloc( size );
memcpy(Key2, Key, 8);
DES_set_odd_parity( &Key2 );
DES_set_key_checked( &Key2, &schedule );
unsigned char buf[9];
buf[8] = 0;
DES_ecb_encrypt(( DES_cblock ) &Msg, ( DES_cblock ) &buf, &schedule, DES_ENCRYPT );
memcpy(Res, buf, sizeof(buf));
return (Res);
}
int main(int argc, char const *argv[]) {
char key[] = "password";
char clear[] = "This is a secret message";
char *encrypted;
encrypted = (char *) malloc(sizeof(clear));
printf("Clear text\t : %s \n",clear);
memcpy(encrypted, Encrypt(key, clear, sizeof(clear)), sizeof(clear));
printf("Encrypted text\t : %s \n",encrypted);
return 0;
}

DES has a 8-byte 56-bit key (the LSB is not used as part of the key, it is for parity) so you can't use a 16-byte key (parity is generally ignored).
Don't use DES, it is not secure and has been replaced with AES.
Don't use ECB mode, it is insecure, see ECB mode, scroll down to the Penguin.
AES allows 128, 192 and 256 bit keys.

Related

Implementing AES encryption with OpenSSL and C++

I'm trying to implement AES using CBC for my application. However the data I'm getting out is different every time I run it. I have been trying to identify the problems using a debugger, but I don't really understand what exactly I'm looking for.
My implementation looks like;
#define AES_KEYLENGTH 256
void NetworkHandler::SendEncryptedPacket(std::vector<std::uint8_t>& data)
{
std::string keyString = "AC3CF1B84D7C946640447DE9670E18BE8A45F49A286FC4D8404DD729491064E4";
std::string ivString = "5D4FB5A040DE76B316794BAC89FC3A48";
printf("noncrypted data: %s\n", data.data());
size_t inputLen = data.size();
size_t encLen = ((inputLen + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
std::vector<std::uint8_t> encOut(encLen);
// Zero out memory for iv & key
std::uint8_t iv[AES_BLOCK_SIZE];
std::uint8_t key[AES_KEYLENGTH];
memset(iv, 0x00, AES_BLOCK_SIZE);
memset(key, 0x00, AES_KEYLENGTH);
std::copy(keyString.begin(), keyString.end(), key);
std::copy(ivString.begin(), ivString.end(), iv);
AES_KEY encKey;
AES_set_encrypt_key(key, AES_KEYLENGTH, &encKey);
AES_cbc_encrypt(data.data(), encOut.data(), encLen, &encKey, iv, AES_ENCRYPT);
printf("encrypted data: %s\n", encOut.data());
SendPacket(encOut);
}
I initially tried to follow the an implemented example found here; AES 256-cbc encryption C++ using OpenSSL.
But looks like I came short.
I came up with this solution.
I'm not sure if it's 100% correct, but I'm getting the same ciphertext each time.
std::vector<std::uint8_t> HexToBytes(const std::string& hexString) {
std::vector<std::uint8_t> byteArray;
for (std::size_t i = 0; i < hexString.size(); i += 2) {
std::string hexByte = hexString.substr(i, 2);
std::uint8_t byte = std::stoi(hexByte, nullptr, 16);
byteArray.push_back(byte);
}
return byteArray;
}
#define AES_KEYLENGTH 256
void NetworkHandler::SendEncryptedPacket(std::vector<std::uint8_t>& data)
{
std::string keyString = "FE7F64F9B5592EDFC84CA5B07DE0901F0671EDB6105FDD5D7C5006C2C10F4ADB";
std::string ivString = "95E060482AD77FB9714DF74150753A37";
printf("noncrypted data: %s\n", data.data());
std::vector<std::uint8_t> encOut(data.size());
auto keyBytes = HexToBytes(keyString);
auto ivBytes = HexToBytes(ivString);
// Zero out memory for iv & key
std::uint8_t iv[AES_BLOCK_SIZE];
std::uint8_t key[AES_KEYLENGTH];
memset(iv, 0x00, AES_BLOCK_SIZE);
memset(key, 0x00, AES_KEYLENGTH);
std::copy(keyBytes.begin(), keyBytes.end(), key);
std::copy(ivBytes.begin(), ivBytes.end(), iv);
AES_KEY encKey;
AES_set_encrypt_key(key, AES_KEYLENGTH, &encKey);
AES_cbc_encrypt(data.data(), encOut.data(), data.size(), &encKey, iv, AES_ENCRYPT);
printf("encrypted data: %s\n", encOut.data());
SendPacket(encOut);
}

OpenSSL EVP_PKEY_verify() returns -1

I wrote a function that should verify a signature by opening a file and checking the signature against unsigned char buff[]= "data";.
This function returns -1, which
indicates an error other than signature verification failure
as per evp_pkey_verify.
What kind of error is this? Why is there no further documentation there? I find it pretty useless if a function returns values that are not described in the function description.
bool verify_sig_of_buff(const string & pub_key_file_path, const unsigned char * buff, size_t buff_len, const string & sig){
FILE * f = fopen(pub_key_file_path.c_str(), "r");
EC_KEY *ec_key = PEM_read_EC_PUBKEY(f, NULL, NULL, NULL);
fclose(f);
EVP_PKEY * key = EVP_PKEY_new();
assert(1==EVP_PKEY_assign_EC_KEY(key, ec_key));
EVP_PKEY_CTX * key_ctx = EVP_PKEY_CTX_new(key,NULL);
assert(1==EVP_PKEY_verify_init(key_ctx));
assert(1==EVP_PKEY_CTX_set_signature_md(key_ctx, EVP_sha256()) );
size_t sig_len=0;
const int ret=EVP_PKEY_verify(key_ctx, (unsigned char * )&sig[0],sig.size(), buff , buff_len);
EVP_PKEY_CTX_free(key_ctx);
EVP_PKEY_free(key);
cout<<ret<<endl;
return ret;
}

How does a server obtain the ek and iv arguments from the client, in order to RSA decrypt a message?

I'm trying to use the EVP utilities in OpenSSL for RSA encryption. My goal is implement the Seal & Open method to encrypt using a public key and decrypt using a private key.
Assuming that the SSL handshake was successful and the client has the public key of the server, I want the client to seal the message before sending it.
Something like this:
int Crypto::rsaEncrypt(const unsigned char *msg, size_t msgLen, unsigned char **encMsg, unsigned char **ek, size_t *ekl, unsigned char **iv, size_t *ivl) {
...
if(!EVP_SealInit(rsaEncryptCtx, EVP_aes_256_cbc(), ek, (int*)ekl, *iv, &remotePubKey, 1)) {
return FAILURE;
}
if(!EVP_SealUpdate(rsaEncryptCtx, *encMsg + encMsgLen, (int*)&blockLen, (const unsigned char*)msg, (int)msgLen)) {
return FAILURE;
}
encMsgLen += blockLen;
if(!EVP_SealFinal(rsaEncryptCtx, *encMsg + encMsgLen, (int*)&blockLen)) {
return FAILURE;
}
...
}
If my understanding is correct, the EVP_SealInit() will generate a public key encrypted secret key pointed to by the ek and an IV corresponding to the cipher. This is all done on the client.
When this encrypted message is sent to the server, I'll use something like this to decrypt:
int Crypto::rsaDecrypt(unsigned char *encMsg, size_t encMsgLen, unsigned char *ek, size_t ekl, unsigned char *iv, size_t ivl, unsigned char **decMsg) {
...
if(!EVP_OpenInit(rsaDecryptCtx, EVP_aes_256_cbc(), ek, ekl, iv, key)) {
return FAILURE;
}
if(!EVP_OpenUpdate(rsaDecryptCtx, (unsigned char*)*decMsg + decLen, (int*)&blockLen, encMsg, (int)encMsgLen)) {
return FAILURE;
}
decLen += blockLen;
if(!EVP_OpenFinal(rsaDecryptCtx, (unsigned char*)*decMsg + decLen, (int*)&blockLen)) {
return FAILURE;
}
...
}
Ok, now my questions is, if the server is calling this decrypt, how does get reference to the ek and iv (since it was created on the client)? or are those generated locally?
I referenced these following OpenSSL API docs for Seal and Open. And this one for the sample source code: Crypto.cpp.

How to encrypt a byte array with Crypto++

How can I encrypt a byte array with Crypto++'s RSA implementation? I already found an example for strings. But I can't find a good example how to do the same for a byte array.
This is my first attempt:
//dataSize: Size of data that is going to be send
//dataToSend Bytes to send to the user
//seedPool is an AutoSeededRandomPool
CryptoPP::RSAES_OAEP_SHA_Encryptor encryptor(publicKey);
int size = 64000;
byte * cipher = new byte(size);
CryptoPP::ArraySink* test = new CryptoPP::ArraySink(cipher, size);
CryptoPP::ArraySource as((byte*)dataToSend, dataSize, true, new CryptoPP::PK_EncryptorFilter(seedPool, encryptor, test));
int newDataSize = test->TotalPutLength();
unsigned int bytesSend = ::send(socketLink, (char *)(cipher), (int)newDataSize, 0);
delete[] cipher;
This doesn't work. TotalPutLength will always return 0 but there is data put in cipher.
What is a safe way to implement this? I don't want to be vulnerable for buffer overflows or any other attack.
byte * cipher = new byte(size);
I believe this should be:
byte * cipher = new byte[size];
Otherwise, I think you get one byte initialized to 6400 (which is truncated to 0x00).
CryptoPP::ArraySink * test = new CryptoPP::ArraySink(cipher, size);
This is kind of different. You can stay out of the memory manager if you'd like:
CryptoPP::ArraySink test(cipher, size);
int newDataSize = test->TotalPutLength();
I've never used TotalPutLength, and I did not see it documented on a BufferedTransformation or Sink. So I don't really have any advice on what its returning.
TotalPutLength is OK to use. An ArraySink could return the wrong value if the sink was full. It would happen if the array was fixed and too small for all the data. We cleared that issue at Crypto++ 5.6.3 or 5.6.4.
If you want to count the number of bytes processed (even if the sink cannot store they bytes), then you can also use a MeterFilter:
byte data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
string encoded;
MeterFilter meter( new StringSink( encoded ) );
ArraySource( data, sizeof( data ), true,
new HexEncoder(
new Redirector( meter ),
true /*UCase*/, 2 /*Group*/,
" " /*Separator*/
)
);
cout << "processed " << meter.GetTotalBytes() << " bytes" << endl;
cout << encoded << endl;
Output:
Processed 23 bytes
00 01 02 03 04 05 06 07
How can you encrypt a byte array with Cryptopp RSA implementation
Now we're talking ;) Try this from the Crypto++ wiki on RSA Encryption.
////////////////////////////////////////////////
// Generate keys
AutoSeededRandomPool rng;
InvertibleRSAFunction params;
params.GenerateRandomWithKeySize( rng, 1536 );
RSA::PrivateKey privateKey( params );
RSA::PublicKey publicKey( params );
string plain="RSA Encryption", cipher, recovered;
////////////////////////////////////////////////
// Encryption
RSAES_OAEP_SHA_Encryptor e( publicKey );
StringSource ss1( plain, true,
new PK_EncryptorFilter( rng, e,
new StringSink( cipher )
) // PK_EncryptorFilter
); // StringSource
////////////////////////////////////////////////
// Decryption
RSAES_OAEP_SHA_Decryptor d( privateKey );
StringSource ss2( cipher, true,
new PK_DecryptorFilter( rng, d,
new StringSink( recovered )
) // PK_DecryptorFilter
); // StringSource
assert( plain == recovered );

blowfish.h usage in a simple client/server application

I am trying to write an application which amongst other things uses the openssl blowfish implementation (blowfish.h) to transport files over a simple server/client pair.
However, whilst some files are encrypted, transported, received and decrypted correctly, some end up being corrupted, after the final decryption stage. This leads me to think that the encryption routines are not being called correctly (since I have also tried with equivalent DES library calls, with the same 'intermittent corruption' results).
The relevant code is pasted below.
Basically, it starts with the function send_file (called by a connected client). This splits the file into chunks. Each 1024 byte chunk is encrypted separately and then sent. Each chunk is then received by the server in the receive_file function, decrypted and saved to disc.
Any idea what the problem could be? (Note if necessary, I will add the code for the whole application).
Cheers,
Ben.
void encryptHelper(const char*,int);
void decryptHelper(const char*,int);
inline void blowfish(unsigned char *data, int data_len, char* key, int enc)
{
// hash the key first!
unsigned char obuf[20];
bzero(obuf,20);
SHA1((const unsigned char*)key, strlen(key), obuf);
BF_KEY bfkey;
int keySize = strlen(key);
BF_set_key(&bfkey, 16, (const unsigned char*)obuf);
unsigned char ivec[8];
memset(ivec, 0, 8);
unsigned char out[1024];// = (unsigned char*) malloc(1024);
bzero(out,1024);
int num = 0;
BF_cfb64_encrypt(data, out, data_len, &bfkey, ivec, &num, enc);
data=out;
//memcpy(data, out, data_len);
//free(out);
}
void MyFrame::encryptHelper(char* orig, int inlength)
{
char *pb=(char*)(std::string((passInput->GetValue()).mb_str()).c_str());
blowfish((unsigned char*)orig, inlength, pb, DES_ENCRYPT);
}
void MyFrame::decryptHelper(char* orig, int inlength)
{
char *pb=(char*)(std::string((passInput->GetValue()).mb_str()).c_str());
blowfish((unsigned char*)orig, inlength, pb, DES_DECRYPT);
}
int MyFrame::send_file(int fd)
{
char rec[10];
struct stat stat_buf;
fstat (fd, &stat_buf);
int size=stat_buf.st_size;
int remSize=size;
int value=0;
while(size > 0)
{
char buffer[1030];
bzero(buffer,1030);
bzero(rec,10);
int n;
if(size>=1024)
{
value+=1024;
n=read(fd, buffer, 1024);
// encrypt is necessary
if(encButtonOn->GetValue()) encryptHelper(buffer,1024);
// Send a chunk of data
n=send(sockFile_, buffer, 1024, 0 );
// Wait for an acknowledgement
n = recv(sockFile_, rec, 10, 0 );
}
else // reamining file bytes
{
value+=size;
n=read(fd, buffer, size);
if(encButtonOn->GetValue()) encryptHelper(buffer,size);
buffer[size]='\0';
n=send(sockFile_,buffer, size, 0 );
n=recv(sockFile_, rec, 10, 0 );
}
MyFooEvent event( 0, 992 );
double firstBit = (double)value/remSize;
firstBit=firstBit*100.0;
event.adouble=firstBit;
wxPostEvent (this, event);
size -= 1024;
}
// Send a completion string
int n = send(sockFile_, "COMP",strlen("COMP"), 0 );
char buf[10];
bzero(buf,10);
// Receive an acknowledgemnt
n = recv(sockFile_, buf, 10, 0 );
return(0);
}
int MyFrame::receive_file()
{
// receive file size and send ack
char sizeBuffer[50];
bzero(sizeBuffer,50);
int n;
//read(This->sockpw,buffer,bufferSize);
n=read(sockFile_, sizeBuffer, 50);
n=send(sockFile_,"OK", strlen("OK"), 0 );
int size = atoi(sizeBuffer);
//std::cout<<size<<std::endl;
// receive file name and send ack
char saveName[256];
bzero(saveName,256);
n=read(sockFile_, saveName, 256);
n=send(sockFile_,"OK",strlen("OK"), 0 );
//std::cout<<saveName_<<std::endl;
// start file writing process to local disk
// decrypt first if necessary
std::cout<<arraySize(saveName)<<std::endl;
std::cout<<strlen(saveName)<<std::endl;
if(encButtonOn->GetValue()) decryptHelper(saveName,strlen(saveName));
ofstream outFile(saveName,ios::out|ios::binary|ios::app);
// vars for status gauge
int remSize=size;
int value=0;
while(size > 0)
{
// buffer for storing incoming data
char buf[1030];
bzero(buf,1030);
if(size>=1024)
{
value+=1024; // for status gauge
// receive chunk of data
n=recv(sockFile_, buf, 1024, 0 );
// decrypt if necessary
if(encButtonOn->GetValue()) decryptHelper(buf,1024);
// write chunk of data to disk
outFile.write(buf,1024);
// send acknowledgement
n = send(sockFile_, "OK", strlen("OK"), 0 );
}
else
{
value+=size;
n=recv(sockFile_, buf, size, 0 );
if(encButtonOn->GetValue()) decryptHelper(buf,size);
buf[size]='\0';
outFile.write(buf,size);
n = send(sockFile_, "OK", strlen("OK"), 0 );
}
// Update status gauge
MyFooEvent event( 0, 992 );
double firstBit = (double)value/remSize;
firstBit=firstBit*100.0;
event.adouble=firstBit;
wxPostEvent (this, event);
size -= 1024;
}
outFile.close();
// Receive 'COMP' and send acknowledgement
// ---------------------------------------
char buf[10];
bzero(buf,10);
n = recv(sockFile_, buf, 10, 0 );
n = send(sockFile_, "OK", strlen("OK"), 0 );
std::cout<<"File received..."<<std::endl;
// Display image event
MyFooEvent eventF( 0, 995 );
eventF.SetText(wxString(saveName, wxConvUTF8));
wxPostEvent (this, eventF);
return(0);
}
I'm assuming that:
char *pb=(char*)(std::string((passInput->GetValue()).mb_str()).c_str());
blowfish((unsigned char*)orig, inlength, pb, DES_DECRYPT);
decrypts into pb, which is actually the buffer of a temporary string. You simply cannot use std::string like this. The fact that you had to use so many casrs to do this shouldhave been a warning - good C and C++ code does not normally require casts at all. Basically, you need to rethink what you are doing.
not sure, could be a buffer overrun somewhere or memory corruption...
you could use valgrind to detect the issue or perhaps try simplifying the conversions/...
Having fixed a few bugs by asking a few other questions, I have gotten the file encryption process working, but only when the client and server are both on the same localhost machine. When they reside on different machines, the file still ends up being corrupted. I think it is due to the fact that send_file and receive file are called from threads as follows:
void
*MyFrame::send_fileT(void* tid)
{
accessHelper* ah = static_cast<accessHelper*>(tid);
MyFrame* This = ah->This;
This->send_file(fileSendID);
pthread_exit(NULL);
}
void
*MyFrame::receive_fileT(void* tid)
{
accessHelper* ah = static_cast<accessHelper*>(tid);
MyFrame* This = ah->This;
This->receive_file();
pthread_exit(NULL);
}
....and then the receive_file or send_file functions are calling the blowfish function to carry out the encryption. Now if a function is called within a pthread (i.e. send_file and receive_file), then if that function calls another function (i.e. encryptHelper -- blowfish), is it possible that the calling function will not 'properly' wait for the called function to finish correctly?
Fixed:
n=read(fd, buffer, 2048);
if(enc)encryptHelper(buffer,n);
n=send(sockFile_, buffer, n, 0 );
[called in a loop]
The problem was, was that it cannot be ensured that all n bytes of the encrypted buffer are transferred. Thus only some of the encrypted bytes are sent leading to inconsistent decryption on the receiving end.