How to decrypt using openssl EVP? - c++

I'm trying to decrypt a file using C (but I can change to C++), but I don't know how to use the EVP library correctly.
The console command that I want to replicate is:
openssl enc -rc2-ecb -d -in myfile.bin -iter 1 -md sha1 -pbkdf2 -pass pass:'Yumi'
My actual C code using EVP is:
unsigned char salt[8] = "Salted__";
ctx=EVP_CIPHER_CTX_new();
PKCS5_PBKDF2_HMAC_SHA1("Yumi", -1,
salt, 8, 1,
EVP_MAX_KEY_LENGTH, key);
EVP_DecryptInit(ctx, EVP_rc2_ecb(), key, iv);
pt = (unsigned char *)malloc(sz + EVP_CIPHER_CTX_block_size(ctx) + 1);
EVP_DecryptUpdate(ctx, pt, &ptlen, ciphertext, sz);
if (!EVP_DecryptFinal(ctx,&pt[ptlen],&tmplen)) {
printf("Error decrypting on padding \n");
} else {
printf("Succesful decryption\n");
}
I suppose that's not working because I have to declare something to use SHA1 instead of SHA256 (default on rc2-ecb), but I'm not seeing how to do it.
Any help will be appreciated

The following hex encoded ciphertext could be decrypted with the posted OpenSSL statement, if this data would be contained hex decoded in myfile.bin:
53616C7465645F5F2DC4C4867D3B9268C82E23A672D6698FB51D41EA8601367A9112623EC27CDEB18FD1444BDB8D8DE16F1A35706EC7FED266CB909D28BF6BEC
The decryption would result in:
The quick brown fox jumps over the lazy dog
For simplicity, the ciphertext is assigned directly and the loading of the ciphertext from a file is skipped:
unsigned char data[] = {
0x53, 0x61, 0x6C, 0x74, 0x65, 0x64, 0x5F, 0x5F, // Salted__
0x2D, 0xC4, 0xC4, 0x86, 0x7D, 0x3B, 0x92, 0x68, // Salt
0xC8, 0x2E, 0x23, 0xA6, 0x72, 0xD6, 0x69, 0x8F, 0xB5, 0x1D, 0x41, 0xEA, 0x86, 0x01, 0x36, 0x7A, // Ciphertext...
0x91, 0x12, 0x62, 0x3E, 0xC2, 0x7C, 0xDE, 0xB1, 0x8F, 0xD1, 0x44, 0x4B, 0xDB, 0x8D, 0x8D, 0xE1,
0x6F, 0x1A, 0x35, 0x70, 0x6E, 0xC7, 0xFE, 0xD2, 0x66, 0xCB, 0x90, 0x9D, 0x28, 0xBF, 0x6B, 0xEC };
int dataLength = sizeof(data) / sizeof(unsigned char);
For decryption, salt and ciphertext must first be separated, e.g.:
int ciphertextLength = dataLength - 16;
unsigned char* salt = (unsigned char*)malloc(sizeof(unsigned char) * 8);
unsigned char* ciphertext = (unsigned char*)malloc(sizeof(unsigned char) * ciphertextLength);
memcpy(salt, data + 8, 8); // Get 8 bytes salt (starts at index 8)
memcpy(ciphertext, data + 16, ciphertextLength); // Get ciphertext (starts at index 16)
The next step is to derive the key, see PKCS5_PBKDF2_HMAC, e.g.:
#define KEYSIZE 16
unsigned char key[KEYSIZE];
const char* password = "'Yumi'"; // The quotation marks (') in the openssl-statement are part of the password.
int passwordLen = strlen(password);
PKCS5_PBKDF2_HMAC(password, passwordLen, salt, 8, 1, EVP_sha1(), KEYSIZE, key);
Finally the decryption can be performed, see here and here, e.g.:
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
EVP_DecryptInit_ex(ctx, EVP_rc2_ecb(), NULL, NULL, NULL);
EVP_CIPHER_CTX_set_key_length(ctx, KEYSIZE); // RC2 is an algorithm with variable key size. Therefore the key size must generally be set.
EVP_DecryptInit_ex(ctx, NULL, NULL, key, NULL);
unsigned char* plaintext = (unsigned char*)malloc(sizeof(unsigned char) * ciphertextLength);
int length;
EVP_DecryptUpdate(ctx, plaintext, &length, ciphertext, ciphertextLength);
int plaintextLength = length;
EVP_DecryptFinal_ex(ctx, plaintext + plaintextLength, &length);
plaintextLength += length;
printf("Plaintext: "); for (int i = 0; i < plaintextLength; i++) { printf("%c", plaintext[i]); } printf("\n");
For simplicity, the code doesn't include exception handling and memory release.
Note the following:
Some of the parameters used in the posted OpenSSL statement are insecure, e.g. the ECB mode and an iteration count of 1. Instead, a mode with an IV should be used and an iteration count of 10,000 or larger if performance allows.
OpenSSL generates a random 8 bytes salt during encryption, which is used to derive the key. The ciphertext consists of the ASCII encoding of Salted__, followed by the 8 bytes salt, followed by the actual ciphertext, here. Just this format is expected by the posted OpenSSL statement for decryption.
RC2 defines a variable key size. The posted OpenSSL statement uses a size of 16 bytes.
The -pass pass: option specifies the password without quotation marks, i.e. in the posted OpenSSL statement the quotation marks are part of the password.

Related

Openssl C++ AES decryption adding unexpected symbols

I'm trying to decrypt in C++ a file that have been encrypted with the Linux command : openssl enc -aes-256-cbc -nosalt -K "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855" -iv "5DF6E0E2761359D30A8275058E299FCC" -p -in file.json -out file.enc
The decryption works well, but unexpected symbols appear at the end of the file when I print it in the terminal, as in the following image Image
Here is my C++ code, can someone help me ?
int main(int argc, char **argv)
{
EVP_CIPHER_CTX *en, *de;
en = EVP_CIPHER_CTX_new();
de = EVP_CIPHER_CTX_new();
unsigned char key_data[] = {0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B,0x78, 0x52, 0xB8, 0x55};
int key_data_len = 32;
std::ifstream in("file.enc");
std::string contents((std::istreambuf_iterator<char>(in)),
std::istreambuf_iterator<char>());
unsigned char iv[] = {0x5D, 0xF6, 0xE0, 0xE2, 0x76, 0x13, 0x59, 0xD3, 0x0A, 0x82, 0x75, 0x05, 0x8E, 0x29, 0x9F, 0xCC};
EVP_CIPHER_CTX_init(en);
EVP_EncryptInit_ex(en, EVP_aes_256_cbc(), NULL, key_data, iv);
EVP_CIPHER_CTX_init(de);
EVP_DecryptInit_ex(de, EVP_aes_256_cbc(), NULL, key_data, iv);
char *plaintext;
int len = strlen(contents.c_str())+1;
plaintext = (char *)aes_decrypt(de, (unsigned char *)contents.c_str(), &len);
printf("%s", plaintext);
free(plaintext);
EVP_CIPHER_CTX_cleanup(en);
EVP_CIPHER_CTX_cleanup(de);
}
And the function to decrypt :
unsigned char *aes_decrypt(EVP_CIPHER_CTX *e, unsigned char *ciphertext, int *len)
{
int p_len = *len, f_len = 0;
unsigned char *plaintext = (unsigned char *)calloc(sizeof(char*), p_len);
EVP_DecryptInit_ex(e, NULL, NULL, NULL, NULL);
EVP_DecryptUpdate(e, plaintext, &p_len, ciphertext, *len);
EVP_DecryptFinal_ex(e, plaintext+p_len, &f_len);
*len = p_len + f_len;
return plaintext;
}
SOLVED : I had to remove the PKCS#7 padding added by the encoder PKCS#7 Padding
The input length is incorrect - strlen(contents.c_str()) + 1 will either return length including additional null byte which should not be included as it is not part of encrypted data, or length of data to the first null byte in encrypted data if there is one. You should use contents.size() instead.
This causes EVP_DecryptUpdate to decrypt all data including last block with padding and expect more data and EVP_DecryptFinal_ex to fail after that. With correct length the padding from last block will be stripped as expected.
There's also issue with output buffer length - it's sizeof(char*) * p_len instead of sizeof(char) * (p_len + EVP_CIPHER_block_size(EVP_aes_256_cbc())). EVP_DecryptUpdate requires output buffer to be large enough to hold input length + cipher block size.
You should also make sure to use only len data in plaintext buffer - printf will output data until null byte, which might not be included in decrypted data.

C++ AES Decrypt and Nodejs AES Decrypt producing different outputs

I've reimplemented this AES c++ decryption in nodejs.
The "buffer" contains the encrypted content.
The "decryptKey" contains the key to decrypt the "buffer".
The "expectedOutput" contains the expected output.
In order to bypass the bad decrypt exception thrown by node I had to disable the autoPadding in my crypt object.
To simplify I added the c++ code and I added tests to three different algorithms (AES-128-ECB, AES-192-ECB, AES-256-ECB). None of the decrypt results match the C++ output.
What am I missing?
var crypto = require('crypto');
var buffer = new Buffer([
0x5e,0x51,0xa3,0x53,0x9d,0xe7,0xe5,0xd3,
0xee,0x30,0xbb,0xf8,0x0c,0x72,0x9f,0x80
]);
var decryptKey = new Buffer([
0x36, 0x46, 0xb4, 0xf6,
0x8e, 0x6d, 0xdc, 0xf4,
0xb0, 0x31, 0x7e, 0x81,
0x6b, 0x5d, 0x96, 0x55
])
/*
After looking to my C++ code I noticed that despite of providing a 32 length key the 128 argument ensures that only the first 16 bytes are used
var decryptKey = new Buffer([
0x36, 0x46, 0xb4, 0xf6,
0x8e, 0x6d, 0xdc, 0xf4,
0xb0, 0x31, 0x7e, 0x81,
0x6b, 0x5d, 0x96, 0x55, // 16
0x15, 0x9c, 0x78, 0x54,
0x8c, 0xca, 0x3e, 0x39,
0x2d, 0x49, 0x75, 0x5d,
0xa1, 0x1a, 0xc3, 0xe3 // 32
])*/
var expectedOutput = new Buffer([
0xc8,0x6c,0x8f,0x2b,0xe8,0x21,0xc4,0x2e,
0xfb,0x4a,0x8e,0x8b,0xc3,0x94,0x19,0xc2
]);
// aes_context aes_ctx;
function decrypt(data, password, algorithm, padding){
if (padding === void 0) padding = true;
algorithm = algorithm || 'aes-128-ecb';
//aes_setkey_dec( &aes_ctx, digest, 128 );
var crypt = crypto.createDecipher(algorithm,password);
crypt.setAutoPadding(padding);
// aes_crypt_ecb( &aes_ctx, AES_DECRYPT, buffer, buffer );
var res = crypt.update(data, null, 'hex')
res += crypt.final('hex');
return new Buffer(res,'hex');
}
// aes_setkey_dec( &aes_ctx, digest, 128 );
var algoList = [
'aes-128-ecb',
'aes-192-ecb',
'aes-256-ecb'
];
for (var i = 0; i<= 1; i++){
console.log('\n ******* AUTO PADDING: ' + (padding ? 'ON': 'OFF') + ' ********* ');
var padding = i === 0;
for (let algo of algoList){
try {
var output = decrypt(buffer, decryptKey, algo, padding);
console.log(algo + ' => ' + output.toString('hex') + ' < ' + (Buffer.compare(expectedOutput, output) === 0 ? 'ok' : 'ko'))
} catch (err){
console.log('Failed to perform ' + algo + ' with autopadding ' + (padding ? ' on ': ' off ') + ' due to ' + err.message);
}
}
}
/*
******* AUTO PADDING: OFF *********
Failed to perform aes-128-ecb with autopadding on due to error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
Failed to perform aes-192-ecb with autopadding on due to error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
Failed to perform aes-256-ecb with autopadding on due to error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
******* AUTO PADDING: ON *********
aes-128-ecb => d9817f142f9bca262b67f6a6be570345 < ko
aes-192-ecb => 9181784373bb6060c04c9ba75de26322 < ko
aes-256-ecb => c5945203368de477e5f0dbeedeb2189f < ko
*/
Heres the c++ code
#include "aes.h"
#include "sha2.h"
int main(int argc, char *argv[]) {
unsigned char data[16] = {
0x5e,0x51,0xa3,0x53,0x9d,0xe7,0xe5,0xd3,0xee,0x30,0xbb,0xf8,0x0c,0x72,0x9f,0x80
};
unsigned char key[32] = {
0x36, 0x46, 0xb4, 0xf6,
0x8e, 0x6d, 0xdc, 0xf4,
0xb0, 0x31, 0x7e, 0x81,
0x6b, 0x5d, 0x96, 0x55, // 16
0x15, 0x9c, 0x78, 0x54,
0x8c, 0xca, 0x3e, 0x39,
0x2d, 0x49, 0x75, 0x5d,
0xa1, 0x1a, 0xc3, 0xe3 // 32
};
aes_context aes_ctx;
aes_setkey_dec(&aes_ctx, key, 128);
aes_crypt_ecb(&aes_ctx, AES_DECRYPT, data, data);
for (int i = 0; i< sizeof(data); ++i)
std::cout << std::hex << (int)data[i];
/* Output => c86c8f2be821c42efb4a8e8bc39419c2*/
}
references:
https://tls.mbed.org/discussions/generic/question-about-using-aes
http://aes.online-domain-tools.com/link/133660agcLyPgFri4s/ - Example of decryption online
The solution based in answer below
var crypto = require('crypto')
var buffer = new Buffer([
0x5e,0x51,0xa3,0x53,0x9d,0xe7,0xe5,0xd3,
0xee,0x30,0xbb,0xf8,0x0c,0x72,0x9f,0x80
]);
var decryptKey = new Buffer([
0x36, 0x46, 0xb4, 0xf6,
0x8e, 0x6d, 0xdc, 0xf4,
0xb0, 0x31, 0x7e, 0x81,
0x6b, 0x5d, 0x96, 0x55
])
var expectedOutput = new Buffer([
0xc8,0x6c,0x8f,0x2b,0xe8,0x21,0xc4,0x2e,
0xfb,0x4a,0x8e,0x8b,0xc3,0x94,0x19,0xc2
]);
// aes_context aes_ctx;
function decrypt(data, password, algorithm, padding){
if (padding === void 0) padding = true;
algorithm = algorithm || 'aes-128-ecb';
//aes_setkey_dec( &aes_ctx, digest, 128 );
var crypt = crypto.createDecipheriv(algorithm,password, new Buffer([]));//new Buffer(32).fill(0).byteLength
crypt.setAutoPadding(padding);
// aes_crypt_ecb( &aes_ctx, AES_DECRYPT, buffer, buffer );
var res = crypt.update(data, null,'hex')
+ crypt.final('hex');
return new Buffer(res,'hex');
}
// aes_setkey_dec( &aes_ctx, digest, 128 );
var output = decrypt(buffer, decryptKey, 'aes-128-ecb', false);
console.log(Buffer.compare(expectedOutput, output) === 0 ? 'ok' : 'ko');
The deprecated crypto.createDecypher() derives the key from the password argument:
The implementation of crypto.createDecipher() derives keys using the OpenSSL function EVP_BytesToKey with the digest algorithm set to MD5, one iteration, and no salt.
What you want instead is to use a raw key. For that you should use crypto.createDecipheriv() instead:
var crypt = crypto.createDecipheriv(algorithm,password,new Buffer([]));
(In ECB mode the IV can be empty)
Of course, the key length must then match the requested algorithm (128, 192 or 256 bits). You key is 128 bits, so only aes-128-ecb will work.
The reason you need to pass false to setAutoPadding is that your ciphertext is not padded. You haven't included your encryption code that generates the ciphertext, but I can tell from the length of it that it is not padded, because a plaintext of one block size in length, when encrypted using PKCS#7 padding, will produce a ciphertext that is two block sizes in length, rather than the single block that you have.
The reason this decrypts with aes_crypt_ecb is that it looks like aes_crypt_ecb simply performs individual block encryption/decryption, so does not do any padding or unpadding. The Javscript code though, if passed true to the setAutoPadding function, will be expecting padding (probably PKCS#7). Which will of course fail because your encryption has not used padding.
Ideally you should modify your encryption code so that it uses proper padding when doing the encryption, as this is much more secure than not using padding. Otherwise you will need to make sure that your call to setAutoPadding is passing false when doing the decryption, so the Javascript knows there is no padding.

Missing something when decompressing HTTP gzipped response

I have recently been setting up various testing environments and in this cas I nneed to read and decode a gzip response from a HTTP server. I know what I have so far works as I have tested it with wireshark and hardcoded data as outlined below, my question is what is wrong with how I am handling the gizzped data from a HTTP server?
Here is what Im using:
From this thread http://www.qtcentre.org/threads/30031-qUncompress-data-from-gzip I am using the gzipDecopress function with the data provided and seeing that it works.
QByteArray gzipDecompress( QByteArray compressData )
{
//Hardcode sample data
const char dat[40] = {
0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xAA, 0x2E, 0x2E, 0x49, 0x2C, 0x29,
0x2D, 0xB6, 0x4A, 0x4B, 0xCC, 0x29, 0x4E, 0xAD, 0x05, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00,
0x2A, 0x63, 0x18, 0xC5, 0x0E, 0x00, 0x00, 0x00};
compressData = QByteArray::fromRawData( dat, 40);
//decompress GZIP data
//strip header and trailer
compressData.remove(0, 10);
compressData.chop(12);
const int buffersize = 16384;
quint8 buffer[buffersize];
z_stream cmpr_stream;
cmpr_stream.next_in = (unsigned char *)compressData.data();
cmpr_stream.avail_in = compressData.size();
cmpr_stream.total_in = 0;
cmpr_stream.next_out = buffer;
cmpr_stream.avail_out = buffersize;
cmpr_stream.total_out = 0;
cmpr_stream.zalloc = Z_NULL;
cmpr_stream.zalloc = Z_NULL;
if( inflateInit2(&cmpr_stream, -8 ) != Z_OK) {
qDebug() << "cmpr_stream error!";
}
QByteArray uncompressed;
do {
int status = inflate( &cmpr_stream, Z_SYNC_FLUSH );
if(status == Z_OK || status == Z_STREAM_END) {
uncompressed.append(QByteArray::fromRawData((char *)buffer, buffersize - cmpr_stream.avail_out));
cmpr_stream.next_out = buffer;
cmpr_stream.avail_out = buffersize;
} else {
inflateEnd(&cmpr_stream);
}
if(status == Z_STREAM_END) {
inflateEnd(&cmpr_stream);
break;
}
}while(cmpr_stream.avail_out == 0);
return uncompressed;
}
When the data is hardcoded as in that example, the string is decompressed. However, when I read the response from a HTTP server and store it in a QByteArray, it cannot be uncompressed. I am reading the response as follows and I can see it works when comparing the results on wireshark
//Read that length of encoded data
char EncodedData[ LengthToRead ];
memset( EncodedData, 0, LengthToRead );
recv( socketDesc, EncodedData, LengthToRead, 0 );
EndOfData = true;
//EncodedDataBytes = QByteArray((char*)EncodedData);
EncodedDataBytes = QByteArray::fromRawData(EncodedData, LengthToRead );
I assume i am missing some header or byte order when reading the response, but at the moment have no idea what. Any help very welcome!!
EDIT: So I have been looking at this a little more over the weekend and at the moment im trying to test the encode and decode of the given hex string, which is "{status:false}" in plain text. I have tried to use online gzip encoders such as http://www.txtwizard.net/compression but it returns some ascii text that does not match the hex string in the above code. When I use PHPs gzcompress( "{status:false}", 1) function it gives me non-ascii values, that I cannot copy/paste to test since they are ascii. So I am wondering if there is any standard reference for gzip encode/decode? It is definitely not in some special encoding since both firefox and wireshark can decode the packets, but my software cannot.
So the issue was with my gzip function, the correct function I found on this link: uncompress error when using zlib
As mentioned above by Cornstalks the infalteInit2 function needs to take MAX_WBITS+16 as its max bit size, I think that was the issue. If anybody knows any libraries or plugins to handle this please post them here! I am surprised that this had to be coded manually when it is so commonly used by HTTP clients/servers.

Function returning wrong value in lpc824

I am working on porting an application running on Arduino Mega to LPC824. The following piece of code is working differently for both the platforms.
/**
* Calculation of CMAC
*/
void cmac(const uint8_t* data, uint8_t dataLength) {
uint8_t trailer[1] = {0x80};
uint8_t bytes[_lenRnd];
uint8_t temp[_lenRnd];
memcpy(temp, data, dataLength);
concatArray(temp, dataLength, trailer, 1);
dataLength ++;
addPadding(temp, dataLength);
memcpy(bytes, _sk2, _lenRnd);
xorBytes(bytes,temp,_lenRnd);
aes128_ctx_t ctx;
aes128_init(_sessionkey, &ctx);
uint8_t* chain = aes128_enc_sendMode(bytes, _lenRnd, &ctx, _ivect);
Board_UARTPutSTR("chain\n\r");
printBytes(chain, 16, true);
memcpy(_ivect, chain, _lenRnd);
//memcpy(_ivect, aes128_enc_sendMode(bytes,_lenRnd,&ctx,_ivect), _lenRnd);
memcpy(_cmac,_ivect, _lenRnd);
Board_UARTPutSTR("Initialization vector\n\r");
printBytes(_ivect, 16, true);
}
I am expecting a value like {0x5d, 0xa8, 0x0f, 0x1f, 0x1c, 0x03, 0x7f, 0x16, 0x7e, 0xe5, 0xfd, 0xf3, 0x45, 0xb7, 0x73, 0xa2} for the chain variable. But the follow function is working differently. The print inside the function has the correct value which I want ({5d, 0xa8, 0x0f, 0x1f, 0x1c, 0x03, 0x7f, 0x16, 0x7e, 0xe5, 0xfd, 0xf3, 0x45, 0xb7, 0x73, 0xa2}).
But when the function returns chain is having a different value, compared to what I am expecting, I get the following value for chain {0x00, 0x20, 0x00, 0x10, 0x03, 0x01, 0x00, 0x00, 0xd5, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00}
Inside the function, the result is correct. But it returns a wrong value to the function which called it. Why is it happening so ?
uint8_t* aes128_enc_sendMode(unsigned char* data, unsigned short len, aes128_ctx_t* key,
const unsigned char* iv) {
unsigned char tmp[16];
uint8_t chain[16];
unsigned char c;
unsigned char i;
memcpy(chain, iv, 16);
while (len >= 16) {
memcpy(tmp, data, 16);
//xorBytes(tmp,chain,16);
for (i = 0; i < 16; i++) {
tmp[i] = tmp[i] ^ chain[i];
}
aes128_enc(tmp, key);
for (i = 0; i < 16; i++) {
//c = data[i];
data[i] = tmp[i];
chain[i] = tmp[i];
}
len -= 16;
data += 16;
}
Board_UARTPutSTR("Chain!!!:");
printBytes(chain, 16, true);
return chain;
}
A good start with an issue like this is to delete as much as you can while reproducing the error, with a minimal code example the answer is typically clear. I have done that for you here.
uint8_t* aes128_enc_sendMode(void) {
uint8_t chain[16];
return chain;
}
The chain variable is a local to the function, it ceases to be defined once the function exists. Accessing a pointer to that variable causes undefined behaviour, don't do it.
In practice the pointer to the array still exists and points to an arbitrary block of memory. This block of memory is no longer reserved and can be overwritten at any time.
I suspect it works for the AVR because it is a simple 8 bit chip and that piece of memory was sitting unmolested by the time you used it. The ARM would have used greater optimisations, possibly running the full array on registers, so the data doesn't survive the transition.
tldr; You need to malloc() any arrays that you want to live past the function's exit. Be careful, malloc and embedded systems go together like diesel and styrofoam, it gets messy real quick.

Convert files of any types to a file with c strings

Please suggest a small command-line utility (for Windows) to convert files from particular directory to a valid c file. Maybe it can be done just with batch commands?
The resulting file should look like this:
static const unsigned char some_file[] = {
/* some_file.html */
0x2f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0,
0x25, 0x21, 0x3a, 0x20, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65
}
static const unsigned char some_other_file[] = {
/* some_other_file.png*/
0x2f, 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0,
0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0x20, 0x20, 0x3c
}
P.S. Please don't suggest Perl and Python ports. They are too heavy for this task.
P.P.S. May be someone knows more customizable utility than bin2h, but less heavy and complex than awt? Which can parse several files and put them into one C. Also specifing custom variable names (using some kind of an index file) whould be great. So it can be added to the build process.
Use xxd -i file.
I use the one included with Vim. For example:
C:\Documents and Settings\user> xxd -i error.log | head -n2
unsigned char error_log[] = {
0x0c, 0x0d, 0x0a, 0x3d, 0x3d, 0x32, 0x30, 0x30, 0x39, 0x2f, 0x35, 0x2f,
See also Is it possible to view a binary in ones and zeros?
Bin2h will do this.
Bin2h - Win32 binary to C header file
converter
A Win32 command-line utility for
converting a binary file into a C
header file, representing the contents
of that file as a block of data.
I don't believe the input file has to be a binary file.
If you want a utility that can be freely used (commercial or whatever) here's a GPL bin2c by Adrian Prantl:
/*
* bin2c: A Program to convert binary data into C source code
* Copyright 2004 by Adrian Prantl <adrian#f4z.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <stdio.h>
#include <stdlib.h>
char* self = 0;
void usage() {
printf("Usage:\n%s input.bin output.h name\n\n", self);
}
void bail_out(const char* s1, const char* s2) {
fprintf(stderr, "%s: FATAL ERROR:\n%s%s\n", self, s1, s2);
exit(1);
}
int main(int argc, char** argv) {
FILE *fi, *fo;
int c, i;
self = argv[0];
if (argc != 4) {
usage();
return 0;
}
if ((fi = fopen(argv[1], "rb")) == 0)
bail_out("Cannot open input file ", argv[1]);
if ((fo = fopen(argv[2], "w")) == 0)
bail_out("Cannot open output file ", argv[2]);
if ((c = fgetc(fi)) != EOF) {
fprintf(fo, "#ifndef %s_H\n", argv[3]);
fprintf(fo, "#define %s_H\n\n", argv[3]);
fprintf(fo, "const unsigned char %s[] = {\n", argv[3]);
fprintf(fo, c < 16 ? " 0x%02x" : " 0x%02x", (unsigned char) c);
}
i = 1;
while ((c = fgetc(fi)) != EOF) {
if (i < 12)
fprintf(fo, c < 16 ? ", 0x%02x" : ", 0x%02x", (unsigned char) c);
else {
fprintf(fo, c < 16 ? ",\n 0x%02x" : ",\n 0x%02x", (unsigned char) c);
i = 0;
}
i++;
}
fprintf(fo, "\n};\n\n");
fprintf(fo, "#endif\n");
printf("converted %s\n", argv[1]);
return 0;
}
It's a single 70 line or so C file - nothing to it to compile and run.
SRecord can do that, and more. Though it is hardly difficult to write your own in C.