Encrypt with arduino and decrypt with python using AES CBC mode - python-3.x
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.
Related
How can I get BCrypt to interpret my key as hex?
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).
How to match .NET AES with Linux EVP encryption
I have a file that I need to decrypt in a C# .NET application. This is a situation where the files are produced by a legacy system that cannot be modified. Here is the code used to decrypt the files in the Linux app (I cut out some things having to do with loading the data from the file and such that were not specific to the encryption): #define BUFFER_SIZE 8192 #define ENCRYPTION_KEY_LENGTH 16 unsigned char OutBuf[BUFFER_SIZE]; unsigned char InBuf[BUFFER_SIZE]; unsigned char arucIV[ENCRYPTION_KEY_LENGTH]; unsigned char arucKey[ENCRYPTION_KEY_LENGTH]; istream * pIn = &std::cin; ostream * pOut = &std::cout; string sInFile, sOutFile; bool decrypt = false; int rc, nOut, nIn; EVP_CIPHER_CTX * pCTX = EVP_CIPHER_CTX_new(); pIn->read((char*)arucIV, ENCRYPTION_KEY_LENGTH); nIn = pIn->gcount(); if(nIn == ENCRYPTION_KEY_LENGTH) { rc = AesKeyGen(arucIV, arucKey, ENCRYPTION_KEY_LENGTH); if(rc == 0) { if(EVP_DecryptInit_ex(pCTX, EVP_aes_128_ctr(), NULL, arucKey, arucIV)) { while(pIn->good() && pOut->good()) { pIn->read((char*)InBuf, BUFFER_SIZE); nIn = pIn->gcount(); if(nIn) { if(EVP_DecryptUpdate(pCTX, OutBuf, &nOut, InBuf, nIn)) { pOut->write((char*)OutBuf, nOut); } } } if(EVP_DecryptFinal_ex(pCTX, OutBuf, &nOut)) { pOut->write((char*)OutBuf, nOut); } } } else { printf("Error Generating key.\n"); } } else { printf("Error reading IV from input.\n"); } In .NET I tried this code and it decrypts the first 16 bytes correctly, but the rest is garbage: byte[] result = new byte[cipherText.Length]; using (RijndaelManaged rm = new RijndaelManaged()) { rm.BlockSize = 128; rm.Key = Key; rm.IV = IV; rm.Mode = CipherMode.CFB; rm.Padding = PaddingMode.Zeros; ICryptoTransform ctr = rm.CreateDecryptor(); int position = 0; while (position + 128 < cipherText.Length) { ctr.TransformBlock(cipherText, position, 128, result, position); position += 128; } ctr.TransformFinalBlock(cipherText, position, cipherText.Length - position); } So the question is what do I have to do in .NET to match how the openssl / linux app is decrypting? The linux box this is happening on is using openssl 1.0.1t. I thought I might try just building the linux app on windows, but when I download openssl for windows 1.0.1t the include folder is empty so none of the headers are available to build it. What do I do?
EVP_aes_128_ctr is AES 128 in CTR mode. And since CTR mode is effectively a stream cipher, there's no notion of padding. .NET does not expose CTR mode, so this isn't directly portable to .NET. If you really need it to work from .NET you'll have to use AES in CipherMode.ECB (and PaddingMode.None with BlockSize = 128) to implement CTR from the description at https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29.
How to use alsa to play sounds simultaneously in c?
I'm using alsa lib in c under linux. I'd like to load several wav files and play them depending on some test conditions. I'm using the following code, but it needs to be improved: // A simple C example to play a mono or stereo, 16-bit 44KHz // WAVE file using ALSA. This goes directly to the first // audio card (ie, its first set of audio out jacks). It // uses the snd_pcm_writei() mode of outputting waveform data, // blocking. // // Compile as so to create "alsawave": // gcc -o alsawave alsawave.c -lasound // // Run it from a terminal, specifying the name of a WAVE file to play: // ./alsawave MyWaveFile.wav #include <stdio.h> #include <stdlib.h> #include <unistd.h> // Include the ALSA .H file that defines ALSA functions/data #include <alsa/asoundlib.h> #pragma pack (1) /////////////////////// WAVE File Stuff ///////////////////// // An IFF file header looks like this typedef struct _FILE_head { unsigned char ID[4]; // could be {'R', 'I', 'F', 'F'} or {'F', 'O', 'R', 'M'} unsigned int Length; // Length of subsequent file (including remainder of header). This is in // Intel reverse byte order if RIFF, Motorola format if FORM. unsigned char Type[4]; // {'W', 'A', 'V', 'E'} or {'A', 'I', 'F', 'F'} } FILE_head; // An IFF chunk header looks like this typedef struct _CHUNK_head { unsigned char ID[4]; // 4 ascii chars that is the chunk ID unsigned int Length; // Length of subsequent data within this chunk. This is in Intel reverse byte // order if RIFF, Motorola format if FORM. Note: this doesn't include any // extra byte needed to pad the chunk out to an even size. } CHUNK_head; // WAVE fmt chunk typedef struct _FORMAT { short wFormatTag; unsigned short wChannels; unsigned int dwSamplesPerSec; unsigned int dwAvgBytesPerSec; unsigned short wBlockAlign; unsigned short wBitsPerSample; // Note: there may be additional fields here, depending upon wFormatTag } FORMAT; #pragma pack() // Size of the audio card hardware buffer. Here we want it // set to 1024 16-bit sample points. This is relatively // small in order to minimize latency. If you have trouble // with underruns, you may need to increase this, and PERIODSIZE // (trading off lower latency for more stability) #define BUFFERSIZE (2*1024) // How many sample points the ALSA card plays before it calls // our callback to fill some more of the audio card's hardware // buffer. Here we want ALSA to call our callback after every // 64 sample points have been played #define PERIODSIZE (2*64) // Handle to ALSA (audio card's) playback port snd_pcm_t *PlaybackHandle; // Handle to our callback thread snd_async_handler_t *CallbackHandle; // Points to loaded WAVE file's data unsigned char *WavePtr; // Size (in frames) of loaded WAVE file's data snd_pcm_uframes_t WaveSize; // Sample rate unsigned short WaveRate; // Bit resolution unsigned char WaveBits; // Number of channels in the wave file unsigned char WaveChannels; // The name of the ALSA port we output to. In this case, we're // directly writing to hardware card 0,0 (ie, first set of audio // outputs on the first audio card) static const char SoundCardPortName[] = "default"; // For WAVE file loading static const unsigned char Riff[4] = { 'R', 'I', 'F', 'F' }; static const unsigned char Wave[4] = { 'W', 'A', 'V', 'E' }; static const unsigned char Fmt[4] = { 'f', 'm', 't', ' ' }; static const unsigned char Data[4] = { 'd', 'a', 't', 'a' }; /********************** compareID() ********************* * Compares the passed ID str (ie, a ptr to 4 Ascii * bytes) with the ID at the passed ptr. Returns TRUE if * a match, FALSE if not. */ static unsigned char compareID(const unsigned char * id, unsigned char * ptr) { register unsigned char i = 4; while (i--) { if ( *(id)++ != *(ptr)++ ) return(0); } return(1); } /********************** waveLoad() ********************* * Loads a WAVE file. * * fn = Filename to load. * * RETURNS: 0 if success, non-zero if not. * * NOTE: Sets the global "WavePtr" to an allocated buffer * containing the wave data, and "WaveSize" to the size * in sample points. */ static unsigned char waveLoad(const char *fn) { const char *message; FILE_head head; register int inHandle; if ((inHandle = open(fn, O_RDONLY)) == -1) message = "didn't open"; // Read in IFF File header else { if (read(inHandle, &head, sizeof(FILE_head)) == sizeof(FILE_head)) { // Is it a RIFF and WAVE? if (!compareID(&Riff[0], &head.ID[0]) || !compareID(&Wave[0], &head.Type[0])) { message = "is not a WAVE file"; goto bad; } // Read in next chunk header while (read(inHandle, &head, sizeof(CHUNK_head)) == sizeof(CHUNK_head)) { // ============================ Is it a fmt chunk? =============================== if (compareID(&Fmt[0], &head.ID[0])) { FORMAT format; // Read in the remainder of chunk if (read(inHandle, &format.wFormatTag, sizeof(FORMAT)) != sizeof(FORMAT)) break; // Can't handle compressed WAVE files if (format.wFormatTag != 1) { message = "compressed WAVE not supported"; goto bad; } WaveBits = (unsigned char)format.wBitsPerSample; WaveRate = (unsigned short)format.dwSamplesPerSec; WaveChannels = format.wChannels; } // ============================ Is it a data chunk? =============================== else if (compareID(&Data[0], &head.ID[0])) { // Size of wave data is head.Length. Allocate a buffer and read in the wave data if (!(WavePtr = (unsigned char *)malloc(head.Length))) { message = "won't fit in RAM"; goto bad; } if (read(inHandle, WavePtr, head.Length) != head.Length) { free(WavePtr); break; } // Store size (in frames) WaveSize = (head.Length * 8) / ((unsigned int)WaveBits * (unsigned int)WaveChannels); close(inHandle); return(0); } // ============================ Skip this chunk =============================== else { if (head.Length & 1) ++head.Length; // If odd, round it up to account for pad byte lseek(inHandle, head.Length, SEEK_CUR); } } } message = "is a bad WAVE file"; bad: close(inHandle); } printf("%s %s\n", fn, message); return(1); } /********************** play_audio() ********************** * Plays the loaded waveform. * * NOTE: ALSA sound card's handle must be in the global * "PlaybackHandle". A pointer to the wave data must be in * the global "WavePtr", and its size of "WaveSize". */ static void play_audio(void) { register snd_pcm_uframes_t count, frames; // Output the wave data count = 0; do { frames = snd_pcm_writei(PlaybackHandle, WavePtr + count, WaveSize - count); // If an error, try to recover from it if (frames < 0) frames = snd_pcm_recover(PlaybackHandle, frames, 0); if (frames < 0) { printf("Error playing wave: %s\n", snd_strerror(frames)); break; } // Update our pointer count += frames; } while (count < WaveSize); // Wait for playback to completely finish //if (count == WaveSize) //snd_pcm_drain(PlaybackHandle); } /*********************** free_wave_data() ********************* * Frees any wave data we loaded. * * NOTE: A pointer to the wave data be in the global * "WavePtr". */ static void free_wave_data(void) { if (WavePtr) free(WavePtr); WavePtr = 0; } int main(int argc, char **argv) { // No wave data loaded yet WavePtr = 0; if (argc < 2) printf("You must supply the name of a 16-bit mono WAVE file to play\n"); // Load the wave file else if (!waveLoad(argv[1])) { register int err; // Open audio card we wish to use for playback if ((err = snd_pcm_open(&PlaybackHandle, &SoundCardPortName[0], SND_PCM_STREAM_PLAYBACK, 0)) < 0) printf("Can't open audio %s: %s\n", &SoundCardPortName[0], snd_strerror(err)); else { switch (WaveBits) { case 8: err = SND_PCM_FORMAT_U8; break; case 16: err = SND_PCM_FORMAT_S16; break; case 24: err = SND_PCM_FORMAT_S24; break; case 32: err = SND_PCM_FORMAT_S32; break; } // Set the audio card's hardware parameters (sample rate, bit resolution, etc) if ((err = snd_pcm_set_params(PlaybackHandle, err, SND_PCM_ACCESS_RW_INTERLEAVED, WaveChannels, WaveRate, 1, 100000)) < 0) printf("Can't set sound parameters: %s\n", snd_strerror(err)); // Play the waveform else play_audio(); int i; usleep(10000); play_audio(); play_audio(); // Close sound card snd_pcm_close(PlaybackHandle); } } // Free the WAVE data free_wave_data(); return(0); } As I would like to play multiple sounds simultaneously, I started to try to play the same sound more than once, so I commented the following lines: if (count == WaveSize) snd_pcm_drain(PlaybackHandle); in the play_audio function. Unfortunately, that doesn't really works, because if I try to play the same sound more than once, it works, but, if I insert a long delay before I play the sound, nothing is played. for instance, in the main function play_audio(); usleep(10000); play_audio(); play_audio(); works, and I can hear the same sound three times. But, if I use usleep(100000), I hear the sound only once. Another problem is that it has to wait for the first sound to end before it starts to play the next one. So, I'd like to be able to send more than one sound, and play several sounds at the same time. I would like to mix them manually (it's not really difficult). The main function will contain a while loop with some tests to determine which sound(s) need to be played. I thought about putting play_audio in a thread and run it in an infinite loop, and have the main thread that modifies (mix, etc.) WavePtr. I just don't really know if this is the right way, or if there is a more efficient method. Any suggestions? Thanks.
Client Server -(TCP)
I am trying to send some text from the client's end to the server. I also want to display time stamps,so as to notify the time at which the message was received. When I try sending the time it sends a blank.However the rest of the string gets displayed. Here my code for sending from the client's end: void ClientSock::OnConnect(int nErrorCode) { // TODO: Add your specialized code here and/or call the base class if(nErrorCode) { AfxMessageBox(_T("Connection Failure.")); Close(); } else { time_t clock; time(&clock); char min[30] = {0}; char s = ctime_s(min,sizeof(min),&clock); char text[100] = {0}; char user[10] = {"UserName"}; int n = m_pDlg->GetDlgItemText(ID_REQUEST,text, 100); Send(text,n); Send(user,sizeof(user)); Send(min,sizeof(min)); //m_pDlg->SetDlgItemText(ID_REQUEST,min); AfxMessageBox(_T(min)); } } and heres how im printing at the Server's console: SOCKET client; char text[100] = {0}; char user[10] = {0}; char min[30] = {0}; int n,m; //(here the server waits for the client and accepts connection requests) client = accept(server, NULL, NULL); //(receiving text from the client) n = recv(client, text, 99, 0); recv(client, user, 9, 0); m = recv(client, min, 29, 0); if(n > 0 && m > 0) { printf("%s:: %s:%s\n",min,user,text); } else printf("ERROR:Communication Failure.\n");
A tcp connection should be treated as a stream of bytes. You're treating it as if it was a stream of objects with type information. After your 3 Send's, the bytes that have been transferred would be e.g. ABC\0UserName\0\0Time\0 - A total of 19 bytes. Then you read 99 bytes, and get all of the data stored into "text", with nothing left in the stream for your next reads. You'll need to either send the length of the text before the text itself, or you'll need to read "data" on the receiving end and scan for e.g. a 0-terminator to extract the 3 logical elements of the stream.
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.