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);
}
Related
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.
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.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I make a controller of heating with DS18B20 and Wemos D1 board, but if i try print or check the temperature in if then give back 0 in int.
What is the problem?
// This Arduino sketch reads DS18B20 "1-Wire" digital
// temperature sensors.
// Copyright (c) 2010 Mark McComb, hacktronics LLC
// License: http://www.opensource.org/licenses/mit-license.php (Go crazy)
// Tutorial:
// http://www.hacktronics.com/Tutorials/arduino-1-wire-tutorial.html
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into pin 3 on the Arduino
#define ONE_WIRE_BUS 0
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
// Assign the addresses of your 1-Wire temp sensors.
// See the tutorial on how to obtain these addresses:
// http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html
const int mintemp = 30;
DeviceAddress insideThermometer = { 0x28, 0xFF, 0x83, 0x51, 0xB2, 0x17, 0x4, 0x8A };
DeviceAddress outsideThermometer = { 0x28, 0xFF, 0x4F, 0xAB, 0xC4, 0x17, 0x5, 0x83 };
DeviceAddress dogHouseThermometer = { 0x28, 0xFF, 0xBF, 0xA9, 0xC4, 0x17, 0x4, 0x7C };
void setup(void)
{
// start serial port
Serial.begin(112500);
// Start up the library
sensors.begin();
// set the resolution to 10 bit (good enough?)
sensors.setResolution(insideThermometer, 10);
sensors.setResolution(outsideThermometer, 10);
sensors.setResolution(dogHouseThermometer, 10);
}
void printTemperature(DeviceAddress deviceAddress)
{
float tempC = sensors.getTempC(deviceAddress);
if (tempC == -127.00) {
Serial.print("Error getting temperature");
} else {
Serial.print("C: ");
Serial.print(tempC);
Serial.print(" F: ");
Serial.print(DallasTemperature::toFahrenheit(tempC));
}
}
void loop(void)
{
delay(2000);
Serial.print("Getting temperatures...\n\r");
sensors.requestTemperatures();
Serial.print("Inside temperature is: ");
printTemperature(insideThermometer);
Serial.print("\n\r");
Serial.print("Outside temperature is: ");
printTemperature(outsideThermometer);
Serial.print("\n\r");
Serial.print("Dog House temperature is: ");
printTemperature(dogHouseThermometer);
Serial.print("\n\r\n\r");
int insideThermometer = (int)insideThermometer;
Serial.print(insideThermometer); //In Serial this give 0.
if(insideThermometer > mintemp){
Serial.print("work");
Serial.print(insideThermometer);
}
}
In this line:
int insideThermometer = (int)insideThermometer;
You create a local variable and assign it to itself. Not what you wanted. The global var you are trying to use is
DeviceAddress insideThermometer = { 0x28, 0xFF, 0x83, 0x51, 0xB2, 0x17, 0x4, 0x8A };
If you look at the source code, DeviceAddress is typdef'd as
typedef uint8_t DeviceAddress[8];
If you want to get the temperature you need to call sensors.getTempC(insideThermometer), which you already do in the printTemperature function. Since you call that function before testing the temp, just modify it to return the temp:
float printTemperature(DeviceAddress deviceAddress)
{
float tempC = sensors.getTempC(deviceAddress);
float tempF = 0;
if (tempC == -127.00) {
Serial.print("Error getting temperature");
} else {
Serial.print("C: ");
Serial.print(tempC);
Serial.print(" F: ");
tempF = DallasTemperature::toFahrenheit(tempC);
Serial.print(tempF);
}
return tempF;
}
Then change to
int insideTempF = printTemperature(insideThermometer);
....
if (insideTempF > mintemp) {
....
(You may want to change the name of the function to something like printAndReturnTemperature as that more clearly states its new functionality.)
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.
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);
}