Related
My current approach doesn't even produce the correct encrypted data as checked against golang's aes implementation. It also doesn't decrypt back to the original plaintext, but that's expected if the encryption step isn't working correctly. My best guess is that I'm misusing the api somehow. This is a self-contained example and can run as is.
#include <mbedtls/aes.h>
#include <vector>
void LogVec(const std::vector<uint8_t>& bin)
{
printf("(size: %i) ", bin.size());
printf("{");
for (auto& b : bin)
{
printf("%#02x, ", b);
}
printf("}\n");
}
mbedtls_aes_context AesContext;
std::vector<uint8_t> EncryptAes(std::vector<uint8_t>& iv, std::vector<uint8_t>& data)
{
std::vector<uint8_t> ivCpy(iv);
uint8_t padByte = 16 - (data.size() % 16);
for (int i = 0; i < padByte; i++)
data.push_back(padByte);
std::vector<uint8_t> ret(data.size());
mbedtls_aes_crypt_cbc(&AesContext, MBEDTLS_AES_ENCRYPT, data.size(), ivCpy.data(), data.data(), ret.data());
return ret;
}
std::vector<uint8_t> DecryptAes(const std::vector<uint8_t>& iv, std::vector<uint8_t>& data)
{
std::vector<uint8_t> ivCpy(iv);
std::vector<uint8_t> ret(data.size());
mbedtls_aes_crypt_cbc(&AesContext, MBEDTLS_AES_DECRYPT, data.size(), ivCpy.data(), data.data(), ret.data());
ret.resize(ret.size() - ret[ret.size() - 1]);
return ret;
}
int main()
{
mbedtls_aes_init(&AesContext);
std::vector<uint8_t> data = { 0x3b, 0xb1, 0x99, 0x3, 0x67, 0xf3, 0x2e, 0x1f, 0x00, 0x67, 0x38, 0xc9, 0x53, 0x92, 0xa4 };
std::vector<uint8_t> key = { 0x15, 0x1, 0xc0, 0xd0, 0xe4, 0xfd, 0xdf, 0xd7, 0x7a, 0x65, 0xf1, 0x2f, 0x45, 0x61, 0xb,
0x59, 0xd9, 0xa, 0x9c, 0x61, 0xc, 0x4, 0x76, 0xdb, 0xb, 0xbe, 0x9e, 0xe4, 0x7f, 0x8d, 0xe1, 0x46 };
std::vector<uint8_t> iv = { 0xa2, 0x78, 0xc9, 0xa4, 0xd8, 0x34, 0x88, 0x9b, 0x28, 0xdc, 0xb9, 0xe2, 0xc0, 0x58, 0x8c, 0xbc };
mbedtls_aes_setkey_enc(&AesContext, key.data(), 256);
mbedtls_aes_setkey_dec(&AesContext, key.data(), 256);
std::vector<uint8_t> dataEnc = EncryptAes(iv, data);
printf("Encrypted data: ");
LogVec(dataEnc);
//std::vector<uint8_t> dataDec = DecryptAes(iv, dataEnc);
//printf("Decrypted data: ");
//LogVec(dataDec);
getchar();
return 1;
}
Output:
Encrypted data: (size: 16) {0x5d, 0x1c, 0x9, 0x2e, 0x92, 0x8e, 0x24, 0x43, 0xfa, 0xaf, 0xb3, 0xf5, 0x37, 0x8, 0x99, 0x93, }
Expected output from using the same key, iv, data in golang:
Encrypted: 34730cba3543e5facf4b94ba9dc8a275
Before calling mbedtls_aes_crypt_cbc to encrypt you should call mbedtls_aes_setkey_enc and before calling mbedtls_aes_crypt_cbc to decrypt you should call mbedtls_aes_setkey_dec. When both are called at initialization like in your code, the latter call to setkey_dec will overwrite important data in the context structure set by setkey_enc required for encryption.
I am trying to use an arduino to encrypt data as AES128 and then decrypt it. I am also experimenting with AES192 and AES256 but first I'd like to get it to work with AES128. I am using the Cyptography Library and I am struggling to figure out what is happening here. In the code below one may observe that a testVector has a name to identify it, a unique key, plain text, and cipher text. When I tried modifying the ".plaintext" in the array it causes the encryption and thus decryption to fail. My goal is to encrypt "My Message" and then decrypt it afterwords.
Please see my code below:
#include <Crypto.h>
#include <AES.h>
#include <string.h>
struct TestVector
{
const char *name;
byte key[32];
byte plaintext[16];
byte ciphertext[16];
};
// Define the ECB test vectors from the FIPS specification.
static TestVector const testVectorAES128 = {
.name = "AES-128-ECB",
.key = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
.plaintext = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
.ciphertext = {0x69, 0xC4, 0xE0, 0xD8, 0x6A, 0x7B, 0x04, 0x30,
0xD8, 0xCD, 0xB7, 0x80, 0x70, 0xB4, 0xC5, 0x5A}
};
static TestVector const testVectorAES192 = {
.name = "AES-192-ECB",
.key = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17},
.plaintext = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
.ciphertext = {0xDD, 0xA9, 0x7C, 0xA4, 0x86, 0x4C, 0xDF, 0xE0,
0x6E, 0xAF, 0x70, 0xA0, 0xEC, 0x0D, 0x71, 0x91}
};
static TestVector const testVectorAES256 = {
.name = "AES-256-ECB",
.key = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F},
.plaintext = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
.ciphertext = {0x8E, 0xA2, 0xB7, 0xCA, 0x51, 0x67, 0x45, 0xBF,
0xEA, 0xFC, 0x49, 0x90, 0x4B, 0x49, 0x60, 0x89}
};
AES128 aes128;
AES192 aes192;
AES256 aes256;
byte buffer[16];
void testCipher(BlockCipher *cipher, const struct TestVector *test)
{
crypto_feed_watchdog();
Serial.print(test->name);
Serial.print(" Encryption ... ");
cipher->setKey(test->key, cipher->keySize());
cipher->encryptBlock(buffer, test->plaintext);
if (memcmp(buffer, test->ciphertext, 16) == 0){
Serial.println("Passed");
String myString = String((char*)buffer);
Serial.println(myString);
}
else
Serial.println("Failed");
Serial.print(test->name);
Serial.print(" Decryption ... ");
cipher->decryptBlock(buffer, test->ciphertext);
if (memcmp(buffer, test->plaintext, 16) == 0){
Serial.println("Passed");
String myString2 = String((char*)buffer);
Serial.println(myString2);
}
else
Serial.println("Failed");
}
void perfCipher(BlockCipher *cipher, const struct TestVector *test)
{
unsigned long start;
unsigned long elapsed;
int count;
crypto_feed_watchdog();
Serial.print(test->name);
Serial.print(" Set Key ... ");
start = micros();
for (count = 0; count < 10000; ++count) {
cipher->setKey(test->key, cipher->keySize());
}
elapsed = micros() - start;
Serial.print(elapsed / 10000.0);
Serial.print("us per operation, ");
Serial.print((10000.0 * 1000000.0) / elapsed);
Serial.println(" per second");
Serial.print(test->name);
Serial.print(" Encrypt ... ");
start = micros();
for (count = 0; count < 5000; ++count) {
cipher->encryptBlock(buffer, buffer);
}
elapsed = micros() - start;
Serial.print(elapsed / (5000.0 * 16.0));
Serial.print("us per byte, ");
Serial.print((16.0 * 5000.0 * 1000000.0) / elapsed);
Serial.println(" bytes per second");
Serial.print(test->name);
Serial.print(" Decrypt ... ");
start = micros();
for (count = 0; count < 5000; ++count) {
cipher->decryptBlock(buffer, buffer);
}
elapsed = micros() - start;
Serial.print(elapsed / (5000.0 * 16.0));
Serial.print("us per byte, ");
Serial.print((16.0 * 5000.0 * 1000000.0) / elapsed);
Serial.println(" bytes per second");
Serial.println();
}
void setup()
{
Serial.begin(9600);
Serial.println();
Serial.println("State Sizes:");
Serial.print("AES128 ... ");
Serial.println(sizeof(AES128));
Serial.print("AES192 ... ");
Serial.println(sizeof(AES192));
Serial.print("AES256 ... ");
Serial.println(sizeof(AES256));
Serial.println();
Serial.println("Test Vectors:");
testCipher(&aes128, &testVectorAES128);
testCipher(&aes192, &testVectorAES192);
testCipher(&aes256, &testVectorAES256);
Serial.println();
Serial.println("Performance Tests:");
perfCipher(&aes128, &testVectorAES128);
perfCipher(&aes192, &testVectorAES192);
perfCipher(&aes256, &testVectorAES256);
}
void loop()
{
}
Here is some information on the library:
https://rweather.github.io/arduinolibs/classBlockCipher.html#ac3ba2450222aa1ea804ae4881ab6440c
I want to ask that how can I store hex values from a string into an integer array.
e.g coverting
String sbox_str= "0x65, 0xea, 0xaf, 0x37, 0xff, 0x3b, 0xc2, 0xd0";
into
uint8_t sbox[8]={0x65, 0xea, 0xaf, 0x37, 0xff, 0x3b, 0xc2, 0xd0};
I will really appreciate if you guide me about how can i do the same thing in QT Creator.
Easy way using QString:
std::string sbox_str= "0x65, 0xea, 0xaf, 0x37, 0xff, 0x3b, 0xc2, 0xd0";
uint8_t sbox[8];
int i = 0;
for( const auto &item: QString(sbox_str.data()).split(", ")) {
if(i == sizeof (sbox)) break; // do something
sbox[i] = item.toInt(nullptr, 16);
++i;
}
I have a C++ compile-at-run-time script written for a VxWorks derived PowerPC platform, which calculates checksums for files on the embedded OS. It uses a pair of lookup tables to compute the checksum (see my code below).
I'm trying to port this script to use on Windows, because the platform dictates that I must hardcode a new script for every single file I wish to calculate the checksum for, and with what I'm trying to do that will take many hours. I need to change a bunch of files on the platform file system and provide their checksums to the system or it will refuse to load them.
I've got the code running, having changed all of the UI/output and file input stuff to work with Windows, but I'm getting the wrong checksum. On my test file, I should be getting 404f and I'm actually getting 5fb4.
Having done some research I believe I may need to convert or regenerate the lookup tables, but I have no idea how to go about this and would be grateful for any input.
Thanks!
// rt6_crc_checker.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#define TRUE 1
#define FALSE 0
#define SKIP 1
#include <windows.h>
#include <iostream>
#include <cstdlib>
#include <sys/stat.h>
using namespace std;
int PL_FileExists( char *p_pPath );
void PL_itoa10( int i , char* s );
void PL_itoa16( int i , char* s );
int change_endian(int num){
int byte0, byte1, byte2, byte3;
byte0 = (num & 0x000000FF) >> 0 ;
byte1 = (num & 0x0000FF00) >> 8 ;
byte2 = (num & 0x00FF0000) >> 16 ;
byte3 = (num & 0xFF000000) >> 24 ;
return((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | (byte3 << 0));
}
/*** MAIN ***/
int main ( int argc, char **argv )
{
char carlu;
char s_nb[16];
char s_i[16];
char CRC_FIC[16];
char CRC_INF[16];
char MessPL[256];
int nb;
int size_FIC;
int size_INF;
int answ;
int CRC;
int c1;
int c2;
int rg;
int i;
int j;
FILE *l_fileIN;
FILE *l_fileOUT;
char l_line[20];
int table_h[]=
{
0x00, 0xdf, 0xbe, 0x61, 0x7c, 0xa3, 0xc2, 0x1d, 0xd3, 0x0c, 0x6d, 0xb2, 0xaf, 0x70, 0x11, 0xce,
0x8d, 0x52, 0x33, 0xec, 0xf1, 0x2e, 0x4f, 0x90, 0x5e, 0x81, 0xe0, 0x3f, 0x22, 0xfd, 0x9c, 0x43,
0x1a, 0xc5, 0xa4, 0x7b, 0x66, 0xb9, 0xd8, 0x07, 0xc9, 0x16, 0x77, 0xa8, 0xb5, 0x6a, 0x0b, 0xd4,
0x97, 0x48, 0x29, 0xf6, 0xeb, 0x34, 0x55, 0x8a, 0x44, 0x9b, 0xfa, 0x25, 0x38, 0xe7, 0x86, 0x59,
0x1f, 0xc0, 0xa1, 0x7e, 0x63, 0xbc, 0xdd, 0x02, 0xcc, 0x13, 0x72, 0xad, 0xb0, 0x6f, 0x0e, 0xd1,
0x92, 0x4d, 0x2c, 0xf3, 0xee, 0x31, 0x50, 0x8f, 0x41, 0x9e, 0xff, 0x20, 0x3d, 0xe2, 0x83, 0x5c,
0x05, 0xda, 0xbb, 0x64, 0x79, 0xa6, 0xc7, 0x18, 0xd6, 0x09, 0x68, 0xb7, 0xaa, 0x75, 0x14, 0xcb,
0x88, 0x57, 0x36, 0xe9, 0xf4, 0x2b, 0x4a, 0x95, 0x5b, 0x84, 0xe5, 0x3a, 0x27, 0xf8, 0x99, 0x46,
0x15, 0xca, 0xab, 0x74, 0x69, 0xb6, 0xd7, 0x08, 0xc6, 0x19, 0x78, 0xa7, 0xba, 0x65, 0x04, 0xdb,
0x98, 0x47, 0x26, 0xf9, 0xe4, 0x3b, 0x5a, 0x85, 0x4b, 0x94, 0xf5, 0x2a, 0x37, 0xe8, 0x89, 0x56,
0x0f, 0xd0, 0xb1, 0x6e, 0x73, 0xac, 0xcd, 0x12, 0xdc, 0x03, 0x62, 0xbd, 0xa0, 0x7f, 0x1e, 0xc1,
0x82, 0x5d, 0x3c, 0xe3, 0xfe, 0x21, 0x40, 0x9f, 0x51, 0x8e, 0xef, 0x30, 0x2d, 0xf2, 0x93, 0x4c,
0x0a, 0xd5, 0xb4, 0x6b, 0x76, 0xa9, 0xc8, 0x17, 0xd9, 0x06, 0x67, 0xb8, 0xa5, 0x7a, 0x1b, 0xc4,
0x87, 0x58, 0x39, 0xe6, 0xfb, 0x24, 0x45, 0x9a, 0x54, 0x8b, 0xea, 0x35, 0x28, 0xf7, 0x96, 0x49,
0x10, 0xcf, 0xae, 0x71, 0x6c, 0xb3, 0xd2, 0x0d, 0xc3, 0x1c, 0x7d, 0xa2, 0xbf, 0x60, 0x01, 0xde,
0x9d, 0x42, 0x23, 0xfc, 0xe1, 0x3e, 0x5f, 0x80, 0x4e, 0x91, 0xf0, 0x2f, 0x32, 0xed, 0x8c, 0x53
};
int table_l[]=
{
0x00, 0x2b, 0x57, 0x7c, 0xaf, 0x84, 0xf8, 0xd3, 0xf6, 0xdd, 0xa1, 0x8a, 0x59, 0x72, 0x0e, 0x25,
0x45, 0x6e, 0x12, 0x39, 0xea, 0xc1, 0xbd, 0x96, 0xb3, 0x98, 0xe4, 0xcf, 0x1c, 0x37, 0x4b, 0x60,
0x8b, 0xa0, 0xdc, 0xf7, 0x24, 0x0f, 0x73, 0x58, 0x7d, 0x56, 0x2a, 0x01, 0xd2, 0xf9, 0x85, 0xae,
0xce, 0xe5, 0x99, 0xb2, 0x61, 0x4a, 0x36, 0x1d, 0x38, 0x13, 0x6f, 0x44, 0x97, 0xbc, 0xc0, 0xeb,
0xbe, 0x95, 0xe9, 0xc2, 0x11, 0x3a, 0x46, 0x6d, 0x48, 0x63, 0x1f, 0x34, 0xe7, 0xcc, 0xb0, 0x9b,
0xfb, 0xd0, 0xac, 0x87, 0x54, 0x7f, 0x03, 0x28, 0x0d, 0x26, 0x5a, 0x71, 0xa2, 0x89, 0xf5, 0xde,
0x35, 0x1e, 0x62, 0x49, 0x9a, 0xb1, 0xcd, 0xe6, 0xc3, 0xe8, 0x94, 0xbf, 0x6c, 0x47, 0x3b, 0x10,
0x70, 0x5b, 0x27, 0x0c, 0xdf, 0xf4, 0x88, 0xa3, 0x86, 0xad, 0xd1, 0xfa, 0x29, 0x02, 0x7e, 0x55,
0xd4, 0xff, 0x83, 0xa8, 0x7b, 0x50, 0x2c, 0x07, 0x22, 0x09, 0x75, 0x5e, 0x8d, 0xa6, 0xda, 0xf1,
0x91, 0xba, 0xc6, 0xed, 0x3e, 0x15, 0x69, 0x42, 0x67, 0x4c, 0x30, 0x1b, 0xc8, 0xe3, 0x9f, 0xb4,
0x5f, 0x74, 0x08, 0x23, 0xf0, 0xdb, 0xa7, 0x8c, 0xa9, 0x82, 0xfe, 0xd5, 0x06, 0x2d, 0x51, 0x7a,
0x1a, 0x31, 0x4d, 0x66, 0xb5, 0x9e, 0xe2, 0xc9, 0xec, 0xc7, 0xbb, 0x90, 0x43, 0x68, 0x14, 0x3f,
0x6a, 0x41, 0x3d, 0x16, 0xc5, 0xee, 0x92, 0xb9, 0x9c, 0xb7, 0xcb, 0xe0, 0x33, 0x18, 0x64, 0x4f,
0x2f, 0x04, 0x78, 0x53, 0x80, 0xab, 0xd7, 0xfc, 0xd9, 0xf2, 0x8e, 0xa5, 0x76, 0x5d, 0x21, 0x0a,
0xe1, 0xca, 0xb6, 0x9d, 0x4e, 0x65, 0x19, 0x32, 0x17, 0x3c, 0x40, 0x6b, 0xb8, 0x93, 0xef, 0xc4,
0xa4, 0x8f, 0xf3, 0xd8, 0x0b, 0x20, 0x5c, 0x77, 0x52, 0x79, 0x05, 0x2e, 0xfd, 0xd6, 0xaa, 0x81
};
i = 0;
j = 0;
size_FIC = 0;
size_INF = 0;
c1 = 0;
c2 = 0;
rg = 0;
CRC = 0;
if ( PL_FileExists( "crc_check.ext" ) != TRUE )
{
cout << "input MISSING !";
return 0;
}
struct stat stat_buf;
int rc = stat("crc_check.ext", &stat_buf);
size_FIC = rc == 0 ? stat_buf.st_size : -1;
cout << "input found " << size_FIC << endl;
PL_itoa10 ( size_FIC , s_nb );
strcpy ( MessPL , "Size : " );
strcat ( MessPL , s_nb );
strcat ( MessPL , " K..." );
cout << MessPL << endl;
// Calculate CRC...
l_fileIN = fopen ( "crc_check.ext", "r");
if ( NULL == l_fileIN )
{
cout << "Error opening" << endl;
}
else
{
cout << "Ok will calculate CRC bear with" << endl;
c1 = 0;
c2 = 0;
rg = 0;
for ( i = 0 ; i < size_FIC ; i++ )
{
fseek ( l_fileIN , i , 0 );
if ( i % 4000 == 0 )
{
j = ( 100 * i ) / size_FIC ;
}
if ( NULL == fgets ( l_line , 2 , l_fileIN ) )
{
PL_itoa10 ( i , s_i );
strcpy ( MessPL , "READ Error ! " );
strcat ( MessPL , s_i );
cout << MessPL << endl;
i = size_FIC;
}
else
{
nb = (int) l_line[0];
if ( nb < 0 )
nb += 256;
rg = c1 ^ nb;
c1 = c2 ^ table_h[rg];
c2 = table_l[rg];
}
}
fclose(l_fileIN);
}
PL_itoa16 ( c1 , s_nb );
if ( c1 < 16 )
{
strcpy ( CRC_FIC , "0" );
strcat ( CRC_FIC , s_nb );
}
else
strcpy ( CRC_FIC , s_nb );
PL_itoa16 ( c2 , s_nb );
if ( c2 < 16 )
{
strcat ( CRC_FIC , "0" );
strcat ( CRC_FIC , s_nb );
}
else
strcat ( CRC_FIC , s_nb );
cout << CRC_FIC << endl;
}
void PL_itoa10 (int i , char* s)
{
char l_s[16];
int n = 0 , m = 0;
if ( i < 0 )
{
s[m++] = '-';
i=-i;
}
do
{
l_s[n++] = (char)('0'+(i%10));
i /= 10;
}
while ( i );
for ( --n ; n>=0 ; n--,m++ )
s[m] = l_s[n];
s[m]=0;
}
void PL_itoa16 (int i , char* s)
{
char l_s[16];
int n = 0 , m = 0;
if ( i < 0 )
{
s[m++] = '-';
i=-i;
}
do
{
if ( i%16 < 10 )
l_s[n++] = (char)('0'+(i%16));
else
l_s[n++] = (char)('a'+(i%16)-10);
i /= 16;
}
while ( i );
for ( --n ; n>=0 ; n--,m++ )
s[m] = l_s[n];
s[m]=0;
}
int PL_FileExists ( char *p_pPath )
{
FILE* l_pFich = NULL;
if (NULL == (l_pFich = fopen (p_pPath, "r")))
{
return (FALSE);
}
else
{
fclose (l_pFich);
return (TRUE);
}
}
This code is labeled as CCITT Standard CRC16 non-reflected CRC using the polynomial 0x1021. Would produced that type of table.
Try this:
static unsigned short crctable[256];
void make_crc_table( void )
{
int i, j;
unsigned long poly, c;
static const byte p[] = {0,5,12};
poly = 0L;
for ( i = 0; i < sizeof( p ) / sizeof( byte ); i++ )
{
poly |= 1L << p[i];
}
for ( i = 0; i < 256; i++ )
{
c = i << 8;
for ( j = 0; j < 8; j++ )
{
c = ( c & 0x8000 ) ? poly ^ ( c << 1 ) : ( c << 1 );
}
crctable[i] = (unsigned short) c;
}
}
I have a telemetry stream that is passed through a hardware CRC generator appending the CRC to the end of each telemetry frame. Now I am trying to make something to verify the hardware generated CRC. I have old legacy code (see below) that computes the correct CRC (verified multiple times). However it is slow since each telemetry frame is 300+ bytes and there can be upwards of 10,000,000+ frames to process.
After some research I found some literature pointing me to a table driven approach. The legacy method uses a Poly of 0x8005, reverses the bit order of each byte before processing, and initializes the CRC to zero. However, after building tables for that poly with reversed and non-reversed input and just trying to work through even the first byte of data (0x10) I can not get anything to match what the legacy method is generating.
Inside the calcCRC16 function (below) the existing method checks the LSB where others seem to check the MSB ... and the bit shifts are to the right where other examples I have seen are to the left. I am getting lost in why this is especially since the bit order is swapped before passing it to this function. I have tried on-line calculators & manually doing the look-ups in tables switching the poly from 8005 to A001(reversed), normal and reversed input bytes, and every combination I can think of but can't get any table approach to match the legacy code which I know to be correct for our hardware implementation.
Can anyone help me out if I am missing something obvious? How would you go about creating a table based approach to create the same output? I am a novice at C++ and not really familiar with CRC generation and could be overlooking something fundamental. Sample code and output which was verified against the hardware CRC follows:
Sample Code: I just hard coded a few bytes out of a know telemetry stream as an example
/** ********************************************************************************
* TEST CRC METHOD
*******************************************************************************/
#include <iostream>
using namespace std;
unsigned char swapBits(unsigned char d);
void calcCRC16(unsigned int *CRCVal, unsigned char value);
/** **************************************************************************
* #function main
* TEST CRC METHOd
*******************************************************************************/
int main(int argc, char* argv[])
{
short dataLength = 5;
unsigned int givenCrc;
unsigned int calcCrc;
unsigned char byte[] = {0x10,0xbb,0x42,0x4d,0xfd};
/* Init CRC. */
calcCrc = 0;
cout << "Inital CRC = " << hex << calcCrc << "\n";
/* Read frame data. */
for (int i = 0; i < dataLength; i++)
{
cout << "byte = " << hex << static_cast<int16_t>(byte[i]) << " ";
calcCRC16(&calcCrc, swapBits(byte[i]));
cout << "calcCRC = " << hex << calcCrc << "\n";
}
}
/** ********************************************************************
* #function swapBits
* Swaps the bits so they match the order sent to CRC Gen Hardware
************************************************************************/
unsigned char swapBits(unsigned char d)
{
unsigned char t = 0;
int i = 0;
int n = 0x80;
for(i=0x01; i<0x100; i=i<<1)
{
if (d & i)
{
t|=n;
}
n=n>>1;
}
return t;
}
/** ********************************************************************
* #function calcCRC16
* WORKING METHOD VERIFIED AGAINST CRC HARDWARE
************************************************************************/
void calcCRC16(unsigned int *CRCVal, unsigned char value)
{
unsigned char lsb;
unsigned char bcnt;
for (bcnt=0 ; bcnt<8 ; bcnt++)
{
lsb = (value ^ *CRCVal) & 0x01;
*CRCVal >>= 1;
value >>= 1;
if (lsb != 0)
{
*CRCVal ^= 0x8005;
}
}
}
Output:
Inital CRC = 0
byte = 10 calcCRC = b804
byte = bb calcCRC = 1fb8
byte = 42 calcCRC = 461d
byte = 4d calcCRC = 3d47
byte = fd calcCRC = 683e
rev16(crc16(0, buf, len)) will give you the CRCs listed.
#include <stdio.h>
static unsigned short crc16_table[] = {
0x0000, 0xa001, 0xe003, 0x4002, 0x6007, 0xc006, 0x8004, 0x2005,
0xc00e, 0x600f, 0x200d, 0x800c, 0xa009, 0x0008, 0x400a, 0xe00b,
0x201d, 0x801c, 0xc01e, 0x601f, 0x401a, 0xe01b, 0xa019, 0x0018,
0xe013, 0x4012, 0x0010, 0xa011, 0x8014, 0x2015, 0x6017, 0xc016,
0x403a, 0xe03b, 0xa039, 0x0038, 0x203d, 0x803c, 0xc03e, 0x603f,
0x8034, 0x2035, 0x6037, 0xc036, 0xe033, 0x4032, 0x0030, 0xa031,
0x6027, 0xc026, 0x8024, 0x2025, 0x0020, 0xa021, 0xe023, 0x4022,
0xa029, 0x0028, 0x402a, 0xe02b, 0xc02e, 0x602f, 0x202d, 0x802c,
0x8074, 0x2075, 0x6077, 0xc076, 0xe073, 0x4072, 0x0070, 0xa071,
0x407a, 0xe07b, 0xa079, 0x0078, 0x207d, 0x807c, 0xc07e, 0x607f,
0xa069, 0x0068, 0x406a, 0xe06b, 0xc06e, 0x606f, 0x206d, 0x806c,
0x6067, 0xc066, 0x8064, 0x2065, 0x0060, 0xa061, 0xe063, 0x4062,
0xc04e, 0x604f, 0x204d, 0x804c, 0xa049, 0x0048, 0x404a, 0xe04b,
0x0040, 0xa041, 0xe043, 0x4042, 0x6047, 0xc046, 0x8044, 0x2045,
0xe053, 0x4052, 0x0050, 0xa051, 0x8054, 0x2055, 0x6057, 0xc056,
0x205d, 0x805c, 0xc05e, 0x605f, 0x405a, 0xe05b, 0xa059, 0x0058,
0xa0e9, 0x00e8, 0x40ea, 0xe0eb, 0xc0ee, 0x60ef, 0x20ed, 0x80ec,
0x60e7, 0xc0e6, 0x80e4, 0x20e5, 0x00e0, 0xa0e1, 0xe0e3, 0x40e2,
0x80f4, 0x20f5, 0x60f7, 0xc0f6, 0xe0f3, 0x40f2, 0x00f0, 0xa0f1,
0x40fa, 0xe0fb, 0xa0f9, 0x00f8, 0x20fd, 0x80fc, 0xc0fe, 0x60ff,
0xe0d3, 0x40d2, 0x00d0, 0xa0d1, 0x80d4, 0x20d5, 0x60d7, 0xc0d6,
0x20dd, 0x80dc, 0xc0de, 0x60df, 0x40da, 0xe0db, 0xa0d9, 0x00d8,
0xc0ce, 0x60cf, 0x20cd, 0x80cc, 0xa0c9, 0x00c8, 0x40ca, 0xe0cb,
0x00c0, 0xa0c1, 0xe0c3, 0x40c2, 0x60c7, 0xc0c6, 0x80c4, 0x20c5,
0x209d, 0x809c, 0xc09e, 0x609f, 0x409a, 0xe09b, 0xa099, 0x0098,
0xe093, 0x4092, 0x0090, 0xa091, 0x8094, 0x2095, 0x6097, 0xc096,
0x0080, 0xa081, 0xe083, 0x4082, 0x6087, 0xc086, 0x8084, 0x2085,
0xc08e, 0x608f, 0x208d, 0x808c, 0xa089, 0x0088, 0x408a, 0xe08b,
0x60a7, 0xc0a6, 0x80a4, 0x20a5, 0x00a0, 0xa0a1, 0xe0a3, 0x40a2,
0xa0a9, 0x00a8, 0x40aa, 0xe0ab, 0xc0ae, 0x60af, 0x20ad, 0x80ac,
0x40ba, 0xe0bb, 0xa0b9, 0x00b8, 0x20bd, 0x80bc, 0xc0be, 0x60bf,
0x80b4, 0x20b5, 0x60b7, 0xc0b6, 0xe0b3, 0x40b2, 0x00b0, 0xa0b1};
static unsigned char rev_table[] = {
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0,
0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4,
0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc,
0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca,
0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6,
0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1,
0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9,
0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd,
0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3,
0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7,
0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf,
0x3f, 0xbf, 0x7f, 0xff};
unsigned crc16(unsigned crc, unsigned char *buf, int len)
{
while (len--) {
crc ^= *buf++ << 8;
crc = (crc << 8) ^ crc16_table[(crc >> 8) & 0xff];
}
return crc & 0xffff;
}
inline unsigned rev16(unsigned val)
{
return (rev_table[val & 0xff] << 8) | rev_table[(val >> 8) & 0xff];
}