The following is a list of hex data and the float numbers it represents:
e77ed8f8201a5440 = 78.4083
0000000000005540 = 82
4c541773e2185040 = 62.3888
0000000000005640 = 86
The following Perl code uses pack/unpack to gets the conversion almost right (out by exactly 2):
use strict;
use warnings;
while (<DATA>)
{
chomp;
my $dat = $_;
my $hval = pack "H*", $dat;
my $fval = unpack "F", $hval;
print "$dat .. $fval \n";
}
__DATA__
e77ed8f8201a5440
0000000000005540
4c541773e2185040
0000000000005640
Output:
e77ed8f8201a5440 .. 80.408262454435
0000000000005540 .. 84
4c541773e2185040 .. 64.3888213851762
0000000000005640 .. 88
What is the Qt/C equivalent of this pack/unpack, or what is the algorithm it is use to "convert" the hex to float so I can that up instead?
What is the Qt/C equivalent of this pack/unpack,
#include <QString>
#include <QByteArray>
#include <algorithm>
#include <cstring>
...
QString value="e77ed8f8201a5440";
// convert the hex string to an array of bytes
QByteArray arr=QByteArray::fromHex(value);
// reverse if necessary
#if Q_BYTE_ORDER==Q_BIG_ENDIAN
std::reverse(arr.begin(), arr.end());
#endif
// if everything went right, copy the bytes in a double
if(arr.size()==sizeof(double))
{
double out;
std::memcpy((void *)&out, (void *)arr.data(), sizeof(double));
// ...
}
Maybe you could also get away with QtEndian (instead of conditionally calling std::reverse over arr), but it's not clear if those functions can be called on anything but integral types.
or what is the algorithm it is use to "convert" the hex to float so I can that up instead?
The data you have is just the dump of the raw content of a little-endian IEEE-754 double; the "algorithm" is simply decoding the hexadecimal to the bytes it represents and copying them to a double variable (reversing the byte order if we are on a big-endian machine).
pack 'H*' is the conversion from hex character pairs to the corresponding bytes.
unpack 'F' is a cast to a double. This can be done using memcpy (to avoid alignment issues), as shown below:
#include <stdio.h>
#include <string.h>
int main() {
char bytes[] = { 0xE7, 0x7e, 0xd8, 0xf8, 0x20, 0x1a, 0x54, 0x40 };
double d;
memcpy(&d, bytes, sizeof(bytes));
printf("%lf\n", d);
return 0;
}
Output:
$ gcc -o a a.c && a
80.408262
Note that this will fail on big-endian machines. You'll have to reverse the bytes before copying them on those machines.
Related
Here I have a simple, exemplary code in MS Visual Studio:
#include<string>
#include<iostream>
using namespace std;
int main()
{
cout << static_cast<int>('ą') << endl; // -71
return 0;
}
The question is why this cout prints out -71 as if MS Visual Studio was using Windows 1250 if as far as I know it uses UTF-8?
Your source file is saved in Windows-1250, not UTF-8, so the byte stored between the two single quotes is 0xB9 (see Windows-1250 table). 0xB9 taken as a signed 8-bit value is -71.
Save your file in UTF-8 encoding and you'll get a different answer. I get 50309 which is 0xc485. since UTF-8 is a multibyte encoding, it would be better to use modern C++ to output the bytes of an explicit UTF-8 string, use UTF-8 source encoding, and tell the compiler explicitly that the source encoding it UTF-8:
test.c - saved in UTF-8 encoding and compiled with /utf-8 switch in MSVS:
#include<string>
#include<iostream>
#include <cstdint>
using namespace std;
int main()
{
string s {u8"ą马"};
for(auto c : s)
cout << hex << static_cast<int>(static_cast<uint8_t>(c)) << endl;
return 0;
}
Output:
c4
85
e9
a9
ac
Note C4 85 is the correct UTF-8 bytes for ą and E9 A9 AC are correct for Chinese 马 (horse).
I've been experimenting with writing to an external EEPROM using SPI and I've had mixed success. The data does get shifted out but in an opposite manner. The EEPROM requires a start bit and then an opcode which is essentially a 2-bit code for read, write and erase. Essentially the start bit and the opcode are combined into one byte. I'm creating a 32-bit unsigned int and then bit-shifting the values into it. When I transmit these I see that the actual data is being seen first and then the SB+opcode and then the memory address. How do I reverse this to see the opcode first then the memory address and then the actual data. As seen in the image below, the data is BCDE, SB+opcode is 07 and the memory address is 3F. The correct sequence should be 07, 3F and then BCDE (I think!).
Here is the code:
uint8_t mem_addr = 0x3F;
uint16_t data = 0xBCDE;
uint32_t write_package = (ERASE << 24 | mem_addr << 16 | data);
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_SPI_Transmit(&hspi1, &write_package, 2, HAL_MAX_DELAY);
HAL_Delay(10);
}
/* USER CODE END 3 */
It looks like as your SPI interface is set up to process 16 bit halfwords at a time. Therefore it would make sense to break up the data to be sent into 16 bit halfwords too. That would take care of the ordering.
uint8_t mem_addr = 0x3F;
uint16_t data = 0xBCDE;
uint16_t write_package[2] = {
(ERASE << 8) | mem_addr,
data
};
HAL_SPI_Transmit(&hspi1, (uint8_t *)write_package, 2, HAL_MAX_DELAY);
EDIT
Added an explicit cast. As noted in the comments, without the explicit cast it wouldn't compile as C++ code, and cause some warnings as C code.
You're packing your information into a 32 bit integer, on line 3 of your code you have the decision about which bits of data are placed where in the word. To change the order you can replace the line with:
uint32_t write_package = ((data << 16) | (mem_addr << 8) | (ERASE));
That is shifting data 16 bits left into the most significant 16 bits of the word, shifting mem_addr up by 8 bits and or-ing it in, and then adding ERASE in the least significant bits.
Your problem is the Endianness.
By default the STM32 uses little edian so the lowest byte of the uint32_t is stored at the first adrress.
If I'm right this is the declaration if the transmit function you are using:
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
It requires a pointer to uint8_t as data (and not a uint32_t) so you should get at least a warning if you compile your code.
If you want to write code that is independent of the used endianess, you should store your data into an array instead of one "big" variable.
uint8_t write_package[4];
write_package[0] = ERASE;
write_package[1] = mem_addr;
write_package[2] = (data >> 8) & 0xFF;
write_package[3] = (data & 0xFF);
Im struggling with fatfs on stm32f4. With no problem i can mount, create file and write on it by : char my_data[]="hello world" and in windows file shows normally but when i try use code as loger :
float bmp180Pressure=1000.1;
char presur_1[6];//bufor znakow do konwersji
sprintf(presur_1,"%0.1f",bmp180Pressure);
char new_line[]="\n\r";
if(f_mount(&myFat, SDPath, 1)== FR_OK)
{
f_open(&myFile, "dane.txt", FA_READ|FA_WRITE);
f_lseek(&myFile, f_size(&myFile));//sets end of data
f_write(&myFile, presur_1, 6, &byteCount);
f_write(&myFile, new_line,4, &byteCount);
f_close(&myFile);
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_15);
}
When i was read from computer i have :top : notepad ++ buttom :windows notepad
There are at least two problems in your code:
The string for the number is too short. C strings are terminated with a null byte. So presur_1 needs to be at least 7 bytes long (6 for the number and 1 for the null byte). Since it's only 6 bytes long, sprintf will write beyond the allocated length and destroy some other data.
The string for the newline is initialized with a string of 2 characters (plus the null byte). However, you write 4 characters to the file. So in addition to the newline, a NUL character and a garbage byte will end up in the file.
The fixed code looks like this:
float bmp180Pressure = 1000.1;
char presur_1[20];//bufor znakow do konwersji
int presur_1_len = sprintf(presur_1,"%0.1f\n\r",bmp180Pressure);
if(f_mount(&myFat, SDPath, 1)== FR_OK)
{
f_open(&myFile, "dane.txt", FA_READ|FA_WRITE);
f_lseek(&myFile, f_size(&myFile));//sets end of data
f_write(&myFile, presur_1, presur_1_len, &byteCount);
f_close(&myFile);
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_15);
}
I'm creating SHA1 and CRC32 hash from plain text using Crypto++ Library as the following:
#include <cryptopp/filters.h>
#include <cryptopp/hex.h>
#include <cryptopp/sha.h>
#include <cryptopp/crc.h>
#include <string.h>
#include <iostream>
int main()
{
// Calculate SHA1
std::string data = "Hello World";
std::string base_encoded_string;
byte sha_hash[CryptoPP::SHA::DIGESTSIZE];
CryptoPP::SHA().CalculateDigest(sha_hash, (byte*)data.data(), data.size());
CryptoPP::StringSource ss1( std::string(sha_hash, sha_hash+CryptoPP::SHA::DIGESTSIZE), true,
new CryptoPP::HexEncoder( new CryptoPP::StringSink( base_encoded_string ) ));
std::cout << base_encoded_string << std::endl;
base_encoded_string.clear();
// Calculate CRC32
byte crc32_hash[CryptoPP::CRC32::DIGESTSIZE];
CryptoPP::CRC32().CalculateDigest(crc32_hash, (byte*)data.data(), data.size());
CryptoPP::StringSource ss2( std::string(crc32_hash, crc32_hash+CryptoPP::CRC32::DIGESTSIZE), true,
new CryptoPP::HexEncoder( new CryptoPP::StringSink( base_encoded_string ) ));
std::cout << base_encoded_string << std::endl;
base_encoded_string.clear();
}
The output I get is:
0A4D55A8D778E5022FAB701977C5D840BBC486D0
56B1174A
Press any key to continue . . .
And, out of these I confirmed that CRC32 is incorrect according to various online resources such as this one: http://www.fileformat.info/tool/hash.htm?text=Hello+World
I have no idea why because I'm creating CRC32 hash by following the same procedure as I followed for SHA1. Is there really different way or am I really doing something wrong in here?
byte crc32_hash[CryptoPP::CRC32::DIGESTSIZE];
I believe you have a bad endian interaction. Treat the CRC32 value is an integer, not a byte array.
So try this:
int32_t crc = (crc32_hash[0] << 0) | (crc32_hash[1] << 8) |
(crc32_hash[2] << 16) | (crc32_hash[3] << 24);
If crc32_hash is integer aligned, then you can:
int32_t crc = ntohl(*(int32_t*)crc32_hash);
Or, this might be easier:
int32_t crc32_hash;
CryptoPP::CRC32().CalculateDigest(&crc32_hash, (byte*)data.data(), data.size());
I might be wrong about int32_t, it might be uint32_t (I did not look at the standard).
I want to implement HMAC encryption algorithm for my iPhone application. Any sample code will really help. Also, please guide me with brief implementation of the same.
Use the Common Crypto functions. The documentation is in man pages, so you'll need to hunt for it a bit. They're in libSystem on iOS and Mac OS X, so no need to add another library or framework to your project. As you can see from the example below, the API is very similar to OpenSSL's.
If you are actually interested in encrypting, as opposed to authenticating data, Common Crypto has functions to perform AES and 3DES (and DES, but don't use it, it's far too weak for modern needs). Take a look at the CCCryptor man page for details.
The example below is equivalent to running openssl dgst -md5 -hmac secret < myfile.txt. Start by initializing the the CCHmacContext, and then call CCHmacUpdate as long as you have data to authenticate. When you've read all the bytes, call CCHmacFinal to get the HMAC into a buffer. I've provided a crude method to convert the HMAC bytes into printable hex.
#include <CommonCrypto/CommonHMAC.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
extern int errno;
int
main( int ac, char *av[] )
{
CCHmacContext ctx;
char *key = "secret";
char buf[ 8192 ];
unsigned char mac[ CC_MD5_DIGEST_LENGTH ];
char hexmac[ 2 * CC_MD5_DIGEST_LENGTH + 1 ];
char *p;
int fd;
int rr, i;
if ( ac != 2 ) {
fprintf( stderr, "usage: %s path\n", av[ 0 ] );
exit( 1 );
}
if (( fd = open( av[ 1 ], O_RDONLY )) < 0 ) {
fprintf( stderr, "open %s: %s\n", av[ 1 ], strerror( errno ));
exit( 2 );
}
CCHmacInit( &ctx, kCCHmacAlgMD5, key, strlen( key ));
while (( rr = read( fd, buf, sizeof( buf ))) > 0 ) {
CCHmacUpdate( &ctx, buf, rr );
}
if ( rr < 0 ) {
perror( "read" );
exit( 2 );
}
CCHmacFinal( &ctx, mac );
(void)close( fd );
p = hexmac;
for ( i = 0; i < CC_MD5_DIGEST_LENGTH; i++ ) {
snprintf( p, 3, "%02x", mac[ i ] );
p += 2;
}
printf( "%s\n", hexmac );
return( 0 );
}
HMAC is not an encryption mechanism, but an authentication digest. It uses an underlying message digest function such as SHA-1, SHA-256, MD5 etc, with a secret key to generate a code that can be used to authenticate data.
Generating an HMAC digest is extremely simple. Here is the description from RFC2104 (via Wikipedia)
Let:
H(·) be a cryptographic hash function (ie. SHA-1, SHA-256, MD5 etc)
K be a secret key padded to the right with extra zeros to the input block size of the hash function, or the hash of the original key if it's longer than that block size
m be the message to be authenticated
| denote concatenation
⊕ denote exclusive or (XOR)
opad be the outer padding (0x5c5c5c…5c5c, one-block-long hexadecimal constant)
ipad be the inner padding (0x363636…3636, one-block-long hexadecimal constant)
Then HMAC(K,m) is mathematically defined by:
HMAC(K,m) = H((K ⊕ opad) | H((K ⊕ ipad) | m)).
For the underlying digest function you can help yourself to one of the C implementations from OpenSSL. In fact it also has a C implementation of HMAC that you can probably just use as is.