How can I get BCrypt to interpret my key as hex? - visual-c++

I'm trying to interact with an API which takes GET and POST requests which include a signature derived from a message and my private key, hashed using HMAC SHA512. The docs give an example:
key (in base-64):
bEDtDJnW0y/Ll4YZitxb+D5sTNnEpQKH67EJRCmQCqN9cvGiB8+IHzB7HjsOs3mSlxLmu4aiPDRpe9anuWzylw==
message:
/account/balance1515058794242
should produce the following (base-64) signature:
NjqZ8Mgdkj6hrtY/xdKBy1S0kLjU2tA7G+pR2TdOBF45b7+evfpzGH/C/PiNHEDvuiRChRBlRo3AGJ7Gcvlwqw==
The docs also state that the key needs to be decoded from base-64 before using in the hmac, but is unclear about what format it should be in.
I've been playing around with online hmac generators and can replicate the example signature with no issue. For example, at https://www.liavaag.org/English/SHA-Generator/HMAC/ - input the above key as input type = Base-64, the above message string as input type = TEXT, and output type = base-64, and the output signature is the same as above. It also works fine when I give the key as HEX-type and use the hex equivalent:
6C40ED0C99D6D32FCB9786198ADC5BF83E6C4CD9C4A50287EBB1094429900AA37D72F1A207CF881F307B1E3B0EB379929712E6BB86A23C34697BD6A7B96CF297
BUT I cannot replicate the example signature using my own program using BCrypt. It seems that the BCrypt hmac is interpreting my key as 'TEXT'-type input in the same way as the online generator. That is, when I give the key as the hex string:
CONST BYTE key[] = { "6C40ED0C99D6D32FCB9786198ADC5BF83E6C4CD9C4A50287EBB1094429900AA37D72F1A207CF881F307B1E3B0EB379929712E6BB86A23C34697BD6A7B96CF297" };
I get an output signature (in hex) of:
16ab16ed3874fab51dbda66155edf269883d128de6067d77762dcee4129f1612b36fc556df10beb358c81262d034efe4c50d68d89ac43606df4318a8af56b
On the online generator I get the same output when I use that hex string (6C40...) as TEXT type key and ouput as HEX.
Is there any way I can force BCrypt to interpret my key as hex? I've even tried declaring the key as hex literals, i.e:
CONST BYTE key[] = { 0x6C, 0x40, 0xed, 0x0c, 0x99, 0xd6, 0xd3, 0x2f,
0xCB, 0x97, 0x86, 0x19, 0x8a, 0xdc, 0x5b, 0xf8,
0x3E, 0x6c, 0x4c, 0xd9, 0xc4, 0xa5, 0x02, 0x87,
0xeb, 0xb1, 0x09, 0x44, 0x29, 0x90, 0x0a, 0xa3,
0x7d, 0x72, 0xf1, 0xa2, 0x07, 0xcf, 0x88, 0x1f,
0x30, 0x7b, 0x1e, 0x3b, 0x0e, 0xb3, 0x79, 0x92,
0x97, 0x12, 0xe6, 0xbb, 0x86, 0xa2, 0x3c, 0x34,
0x69, 0x7b, 0xd6, 0xa7, 0xb9, 0x6c, 0xf2, 0x97 };
But this gives another, different signature. At least the hex string key is getting something sort of like replicating the online converter. Sorry for any confusion around why I'm using hex instead of base-64, which is what I'll eventually need to use - it's just an extra complicating step at the moment, so for now I'm just trying to get the hex equivalent working, and then I can concentrate on encoding it as base-64. The hex equivalent of the base-64 signature I'm trying to get is:
363a99f0c81d923ea1aed63fc5d281cb54b490b8d4dad03b1bea51d9374e045e396fbf9ebdfa73187fc2fcf88d1c40efba2442851065468dc0189ec672f970ab
Full code I'm using is below:
#include <windows.h>
#include <stdio.h>
#include <bcrypt.h>
#pragma comment(lib, "bcrypt.lib")
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
#include <fstream>
int hexToInt(char ch)
{
return 0;
}
void __cdecl wmain(
int argc,
__in_ecount(argc) LPWSTR *wargv)
{
std::wofstream fout;
fout.open("signature.txt");
BCRYPT_ALG_HANDLE hAlg = NULL;
BCRYPT_HASH_HANDLE hHash = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL;
DWORD cbData = 0,
cbHash = 0,
cbHashObject = 0;
PBYTE pbHashObject = NULL;
PBYTE pbHash = NULL;
CONST BYTE message[] = { "/account/balance1515058794242" };
CONST BYTE key[] = { "6C40ED0C99D6D32FCB9786198ADC5BF83E6C4CD9C4A50287EBB1094429900AA37D72F1A207CF881F307B1E3B0EB379929712E6BB86A23C34697BD6A7B96CF297" };
//open an algorithm handle
if (!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(
&hAlg,
BCRYPT_SHA512_ALGORITHM,
NULL,
BCRYPT_ALG_HANDLE_HMAC_FLAG)))
{
fout << "**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n" << status;
goto Cleanup;
}
//calculate the size of the buffer to hold the hash object
if (!NT_SUCCESS(status = BCryptGetProperty(
hAlg,
BCRYPT_OBJECT_LENGTH,
(PBYTE)&cbHashObject,
sizeof(DWORD),
&cbData,
0)))
{
fout << "**** Error 0x%x returned by BCryptGetProperty\n" << status;
goto Cleanup;
}
//allocate the hash object on the heap
pbHashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHashObject);
if (NULL == pbHashObject)
{
fout << "**** memory allocation failed\n";
goto Cleanup;
}
//calculate the length of the hash
if (!NT_SUCCESS(status = BCryptGetProperty(
hAlg,
BCRYPT_HASH_LENGTH,
(PBYTE)&cbHash,
sizeof(DWORD),
&cbData,
0)))
{
fout << "**** Error 0x%x returned by BCryptGetProperty\n" << status;
goto Cleanup;
}
//allocate the hash buffer on the heap
pbHash = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHash);
if (NULL == pbHash)
{
fout << "**** memory allocation failed\n";
goto Cleanup;
}
//create a hash
if (!NT_SUCCESS(status = BCryptCreateHash(
hAlg,
&hHash,
pbHashObject,
cbHashObject,
(PBYTE)key,
sizeof(key) - 1,
0)))
{
fout << "**** Error 0x%x returned by BCryptCreateHash\n" << status;
goto Cleanup;
}
//hash some data
if (!NT_SUCCESS(status = BCryptHashData(
hHash,
(PBYTE)message,
sizeof(message) - 1,
0)))
{
fout << "**** Error 0x%x returned by BCryptHashData\n" << status;
goto Cleanup;
}
//close the hash
if (!NT_SUCCESS(status = BCryptFinishHash(
hHash,
pbHash,
cbHash,
0)))
{
fout << "**** Error 0x%x returned by BCryptFinishHash\n" << status;
goto Cleanup;
}
fout << "\nThe hash is: \n";
for (DWORD i = 0; i < cbHash; i++)
{
fout << std::hex << pbHash[i];
}
Cleanup:
if (hAlg)
{
BCryptCloseAlgorithmProvider(hAlg, 0);
}
if (hHash)
{
BCryptDestroyHash(hHash);
}
if (pbHashObject)
{
HeapFree(GetProcessHeap(), 0, pbHashObject);
}
if (pbHash)
{
HeapFree(GetProcessHeap(), 0, pbHash);
}
fout.close();
};

You need to use the CONST BYTE key[] = { 0x6C, ... }; method of specifying your key. Keys and input data are binary data, represented as byte arrays in most programming languages. Hexadecimals and base 64 are two ways of representing or encoding binary values so that they can be used as printable text.
However, if you use a byte array then sizeof will return the number of actual bytes. Arrays aren't null terminated, so there is no reason to remove the final null byte. So sizeof(key) - 1 will remove the last byte of the key as input parameter, rather than remove the non-existent null byte.
The message string is null terminated, so it should work well. You may however explicitly want to mention that the message needs to be US-ASCII or explicitly encode the string (e.g. to UTF-8).

Related

Encrypt with arduino and decrypt with python using AES CBC mode

I'm very new to programming and I've been trying to encrypt a message using Arduino and decrypting with Python.
On the Arduino, I managed to encrypt and decrypt correctly, but when I try to decrypt with Python it doesn't show an error but the result isn't right.
I've used the library AESlib with the latest version (2.2.1) on Arduino with MEGA2560.
On the Arduino part I encrypted and decrypted the message correctly, I used the simple example that the AESlib offer but changed a bit to be able to do what I need it, encrypting with AES and encoding with base64, and then decoding with base64 to be able to decrypt with AES again. When that worked I printed the base64 encoded message and then copied it into a function on the python program and tried to decrypt it without working.
On the Python part, I've used the CBC mode for the decryption. Copied the key, the IV, and the encoded message for then decoded and decrypted.
Here is the message with the key and IV that I've used:
#define INPUT_BUFFER_LIMIT (400 + 1) //Maximum message caracters
unsigned char cleartext[INPUT_BUFFER_LIMIT] = {0}; // THIS IS INPUT BUFFER (FOR TEXT)
unsigned char ciphertext[2*INPUT_BUFFER_LIMIT] = {0}; // THIS IS OUTPUT BUFFER (FOR BASE64-ENCODED ENCRYPTED DATA)
unsigned char decryptedtext[INPUT_BUFFER_LIMIT] = {0}; // THIS IS OUTPUT BUFFER (FOR DECRYPTED TEXT)
unsigned char readBuffer[399] = "0013;0013;0013;15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3;NULL";//THIS IS THE VARIABLE THAT CONTAINS THE MESSAGE TO ENCRYPT
byte aes_key[N_BLOCK] = "06a9214036b8a15b512e03d534120006"; // THIS IS THE VARIABLE THAT CONTAINS THE KEY
byte aes_iv[N_BLOCK] = "6543210987654"; // THIS IS THE VARIABLE THAT CONTAINS THE IV
Arduino code:
#include "AESLib.h"
#define BAUD 9600
AESLib aesLib;
#define INPUT_BUFFER_LIMIT (400 + 1)
unsigned char cleartext[INPUT_BUFFER_LIMIT] = {0}; // THIS IS INPUT BUFFER (FOR TEXT)
unsigned char ciphertext[2*INPUT_BUFFER_LIMIT] = {0}; // THIS IS OUTPUT BUFFER (FOR BASE64-ENCODED ENCRYPTED DATA)
unsigned char decryptedtext[INPUT_BUFFER_LIMIT] = {0}; // THIS IS OUTPUT BUFFER (FOR DECRYPTED TEXT)
unsigned char readBuffer[399] = "0013;0013;0013;15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3;NULL";//THIS IS THE VARIABLE THAT CONTAINS THE MESSAGE TO ENCRYPT
byte aes_key[N_BLOCK] = "06a9214036b8a15b512e03d534120006"; // THIS IS THE VARIABLE THAT CONTAINS THE KEY
byte aes_iv[N_BLOCK] = "6543210987654"; // THIS IS THE VARIABLE THAT CONTAINS THE IV
// Generate IV
void aes_init() {
aesLib.gen_iv(aes_iv);
aesLib.set_paddingmode((paddingMode)0);
}
uint16_t encrypt_to_ciphertext(char * msg, uint16_t msgLen, byte iv[]) {
int i = 0;
Serial.println("Calling encrypt (string)...");
int cipherlength = aesLib.encrypt((byte*)msg, msgLen, (char*)ciphertext, aes_key, sizeof(aes_key), iv);
// uint16_t encrypt(byte input[], uint16_t input_length, char * output, byte key[],int bits, byte my_iv[]);
return cipherlength;
}
uint16_t decrypt_to_cleartext(byte msg[], uint16_t msgLen, byte iv[]) {
int i = 0;
Serial.print("Calling decrypt...; ");
uint16_t dec_bytes = aesLib.decrypt(msg, msgLen, (char*)decryptedtext, aes_key, sizeof(aes_key), iv);
Serial.print("Decrypted bytes: "); Serial.println(dec_bytes);
return dec_bytes;
}
void setup() {
Serial.begin(BAUD);
Serial.setTimeout(60000);
delay(2000);
aes_init(); // generate random IV, should be called only once? causes crash if repeated...
Serial.println(readBuffer[2]);
}
/* non-blocking wait function */
void wait(unsigned long milliseconds) {
unsigned long timeout = millis() + milliseconds;
while (millis() < timeout) {
yield();
}
}
byte enc_iv_to[N_BLOCK] = "6543210987654"; //A COPY OF THE IV TO DECRYPT WITH THE SAME IV
void loop() {
int i = 0;
Serial.print("readBuffer length: "); Serial.println(sizeof(readBuffer));
// must not exceed INPUT_BUFFER_LIMIT bytes; may contain a newline
sprintf((char*)cleartext, "%s", readBuffer);
// Encrypt
// iv_block gets written to, provide own fresh copy... so each iteration of encryption will be the same.
uint16_t msgLen = sizeof(readBuffer);
memcpy(aes_iv, enc_iv_to, sizeof(enc_iv_to));
uint16_t encLen = encrypt_to_ciphertext((char*)cleartext, msgLen, aes_iv); //CALL THE FUNCTION TO ENCRYPT THE MESSAGE
unsigned char base64encoded[2*INPUT_BUFFER_LIMIT] = {0};
base64_encode((char*)base64encoded, (char*)ciphertext, sizeof(ciphertext)); //CALL THE FUNCTION TO ENCODE THE ENCRYPTED MESSAGE
Serial.println("ciphertext_base64_encoded");
Serial.println((char*)base64encoded);
delay(5000);
Serial.print("Encrypted length = "); Serial.println(encLen);
Serial.print("Encrypted base64 length = "); Serial.println(sizeof(base64encoded));
Serial.println("Encrypted. Decrypting..."); Serial.println(sizeof(base64encoded)); Serial.flush();
unsigned char base64decoded[2*INPUT_BUFFER_LIMIT] = {0};
base64_decode((char*)base64decoded, (char*)base64encoded, sizeof(base64encoded));
Serial.println((char*)base64decoded);
delay(3000);
memcpy(aes_iv, enc_iv_to, sizeof(enc_iv_to));
uint16_t decLen = decrypt_to_cleartext((char*)base64decoded, encLen, aes_iv);
Serial.print("Decrypted cleartext of length: "); Serial.println(decLen);
Serial.print("Decrypted cleartext:\n"); Serial.println((char*)decryptedtext);
if (strcmp((char*)readBuffer, (char*)decryptedtext) == 0) {
Serial.println("Decrypted correctly.");
} else {
Serial.println("Decryption test failed.");
}
delay(3000);
Serial.println("---");
exit(0);
}
Python code:
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad, pad
from Crypto.Random import get_random_bytes
from Crypto.Util.strxor import strxor
import random, base64, hashlib, getpass, argparse, re
def decrypt_CBC_base64(key, ciphertext_base64, iv):
ciphertext_base64 += "=" * ((4 - len(ciphertext_base64) % 4) % 4)
ciphertext = base64.b64decode(ciphertext_base64)
ciphertext = pad (ciphertext, 16)
py_bytes = decrypt_CBC(key, ciphertext, iv)
return py_bytes
def decrypt_CBC(key, ciphertext, iv):
cipher = AES.new(key, AES.MODE_CBC, iv)
pt_bytes = cipher.decrypt(ciphertext)
return pt_bytes
try:
key = b'06a9214036b8a15b512e03d534120006'
iv = b'6543210987654321'
plaintext = b'0013;0013;0013;15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3,15.3;NULL'
ciphertext_base64 = 'aS/80Cy1jEqiclhtrYmqkYmLsxlKERuSeTfSGHfmN86N/VJHizQEmLAUJ8T7qlIgNZVr1EZzNCG2/8qzwRwHoLdMmmZKjIOKPSpbqWfiMRbvZNoREnOBv8EtGIDM4GElUvGCdJ1FYYT+S2ThZB71cRjM+oOn53w6tIQwgNuUHuZ9UMzOVBtcNKVJRUs93CXZs76qZdy7amNTyYEFkuqRjBEvA+dM8ucaxrJUUhrKfbXn2bIqHDeRJr7nldnNSqn3yT98uzJzz/YHZm4I0ZKtP3P3G7LfCmm2tGlKFiUBVsIKF+Z7WD9PHqZ55x7cHZrk3Y1T1j0l9LOIj0BHj5pjkH5ilAW0+kMU9+iyPD1AVO600U41EcPD9Iohw0pU13ooFn4Q+HDgXBHzV9Aufx8ORkw/5U/okjNxujhp07Xg/chbBXQBR1tzHgoj//XZoD5l/G+zrJVmOXCffRipV08PjbN9dDYjaFMmTsAcCBCNWd8yUGsEwOuv/cePuYSrALg3hh/tfaMZ0/H7C2gvS4XMHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
print(ciphertext_base64)
decrypted = decrypt_CBC_base64(key, ciphertext_base64, iv)
print(decrypted)
except Exception as err:
print("error: {0}".format(err))
except KeyboardInterrupt:
print("\n\n[*] (Ctrl-C) Detected, shutting down...")
exit()
Any solutions? Hope there's enough information.
The AESLib iterates over data in 16 byte chunks, encrypting one chunk of 16 bytes at a time. To decrypt the data in Python using the pycryptodome library, you would need to decrypt 16 bytes at a time and then concatenate all the decrypted data together.

I was getting a error on data structure question and unable to identify

The question is { WAP to demonstrate malloc(),calloc() and realloc() function for dynamic memory allocation}
Source Code-
#include<iostream>
#include<stdlib.h>
using namespace std;
int main()
{
int n,i,*p,n1;
char ch;
cout<<"Enter total elements ";
cin>>n;
p=(int*) malloc (p*sizeof(int));
/* p=(int*)calloc(p,sizeof(int)); */
if(p==NULL)
{
cout<<"Memory allocation failed\n";
exit(1);
}
for(i=0;i<n;i++)
{
cout<<"Enter the element ";
cin >> *(p+i);
}
for(i=0;i<n;i++)
{
cout<<*(p+i);
}
cout<<"Enter new size ";
cin>>n1;
p=(int*)realloc(p,sizeof(int));
if(p==NULL)
{
cout<<"Memory allocation failed\n";
exit(1);
}
for(i=n;i<n1;i++)
{
cout<<"Enter the element ";
cin >>*(p+i);
}
for(i=0;i<n1;i++)
{
cout<<*(p+i);
}
free(p);
return(0);
}
Error code line according to visual studio code
p=(int*) malloc (p*sizeof(int));
Error Message, I was getting-
expression must have arithmetic or unscoped enum type
p*sizeof(int)
You should multiply sizeof(int) and some number, but not 'p' - pointer value.
int size = 20;
p=(int*) malloc (size * sizeof(int));

Converting QString to utf16 hex representation for non ascii characters

I am going to convert a QString to its hex representation, everything works fine, until I put some special characters like '€':
QString l_str = "How are you";
qDebug() << "hex: " << l_str.toUtf8().toHex();
qDebug() << "readable:" << l_str.toUtf8();
prints out:
hex: "486f772061726520796f753f"
readable: "How are you?"
And so it easy to convert back the hex values to ascii, being just two values (48 = H etc.) the hex representation of an ascii char it is enough to iterate and convert every two chars.
If I set l_str = "H€w ar€ you?", and the hex € sign in utf8 is "e282ac" which are 6 values, the result is as following:
hex: "48e282ac77206172e282ac20796f753f"
but how can I get it back to a readable string?
It would be better having a conversion which results in an utf16 string:
hex: "0048006F20AC00200061007220AC00200079006F0075003F"
Consider that the "Ho€ ar€ you" string is created at runtime (so no QStringLiteral available), and I cannot use the auto keyword.
You can convert the string to utf8/16, and then convert the buffer that holds that into hexadecimal representation. These steps can be followed in reverse order to go from hex to utf8/16 to a string.
The toUtf16Hex function prepends a byte order mark so that both little- and big-endian hosts can correctly decode the Utf16 representation.
// https://github.com/KubaO/stackoverflown/tree/master/questions/str-to-utf-38831190
#include <QtCore>
QByteArray toUtf8Hex(const QString & str) {
return str.toUtf8().toHex();
}
QString fromUtf8Hex(const QByteArray & hex) {
return QString::fromUtf8(QByteArray::fromHex(hex));
}
QByteArray toUtf16Hex(QString str) {
str.prepend(QChar::ByteOrderMark);
// It is OK to use `fromRawData` since toHex copies it.
return QByteArray::fromRawData(
reinterpret_cast<const char*>(str.constData()), (str.size()+1)*2).toHex();
}
QString fromUtf16Hex(const QByteArray & hex) {
const QByteArray utf16 = QByteArray::fromHex(hex);
return QString::fromUtf16(reinterpret_cast<const quint16*>(utf16.data()));
}
int main() {
const QString str = QStringLiteral("H€w ar€ you?");
// To Utf8 and back
const QByteArray hex8 = toUtf8Hex(str);
Q_ASSERT(fromUtf8Hex(hex8) == str);
// To Utf16 and back
const QByteArray hex16 = toUtf16Hex(str);
Q_ASSERT(fromUtf16Hex(hex16) == str);
}
I found a hackish but working solution:
QString l_str = "Ho€ Ar€ you?";
qDebug() << "hex: " << l_str.toUtf8().toHex();
qDebug() << "readable:" << l_str.toUtf8();
QTextCodec* l_codec = QTextCodec::codecForName("UTF-16");
QByteArray l_string = l_codec->fromUnicode(l_str).toHex();
qDebug() << "utf16 encoded: " << l_string;
QByteArray l_reversed;
for(int i=0; i < l_string.length(); i=i+4)
{
QString l_hex_chars_1 = l_string.mid(i, 2);
QString l_hex_chars_2 = l_string.mid(i+2, 2);
l_reversed.append(l_hex_chars_2);
l_reversed.append(l_hex_chars_1);
}
QByteArray l_bom("feff");
if(l_reversed.startsWith(l_bom))
{
l_reversed.remove(0, l_bom.length());
}
QString l_res;
for(int i=0; i < l_reversed.length(); i=i+4)
{
QString l_hex_chars_1 = l_reversed.mid(i, 2);
QString l_hex_chars_2 = l_reversed.mid(i+2, 2);
int l_val = l_hex_chars_1.toInt(0,16)*256+l_hex_chars_2.toInt(0,16);
QChar l_char(l_val);
l_res.append(l_char);
}
qDebug() << "back to string: " << l_res;
This prints out:
hex: "48e282ac77206172e282ac20796f753f"
readable: "H€w ar€ you?"
utf16 encoded: "fffe4800ac207700200061007200ac20200079006f0075003f00"
byte-reversed: "004820ac007700200061007220ac00200079006f0075003f"
back to string: "H€w ar€ you?"

WriteFile fails with error 87 (the parameter is incorrect) but works fine when debugging in Visual Studio

I create a file:
m_fileHandle = CreateFileA(
m_pszFilename,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
NULL);
Then write to it:
const BOOL bSuccess = WriteFile(
m_fileHandle,
buffer,
dataSize,
&tempBytesWritten,
NULL );
When I start the program, WriteFile fails and GetLastError() returns error 87.
I read that WriteFile on a file created with flag FILE_FLAG_NO_BUFFERING fails when dataSize is not a multiple of hard disk sector size.
If that is the reason for the error, then why does the code work fine when I debug in Visual Studio Express 2012?
Solution was here: File Buffering https://msdn.microsoft.com/en-us/library/windows/desktop/cc644950%28v=vs.85%29.aspx
Working code:
#include "stdafx.h"
#include "assert.h"
#include <iostream>
#include <Windows.h>
#include <comutil.h>
using namespace std;
namespace{
unsigned long tempBytesWritten = 0;
HANDLE m_fileHandle;
char m_pszFilename[_MAX_PATH] = "";
// Create a temporary file for benchmark
int createFile()
{
WCHAR tempPath[MAX_PATH];
GetTempPath(_countof(tempPath), tempPath);
_bstr_t p(tempPath);
const char* c = p;
strcpy(m_pszFilename, c);
strcat(m_pszFilename, "testRawFile.raw");
cout << "Writing to " << m_pszFilename << endl;
m_fileHandle = CreateFileA(
m_pszFilename,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
NULL);
if (m_fileHandle == INVALID_HANDLE_VALUE)
{
assert( false );
}
return 0;
}
}
DWORD DetectSectorSize( WCHAR * devName, PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR pAlignmentDescriptor)
{
DWORD Bytes = 0;
BOOL bReturn = FALSE;
DWORD Error = NO_ERROR;
STORAGE_PROPERTY_QUERY Query;
ZeroMemory(&Query, sizeof(Query));
HANDLE hFile = CreateFileW( devName,
STANDARD_RIGHTS_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile==INVALID_HANDLE_VALUE) {
wprintf(L" hFile==INVALID_HANDLE_VALUE. GetLastError() returns %lu.\n", Error=GetLastError());
return Error;
}
Query.QueryType = PropertyStandardQuery;
Query.PropertyId = StorageAccessAlignmentProperty;
bReturn = DeviceIoControl( hFile,
IOCTL_STORAGE_QUERY_PROPERTY,
&Query,
sizeof(STORAGE_PROPERTY_QUERY),
pAlignmentDescriptor,
sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR),
&Bytes,
NULL);
if (bReturn == FALSE) {
wprintf(L" bReturn==FALSE. GetLastError() returns %lu.\n", Error=GetLastError());
}
CloseHandle(hFile);
return Error;
}
int main()
{
unsigned int dataSize = 2000;
DWORD Error = NO_ERROR;
STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR Alignment = {0};
// WCHAR szDisk[] = L"\\\\.\\PhysicalDrive0";
WCHAR szDisk[] = L"\\\\.\\C:";
Error = DetectSectorSize(szDisk, &Alignment);
if (Error) {
wprintf(L"Error %lu encountered while querying alignment.\n", Error);
return Error;
}
wprintf(L"Disk %s Properties\n", (WCHAR*) szDisk);
if (Alignment.BytesPerLogicalSector < Alignment.BytesPerPhysicalSector) {
wprintf(L" Emulated sector size is %lu bytes.\n", Alignment.BytesPerLogicalSector);
}
wprintf(L" Physical sector size is %lu bytes.\n", Alignment.BytesPerPhysicalSector);
dataSize = ((unsigned int)(dataSize + Alignment.BytesPerPhysicalSector - 1)/Alignment.BytesPerPhysicalSector) * Alignment.BytesPerPhysicalSector;
// Allocate buffer for file
unsigned char *buffer = new unsigned char[dataSize];
// Create file to write to
if ( createFile() != 0 )
{
printf("There was error creating the files... press Enter to exit.");
getchar();
return -1;
}
const BOOL bSuccess = WriteFile(m_fileHandle, buffer, dataSize, &tempBytesWritten, NULL );
if (!bSuccess)
{
cout << "Write failed with error " << GetLastError() << endl;
}
// clean up and remove file
CloseHandle(m_fileHandle);
wchar_t wtext[_MAX_PATH];
mbstowcs(wtext, m_pszFilename, strlen(m_pszFilename)+1);
DeleteFile(wtext);
return 0;
}

base64 digest- invalid input?

I have here the following data for which I have to find the sha1 digest using openssl.
data:
AwAIAOwIAAABABwAgAIAABYAAAAAAAAAAAAAAHQAAAAAAAAAAAAAAAgAAAAkAAAAQgAAAFQAAABsAAAAhgAAAJgAAACuAAAAwgAAAM4AAADsAAAAAgEAAAwBAAAoAQAARgEAAFgBAACwAQAAtAEAANABAADkAQAA+gEAAAIAaQBkAAAADABsAGEAeQBvAHUAdABfAHcAaQBkAHQAaAAAAA0AbABhAHkAbwB1AHQAXwBoAGUAaQBnAGgAdAAAAAcAZwByAGEAdgBpAHQAeQAAAAoAYgBhAGMAawBnAHIAbwB1AG4AZAAAAAsAbwByAGkAZQBuAHQAYQB0AGkAbwBuAAAABwBwAGEAZABkAGkAbgBnAAAACQB0AGUAeAB0AEMAbwBsAG8AcgAAAAgAdABlAHgAdABTAGkAegBlAAAABAB0AGUAeAB0AAAADQBwAGEAZABkAGkAbgBnAEIAbwB0AHQAbwBtAAAACQBzAGMAYQBsAGUAVAB5AHAAZQAAAAMAcwByAGMAAAAMAHAAYQBkAGQAaQBuAGcAUgBpAGcAaAB0AAAADQBsAGEAeQBvAHUAdABfAHcAZQBpAGcAaAB0AAAABwBhAG4AZAByAG8AaQBkAAAAKgBoAHQAdABwADoALwAvAHMAYwBoAGUAbQBhAHMALgBhAG4AZAByAG8AaQBkAC4AYwBvAG0ALwBhAHAAawAvAHIAZQBzAC8AYQBuAGQAcgBvAGkAZAAAAAAAAAAMAEwAaQBuAGUAYQByAEwAYQB5AG8AdQB0AAAACABUAGUAeAB0AFYAaQBlAHcAAAAJAEkAbQBhAGcAZQBWAGkAZQB3AAAABgBCAHUAdAB0AG8AbgAAAAAAgAEIAEQAAADQAAEB9AABAfUAAQGvAAEB1AABAcQAAQHVAAEBmAABAZUAAQFPAQEB2QABAR0BAQEZAQEB2AABAYEBAQEAARAAGAAAABEAAAD/////DwAAABAAAAACARAAsAAAABEAAAD//////////xIAAAAUABQABwAAAAAAAAAQAAAAAwAAAP////8IAAAREQAAABAAAAAFAAAA/////wgAABABAAAAEAAAAAAAAAD/////CAAAAR0AB38QAAAABAAAAP////8IAAABEQAGfxAAAAAGAAAA/////wgAAAUBEAAAEAAAAAEAAAD/////CAAAEP////8QAAAAAgAAAP////8IAAAQ/////wIBEACcAAAAGgAAAP//////////EwAAABQAFAAGAAAAAAAAABAAAAAIAAAA/////wgAAAUCEgAAEAAAAAcAAAD/////CAAAARAABn8QAAAACgAAAP////8IAAAFARgAABAAAAABAAAA/////wgAABD/////EAAAAAIAAAD/////CAAAEP7///8QAAAACQAAAP////8IAAABRwAIfwMBEAAYAAAAIAAAAP//////////EwAAAAIBEAB0AAAAIgAAAP//////////EgAAABQAFAAEAAAAAAAAABAAAAAFAAAA/////wgAABAAAAAAEAAAAAQAAAD/////CAAAAREABn8QAAAAAQAAAP////8IAAAQ/////xAAAAACAAAA/////wgAABD+////AgEQAIgAAAAoAAAA//////////8UAAAAFAAUAAUAAAAAAAAAEAAAAA0AAAD/////CAAABQEYAAAQAAAAAQAAAP////8IAAAQ/v///xAAAAACAAAA/////wgAABD+////EAAAAAwAAAD/////CAAAAQEAAn8QAAAACwAAAP////8IAAAQBQAAAAMBEAAYAAAALQAAAP//////////FAAAAAIBEAB0AAAALwAAAP//////////EgAAABQAFAAEAAAAAAAAABAAAAAFAAAA/////wgAABABAAAAEAAAAAEAAAD/////CAAABQEAAAAQAAAAAgAAAP////8IAAAQ/v///xAAAAAOAAAA/////wgAAAQAAIA/AgEQAHQAAAA1AAAA//////////8VAAAAFAAUAAQAAAAAAAAAEAAAAAAAAAD/////CAAAASgAB38QAAAAAQAAAP////8IAAAQ/////xAAAAACAAAA/////wgAABD+////EAAAAAkAAAD/////CAAAARUACH8DARAAGAAAADgAAAD//////////xUAAAACARAAdAAAADoAAAD//////////xUAAAAUABQABAAAAAAAAAAQAAAAAAAAAP////8IAAABKgAHfxAAAAABAAAA/////wgAABD/////EAAAAAIAAAD/////CAAAEP7///8QAAAACQAAAP////8IAAABGgAIfwMBEAAYAAAAPQAAAP//////////FQAAAAMBEAAYAAAAPwAAAP//////////EgAAAAIBEAB0AAAAQQAAAP//////////EgAAABQAFAAEAAAAAAAAABAAAAAFAAAA/////wgAABABAAAAEAAAAAEAAAD/////CAAABQEAAAAQAAAAAgAAAP////8IAAAQ/v///xAAAAAOAAAA/////wgAAAQAAIA/AgEQAHQAAABHAAAA//////////8VAAAAFAAUAAQAAAAAAAAAEAAAAAAAAAD/////CAAAASkAB38QAAAAAQAAAP////8IAAAQ/////xAAAAACAAAA/////wgAABD+////EAAAAAkAAAD/////CAAAARYACH8DARAAGAAAAEoAAAD//////////xUAAAACARAAdAAAAEwAAAD//////////xUAAAAUABQABAAAAAAAAAAQAAAAAAAAAP////8IAAABKwAHfxAAAAABAAAA/////wgAABD/////EAAAAAIAAAD/////CAAAEP7///8QAAAACQAAAP////8IAAABGQAIfwMBEAAYAAAATwAAAP//////////FQAAAAMBEAAYAAAAUQAAAP//////////EgAAAAMBEAAYAAAAUwAAAP//////////EgAAAAMBEAAYAAAAVQAAAP//////////EgAAAAEBEAAYAAAAVQAAAP////8PAAAAEAAAABgAAAA9AAAA//////////8fAAAAAgEQAGAAAAA/AAAA//////////8eAAAAFAAUAAMAAAAAAAAAGQAAAAUAAAD/////CAAAEAAAAAAZAAAAAAAAAP////8IAAAQ/v///xkAAAABAAAA/////wgAABD+////AgEQAMQAAABEAAAA//////////8gAAAAFAAUAAgAAAAAAAAAGQAAABIAAAD/////CAAABQIOAAAZAAAAEQAAAP////8IAAARAQAAABkAAAAQAAAA/////wgAAAEGAAZ/GQAAAAIAAAD/////CAAAARIAB38ZAAAAEwAAAP////8IAAAFAQQAABkAAAAAAAAA/////wgAABD+////GQAAAAEAAAD/////CAAAEP7///8ZAAAADwAAAP////8IAAABMwAIfwMBEAAYAAAASwAAAP//////////IAAAAAIBEACIAAAATQAAAP//////////IAAAABQAFAAFAAAAAAAAABkAAAASAAAA/////wgAAAUCDgAAGQAAABAAAAD/////CAAAAQYABn8ZAAAAAgAAAP////8IAAABEwAHfxkAAAAAAAAA/////wgAABD+////GQAAAAEAAAD/////CAAAEP7///8DARAAGAAAAFEAAAD//////////yAAAAADARAAGAAAAFMAAAD//////////x4AAAACARAAYAAAAFUAAAD//////////x4AAAAUABQAAwAAAAAAAAAZAAAABQAAAP////8IAAAQAAAAABkAAAAAAAAA/////wgAABD+////GQAAAAEAAAD/////CAAAEP7///8CARAAxAAAAFoAAAD//////////yAAAAAUABQACAAAAAAAAAAZAAAAEgAAAP////8IAAAFAg4AABkAAAARAAAA/////wgAABEBAAAAGQAAABAAAAD/////CAAAAQYABn8ZAAAAAgAAAP////8IAAABFAAHfxkAAAATAAAA/////wgAAA
The digest as given to me is:
Wk2pJnOErEHsElMw4TMX+rjHsQQ=
But when I use(f1= file where I copied the above data):
base64 -d f1.txt | openssl dgst -sha1 -binary | base64
I get a "base64: invalid input" error and the following digest which seems completely different :(
BaRlDid73RYBFMgqveC8G+gFBBU=
Can somebody confirm and explain if there is some mistake??
UPDATED:
Scenario: Client's binary file is base64 encoded and sent to server. Server decodes this and computes the sha1 digest. Since I have client's base64 encoded sha1 digest, the server also encodes the digest to base64. Now these two should match. And it doesn't! I receive all data. I have rechecked it. I shall present part of the code here:
//RCVBUFSIZE = 1024 (defined)
void HandleClient(int clntSocket)
{
char echoBuffer[RCVBUFSIZE] ; /* Buffer for echo string */
memset(echoBuffer, 0, RCVBUFSIZE);
char inBuffer; /* Buffer for first string */
char recv_data;
int recvMsgSize = 0; /* Size of received message */
char replyBuffer[32];
int bytes_received = 0;
int rv = 0;
int connected = clntSocket;
int len= 0;
int i = 0;
EVP_MD_CTX md_ctx;
const EVP_MD *md;
unsigned char md_value[EVP_MAX_MD_SIZE];
unsigned int md_len;
OpenSSL_add_all_digests();
md = EVP_get_digestbyname("sha1");
EVP_MD_CTX_init(&md_ctx);
EVP_DigestInit_ex(&md_ctx, md, NULL);
/* Receive message from client */
while (((bytes_received = recv(connected,&inBuffer,1,0)) > 0) && (inBuffer != '\n')){
/* Send received string and receive again until end of transmission */
if (bytes_received > 0) /* zero indicates end of transmission */
{
printf("Message received from Client is : %c\n", inBuffer);
char n = inBuffer;
int indicator = 0;
int current = 0;
unsigned long fileLen;
if(n =='6'){
if ((recvMsgSize = recv(connected, echoBuffer, RCVBUFSIZE, 0)) < 0)
DieWithError("recv() failed");
printf("no. of bytes got : %d\n", recvMsgSize);
if (recvMsgSize > 0)
echoBuffer[recvMsgSize] = '\0';
len= atoi(echoBuffer);
char *data =NULL;
printf("length of following message : %d\n", len);
if(len>0){
for( i = RCVBUFSIZE; i < (len+RCVBUFSIZE); i=i+RCVBUFSIZE){
if(i>len)
recvMsgSize = recv(connected, echoBuffer, (len - (i-RCVBUFSIZE)), 0);
else
recvMsgSize = recv(connected, echoBuffer, RCVBUFSIZE, 0);
echoBuffer[recvMsgSize] = '\0';
decode(echoBuffer, recvMsgSize, "file_out");
data = readFileBuffer("file_out");
EVP_DigestUpdate(&md_ctx, data, strlen(data));
}
}
len = 0;
memset(echoBuffer, 0, RCVBUFSIZE);
recvMsgSize = 0;
}
if (n =='5'){
printf("Update Digest Over- Calculate Final Dgst!!!!! \n");
n= 0;
EVP_DigestFinal_ex(&md_ctx, md_value, &md_len); //retrieve digest from ctx unto md_value and #bytes written is copied into md_len
EVP_MD_CTX_cleanup(&md_ctx);
FILE *f;
f = fopen("file_sha1", "w");
printf("\n");
printf("******************************************************\n ");
printf("Digest is: ");
for(i = 0; i < md_len; i++){
if ( f !=NULL){
fputc(md_value[i], f);
}
printf("%02x", md_value[i]);
}
printf("\n");
printf("******************************************************\n ");
fclose(f);
}
printf("socket closing\n");
close(connected); /* Close client socket */
}
}
char *readFileBuffer(char *name)
{
FILE *file;
char *buffer = NULL;
unsigned long fileLen;
//Open file
file = fopen(name, "rb");
if (!file)
{
fprintf(stderr, "Unable to open file %s", name);
return;
}
//Get file length
fseek(file, 0, SEEK_END);
fileLen=ftell(file);
printf("file length = %ld\n", fileLen);
fseek(file, 0, SEEK_SET);
//printf("Allocate memory\n");
buffer=(char *)malloc(fileLen+1);
printf("length of write buffer = %d\n", strlen(buffer));
if (!buffer)
{
fprintf(stderr, "Memory error!");
}
long int n = fread(buffer,1, fileLen,file);
buffer[n] = '\0';
printf("Read no. of bytes = %ld into buffer \n", n);
printf("len of buffer %d \n", strlen(buffer));
if (!buffer)
{
fprintf(stderr, "Memory error!");
fclose(file);
}
fclose(file);
//free(name);
return buffer;
}
// reads b64 encoded msg (ReadBuffer) and writes to WriiteFile.
void decode(char *ReadBuffer, int Length, char *WriteFile)
{
char *msg = (char *)malloc(Length);
memset(msg, 0x00, Length);
int readbytes = -1;
printf("buffer write file %s\n", WriteFile);
// the decode msg is written to this bio
BIO *fileWrBIO = BIO_new_file(WriteFile, "w");
BIO *b64 = BIO_new(BIO_f_base64());
BIO *bio = BIO_new_mem_buf(ReadBuffer, Length);
bio = BIO_push(b64, bio);
BIO_set_flags(bio,BIO_FLAGS_BASE64_NO_NL);
while ((readbytes = BIO_read(bio, msg, Length)) > 0)
{
printf("readbytes: %d\n", readbytes);
BIO_write(fileWrBIO, msg, readbytes);
BIO_flush(fileWrBIO);
memset(msg, 0x00, sizeof(msg));
}
free(msg);
BIO_free_all(bio);
BIO_free_all(fileWrBIO);
}
FWIW...
There are implementations where base64 cannot read its own output.
# base64 ssh_host_rsa_key | base64 -d
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA7qHASF1Jgbase64: invalid input
This is on a CentOS 5 machine.
Reason is that base64 produces output with line breaks, which are garbage chars for the decoder.
Solution is to either produce the base64 without linebreaks (-w 0) or make the decoder ignore garbage chars (-i).
Your data is invalid, probably partial. A valid base64 encoded string should have a length multiple of 4. So the different digest output is expected.
You can encrypt using this command
base64 -w 0 < id_rsa
Well, the data doesn't seem to be a valid base64 string. You might be missing some characters.
Just hit this, also on CentOS 5. Both -w 0 and -i were required, -i didn't work alone. e.g.:
tar -cf - /home/backup | gzip | base64 -w 0
base64 -d -i | gunzip | tar -xvf - -C /
worked fine to move a small home directory via copy&paste.

Resources