Related
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.
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];
}
}
I am looking for examples of calling the libtomcrypt ecc sign and verify code using inputs created using the OpenSSL command line. I have created private and public keys, using the prime256v1 curve, created a signature for a text file and verified it using the command line. I have pulled those keys and the signature in to my C++ test driver and used the libtomcrypt methods to import those. I created the hash of the text file using the openssl command line and put that into my test driver as well, but when I call the libtomcrypt ecc_verify_hash method, it fails to verify. At this point I have verified that the keys and the signature are importing correctly, so I'm not sure what I'm doing incorrectly.
Here is the code for my test driver. Any help with this would be greatly appreciated.
int main ()
{
ltc_mp = ltm_desc;
int idx = 0;
prng_state myPrng;
//unsigned char buf[4096];
//unsigned long b;
int stat, err;
ecc_key pubKey;
ecc_key privKey;
void* sig;
static unsigned char MSG_STR[] = "Test Message";
const int MSG_STR_LEN = 12;
static unsigned char DGST[] =
"C87D25A09584C040F3BFC53B5701199591DEB10BA";
const int DGST_LEN = 41;
// the DER forms of the keys
static unsigned char PRIV_KEY[] =
{
0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x4f,
0xab, 0xef, 0xfb, 0x6a, 0xe4, 0xcd, 0xd5, 0x83,
0xb7, 0x39, 0x57, 0xf5, 0x63, 0xd4, 0x60, 0xa6,
0x83, 0x26, 0x56, 0xb8, 0x1e, 0x78, 0xee, 0x3d,
0xf0, 0xa9, 0xe8, 0x3b, 0x2c, 0x34, 0xc1, 0xa0,
0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00,
0x04, 0x24, 0x72, 0xcb, 0x56, 0xb5, 0xae, 0x0a,
0x8e, 0x14, 0xc9, 0x89, 0x3d, 0xc8, 0x61, 0xb6,
0xed, 0x74, 0xa2, 0x2f, 0x15, 0xb7, 0x31, 0x14,
0xc6, 0xd5, 0x38, 0x71, 0xaa, 0x3f, 0x52, 0x5c,
0x8e, 0x3e, 0x59, 0xaa, 0x68, 0xcd, 0xcd, 0x8c,
0x2c, 0x63, 0x9b, 0xbc, 0x46, 0x79, 0x87, 0xd4,
0xdd, 0x4f, 0xbd, 0x97, 0x2b, 0xc2, 0x6a, 0x5d,
0x5c, 0xb5, 0xc7, 0x91, 0xaa, 0x15, 0xf8, 0x7c,
0x27
};
const int PRIV_KEY_LEN = 121;
static unsigned char PUB_KEY[] =
{
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
0x42, 0x00, 0x04, 0x24, 0x72, 0xcb, 0x56, 0xb5,
0xae, 0x0a, 0x8e, 0x14, 0xc9, 0x89, 0x3d, 0xc8,
0x61, 0xb6, 0xed, 0x74, 0xa2, 0x2f, 0x15, 0xb7,
0x31, 0x14, 0xc6, 0xd5, 0x38, 0x71, 0xaa, 0x3f,
0x52, 0x5c, 0x8e, 0x3e, 0x59, 0xaa, 0x68, 0xcd,
0xcd, 0x8c, 0x2c, 0x63, 0x9b, 0xbc, 0x46, 0x79,
0x87, 0xd4, 0xdd, 0x4f, 0xbd, 0x97, 0x2b, 0xc2,
0x6a, 0x5d, 0x5c, 0xb5, 0xc7, 0x91, 0xaa, 0x15,
0xf8, 0x7c, 0x27
};
const int PUB_KEY_LEN = 91;
static unsigned char OPENSSL_SIG[] =
{
0x30, 0x46, 0x02, 0x21, 0x00, 0xf3, 0x69, 0xd9,
0xaf, 0xad, 0xc7, 0x16, 0xac, 0x03, 0x9a, 0x5c,
0xae, 0xf7, 0x05, 0x86, 0x56, 0x24, 0x18, 0x09,
0x44, 0x3b, 0x07, 0xc9, 0xec, 0x6b, 0x72, 0x69,
0x18, 0x13, 0x10, 0xd7, 0x32, 0x02, 0x21, 0x00,
0xd5, 0xa1, 0x21, 0xc0, 0xf8, 0x5d, 0xb6, 0x6f,
0x46, 0x04, 0x9b, 0x2e, 0x1f, 0x96, 0xdc, 0x55,
0xd6, 0x5e, 0xc5, 0x14, 0x3c, 0x68, 0x70, 0x2a,
0x0c, 0x17, 0xad, 0xa1, 0xb8, 0x90, 0x0b, 0x07
};
const int OPENSSL_SIG_LEN = 72;
static unsigned char RAND_DATA[] =
"8e2582c586c37099c3126170e48352c5416c41ef44972ec0708ef2caab08"
"583f10b277276c2507dee509a0c492bb806108590db675f6d908025999a6"
"7cc049290fe4ea0beb6b62004cbc82c580e5c00fa360d2f55b565535f6ec"
"41a2adfe83ffc3a2007ee1e1ba03b94fb777350e1c3a2caffcf6434534bd"
"8d29c2b62a9abf279c9a419a53ae54c3f22d0d0886ced81d7422bfb2493b"
"2231d8aad890d80f1dc42280e6803fa768d2a5ebaf954e91713d9e0d93d9"
"9749b7b29d8deac683fa930d39758212020e6ebc850993804ce6a6a969a3"
"261ad870040634bb2c506c911e06b20ab723d03df239c39ecf210fa67ab2"
"54573c5531a475c3e7158eb89074a77238182b9b72d0f4d1407cffb6d59c"
"53ec202a5b36bd649b2a6f31ad182072d549402df2e1ed8289ad08973444"
"1269bbccca6bc8899e8a750329c35a1c7a19281bf90c1575ebc5c197e19f"
"5cc4e3f3dd5f507df6457a6e39b4609a774c11e5b15210d2a49ee3dab9e3"
"fb89966b8fa83cc9c3045f67001f8447d9d035c512f3c1c6332c701b403c"
"52d424d116b78426e013e34b1c3b7dbf87669970799a719971e1583135db"
"727ea7297bf76d093fc4648fca0cf79dbd6144963061838178d8b32efe9d"
"ee5ff58e9c6e6fc922b9e94631c7d76e06a0d28fc1c40d634e65e332ed4d"
"ff85293e5a9f103410c5e974775be91a773508293b5fcd8672a1a30640a7"
"9e42755d2b5229292848b6e56b540ba2d1bd2e7e5d61895293c5e9ee83ce"
"bba4194a3191fc9f0e6924835761c512d0515bb63b334c5e98dc0d43e7ce"
"3ee11e46872e4d8d767104189429f5cbcf4fd8db7c3022dd5e5ae99f5a48"
"e595fdff8d9db23e3beebef219341c53aa7e6da2fad750d2a648b58a0151"
"d0b029cf5d1900b65c047b95dd3004a048be4611d49f6a96f3f054b3c476"
"4b2e1a521a57e46b3df537d8a442726ce0e318fc356538e888d8825edfa2"
"4c3c42716a628c331db6261455c9c5d4b98d466f4831d28a6f9eb2abe758"
"38f81ca42e06f362d3d263a9c0e7bffaff635fc640434b02dd2f740a4737"
"6180bbe217436b86d481f83825e28b92ab3444b7c3326e18d796ac9c2633"
"4d9cc9310f29f42dfe4d9b53bd40b7f1433708c87ad412bbf8b646ec1468"
"76a8083e08029de1b84f7ebb606bf84a59dc7f1b46df2cc5c0ba5008761d"
"9da2344434f524e7ad6e648964a761907c1a0ccb1fdee645ad7aaf4ea0c8"
"68fd39ae75b2bc41b8c86f5adaa2105f84e9b187c5a887c9e0d726383564"
"34fe79c7ae0460cc7eddffe3f3109f83cf7a80ba8432ff9dd9f0b664cb6d"
"fc215800e4253d0bfa1a74df5f7b52f0d0ac9e3ce1af856058d7c2b117ae"
"7a5a7cfac7ea592e88c8417d16fe10f4545af981e937fb194c26a2e44f3f"
"40ea26dd794ad8f2d16f36eb27c6eaa6780925e8d7e96dfdde483800a9b3"
"95c7a358";
const int RAND_DATA_LEN = 2049;
ltm_desc.init(&privKey.k);
ltm_desc.init(&pubKey.pubkey.x);
ltm_desc.init(&pubKey.pubkey.y);
ltm_desc.init(&pubKey.pubkey.z);
ltm_desc.init(&sig);
// set up the random number generator
if ((err = register_prng(&yarrow_desc)) != CRYPT_OK) {
cout << "Failed to register prng. Err = " << err << endl;
return err;
}
if ((err = yarrow_start(&myPrng)) != CRYPT_OK) {
cout << "Yarrow failed to start! Err = " << err << endl;
return err;
}
if ((err = yarrow_add_entropy(RAND_DATA, RAND_DATA_LEN, &myPrng))
!= CRYPT_OK) {
cout << "Failed adding entropy Err = " << err << endl;
return err;
}
if ((err = yarrow_ready(&myPrng)) != CRYPT_OK) {
cout << "Failed to set state to ready. Err = " << err << endl;
return err;
}
// read in the private key information
if ((err = ecc_import_openssl(PRIV_KEY, PRIV_KEY_LEN, &privKey))
!= CRYPT_OK)
{
cout << "Failed to import private key, err =" << err << endl;
return err;
}
// read in the public key information
if ((err = ecc_import_openssl(PUB_KEY, PUB_KEY_LEN, &pubKey))
!= CRYPT_OK)
{
cout << "Failed to import public key, err =" << err << endl;
return err;
}
// try to verify the signature created using OpenSSL
// with the libtom verify method
if (((err = ecc_verify_hash(OPENSSL_SIG,
OPENSSL_SIG_LEN,
DGST,
DGST_LEN,
&stat,
&pubKey)) != CRYPT_OK)) {
cout << "Failed to verify OpenSSL signature using libtom. Error ="
<< err << endl;
return err;
} else if (stat == 0) {
cout << "Failed to verify OpenSSL signature using libtom. Error ="
<< err << endl;
return err;
}
else {
cout << "Successfully verifed OpenSSL signature using libtom."
<< endl;
}
ecc_free (&pubKey);
ecc_free (&privKey);
}
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];
}
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'