openssl 3des with c++ - c++

I want to use the openssl library in C++ to decrypt data.
I have the key and IV and the encoded base64 string.
I couldn't make it through the documentation, all decryption methods in the header file (openssl/des.h) take 3 keys.
I've managed to achieve the result with the following python code.
from pyDes import *
import base64
key = base64.b64decode("****")
iv = base64.b64decode("***")
enc = base64.b64decode("******")
encryptor = triple_des(key, CBC, iv)
plain = encryptor.decrypt(enc)
print(plain.decode("utf-8"))
I want to get the same result using C++ code and OpenSSL library.

3DES uses three keys. The python function you are using probably derives three keys from the key argument you pass, probably splitting it in three parts.
To use the OpenSSL function, you have to generate 3 keys with 8 bytes each (or a 24 bytes key split in 3).
I adapted the code I found here to use ECB instead of CBC. But, for security reasons, you should consider using CBC, or even AES encryption instead of 3DES.
The example only shows how to use the DES_ecb3_encrypt function with hard coded keys. In a final solution, you have to generate your own keys, using a good RNG.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/des.h>
/* Triple DES key for Encryption and Decryption */
DES_cblock Key1 = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 };
DES_cblock Key2 = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 };
DES_cblock Key3 = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33 };
DES_key_schedule SchKey1,SchKey2,SchKey3;
/* Print Encrypted and Decrypted data packets */
void print_data(const char *tittle, const void* data, int len);
int main()
{
/* Input data to encrypt */
DES_cblock input_data = {0x01, 0x02, 0x03, 0x04, 0x05, 0x6, 0x7, 0x8};
/* Check for Weak key generation */
if ( -2 == (DES_set_key_checked(&Key1, &SchKey1) || DES_set_key_checked(&Key2, &SchKey2) || DES_set_key_checked(&Key3, &SchKey3)))
{
printf(" Weak key ....\n");
return 1;
}
/* Buffers for Encryption and Decryption */
DES_cblock cipher;
DES_cblock text;
/* Triple-DES ECB Encryption */
DES_ecb3_encrypt(&input_data, &cipher, &SchKey1, &SchKey2, &SchKey3, DES_ENCRYPT);
/* Triple-DES ECB Decryption */
DES_ecb3_encrypt(&cipher, &text, &SchKey1, &SchKey2, &SchKey3, DES_DECRYPT);
/* Printing and Verifying */
print_data("\n Original ", (const void*) input_data, sizeof(input_data));
print_data("\n Encrypted", (const void*) cipher, sizeof(input_data));
print_data("\n Decrypted", (const void*) text, sizeof(input_data));
return 0;
}
void print_data(const char *tittle, const void* data, int len)
{
printf("%s : ",tittle);
const unsigned char * p = (const unsigned char*)data;
int i = 0;
for (; i<len;++i)
printf("%02X ", *p++);
printf("\n");
}
OpenSSL reference:
void DES_ecb3_encrypt(const_DES_cblock *input, DES_cblock *output,
DES_key_schedule *ks1, DES_key_schedule *ks2,
DES_key_schedule *ks3, int enc);
DES_ecb3_encrypt() encrypts/decrypts the input block by using three-key Triple-DES encryption in ECB mode. This involves encrypting the input with ks1, decrypting with the key schedule ks2, and then encrypting with ks3. This routine greatly reduces the chances of brute force breaking of DES and has the advantage of if ks1, ks2 and ks3 are the same, it is equivalent to just encryption using ECB mode and ks1 as the key.

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);
}

uint8 array passing value fail - only one uint8_t sent

I try to start a array in the header file
rs485.h
class RS485
{
public:
uint8_t off[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
void sendmsg(uint8_t* cmd);
};
rs485.cpp
void RS485::sendmsg(uint8_t* cmd)
{
//digitalWrite(ENTX_PIN, HIGH); // enable to transmit
Serial.println("sending message------------");
Serial2.write(cmd[0]);
Serial.println(cmd[0], HEX);
Serial2.write(cmd[1]);
Serial.println(cmd[1], HEX);
Serial2.write(cmd[2]);
Serial.println(cmd[2], HEX);
Serial2.write(cmd[3]);
Serial.println(cmd[3], HEX);
Serial2.write(cmd[4]);
Serial.println(cmd[4], HEX);
Serial2.write(cmd[5]);
Serial.println(cmd[5], HEX);
Serial2.write(cmd[6]);
Serial.println(cmd[6], HEX);
Serial2.write(cmd[7]);
Serial.println(cmd[7], HEX);
Serial.println("--------------------------");
}
main.cpp
void callback(char *topic, byte *payload, unsigned int length)
{
'''omit'''
if (cmd)
{
Serial.print("cmd: ");
Serial.println(cmd);
if (cmd == 700)
{
rs485.sendmsg(rs485.off);
}
else if (cmd == 701)
{
rs485.sendmsg(rs485.on);
}
'''omit'''
}
'''omit'''
}
complier have an error message of "too many initializer values".
When I try to use
uint8_t off[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
it build normally. The problem is when in use this variable in main.cpp and pass it to rs485.cpp only one element off[0] is pass normally.
rs485.sendmsg(rs485.off);
I have use serial print to check all value it can all print out but the rs485 cannot tx all char.
Serial2.write(cmd[0]);
Serial.println(cmd[0], HEX);
Serial2.write(cmd[1]);
Serial.println(cmd[1], HEX);
Serial2.write(cmd[2]);
Serial.println(cmd[2], HEX);
Serial2.write(cmd[3]);
Serial.println(cmd[3], HEX);
Serial2.write(cmd[4]);
Serial.println(cmd[4], HEX);
Serial2.write(cmd[5]);
Serial.println(cmd[5], HEX);
Serial2.write(cmd[6]);
Serial.println(cmd[6], HEX);
Serial2.write(cmd[7]);
Serial.println(cmd[7], HEX);
Any result for that?
add the wiring
gpio26 -->DE+RE
gpio21 -->DI
gpio25 -->RO
A member variable declared as
uint8_t off[] = { ... };
does not become an array with the number of elements in the initializer list, like when you declare a non-member variable. Instead, it then becomes a "flexible array" (a C thing that g++ enables by default in C++) - and flexible arrays can't have initializers, which is why you get "too many initializer values".
The correct way is therefore to specify the number of elements:
uint8_t off[8] = { ... };
I suggest that you send them all out at once and check how many that are actully written:
size_t written = Serial2.write(cmd, 8);
Serial.println(written);
This should display 8 if the sending code works.

Decrypting DES using OpenSSL Qt, C++

I'm writing a new version of program in C++ using Qt library, and want to maintain compatibility with the old version written in C#.
How can I convert this code to C++ / Qt?
DESCryptoServiceProvider dESCryptoServiceProvider = new DESCryptoServiceProvider();
emoryStream stream = new MemoryStream(Convert.FromBase64String(p0));
CryptoStream stream2 = new CryptoStream(stream, dESCryptoServiceProvider.CreateDecryptor(Encoding.ASCII.GetBytes("B5B126C5"),
Encoding.UTF32.GetBytes("0907427F93EC3A3FCFDFEBE3CB55011")), CryptoStreamMode.Read);
StreamReader streamReader = new StreamReader(stream2);
String text = streamReader.ReadToEnd();
My actually Qt/C++ code:
QByteArray encrypted = code.toLatin1();
encrypted = QByteArray::fromBase64(encrypted);
/////////////////////////////////////////////////////////////////////////////////////
DES_cblock key = { 0x9, 0x7, 0x42, 0x7, 0xf9, 0x3e, 0xC3, 0xa3, 0xfC, 0xfd, 0xfe, 0xbe, 0x3c, 0xb5, 0x50, 0x85 };
//this key is too long...
///////////////////////////////////////////////////////////////////////////////////////
DES_cblock iv = { 0xB5, 0xb1, 0x26, 0xc11 };
DES_key_schedule schedule;
unsigned char decrypted[encrypted.size()];
DES_set_odd_parity(&key);
DES_set_key_checked(&key, &schedule);
DES_ncbc_encrypt((unsigned char * )encrypted.constData(), (unsigned char * )decrypted, encrypted.size(), &schedule, &iv, DES_DECRYPT);
unsigned int data_size = 0;
QString text = QByteArray::fromRawData((char * )decrypted, data_size);
When I try to build receive an error:
C:\Project1_Qt\trunk\Core\OldHashDecoder.cpp:1383: error: too many initializers for 'DES_cblock {aka unsigned char [8]}'
Please help
Best regards
You have several issues here ongoing.
It seems that you have a long key as you noted yourself in the comment. You will need to make that shorter.
DES keys are of fixed length as rightfully noted in the comment.
You cannot fix 0xc11 in one byte.
As for the C# code, you pasted, I am not sure. I am not good at that language, but perhaps it may have truncated the length for you silently.

How to put a uint8_t in a char array?

I'm trying to send some data to a device using serial comunication:
void VcpBridge::write_speed(char address, int spd) {
uint8_t speed = (uint8_t)(127);
ROS_ERROR("VCP BRIDGE: Sending %u to %u", speed, address);
char msg[8];
char command = 0x55, size = 0x02, csum;
csum = speed + 0x64 + address;
sprintf(msg, "%c%c%c%c%c%c", command, address, speed, size, 0x64, csum);
ROS_ERROR(msg);
write(fd_, msg, 6);
}
ROS_ERROR here does the same as printf.
Everything works fine except when the value of speed is over 127. Then it always prints a ? in it's position and the device doesn't recive the right info. Do you know any way to cast it correctly? I've tried %u but then the program crashes.
There is no good reason to use sprintf in your example. Try this:
void VcpBridge::write_speed(char address, int spd) {
uint8_t speed = (uint8_t)(127);
ROS_ERROR("VCP BRIDGE: Sending %u to %u", speed, address);
char command = 0x55, size = 0x02, csum;
csum = speed + 0x64 + address;
ROS_ERROR(msg);
char msg[] = { command, address, speed, size, 0x64, csum};
write(fd_, msg, sizeof msg);
}
Thanks to your answer I could figure out hot to fix the problem. Not using sprintf and using unsigned int was the kay.There's the final code:
void VcpBridge::write_speed(char address,int spd){
uint8_t speed = (uint8_t)(200);
unsigned char command = 0x55, size=0x02, csum;
csum=speed+0x64+address;
unsigned char msg[8]= { command, address, speed, size, 0x64, csum };
write( fd_, msg, 6);
}

Decrypting DES with OpenSSL

I'm trying to decrypt a DES-encrypted file from an external source with a known key and IV using OpenSSL (other libraries aren't really an option, as the application links against it already and I don't want to introduce new dependencies). It's a Qt application, so the data's coming in and out as QByteArrays.
Here's the code I have at the moment (set to write the decrypted data out to a file for inspection):
AmzHandler::AmzHandler(QByteArray encoded)
{
QByteArray encrypted = QByteArray::fromBase64(encoded);
QByteArray decrypted = decrypt(encrypted);
QFile fred ("decrypted");
fred.open(QFile::WriteOnly);
fred.write(decrypted);
fred.close();
}
QByteArray AmzHandler::decrypt(QByteArray encrypted)
{
DES_cblock key = {0x29, 0xab, 0x9d, 0x18, 0xb2, 0x44, 0x9e, 0x31};
DES_cblock iv = {0x5e, 0x72, 0xd7, 0x9a, 0x11, 0xb3, 0x4f, 0xee};
DES_key_schedule schedule;
unsigned char decrypted[encrypted.size()];
DES_set_odd_parity(&key);
DES_set_key_checked(&key, &schedule);
DES_ncbc_encrypt((unsigned char * )encrypted.constData(), (unsigned char * )decrypted, encrypted.size(), &schedule, &iv, DES_DECRYPT);
return QByteArray::fromRawData((char * )decrypted, length);
}
The output file for my test input is nonsense, and is not consistent across multiple runs. (I have a working implementation in Python, which is attached at the bottom of this post, to test against.) I'm not really sure what's going on; whether I've made some simple screwup in the conversions to char or am misusing OpenSSL.
EDIT: Solved. It turns out the line DES_set_odd_parity(&key); was missing. Add that and it works.
Here's working code in Python:
def AmzHandler(encoded):
encrypted = base64.b64decode(encoded)
d = pyDes.des(hex_to_str("29AB9D18B2449E31"), mode=pyDes.CBC, IV=hex_to_str("5E72D79A11B34FEE"))
decrypted = d.decrypt(encrypted)
f = open("decrypted-py", "w")
f.write(decrypted)
f.close()
The issue was just a missing call to DES_set_odd_parity(&key);, which appears to be necessary for correct decoding with this implementation. Working code is as follows:
QByteArray AmzHandler::decrypt(QByteArray encrypted)
{
DES_cblock key = {0x29, 0xab, 0x9d, 0x18, 0xb2, 0x44, 0x9e, 0x31};
DES_cblock iv = {0x5e, 0x72, 0xd7, 0x9a, 0x11, 0xb3, 0x4f, 0xee};
DES_key_schedule schedule;
unsigned char decrypted[encrypted.size()];
DES_set_odd_parity(&key);
DES_set_key_checked(&key, &schedule);
DES_ncbc_encrypt((unsigned char * )encrypted.constData(), (unsigned char * )decrypted, encrypted.size(), &schedule, &iv, DES_DECRYPT);
return QByteArray::fromRawData((char * )decrypted, length);
}