CRC16 checksum calculation: which one is correct? - c++

Currently I'm working on Modbus protocol, which requires a CRC checksum. I implemented three functions, generating different results:
CRC16_table: implemented based on modbus manual above page 114, this's a look-up-table way, but I didn't verify the table provided in the manual.
CRC16_modbus: implemented based on modbus manual page 112, this's a naive way
CRC16_origin: implemented based on this article and have the same result with this calculator at least.
My code is as follow:
#include <iostream>
#include <iomanip>
using namespace std;
static unsigned char auchCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40
};
static char auchCRCLo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
0x40
};
unsigned short CRC16_table(char* message, int len)
{
unsigned char uchCRCHi = 0xFF;
unsigned char uchCRCLo = 0xFF;
unsigned uIndex;
while(len--)
{
uIndex = uchCRCHi ^ *message++;
uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];
uchCRCLo = auchCRCLo[uIndex];
}
return (((unsigned short)uchCRCHi << 8) | (unsigned short)uchCRCLo);
}
unsigned short CRC16_origin(char* message, int len)
{
const unsigned short generator = 0xA001;
unsigned short crc = 0;
for(int i = 0; i < len; ++i)
{
crc ^= (unsigned short)(message[i] << 8);
for(int b = 0; b < 8; ++b)
{
if((crc & 0x8000) != 0)
{
crc <<= 1;
crc ^= generator;
}
else
crc <<= 1;
}
}
return crc;
}
unsigned short CRC16_modbus(char* message, int len)
{
const unsigned short generator = 0xA001;
unsigned short crc = 0xFFFF;
for(int i = 0; i < len; ++i)
{
crc ^= (unsigned short)message[i];
for(int b = 0; b < 8; ++b)
{
if((crc & 1) != 0)
{
crc >>= 1;
crc ^= generator;
}
else
crc >>= 1;
}
}
return crc;
}
int main()
{
char message[] = {0x01, 0x06,0x00, 0x63, 0x04, 0x00};
int len = 6;
unsigned short temp1 = CRC16_table(message, len);
unsigned short temp2 = CRC16_origin(message, len);
unsigned short temp3 = CRC16_modbus(message, len);
cout<<hex<<temp1<<endl;
cout<<hex<<temp2<<endl;
cout<<hex<<temp3<<endl;
return 0;
}
Could anyone help me point out which one is correct? Based on what I read, I believe CRC16_origin is most likely right, but I'm still not sure because the other two are from an official manual; I'm stuck on this for almost a week, let me know if you have any advice, thanks!

Modbus uses an initial value of 0xffff.
Your third example uses an initial value of zero, poorly enforced in their illiterate example.
They aren't going to deliver the same results. Stick with the Modbus code.

Of the three approaches:
CRC16_table is correct, but only on a big endian CPU. In the old days a table-based approach would be the fastest approach, but it does not port between processors well.
CRC16_origin uses the wrong seed value. It computes a CRC for something, but not modbus.
CRC16_modbus is correct and portable.
With a modern processor the performance difference between the CRC16_table and CRC16_modbus approaches may not be worth the portability issues. Profile it and find out. On my PC they run neck-and-neck, which say go with the simplest and most portable. On an ARM or MSP430, who can say?
Experimental hack code:
#include <stdint.h>
#include <iostream>
#include <chrono>
uint16_t sizeeffect; // hack global to force execution of loops
static unsigned char auchCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40
};
static unsigned char auchCRCLo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
0x40
};
unsigned short CRC16_table(char* message, int len)
{
unsigned char uchCRCHi = 0xFF;
unsigned char uchCRCLo = 0xFF;
unsigned uIndex;
while(len--)
{
uIndex = uchCRCHi ^ *message++;
uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];
uchCRCLo = auchCRCLo[uIndex];
}
return (((unsigned short)uchCRCHi << 8) | (unsigned short)uchCRCLo);
}
// CRC table I'm using for Wintell and PC linux
static const uint16_t lCRCTable[] =
{
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};
// CRC table I'm using for Wintell and PC linux
uint16_t CRC16 (const uint8_t *datap, size_t len)
{
uint8_t loc;
uint16_t crc = 0xFFFF;
while (len--)
{
loc = *datap++ ^ crc;
crc >>= 8;
crc ^= lCRCTable[loc];
}
return crc;
}
unsigned short CRC16_modbus(const char* message, int len)
{
const unsigned short generator = 0xA001;
unsigned short crc = 0xFFFF;
for(int i = 0; i < len; ++i)
{
crc ^= (unsigned short)message[i];
for(int b = 0; b < 8; ++b)
{
if((crc & 1) != 0)
{
crc >>= 1;
crc ^= generator;
}
else
crc >>= 1;
}
}
return crc;
}
int main()
{
char message[] = "I am the very model of a modern major general.";
uint16_t a = CRC16((uint8_t *)message, sizeof(message));
uint16_t b = CRC16_modbus(message, sizeof(message));
uint16_t c = CRC16_table(message, sizeof(message));
if (a == b)
{
std::cout << "A-B Match"<< std::endl;
}
else
{
std::cout << a << std::endl;
std::cout << b << std::endl;
}
if (a == c)
{
std::cout << "A-C Match"<< std::endl;
}
else
{
std::cout << a << std::endl;
std::cout << c << std::endl;
}
int count = 10000000;
std::chrono::time_point<std::chrono::high_resolution_clock> start, end;
start = std::chrono::high_resolution_clock::now();
while (count--)
{
sizeeffect = CRC16((uint8_t *)message, sizeof(message));
}
end = std::chrono::high_resolution_clock::now();
std::cout << "Table took " << std::chrono::duration_cast<std::chrono::microseconds>(end-start).count() << "\n";
count = 10000000;
start = std::chrono::high_resolution_clock::now();
while (count--)
{
sizeeffect = CRC16((uint8_t *)message, sizeof(message));
}
end = std::chrono::high_resolution_clock::now();
std::cout << "Calc took " << std::chrono::duration_cast<std::chrono::microseconds>(end-start).count() << "\n";
}
Typical output:
A-B Match
5874
61974
Table took 900167
Calc took 892935

Besides other answer, I should use unsigned char* as the first parameter instead of char* in my functions because when I convert it to unsigned short, if it's char * and MSB is 1, it will add ff for the high byte, which is obviously wrong!
Thanks everyone here! Solved!

Related

CRC8 Slice-by-4 algorithm

I am in need of a highly optimized CRC8 algorithm. My goal is to develop a Slice-by-4 solution as known from CRC16 / CRC32. I want to keep the code as close to the solution which I am using for CRC16 posted below.
Functions to generate the CRC LookUp-Table:
void crcspeed16_genTable(crcfn16 crcfn, uint16_t table[8][256]) {
uint16_t crc;
/* generate CRCs for all single byte sequences */
for (int n = 0; n < 256; n++) {
table[0][n] = crcfn(0, &n, 1);
}
/* generate nested CRC table for future slice-by-8 lookup */
for (int n = 0; n < 256; n++) {
crc = table[0][n];
for (int k = 1; k < 8; k++) {
crc = table[0][(crc >> 8) & 0xff] ^ (crc << 8);
table[k][n] = crc;
}
}
}
uint16_t crc16(uint16_t crc, const void *in_data, uint64_t len) {
const uint8_t *data = (const uint8_t*) in_data;
for (uint64_t i = 0; i < len; i++) {
crc = crc ^ (data[i] << 8);
for (int j = 0; j < 8; j++) {
if (crc & 0x8000) {
crc = (crc << 1) ^ CRC16_POLYNOMINAL;
} else {
crc = (crc << 1);
}
}
}
return crc;
}
Call to generate the table:
crcspeed16_genTable(crc16, crc16_LUT);
Function to generate the CRC16 based on the Slice-by-4 solution:
uint16_t crc16_slice4(const void *buf, size_t len, uint16_t initialValue, uint16_t XOR_OUT) {
uint16_t crc = initialValue;
unsigned char *next = (unsigned char *)buf;
// process individual bytes until we reach an 8-byte aligned pointer
while (len && ((uintptr_t)next & 7) != 0) {
crc = crc16_LUT[0][((crc >> 8) ^ *next++) & 0xff] ^ (crc << 8);
len--;
}
// fast middle processing, 4 bytes (aligned!) per loop */
while (len >= 4) {
uint32_t n = *(uint32_t *)next;
crc = crc16_LUT[3][(n & 0xff) ^ ((crc >> 8) & 0xff)] ^
crc16_LUT[2][((n >> 8) & 0xff) ^ (crc & 0xff)] ^
crc16_LUT[1][(n >> 16) & 0xff] ^
crc16_LUT[0][n >> 24];
next += 4;
len -= 4;
}
// process remaining bytes (can't be larger than 8)
while (len) {
crc = crc16_LUT[0][((crc >> 8) ^ *next++) & 0xff] ^ (crc << 8);
len--;
}
return crc ^ XOR_OUT;
}
My aim is to adapt the algorithm to be working for CRC8 and CRC4. What I have managed so far is to change the LUT-Generator to be generating a valid first row of the LUT and process a valid CRC based on this LUT data. I am failing to adapt the middle part to calculate and utilize the full potential of the CRC table.
Adapted functions (not fully functional) for CRC8:
Table generation:
void crcspeed8_genTable(crcfn8 crcfn, uint8_t table[8][256]) {
uint16_t crc;
/* generate CRCs for all single byte sequences */
for (int n = 0; n < 256; n++) {
table[0][n] = crcfn(0, &n, 1);
}
/* generate nested CRC table for future slice-by-8 lookup */
for (int n = 0; n < 256; n++) {
crc = table[0][n];
for (int k = 1; k < 8; k++) {
//crc = table[0][crc] ^ crc;
crc = table[0][(crc >> 4) & 0x0f] ^ (crc << 4);
table[k][n] = crc;
}
}
}
uint8_t crc8(uint8_t crc, const void *in_data, uint64_t len) {
const uint8_t *data = (const uint8_t*) in_data;
for (uint64_t i = 0; i < len; i++) {
//crc = crc ^ (data[i] << 8);
crc = crc ^ data[i];
for (int j = 0; j < 8; j++) {
if (crc & 0x80) {
crc = (crc << 1) ^ CRC8_POLYNOMINAL;
} else {
crc = (crc << 1);
}
}
}
return crc;
}
CRC calculation:
uint8_t crc8_slice4(const void *buf, size_t len, uint8_t initialValue, uint8_t XOR_OUT) {
uint8_t crc = initialValue;
unsigned char *next = (unsigned char *)buf;
// process individual bytes until we reach an 8-byte aligned pointer
while (len && ((uintptr_t)next & 7) != 0) {
printf("\nAlign processing");
crc = crc8_LUT[0][crc ^ *next++];
len--;
}
//fast middle processing, 4 bytes (aligned!) per loop
while (len >= 4) {
printf("\nSlice processing");
uint32_t n = *(uint32_t *)next;
//This part should be adopted to work for CRC8
/*crc = crc8_LUT[3][(n & 0xff) ^ crc] ^
crc8_LUT[2][(n >> 8) & 0xff] ^
crc8_LUT[1][(n >> 16) & 0xff] ^
crc8_LUT[0][n >> 24]; */
uint32_t n0 = (n & 0xFF) ^ crc;
uint32_t n1 = (n >> 8) & 0xFF;
uint32_t n2 = (n >> 16) & 0xFF;
uint32_t n3 = (n >> 24);
//Working multi step for CRC 4 only using first row of LUT
uint8_t crc0 = crc8_LUT[0][crc ^ n0];
uint8_t crc1 = crc8_LUT[0][crc0 ^ n1];
uint8_t crc2 = crc8_LUT[0][crc1 ^ n2];
uint8_t crc3 = crc8_LUT[0][crc2 ^ n3];
crc = crc3;
next += 4;
len -= 4;
}
// process remaining bytes (can't be larger than 8)
while (len) {
printf("\nRemain processing");
crc = crc8_LUT[0][crc ^ *next++];
len--;
}
return crc ^ XOR_OUT;
}
I tried to change the functions to be working for CRC8 but I can't figure out the middle part. A solution explaining the general approach to generating Look-Up-Tables for various CRCs (4/8/16/24/32...) would also be highly appreciated.
Thanks for hopefully pointing me in the right direction.
You didn't provide your polynomial, initial value, or final exclusive or. With those (and that the CRC in your case is not reflected), you can use crcany to generate the code for you.
Here is an example for little-endian slice-by-4:
#include <stddef.h>
#include <stdint.h>
#define table_byte table_word[0]
static uint8_t const table_word[][256] = {
{0xbd, 0x92, 0xe3, 0xcc, 0x01, 0x2e, 0x5f, 0x70, 0xea, 0xc5, 0xb4, 0x9b, 0x56,
0x79, 0x08, 0x27, 0x13, 0x3c, 0x4d, 0x62, 0xaf, 0x80, 0xf1, 0xde, 0x44, 0x6b,
0x1a, 0x35, 0xf8, 0xd7, 0xa6, 0x89, 0xce, 0xe1, 0x90, 0xbf, 0x72, 0x5d, 0x2c,
0x03, 0x99, 0xb6, 0xc7, 0xe8, 0x25, 0x0a, 0x7b, 0x54, 0x60, 0x4f, 0x3e, 0x11,
0xdc, 0xf3, 0x82, 0xad, 0x37, 0x18, 0x69, 0x46, 0x8b, 0xa4, 0xd5, 0xfa, 0x5b,
0x74, 0x05, 0x2a, 0xe7, 0xc8, 0xb9, 0x96, 0x0c, 0x23, 0x52, 0x7d, 0xb0, 0x9f,
0xee, 0xc1, 0xf5, 0xda, 0xab, 0x84, 0x49, 0x66, 0x17, 0x38, 0xa2, 0x8d, 0xfc,
0xd3, 0x1e, 0x31, 0x40, 0x6f, 0x28, 0x07, 0x76, 0x59, 0x94, 0xbb, 0xca, 0xe5,
0x7f, 0x50, 0x21, 0x0e, 0xc3, 0xec, 0x9d, 0xb2, 0x86, 0xa9, 0xd8, 0xf7, 0x3a,
0x15, 0x64, 0x4b, 0xd1, 0xfe, 0x8f, 0xa0, 0x6d, 0x42, 0x33, 0x1c, 0x5e, 0x71,
0x00, 0x2f, 0xe2, 0xcd, 0xbc, 0x93, 0x09, 0x26, 0x57, 0x78, 0xb5, 0x9a, 0xeb,
0xc4, 0xf0, 0xdf, 0xae, 0x81, 0x4c, 0x63, 0x12, 0x3d, 0xa7, 0x88, 0xf9, 0xd6,
0x1b, 0x34, 0x45, 0x6a, 0x2d, 0x02, 0x73, 0x5c, 0x91, 0xbe, 0xcf, 0xe0, 0x7a,
0x55, 0x24, 0x0b, 0xc6, 0xe9, 0x98, 0xb7, 0x83, 0xac, 0xdd, 0xf2, 0x3f, 0x10,
0x61, 0x4e, 0xd4, 0xfb, 0x8a, 0xa5, 0x68, 0x47, 0x36, 0x19, 0xb8, 0x97, 0xe6,
0xc9, 0x04, 0x2b, 0x5a, 0x75, 0xef, 0xc0, 0xb1, 0x9e, 0x53, 0x7c, 0x0d, 0x22,
0x16, 0x39, 0x48, 0x67, 0xaa, 0x85, 0xf4, 0xdb, 0x41, 0x6e, 0x1f, 0x30, 0xfd,
0xd2, 0xa3, 0x8c, 0xcb, 0xe4, 0x95, 0xba, 0x77, 0x58, 0x29, 0x06, 0x9c, 0xb3,
0xc2, 0xed, 0x20, 0x0f, 0x7e, 0x51, 0x65, 0x4a, 0x3b, 0x14, 0xd9, 0xf6, 0x87,
0xa8, 0x32, 0x1d, 0x6c, 0x43, 0x8e, 0xa1, 0xd0, 0xff},
{0xfa, 0x13, 0x07, 0xee, 0x2f, 0xc6, 0xd2, 0x3b, 0x7f, 0x96, 0x82, 0x6b, 0xaa,
0x43, 0x57, 0xbe, 0xdf, 0x36, 0x22, 0xcb, 0x0a, 0xe3, 0xf7, 0x1e, 0x5a, 0xb3,
0xa7, 0x4e, 0x8f, 0x66, 0x72, 0x9b, 0xb0, 0x59, 0x4d, 0xa4, 0x65, 0x8c, 0x98,
0x71, 0x35, 0xdc, 0xc8, 0x21, 0xe0, 0x09, 0x1d, 0xf4, 0x95, 0x7c, 0x68, 0x81,
0x40, 0xa9, 0xbd, 0x54, 0x10, 0xf9, 0xed, 0x04, 0xc5, 0x2c, 0x38, 0xd1, 0x6e,
0x87, 0x93, 0x7a, 0xbb, 0x52, 0x46, 0xaf, 0xeb, 0x02, 0x16, 0xff, 0x3e, 0xd7,
0xc3, 0x2a, 0x4b, 0xa2, 0xb6, 0x5f, 0x9e, 0x77, 0x63, 0x8a, 0xce, 0x27, 0x33,
0xda, 0x1b, 0xf2, 0xe6, 0x0f, 0x24, 0xcd, 0xd9, 0x30, 0xf1, 0x18, 0x0c, 0xe5,
0xa1, 0x48, 0x5c, 0xb5, 0x74, 0x9d, 0x89, 0x60, 0x01, 0xe8, 0xfc, 0x15, 0xd4,
0x3d, 0x29, 0xc0, 0x84, 0x6d, 0x79, 0x90, 0x51, 0xb8, 0xac, 0x45, 0xfd, 0x14,
0x00, 0xe9, 0x28, 0xc1, 0xd5, 0x3c, 0x78, 0x91, 0x85, 0x6c, 0xad, 0x44, 0x50,
0xb9, 0xd8, 0x31, 0x25, 0xcc, 0x0d, 0xe4, 0xf0, 0x19, 0x5d, 0xb4, 0xa0, 0x49,
0x88, 0x61, 0x75, 0x9c, 0xb7, 0x5e, 0x4a, 0xa3, 0x62, 0x8b, 0x9f, 0x76, 0x32,
0xdb, 0xcf, 0x26, 0xe7, 0x0e, 0x1a, 0xf3, 0x92, 0x7b, 0x6f, 0x86, 0x47, 0xae,
0xba, 0x53, 0x17, 0xfe, 0xea, 0x03, 0xc2, 0x2b, 0x3f, 0xd6, 0x69, 0x80, 0x94,
0x7d, 0xbc, 0x55, 0x41, 0xa8, 0xec, 0x05, 0x11, 0xf8, 0x39, 0xd0, 0xc4, 0x2d,
0x4c, 0xa5, 0xb1, 0x58, 0x99, 0x70, 0x64, 0x8d, 0xc9, 0x20, 0x34, 0xdd, 0x1c,
0xf5, 0xe1, 0x08, 0x23, 0xca, 0xde, 0x37, 0xf6, 0x1f, 0x0b, 0xe2, 0xa6, 0x4f,
0x5b, 0xb2, 0x73, 0x9a, 0x8e, 0x67, 0x06, 0xef, 0xfb, 0x12, 0xd3, 0x3a, 0x2e,
0xc7, 0x83, 0x6a, 0x7e, 0x97, 0x56, 0xbf, 0xab, 0x42},
{0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb, 0xa1, 0xaf, 0xbd, 0xb3, 0x99,
0x97, 0x85, 0x8b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, 0x41, 0x4f,
0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x3e, 0x30, 0x22, 0x2c, 0x06, 0x08, 0x1a,
0x14, 0x4e, 0x40, 0x52, 0x5c, 0x76, 0x78, 0x6a, 0x64, 0xde, 0xd0, 0xc2, 0xcc,
0xe6, 0xe8, 0xfa, 0xf4, 0xae, 0xa0, 0xb2, 0xbc, 0x96, 0x98, 0x8a, 0x84, 0x20,
0x2e, 0x3c, 0x32, 0x18, 0x16, 0x04, 0x0a, 0x50, 0x5e, 0x4c, 0x42, 0x68, 0x66,
0x74, 0x7a, 0xc0, 0xce, 0xdc, 0xd2, 0xf8, 0xf6, 0xe4, 0xea, 0xb0, 0xbe, 0xac,
0xa2, 0x88, 0x86, 0x94, 0x9a, 0xcf, 0xc1, 0xd3, 0xdd, 0xf7, 0xf9, 0xeb, 0xe5,
0xbf, 0xb1, 0xa3, 0xad, 0x87, 0x89, 0x9b, 0x95, 0x2f, 0x21, 0x33, 0x3d, 0x17,
0x19, 0x0b, 0x05, 0x5f, 0x51, 0x43, 0x4d, 0x67, 0x69, 0x7b, 0x75, 0x1c, 0x12,
0x00, 0x0e, 0x24, 0x2a, 0x38, 0x36, 0x6c, 0x62, 0x70, 0x7e, 0x54, 0x5a, 0x48,
0x46, 0xfc, 0xf2, 0xe0, 0xee, 0xc4, 0xca, 0xd8, 0xd6, 0x8c, 0x82, 0x90, 0x9e,
0xb4, 0xba, 0xa8, 0xa6, 0xf3, 0xfd, 0xef, 0xe1, 0xcb, 0xc5, 0xd7, 0xd9, 0x83,
0x8d, 0x9f, 0x91, 0xbb, 0xb5, 0xa7, 0xa9, 0x13, 0x1d, 0x0f, 0x01, 0x2b, 0x25,
0x37, 0x39, 0x63, 0x6d, 0x7f, 0x71, 0x5b, 0x55, 0x47, 0x49, 0xed, 0xe3, 0xf1,
0xff, 0xd5, 0xdb, 0xc9, 0xc7, 0x9d, 0x93, 0x81, 0x8f, 0xa5, 0xab, 0xb9, 0xb7,
0x0d, 0x03, 0x11, 0x1f, 0x35, 0x3b, 0x29, 0x27, 0x7d, 0x73, 0x61, 0x6f, 0x45,
0x4b, 0x59, 0x57, 0x02, 0x0c, 0x1e, 0x10, 0x3a, 0x34, 0x26, 0x28, 0x72, 0x7c,
0x6e, 0x60, 0x4a, 0x44, 0x56, 0x58, 0xe2, 0xec, 0xfe, 0xf0, 0xda, 0xd4, 0xc6,
0xc8, 0x92, 0x9c, 0x8e, 0x80, 0xaa, 0xa4, 0xb6, 0xb8},
{0x84, 0x31, 0xc1, 0x74, 0x0e, 0xbb, 0x4b, 0xfe, 0xbf, 0x0a, 0xfa, 0x4f, 0x35,
0x80, 0x70, 0xc5, 0xf2, 0x47, 0xb7, 0x02, 0x78, 0xcd, 0x3d, 0x88, 0xc9, 0x7c,
0x8c, 0x39, 0x43, 0xf6, 0x06, 0xb3, 0x68, 0xdd, 0x2d, 0x98, 0xe2, 0x57, 0xa7,
0x12, 0x53, 0xe6, 0x16, 0xa3, 0xd9, 0x6c, 0x9c, 0x29, 0x1e, 0xab, 0x5b, 0xee,
0x94, 0x21, 0xd1, 0x64, 0x25, 0x90, 0x60, 0xd5, 0xaf, 0x1a, 0xea, 0x5f, 0x73,
0xc6, 0x36, 0x83, 0xf9, 0x4c, 0xbc, 0x09, 0x48, 0xfd, 0x0d, 0xb8, 0xc2, 0x77,
0x87, 0x32, 0x05, 0xb0, 0x40, 0xf5, 0x8f, 0x3a, 0xca, 0x7f, 0x3e, 0x8b, 0x7b,
0xce, 0xb4, 0x01, 0xf1, 0x44, 0x9f, 0x2a, 0xda, 0x6f, 0x15, 0xa0, 0x50, 0xe5,
0xa4, 0x11, 0xe1, 0x54, 0x2e, 0x9b, 0x6b, 0xde, 0xe9, 0x5c, 0xac, 0x19, 0x63,
0xd6, 0x26, 0x93, 0xd2, 0x67, 0x97, 0x22, 0x58, 0xed, 0x1d, 0xa8, 0x45, 0xf0,
0x00, 0xb5, 0xcf, 0x7a, 0x8a, 0x3f, 0x7e, 0xcb, 0x3b, 0x8e, 0xf4, 0x41, 0xb1,
0x04, 0x33, 0x86, 0x76, 0xc3, 0xb9, 0x0c, 0xfc, 0x49, 0x08, 0xbd, 0x4d, 0xf8,
0x82, 0x37, 0xc7, 0x72, 0xa9, 0x1c, 0xec, 0x59, 0x23, 0x96, 0x66, 0xd3, 0x92,
0x27, 0xd7, 0x62, 0x18, 0xad, 0x5d, 0xe8, 0xdf, 0x6a, 0x9a, 0x2f, 0x55, 0xe0,
0x10, 0xa5, 0xe4, 0x51, 0xa1, 0x14, 0x6e, 0xdb, 0x2b, 0x9e, 0xb2, 0x07, 0xf7,
0x42, 0x38, 0x8d, 0x7d, 0xc8, 0x89, 0x3c, 0xcc, 0x79, 0x03, 0xb6, 0x46, 0xf3,
0xc4, 0x71, 0x81, 0x34, 0x4e, 0xfb, 0x0b, 0xbe, 0xff, 0x4a, 0xba, 0x0f, 0x75,
0xc0, 0x30, 0x85, 0x5e, 0xeb, 0x1b, 0xae, 0xd4, 0x61, 0x91, 0x24, 0x65, 0xd0,
0x20, 0x95, 0xef, 0x5a, 0xaa, 0x1f, 0x28, 0x9d, 0x6d, 0xd8, 0xa2, 0x17, 0xe7,
0x52, 0x13, 0xa6, 0x56, 0xe3, 0x99, 0x2c, 0xdc, 0x69}
};
// This code assumes that integers are stored little-endian.
uint8_t crc8autosar_word(uint8_t crc, void const *mem, size_t len) {
unsigned char const *data = mem;
if (data == NULL)
return 0;
while (len && ((ptrdiff_t)data & 0x3)) {
len--;
crc = table_byte[crc ^ *data++];
}
size_t n = len >> 2;
for (size_t i = 0; i < n; i++) {
uint32_t word = crc ^ ((uint32_t const *)data)[i];
crc = table_word[3][word & 0xff] ^
table_word[2][(word >> 8) & 0xff] ^
table_word[1][(word >> 16) & 0xff] ^
table_word[0][word >> 24];
}
data += n << 2;
len &= 3;
while (len) {
len--;
crc = table_byte[crc ^ *data++];
}
return crc;
}
The convention for this code is that when called with mem == NULL, crc is ignored and the initial CRC, i.e. the CRC of an empty message, is returned.

C++ negative byte value

I have c++ code that read 16 byte from a file as char value
And I have a table of unsigned char from 0 to 255
I want to use byte values from file as a index in my unsigned char table to change the original file byte values but I get negative value from file and as you know you can't use negative value as a index in array
What should I do ?
Edit
const unsigned char TopSbox[256] = {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
};
void RunFunction(){
ifstream reader;
ofstream writer;
reader.open(myfile_address, ifstream::binary);
writer.open(storage_file,ofstream::out);
unsigned int BufferSize =16;
char *Transform_Buffer = new char[BufferSize];
reader.read(Transform_Buffer, BufferSize);
ExchangeData(Transform_Buffer, BufferSize);
writer.write(Transform_Buffer, BufferSize);
writer.flush();
}
void EData::ExchangeData(char data[], const unsigned int size){
for (unsigned int i = 0; i<size; i++){
data[i] = TopSbox[data[i]];
}
}
Don't use operator new unless absolutely necessary.
Rather than
char *Transform_Buffer = new char[BufferSize];
you can define the buffer as a local array:
const unsigned int BufferSize = 16;
unsigned char Transform_Buffer[BufferSize];
For this to work, you should declare BufferSize as const. Notice also that I declared the elements of the buffer as unsigned char.
Then, this line
reader.read(Transform_Buffer, BufferSize);
can be replaced with
reader.read(reinterpret_cast<char*>(Transform_Buffer), BufferSize);
and similarly for writer.
Please also replace all char* in function declarations with unsigned char*, eg:
void EData::ExchangeData(unsigned char data[], const unsigned int size){
I guess everything should work as expected now.
Just have buffer of unsigned chars. Then pass it as char* to ifstream::read. Let's say char* works kind of like a generic pointer.
You may want to prefer to use standard containers.
std::vector<unsigned char> transform_buffer(buffer_size);
reader.read(static_cast<char*>(transform_buffer.data()), transform_buffer.size());
exchange_data(transform_buffer);
}
void exchange_data(std::vector<unsigned char>& transform_buffer) {
for (auto&& i : transform_buffer) {
i = TopSbox[i];
}
}

Swift - CRC8 calculation conversion from C++

As part of a project I'm working on with pulling data from a bluetooth device, I was provided a CRC8 function from the manufacturer to use. I'm writing the application in Swift, but the function they provided is in C++.
Below is the function they've provided in C++
unsigned char xTable_CRC8[]={0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 };
uint8_t CRC8(char *RP_ByteData, unsigned int Buffer_Size) {
uint8_t x,R_CRC_Data;
R_CRC_Data=0;
for(unsigned int i = 0; i < Buffer_Size; i++) {
x = R_CRC_Data ^ (*RP_ByteData);
R_CRC_Data = xTable_CRC8[x];
RP_ByteData++;
}
return R_CRC_Data;
}
Here is my attempt at converting it so far:
func calCR8(buf : [UInt8]) -> UInt8 {
let initialValue : UInt8 = UInt8.min;
let Table_CRC8 : [UInt8] = [
0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 ];
var crc = initialValue;
let x: UInt8
for i in 0 ..< buf.count{
x = crc ^ buf
crc = Table_CRC8[x]
}
return crc;
}
}
I'm dealing with two type errors: Cannot convert value of type '[UInt8]' to expected argument type 'UInt8', and Cannot convert value of type 'UInt8' to expected argument type 'Int'. I feel very lost and uncomfortable here.
Basically, this function will be called in a manner as such:
var buf : [UInt8] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
buf[0] = 0xAA;
buf[1] = 0x14;
buf[2] = ~0x14
buf[buf.count - 1] = self.calcCR8(buf)
Based on this byte array being use a parameter for this example, I'm expecting to get 0xC6 returned.
You have a few small mistakes. First, you are trying to perform the xor calculation on buf - this is the entire array; You need to access a single element buf[i].
Your second issue is that you can't index a sequence with a UInt8, so you need to make an Int equivalent in order to access the Table_CRC8 array.
Finally you are declaring x as a let (constant) outside the for loop, so you can't change it. You can move the declaration of x inside the for loop to address this.
Making these small changes will give you code that compiles:
for i in 0 ..< buf.count {
let x = crc ^ buf[i]
crc = Table_CRC8[Int(x)]
}
You can make it more 'Swifty' by changing the name of the CRC table to conform to Swift idioms and use an iteration loop rather than a for in <range> loop:
func calcCRC8(_ buf : [UInt8]) -> UInt8 {
let tableCRC8 : [UInt8] = [
0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 ];
var crc = UInt8.min
for byte in buf {
let x = crc ^ byte
crc = tableCRC8[Int(x)]
}
return crc
}

Could not find space (120 bytes) for variable

I have an array defined with 60 hex values.
int ary[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13,
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
0x47, 0x48, 0x49, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59
};
When i compile this i get the error
could not find space (120 bytes) for variable _ary
Why is this happening, This is for a PIC program and i need the array to be type of int. What can i do?

RSASSA_PKCS1v15_SHA_Signer and PK_SignatureScheme::KeyTooShort exception

I am using Crypto++ for the first time, and I am having some trouble. Why does this work in C# (with the same keys), but not with Crypto++? I will show my C# and C++ code below.
C# code (this works!):
byte[] Modulus = new byte[] { 0xA3, 0x1D, 0x6C, 0xE5, 0xFA, 0x95, 0xFD, 0xE8, 0x90, 0x21, 0xFA, 0xD1, 0x0C, 0x64, 0x19, 0x2B, 0x86, 0x58, 0x9B, 0x17, 0x2B, 0x10, 0x05, 0xB8, 0xD1, 0xF8, 0x4C, 0xEF, 0x53, 0x4C, 0xD5, 0x4E, 0x5C, 0xAE, 0x86, 0xEF, 0x92, 0x7B, 0x90, 0xD1, 0xE0, 0x62, 0xFD, 0x7C, 0x54, 0x55, 0x9E, 0xE0, 0xE7, 0xBE, 0xFA, 0x3F, 0x9E, 0x15, 0x6F, 0x6C, 0x38, 0x4E, 0xAF, 0x07, 0x0C, 0x61, 0xAB, 0x51, 0x5E, 0x23, 0x53, 0x14, 0x18, 0x88, 0xCB, 0x6F, 0xCB, 0xC5, 0xD6, 0x30, 0xF4, 0x06, 0xED, 0x24, 0x23, 0xEF, 0x25, 0x6D, 0x00, 0x91, 0x77, 0x24, 0x9B, 0xE5, 0xA3, 0xC0, 0x27, 0x90, 0xC2, 0x97, 0xF7, 0x74, 0x9D, 0x6F, 0x17, 0x83, 0x7E, 0xB5, 0x37, 0xDE, 0x51, 0xE8, 0xD7, 0x1C, 0xE1, 0x56, 0xD9, 0x56, 0xC8, 0xC3, 0xC3, 0x20, 0x9D, 0x64, 0xC3, 0x2F, 0x8C, 0x91, 0x92, 0x30, 0x6F, 0xDB };
byte[] Exponent = new byte[] { 0x00, 0x01, 0x00, 0x01 };
byte[] P = new byte[] { 0xCC, 0xE7, 0x5D, 0xFE, 0x72, 0xB6, 0xFD, 0xE7, 0x1D, 0xE3, 0x1A, 0x0E, 0xAC, 0x33, 0x7A, 0xB9, 0x21, 0xE8, 0x8A, 0x84, 0x9B, 0xDA, 0x9F, 0x1E, 0x58, 0x34, 0x68, 0x7A, 0xB1, 0x1D, 0x7E, 0x1C, 0x18, 0x52, 0x65, 0x7B, 0x97, 0x8E, 0xA7, 0x6A, 0x9D, 0xEE, 0x5A, 0x77, 0x52, 0x3B, 0x71, 0x8F, 0x33, 0xD0, 0x49, 0x5E, 0xC3, 0x30, 0x39, 0x72, 0x36, 0xBF, 0x1D, 0xD9, 0xF2, 0x24, 0xE8, 0x71 };
byte[] Q = new byte[] { 0xCB, 0xCA, 0x58, 0x74, 0xD4, 0x03, 0x62, 0x93, 0x06, 0x50, 0x1F, 0x42, 0xF6, 0xAA, 0x59, 0x36, 0xA7, 0xA1, 0xF3, 0x97, 0x5C, 0x9A, 0xC8, 0x6A, 0x27, 0xCF, 0x85, 0x05, 0x2A, 0x66, 0x41, 0x6A, 0x7F, 0x2F, 0x84, 0xC8, 0x18, 0x13, 0xC6, 0x1D, 0x8D, 0xC7, 0x32, 0x2F, 0x72, 0x19, 0x3F, 0xA4, 0xED, 0x71, 0xE7, 0x61, 0xC0, 0xCF, 0x61, 0xAE, 0x8B, 0xA0, 0x68, 0xA7, 0x7D, 0x83, 0x23, 0x0B };
byte[] DP = new byte[] { 0x4C, 0xCA, 0x74, 0xE6, 0x74, 0x35, 0x72, 0x48, 0x58, 0x62, 0x11, 0x14, 0xE8, 0xA2, 0x4E, 0x5E, 0xED, 0x7F, 0x49, 0xD2, 0x52, 0xDA, 0x87, 0x01, 0x87, 0x4A, 0xF4, 0xD0, 0xEE, 0x69, 0xC0, 0x26, 0x65, 0x53, 0x13, 0xE7, 0x52, 0xB0, 0x4A, 0xBB, 0xE1, 0x3E, 0x3F, 0xB7, 0x32, 0x21, 0x46, 0xF8, 0xC5, 0x11, 0x4D, 0x3D, 0xEF, 0x66, 0xB6, 0x50, 0xC0, 0x85, 0xB5, 0x79, 0x45, 0x8F, 0x61, 0x71 };
byte[] InverseQ = new byte[] { 0x28, 0x6A, 0xBB, 0xD1, 0x93, 0x95, 0x94, 0x1A, 0x6E, 0xED, 0xD7, 0x0E, 0xC0, 0x61, 0x2B, 0xC2, 0xEF, 0xE1, 0x86, 0x3D, 0x34, 0x12, 0x88, 0x6F, 0x94, 0xA4, 0x48, 0x6E, 0xC9, 0x87, 0x1E, 0x46, 0x00, 0x46, 0x00, 0x52, 0x8E, 0x9F, 0x47, 0xC0, 0x8C, 0xAB, 0xBC, 0x49, 0xAC, 0x5B, 0x13, 0xF2, 0xEC, 0x27, 0x8D, 0x1B, 0x6E, 0x51, 0x06, 0xA6, 0xF1, 0x62, 0x1A, 0xEB, 0x78, 0x2E, 0x88, 0x48 };
byte[] D = new byte[] { 0x9B, 0xF9, 0xDE, 0xC2, 0x45, 0x93, 0x4C, 0x4C, 0xAC, 0x48, 0x2B, 0xA8, 0x4D, 0xFC, 0xD7, 0xED, 0xB2, 0xFB, 0x72, 0xE9, 0xEA, 0xC1, 0x88, 0x39, 0x07, 0x2A, 0x6F, 0x34, 0x07, 0x81, 0x97, 0x7E, 0xCD, 0xFA, 0x21, 0x02, 0xF5, 0xDD, 0x30, 0xDD, 0x22, 0x4A, 0xB3, 0x41, 0xE5, 0x89, 0x80, 0x73, 0xC4, 0xAF, 0x90, 0x9E, 0x2B, 0x50, 0x8A, 0x0A, 0xD4, 0x6E, 0xBD, 0x0F, 0x15, 0x79, 0x37, 0x95, 0xE8, 0x3D, 0xCF, 0x4C, 0x6D, 0xFF, 0x51, 0x65, 0xE7, 0x90, 0xC1, 0xAC, 0x2D, 0xC6, 0xEB, 0x47, 0x19, 0x2D, 0xD0, 0x58, 0x74, 0x79, 0xAC, 0x08, 0x1C, 0xA3, 0x1D, 0xD0, 0xCE, 0x39, 0x2E, 0xC3, 0xFA, 0x66, 0xEF, 0xC7, 0x8E, 0x10, 0x2F, 0xE4, 0xA1, 0xE7, 0x4E, 0xA8, 0x42, 0xF0, 0xF4, 0xFD, 0x10, 0xA6, 0x67, 0x64, 0xCB, 0x3A, 0x6D, 0x4D, 0x51, 0xEC, 0x1F, 0x9D, 0x56, 0x26, 0xC2, 0xFC };
byte[] DQ = new byte[] { 0xAF, 0xDC, 0x46, 0xE7, 0x52, 0x8A, 0x35, 0x47, 0xA1, 0x1C, 0x05, 0x4E, 0x39, 0x24, 0x99, 0xE6, 0x43, 0x54, 0xCB, 0xAB, 0xE3, 0xDB, 0x22, 0x76, 0x11, 0x32, 0xD0, 0x9C, 0xBB, 0x91, 0x10, 0x84, 0x81, 0x8B, 0x15, 0x2F, 0xC3, 0x2F, 0x55, 0x38, 0xED, 0xBF, 0x67, 0x3C, 0x70, 0x5E, 0xFF, 0x80, 0x28, 0xF3, 0xB1, 0x73, 0xB6, 0xFA, 0x7F, 0x56, 0x2B, 0xE1, 0xDA, 0x4E, 0x27, 0x4E, 0xC2, 0x2F };
RSAParameters rsaParams = new RSAParameters();
rsaParams.Modulus = Modulus;
rsaParams.Exponent = Exponent;
rsaParams.P = P;
rsaParams.Q = Q;
rsaParams.DP = DP;
rsaParams.InverseQ = InverseQ;
rsaParams.D = D;
rsaParams.DQ = DQ;
RSACryptoServiceProvider crypt = new RSACryptoServiceProvider();
crypt.ImportParameters(rsaParams);
RSAPKCS1SignatureFormatter formatter = new RSAPKCS1SignatureFormatter();
formatter.SetHashAlgorithm("SHA1");
formatter.SetKey(crypt);
byte[] dataFile = new byte[] { 0x6F, 0x9F, 0x07, 0x04, 0xE2, 0x1A, 0xF7, 0xB8, 0xB2, 0x4F, 0x8D, 0x66, 0x49, 0xA1, 0x09, 0xA7, 0xB2, 0x22, 0x3C, 0xF9};
byte[] signature = formatter.CreateSignature(dataFile);
Now, my C++ code, which doesn't work:
const char ModulusCON[0x80] = { 0xA3, 0x1D, 0x6C, 0xE5, 0xFA, 0x95, 0xFD, 0xE8, 0x90, 0x21, 0xFA, 0xD1, 0x0C, 0x64, 0x19, 0x2B, 0x86, 0x58, 0x9B, 0x17, 0x2B, 0x10, 0x05, 0xB8, 0xD1, 0xF8, 0x4C, 0xEF, 0x53, 0x4C, 0xD5, 0x4E, 0x5C, 0xAE, 0x86, 0xEF, 0x92, 0x7B, 0x90, 0xD1, 0xE0, 0x62, 0xFD, 0x7C, 0x54, 0x55, 0x9E, 0xE0, 0xE7, 0xBE, 0xFA, 0x3F, 0x9E, 0x15, 0x6F, 0x6C, 0x38, 0x4E, 0xAF, 0x07, 0x0C, 0x61, 0xAB, 0x51, 0x5E, 0x23, 0x53, 0x14, 0x18, 0x88, 0xCB, 0x6F, 0xCB, 0xC5, 0xD6, 0x30, 0xF4, 0x06, 0xED, 0x24, 0x23, 0xEF, 0x25, 0x6D, 0x00, 0x91, 0x77, 0x24, 0x9B, 0xE5, 0xA3, 0xC0, 0x27, 0x90, 0xC2, 0x97, 0xF7, 0x74, 0x9D, 0x6F, 0x17, 0x83, 0x7E, 0xB5, 0x37, 0xDE, 0x51, 0xE8, 0xD7, 0x1C, 0xE1, 0x56, 0xD9, 0x56, 0xC8, 0xC3, 0xC3, 0x20, 0x9D, 0x64, 0xC3, 0x2F, 0x8C, 0x91, 0x92, 0x30, 0x6F, 0xDB };
const char ExponentCON[0x4] = { 0x00, 0x01, 0x00, 0x01 };
const char PCON[0x40] = { 0xCC, 0xE7, 0x5D, 0xFE, 0x72, 0xB6, 0xFD, 0xE7, 0x1D, 0xE3, 0x1A, 0x0E, 0xAC, 0x33, 0x7A, 0xB9, 0x21, 0xE8, 0x8A, 0x84, 0x9B, 0xDA, 0x9F, 0x1E, 0x58, 0x34, 0x68, 0x7A, 0xB1, 0x1D, 0x7E, 0x1C, 0x18, 0x52, 0x65, 0x7B, 0x97, 0x8E, 0xA7, 0x6A, 0x9D, 0xEE, 0x5A, 0x77, 0x52, 0x3B, 0x71, 0x8F, 0x33, 0xD0, 0x49, 0x5E, 0xC3, 0x30, 0x39, 0x72, 0x36, 0xBF, 0x1D, 0xD9, 0xF2, 0x24, 0xE8, 0x71 };
const char QCON[0x40] = { 0xCB, 0xCA, 0x58, 0x74, 0xD4, 0x03, 0x62, 0x93, 0x06, 0x50, 0x1F, 0x42, 0xF6, 0xAA, 0x59, 0x36, 0xA7, 0xA1, 0xF3, 0x97, 0x5C, 0x9A, 0xC8, 0x6A, 0x27, 0xCF, 0x85, 0x05, 0x2A, 0x66, 0x41, 0x6A, 0x7F, 0x2F, 0x84, 0xC8, 0x18, 0x13, 0xC6, 0x1D, 0x8D, 0xC7, 0x32, 0x2F, 0x72, 0x19, 0x3F, 0xA4, 0xED, 0x71, 0xE7, 0x61, 0xC0, 0xCF, 0x61, 0xAE, 0x8B, 0xA0, 0x68, 0xA7, 0x7D, 0x83, 0x23, 0x0B };
const char DPCON[0x40] = { 0x4C, 0xCA, 0x74, 0xE6, 0x74, 0x35, 0x72, 0x48, 0x58, 0x62, 0x11, 0x14, 0xE8, 0xA2, 0x4E, 0x5E, 0xED, 0x7F, 0x49, 0xD2, 0x52, 0xDA, 0x87, 0x01, 0x87, 0x4A, 0xF4, 0xD0, 0xEE, 0x69, 0xC0, 0x26, 0x65, 0x53, 0x13, 0xE7, 0x52, 0xB0, 0x4A, 0xBB, 0xE1, 0x3E, 0x3F, 0xB7, 0x32, 0x21, 0x46, 0xF8, 0xC5, 0x11, 0x4D, 0x3D, 0xEF, 0x66, 0xB6, 0x50, 0xC0, 0x85, 0xB5, 0x79, 0x45, 0x8F, 0x61, 0x71 };
const char InverseQCON[0x40] = { 0x28, 0x6A, 0xBB, 0xD1, 0x93, 0x95, 0x94, 0x1A, 0x6E, 0xED, 0xD7, 0x0E, 0xC0, 0x61, 0x2B, 0xC2, 0xEF, 0xE1, 0x86, 0x3D, 0x34, 0x12, 0x88, 0x6F, 0x94, 0xA4, 0x48, 0x6E, 0xC9, 0x87, 0x1E, 0x46, 0x00, 0x46, 0x00, 0x52, 0x8E, 0x9F, 0x47, 0xC0, 0x8C, 0xAB, 0xBC, 0x49, 0xAC, 0x5B, 0x13, 0xF2, 0xEC, 0x27, 0x8D, 0x1B, 0x6E, 0x51, 0x06, 0xA6, 0xF1, 0x62, 0x1A, 0xEB, 0x78, 0x2E, 0x88, 0x48 };
const char DCON[0x80] = { 0x9B, 0xF9, 0xDE, 0xC2, 0x45, 0x93, 0x4C, 0x4C, 0xAC, 0x48, 0x2B, 0xA8, 0x4D, 0xFC, 0xD7, 0xED, 0xB2, 0xFB, 0x72, 0xE9, 0xEA, 0xC1, 0x88, 0x39, 0x07, 0x2A, 0x6F, 0x34, 0x07, 0x81, 0x97, 0x7E, 0xCD, 0xFA, 0x21, 0x02, 0xF5, 0xDD, 0x30, 0xDD, 0x22, 0x4A, 0xB3, 0x41, 0xE5, 0x89, 0x80, 0x73, 0xC4, 0xAF, 0x90, 0x9E, 0x2B, 0x50, 0x8A, 0x0A, 0xD4, 0x6E, 0xBD, 0x0F, 0x15, 0x79, 0x37, 0x95, 0xE8, 0x3D, 0xCF, 0x4C, 0x6D, 0xFF, 0x51, 0x65, 0xE7, 0x90, 0xC1, 0xAC, 0x2D, 0xC6, 0xEB, 0x47, 0x19, 0x2D, 0xD0, 0x58, 0x74, 0x79, 0xAC, 0x08, 0x1C, 0xA3, 0x1D, 0xD0, 0xCE, 0x39, 0x2E, 0xC3, 0xFA, 0x66, 0xEF, 0xC7, 0x8E, 0x10, 0x2F, 0xE4, 0xA1, 0xE7, 0x4E, 0xA8, 0x42, 0xF0, 0xF4, 0xFD, 0x10, 0xA6, 0x67, 0x64, 0xCB, 0x3A, 0x6D, 0x4D, 0x51, 0xEC, 0x1F, 0x9D, 0x56, 0x26, 0xC2, 0xFC };
const char DQCON[0x40] = { 0xAF, 0xDC, 0x46, 0xE7, 0x52, 0x8A, 0x35, 0x47, 0xA1, 0x1C, 0x05, 0x4E, 0x39, 0x24, 0x99, 0xE6, 0x43, 0x54, 0xCB, 0xAB, 0xE3, 0xDB, 0x22, 0x76, 0x11, 0x32, 0xD0, 0x9C, 0xBB, 0x91, 0x10, 0x84, 0x81, 0x8B, 0x15, 0x2F, 0xC3, 0x2F, 0x55, 0x38, 0xED, 0xBF, 0x67, 0x3C, 0x70, 0x5E, 0xFF, 0x80, 0x28, 0xF3, 0xB1, 0x73, 0xB6, 0xFA, 0x7F, 0x56, 0x2B, 0xE1, 0xDA, 0x4E, 0x27, 0x4E, 0xC2, 0x2F };
// set the params
CryptoPP::AutoSeededRandomPool rng;
InvertibleRSAFunction params;
Integer integ(ModulusCON);
params.SetModulus(integ);
Integer integ1(ExponentCON);
params.SetPublicExponent(integ1);
Integer integ2(PCON);
params.SetPrime1(integ2);
Integer integ3(QCON);
params.SetPrime2(integ3);
Integer integ4(DPCON);
params.SetModPrime1PrivateExponent(integ4);
Integer integ5(InverseQCON);
params.SetMultiplicativeInverseOfPrime2ModPrime1(integ5);
Integer integ6(DCON);
params.SetPrivateExponent(integ6);
Integer integ7(DQCON);
params.SetModPrime2PrivateExponent(integ7);
// create the keys
RSA::PrivateKey privateKey(params);
RSA::PublicKey publicKey(params);
CryptoPP::RSASSA_PKCS1v15_SHA_Signer signer(privateKey);
unsigned char data[20] = { 0x6F, 0x9F, 0x07, 0x04, 0xE2, 0x1A, 0xF7, 0xB8, 0xB2, 0x4F, 0x8D, 0x66, 0x49, 0xA1, 0x09, 0xA7, 0xB2, 0x22, 0x3C, 0xF9 };
BYTE *signature = new BYTE[0x80];
signer.SignMessage(rng, data, 20, signature);
Based on what I know, Crypto++'s 'RSASSA_PKCS1v15_SHA_Signer' is what I want equivalent to C#'s 'RSAPKCS1SignatureFormatter' and setting the hash algorithm to SHA1.
The error it throws is:
Unhandled exception at at 0x7646B9BC in proj.exe: Microsoft C++ exception: > CryptoPP::PK_SignatureScheme::KeyTooShort at memory location 0x0040EF18.
Thanks for any help, Hetelek.
I can't answer as to why this works in C#, but as for Crypto++, there are a couple of issues.
Firstly, you're probably invoking the wrong constructor of Integer. I guess you want this one which converts from big-endian byte array:
Integer (const byte *encodedInteger, size_t byteCount, Signedness s=UNSIGNED)
but are using this one which convert from a string in base 2, 8, 10, or 16 (in your case base 10).
So, using ExponentCON as an example, you should do:
const int ExponentSize(0x4);
const byte ExponentCON[ExponentSize] = { 0x00, 0x01, 0x00, 0x01 };
Integer integ1(ExponentCON, ExponentSize);
or possibly better still:
std::string ExponentCON("101h"); // <-- Note trailing 'h' indicating hex encoding
Integer integ1(ExponentCON.c_str());
Next, the members of InvertibleRSAFunction must satisfy certain conditions in order to qualify as a valid key. These can be seen by stepping through the InvertibleRSAFunction::Validate function and I assume check for the conditions described here.
params.Validate(rng, 3); // Returns false for your input data
There are some helper functions which are designed to avoid having to set everything explicitly as you're doing. I don't know if these are suitable for you, but I'm referring to InvertibleRSAFunction::GenerateRandomWithKeySize and the overloaded InvertibleRSAFunction::Initialize.
The Crypto++ Wiki describes the use of these functions with example code.
TLDR: your private exponent, d, is wrong in your sample program. You have other, more obvious problems, too. But d is causing the mathematical problems.
And it begs the question, how did that work in C#? The math does not change across computer languages and runtimes.
The first problem is the declarations using chars:
...
const char ExponentCON[0x4] = { 0x00, 0x01, 0x00, 0x01 };
...
This causes you to use the constructors for ASCII strings, which is the wrong Integer constructor. It results in at least two issues:
// Added for testing
if (integ != integ2 * integ3)
{
cerr << "error: n != p*q" << endl;
}
// Added for testing
params.ThrowIfInvalid(prng, 3);
When running the program, ThrowIfInvalid validates the parameters and its the source of CryptoMaterial: ...:
error: n != p*q
CryptoMaterial: this object contains invalid values
The const char need to be changed to const byte. Then:
Integer integ(ModulusCON, sizeof(ModulusCON));
params.SetModulus(integ);
Integer integ1(ExponentCON, sizeof(ExponentCON));
params.SetPublicExponent(integ1);
Integer integ2(PCON, sizeof(PCON));
params.SetPrime1(integ2);
Integer integ3(QCON, sizeof(QCON));
params.SetPrime2(integ3);
...
With that change in place, this error message from above disappears: error: n != p*q. But the CryptoMaterial: this object contains invalid values remains.
The second problem appears to be some of your private key parameters are not correct. You can see what tests InvertibleRSAFunction::Validate is performing by looking at the source code in rsa.cpp near line 250.
You can partially side step it by using Initialize that takes {n,e,d}, and let Initialize factor and solve:
Integer n(ModulusCON, sizeof(ModulusCON));
Integer e(ExponentCON, sizeof(ExponentCON));
Integer d(DCON, sizeof(DCON));
params.Initialize(n,e,d);
params.ThrowIfInvalid(prng, 3);
However, that results in:
InvertibleRSAFunction: input is not a valid RSA private key
Next, check p and q. #include <nbtheory.h>, and then:
Integer p(PCON, sizeof(PCON));
Integer q(QCON, sizeof(QCON));
cout << "P is prime: " << (VerifyPrime(prng, p, 10) ? "yes" : "no") << endl;
cout << "Q is prime: " << (VerifyPrime(prng, q, 10) ? "yes" : "no") << endl;
It results in:
$ ./test.exe
P is prime: yes
Q is prime: yes
At this point, it appears the problem is with one of the exponents.
Next, assume e is relatively prime to phi, #include <modarith.h>, and then:
Integer n(ModulusCON, sizeof(ModulusCON));
Integer p(PCON, sizeof(PCON));
Integer q(QCON, sizeof(QCON));
Integer e(ExponentCON, sizeof(ExponentCON));
Integer phi = (p-1)*(q-1);
ModularArithmetic ma(phi);
Integer d = ma.MultiplicativeInverse(e);
params.Initialize(n,e,d);
params.ThrowIfInvalid(prng, 3);
cout << "Validated parameters" << endl;
It results in:
$ ./test.exe
Validated parameters
So, the problem is with your d exponent. It is easy enough to print with cout << std::hex << d << endl:
$ ./test.exe
Validated parameters
174bcc91cc08400b470a9357e7fd23db2384e4219af4dedc56a0afdc3e796abd965f16c680954549
b4526f01a2c9d7b727620f3ba6c848f19bd9210650ae62593249d7a4e0522ad48aea559d4f6a1f3f
6ae9953bed7c947e273d455a4982523dd90640b0a25572ae8c5e064e39807ddf778af96afd492999
acc40919a4d4f601h
As you can see, the first octet of the calculated d is 0x17, but the first octet of the d you provided is 0x9B.
Also, you might want to do something like the following:
unsigned char data[20] = { 0x6F, 0x9F, 0x07, 0x04, 0xE2, 0x1A, 0xF7, 0xB8, 0xB2, 0x4F,
0x8D, 0x66, 0x49, 0xA1, 0x09, 0xA7, 0xB2, 0x22, 0x3C, 0xF9 };
const size_t req = signer.MaxSignatureLength(sizeof(data));
byte signature[req];
const size_t used = signer.SignMessage(prng, data, 20, signature);
// Trim 'signature' to 'used'