I am having problems with the last characters of the encrypted message that I am generating with the OpenSSL library and the AES 128 algorithm in CBC mode, these are the data I am using:
Message in Hex = "7b22494443223a2232363930393439376434222c22444553223a2256656e74616d656e7564656f222c22414d4f223a3530302c22444154223a313530383233303035383730362c22524546223a302c22434f4d223a312c22545950223a31392c2276223a7b224e414d223a2252616661656c56616c656e7a75656c614172656e6173222c22414343223a2235383732313233343536373836303132222c2242414e223a34303132372c22545943223a332c22444556223a22353532373139323132382f30227d7da"
Key128 in Hex = "dadf11e74d014a62d73ccadd9591442a"
Initialization Vector in Hex = "cab9da8940cd7dc9510c7249fe47c6e6"
This is the Code I'm using:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <math.h>
#include <assert.h>
#include <stdint.h>
#include <stdbool.h>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <locale>
#include <openssl/aes.h>
#include <openssl/des.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
using namespace std;
/* AES key for Encryption and Decryption */
const static unsigned char aes_key[16]={0xda, 0xdf, 0x11, 0xe7, 0x4d, 0x01, 0x4a, 0x62, 0xd7, 0x3c, 0xca, 0xdd, 0x95, 0x91, 0x44, 0x2a};
/* Print Encrypted and Decrypted data packets */
void print_data(const char *tittle, const void* data, int len)
{
printf("%s : ",tittle);
const unsigned char * p = (const unsigned char*)data;
int i = 0;
for (; i<len; ++i)
{
printf("%02X ", *p++);
}
printf("\n");
}
int main( )
{
/* Input data to encrypt */
unsigned char enc_out[235]={0x7b, 0x22, 0x49, 0x44, 0x43, 0x22, 0x3a, 0x22, 0x32, 0x36, 0x39, 0x30, 0x39, 0x34, 0x39, 0x37, 0x64, 0x34, 0x22, 0x2c, 0x22, 0x44, 0x45, 0x53, 0x22, 0x3a, 0x22, 0x56, 0x65, 0x6e, 0x74, 0x61, 0x6d, 0x65, 0x6e, 0x75, 0x64, 0x65, 0x6f, 0x22, 0x2c, 0x22, 0x41, 0x4d, 0x4f, 0x22, 0x3a, 0x35, 0x30, 0x30, 0x2c, 0x22, 0x44, 0x41, 0x54, 0x22, 0x3a, 0x31, 0x35, 0x30, 0x38, 0x32, 0x33, 0x30, 0x30, 0x35, 0x38, 0x37, 0x30, 0x36, 0x2c, 0x22, 0x52, 0x45, 0x46, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x43, 0x4f, 0x4d, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x54, 0x59, 0x50, 0x22, 0x3a, 0x31, 0x39, 0x2c, 0x22, 0x76, 0x22, 0x3a, 0x7b, 0x22, 0x4e, 0x41, 0x4d, 0x22, 0x3a, 0x22, 0x52, 0x61, 0x66, 0x61, 0x65, 0x6c, 0x56, 0x61, 0x6c, 0x65, 0x6e, 0x7a, 0x75, 0x65, 0x6c, 0x61, 0x41, 0x72, 0x65, 0x6e, 0x61, 0x73, 0x22, 0x2c, 0x22, 0x41, 0x43, 0x43, 0x22, 0x3a, 0x22, 0x35, 0x38, 0x37, 0x32, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x36, 0x30, 0x31, 0x32, 0x22, 0x2c, 0x22, 0x42, 0x41, 0x4e, 0x22, 0x3a, 0x34, 0x30, 0x31, 0x32, 0x37, 0x2c, 0x22, 0x54, 0x59, 0x43, 0x22, 0x3a, 0x33, 0x2c, 0x22, 0x44, 0x45, 0x56, 0x22, 0x3a, 0x22, 0x35, 0x35, 0x32, 0x37, 0x31, 0x39, 0x32, 0x31, 0x32, 0x38, 0x2f, 0x30, 0x22, 0x7d, 0x7d, 0xa};
/* Init vector */
unsigned char iv[16]={0xca, 0xb9, 0xda, 0x89, 0x40, 0xcd, 0x7d, 0xc9, 0x51, 0x0c, 0x72, 0x49, 0xfe, 0x47, 0xc6, 0xe6};
//memset(iv, 0x00, AES_BLOCK_SIZE);
/* Buffers for Encryption and Decryption */
unsigned char dec_out[400];
unsigned char aux_out[400];
memset(dec_out, 0, sizeof(dec_out));
memset(aux_out, 0, sizeof(aux_out));
/* AES-128 bit CBC Encryption */
AES_KEY enc_key, dec_key;
AES_set_encrypt_key(aes_key, sizeof(aes_key)*8, &enc_key);
AES_cbc_encrypt(enc_out, dec_out, sizeof(enc_out), &enc_key, iv, AES_ENCRYPT);
/* AES-128 bit CBC Decryption */
memset(iv, 0x00, AES_BLOCK_SIZE); // don't forget to set iv vector again, else you can't decrypt data properly
AES_set_decrypt_key(aes_key, sizeof(aes_key)*8, &dec_key); // Size of key is in bits
AES_cbc_encrypt(dec_out, aux_out, sizeof(enc_out), &dec_key, iv, AES_DECRYPT);
/* Printing and Verifying */
print_data("\n Original ",enc_out, sizeof(enc_out)); // you can not print data as a string, because after Encryption its not ASCII
print_data("\n Encrypted",dec_out, sizeof(enc_out));
print_data("\n Decrypted",aux_out, sizeof(dec_out));
return 0;
}
Apparently only the end of the chain is the one that is incorrect (the last 32 characters) the rest is fine, I have researched a bit and everything points to what is the type of padding of the text but according to what I read it is already paddated with PKCS5 (which is the padding I need in fact) so I can not see what the error is.
The Correct Encryption = EFC063DD33406D424D359809695D0B1E2D65027E803962C6A115DF7CCABEEB0C8C358830E556ED23943FA4F02E6461D235EF913CFCE5519F7CE2279DD07D3C4054D045827D5D7D9FE94DA3C5B718A24E79539B3FFC1E68E4C3FF441EEA176F61EE3D7B33B622E3069D95815F6407FBC79342BB972A2DDE4E50FDE9302BDE4409B7D2BD388AB6A043B9EF236D982937D8537F954564FF4134BD8A6EAB994FE4C29E9DC4E54D53A561A4688C45C90961EDB1763B6EF6C86B593C7E16FDF35C49CE16B1E6948BB1EAE6A8692326A019960B
The Output of the Program = EFC063DD33406D424D359809695D0B1E2D65027E803962C6A115DF7CCABEEB0C8C358830E556ED23943FA4F02E6461D235EF913CFCE5519F7CE2279DD07D3C4054D045827D5D7D9FE94DA3C5B718A24E79539B3FFC1E68E4C3FF441EEA176F61EE3D7B33B622E3069D95815F6407FBC79342BB972A2DDE4E50FDE9302BDE4409B7D2BD388AB6A043B9EF236D982937D8537F954564FF4134BD8A6EAB994FE4C29E9DC4E54D53A561A4688C45C90961EDB1763B6EF6C86B593C7E16FDF35C49CE608E3F73FC8E3DDF1D3BCF40B3DFACD00B732A9FCC10F6E0FB18E126A1C21A082D7A4F053F131A9329474D
I understand that the code has many improvements and I am not contemplating the desencryption, but at the moment I do not need it.
AES_cbc_encrypt is encrypting using the low level primitives. It does not perform any kind of padding. Here is a link to the underlying CBC source code that the AES CBC code directly calls: https://github.com/openssl/openssl/blob/master/crypto/modes/cbc128.c - no padding indicated at all.
The real question is why you would use ill-described, low level implementation functions rather than the EVP API that OpenSSL itself advocates. You may think that the lower level primitives are more performant, but this may not be the case if e.g. AES-NI is deployed; the calling overhead will be minimal compared to the cipher itself anyway.
The enc_out-array is dimensioned for 235 bytes, but is only initialized explicitly for 200 bytes, i.e. the remaining bytes are implicitly initialized with 0x00-values. This corresponds to a ciphertext with a length of 240 bytes (= 15 x 16 bytes). Therefore, the current code returns a ciphertext with a length of 240 bytes whose last three blocks are:
608E3F73FC8E3DDF1D3BCF40B3DFACD0 0B732A9FCC10F6E0FB18E126A1C21A08 2D7A4F053F131A9329474DE44DA772BC
This corresponds to an implicit padding with 0x00-values. The last 5 bytes are missing in the posted ciphertext, which is because the length of the plaintext (instead of the ciphertext) is used for the output.
Most likely only the first 200 bytes should be encrypted. This would correspond to a ciphertext with a length of 208 bytes (= 13 x 16 bytes), which is just the length of the expected ciphertext. For this, the size of the enc_out-array must be reduced from 235 to 200, or even better, the size should not be explicitly specified at all.
Then a two blocks shorter, but otherwise identical ciphertext is generated, which differs from the expected ciphertext only in the last block, which is now caused only by the missing PKCS7-padding.
Related
I am using the c code generated by asn1c from the MAP protocol specification (i.e., the corresponding ASN1 files). Please consider the following sample code:
// A real byte stream of a MAP message:
unsigned char packet_bytes[] = {
0xa2, 0x60, 0x02, 0x01, 0x00, 0x30, 0x5b, 0x02,
0x01, 0x38, 0xa3, 0x56, 0xa1, 0x54, 0x30, 0x52,
0x04, 0x10, 0x7a, 0x0e, 0x1f, 0xef, 0x73, 0x77,
0xbe, 0xb0, 0x9d, 0x6f, 0x23, 0x13, 0xfb, 0xc2,
0x32, 0xa6, 0x04, 0x08, 0x65, 0xda, 0x19, 0x1e,
0x18, 0x4b, 0x04, 0x99, 0x04, 0x10, 0x47, 0xe1,
0x36, 0x82, 0xe9, 0xb3, 0xf3, 0x54, 0x76, 0x67,
0x1d, 0xe4, 0xed, 0x25, 0xc8, 0x76, 0x04, 0x10,
0x37, 0x1d, 0x80, 0x82, 0xde, 0xec, 0x70, 0x51,
0xc6, 0xcd, 0x08, 0xc9, 0x30, 0x64, 0xc6, 0x54,
0x04, 0x10, 0x82, 0xbc, 0x2d, 0xdb, 0x1d, 0x92,
0x82, 0x34, 0x55, 0xbc, 0xeb, 0x87, 0x72, 0xf3,
0x90, 0xce
};
// Initializing ...
MAP_Component_t _pdu, *pdu = &_pdu;
memset(pdu, 0, sizeof(*pdu));
// Decoding:
asn_dec_rval_t dec_ret = ber_decode(NULL, &asn_DEF_MAP_Component, (void **) &pdu, MAP_packet_bytes, sizeof(MAP_packet_bytes));
The invokeId and opCode parameters are truely detected, and the parser gives us a buffer named as invokeParameters which is of type ANY.
GSM Mobile Application
Component: invoke (1)
invoke
invokeID: -70
opCode: localValue (0)
invokeParameters: ....
The question is how to decode (parse) invokeParameters?
GSM Mobile Application
Component: returnResultLast (2)
returnResultLast
invokeID: 0
resultretres
opCode: localValue (0)
localValue: sendAuthenticationInfo (56)
authenticationSetList: quintupletList (1)
quintupletList: 1 item
AuthenticationQuintuplet
rand: 7a0e1fef7377beb09d6f2313fbc232a6
xres: 65da191e184b0499
ck: 47e13682e9b3f35476671de4ed25c876
ik: 371d8082deec7051c6cd08c93064c654
autn: 82bc2ddb1d92823455bceb8772f390ce
The invokeId and opCode parameters are truely detected, and the parser gives us a buffer named as invokeParameters which is of type ANY.
The question is how to decode (parse) invokeParameters?
You need to call ber_decode with the appropriate type (depending on the operation code) and the content of the ANY buffer. From ANY.h
typedef struct ANY {
uint8_t *buf; /* BER-encoded ANY contents */
int size; /* Size of the above buffer */
asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */
} ANY_t;
In your case it should be something like
SendAuthenticationInfoArg_t _sai, *sai = &_sai;
memset(sai, 0, sizeof(*sai));
asn_dec_rval_t dec_ret = ber_decode(NULL,
&asn_DEF_SendAuthenticationInfoArg,
(void **) &sai,
_pdu.invoke.invokeparameter->buf,
_pdu.invoke.invokeparameter->size);
I was playing around with xxd -i this weekend to convert binary files into unsigned char arrays, thinking I could use it to embed small binary files into arduino code for transmission on mini web and other services. Problem is, it seems the functions in the existing libraries either expect const char *, string or File data types. (and of course, unsigned char arrays aren't really char arrays so they don't convert well to strings)
Not being someone familiar with c++ in depth (still learning) I'm wondering if there is any easy way to stream the unsigned char array created from xxd over the ESP webserver code or something similar? And/or is there a better way to encode a binary file for sending from same?
I'm basically looking at building primarily 'rest' based esp devices, but wanted to have some kind of very rudimentary html/js interface to directly connect and configure basic functionality or get basic telemetry back from the devices. My thought was that with very streamline html/js coding combined with a minify followed by a gzip, I could put such basic primitive interfaces directly into the code in a binary array to be served up when needed. For more complex devices, I've gotten the sd card webserver to work fine, but would prefer not to have to use sd cards for all applications. Before I go back to relying upon html content in huge strings or function calls full of concatenations/prints, I'd like to try to get this to work as another option.
Any help is appreciated.
--- EDITED ---
Example from xxd -i
unsigned char index_htm_gz[] = {
0x1f, 0x8b, 0x08, 0x08, 0x25, 0x38, 0xcf, 0x58, 0x02, 0x03, 0x69, 0x6e,
0x64, 0x65, 0x78, 0x2e, 0x6d, 0x69, 0x6e, 0x2e, 0x68, 0x74, 0x6d, 0x00,
0x5d, 0x8d, 0xb1, 0x6a, 0xc4, 0x30, 0x10, 0x44, 0x7b, 0x7d, 0xc5, 0xe6,
0x03, 0xce, 0x4a, 0xc0, 0x98, 0x14, 0x2b, 0x35, 0x97, 0x40, 0xba, 0x4b,
0x61, 0x08, 0x29, 0x65, 0x7b, 0x2d, 0x2d, 0xb7, 0xb2, 0x8d, 0xb4, 0xc9,
0x91, 0xbf, 0x8f, 0x42, 0xba, 0x83, 0x61, 0x18, 0x1e, 0x33, 0x0c, 0x3e,
0xbc, 0x5c, 0xce, 0xe3, 0xe7, 0xfb, 0x2b, 0x24, 0xcd, 0xe2, 0xf1, 0xcf,
0x41, 0xc2, 0x16, 0x1d, 0x6d, 0x1e, 0x33, 0x69, 0x80, 0x39, 0x85, 0x52,
0x49, 0xdd, 0x97, 0xae, 0xa7, 0x67, 0x8f, 0xca, 0x2a, 0xe4, 0xdf, 0x48,
0x64, 0x07, 0xf3, 0xb1, 0x17, 0x59, 0xd0, 0xfe, 0x33, 0x14, 0xde, 0xae,
0x90, 0x0a, 0xad, 0x6e, 0xae, 0xd5, 0xe6, 0xc0, 0x5b, 0xd7, 0x02, 0x14,
0x12, 0x57, 0xf5, 0x47, 0xa8, 0x26, 0x22, 0x6d, 0x1f, 0x4f, 0x77, 0xf3,
0x06, 0xf0, 0xf0, 0x63, 0xe2, 0x0a, 0x4d, 0x01, 0x6e, 0x34, 0xc1, 0x11,
0x22, 0x75, 0x68, 0x0f, 0x8f, 0x9c, 0x23, 0x4c, 0x7b, 0x59, 0xa8, 0xb8,
0x47, 0x48, 0xc4, 0x31, 0xa9, 0x1b, 0x7a, 0x30, 0xb5, 0xcc, 0x8e, 0x73,
0xab, 0x55, 0xfb, 0x3d, 0x45, 0xda, 0x87, 0xbe, 0x8b, 0xbc, 0xc2, 0x8d,
0x17, 0x4d, 0xad, 0xe0, 0x8d, 0xf9, 0x05, 0x3d, 0x2a, 0xb3, 0xe0, 0xdd,
0x00, 0x00, 0x00
};
unsigned int index_htm_gz_len = 207;
As mentioned in comments, one thing I tried was switching the type from unsigned char to const char then running through the following:
void sendCompressed(String content_type, const char * content, unsigned int len) {
webServer.setContentLength(len);
webServer.sendHeader("Content-Encoding", "gzip");
webServer.send(200, content_type, String(content));
}
In such a case, my handleRoot function would call the sendCompressed with the data from the header:
void function handleRoot() {
sendCompressed("text/html", index_htm_gz, index_htm_gz_len);
}
It compiled without errors, but outputs nothing. I would also expect this not to be ideal as String data is generally 7-bit and obviously, binary compressed data is not.
This binary serve worked for me:
const char favicon[1344] = {
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49,
... // ( way shortened )
0x44, 0xae, 0x42, 0x60, 0x82
};
void handleFavicon() {
server.send_P(200, "image/x-icon", favicon, sizeof(favicon));
}
server.on("/favicon.ico", handleFavicon); // in setup() or something like it
you might need to adjust your gzip header, but this method of embeding binary content works enough to show the right icon, i'd imaging a gzip stream works the same way...
I need to do AES-128/CTR encryption/decryption using Intel TinyCrypt (written in C). I took a look at the test case provided by the library, but still have a few questions on how to use it. Here's the code of the test case (see the complete source code here):
/*
* NIST SP 800-38a CTR Test for encryption and decryption.
*/
uint32_t test_1_and_2(void)
{
const uint8_t key[16] = {
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88,
0x09, 0xcf, 0x4f, 0x3c
};
uint8_t ctr[16] = {
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
0xfc, 0xfd, 0xfe, 0xff
};
const uint8_t plaintext[64] = {
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11,
0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46,
0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b,
0xe6, 0x6c, 0x37, 0x10
};
const uint8_t ciphertext[80] = {
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
0xfc, 0xfd, 0xfe, 0xff, 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26,
0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce, 0x98, 0x06, 0xf6, 0x6b,
0x79, 0x70, 0xfd, 0xff, 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e, 0x5b, 0x4f, 0x09, 0x02,
0x0d, 0xb0, 0x3e, 0xab, 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1,
0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee
};
struct tc_aes_key_sched_struct sched;
uint8_t out[80];
uint8_t decrypted[64];
uint32_t result = TC_PASS;
TC_PRINT("CTR test #1 (encryption SP 800-38a tests):\n");
(void)tc_aes128_set_encrypt_key(&sched, key);
(void)memcpy(out, ctr, sizeof(ctr));
if (tc_ctr_mode(&out[TC_AES_BLOCK_SIZE], sizeof(plaintext),
plaintext, sizeof(plaintext), ctr, &sched) == 0) {
TC_ERROR("CTR test #1 (encryption SP 800-38a tests) failed in %s.\n", __func__);
result = TC_FAIL;
goto exitTest1;
}
result = check_result(1, ciphertext, sizeof(out), out, sizeof(out));
TC_END_RESULT(result);
TC_PRINT("CTR test #2 (decryption SP 800-38a tests):\n");
(void) memcpy(ctr, out, sizeof(ctr));
if (tc_ctr_mode(decrypted, sizeof(decrypted), &out[TC_AES_BLOCK_SIZE],
sizeof(decrypted), ctr, &sched) == 0) {
TC_ERROR("CTR test #2 (decryption SP 800-38a tests) failed in %s.\n", __func__);
result = TC_FAIL;
goto exitTest1;
}
result = check_result(2, plaintext, sizeof(plaintext),
decrypted, sizeof(plaintext));
exitTest1:
TC_END_RESULT(result);
return result;
}
My input data is a double pointer (2D array) and I'd like to keep it that way:
uint8_t ** mydata = gen_rand_data(const size_t height, const size_t length);
Here's my understanding (correct me if I'm wrong):
AES-128 is a block cipher, with 128-bit key.
CTR mode makes the AES-128 a stream cipher and lets encrypt/decrypt data with arbitrary size.
Having AES-128/CTR, the output (ciphertext) has the same length as plaintext.
To improve the security, it's better to use 128-bit IV (nonce) for encryption.
Now here's my questions:
Can I say ctr (initial counter, right?) is our IV?
Why the ciphertext (expected value) and out (calculated value) are 128-bit bigger than plaintext?
Why the code copies ctr value in the beginning of out?
To encrypt mydata (2D array), I just need to loop over it and simple feed bytes from mydata to tc_ctr_mode, regardless of the dimension of mydata. Is this correct?
Thanks in advance.
The counter is generally supplied as the iv parameter if there is no specific counter parameter.
The output is 16-bytes longer because the counter is prepended, the counter is block sized and AES has a 16-byte block size..
The counter value is not secret and is needed for decryption. Since the same key/counter combination can never be reused if the key is going to be reused (a common situation) the counter must be unique and thus not pre-shared. The general answer is to pre-pend the counter value to the encrypted data.
Yes providing the decryption end knows a priori the array dimensions. But is is probably better to use some form of marshaling to preserve the array shape.
I am attempting to compile the mbedtls for the mbed LPC1768 microcontroller using the gcc4mbed offline compiler.
I would like to get a basic AESCBC encrypt and decrypt example to learn from;
I am not sure if I am missing an include or if I didn't instantiate correctly. error:
error: 'aes_setkey' was not declared in this scope
I am working from this guide in the knowledge base: knowledge base
Code:
#include "mbed.h"
#include "crypto/include/polarssl/config.h"
#include "crypto/include/polarssl/platform.h"
#include "crypto/include/polarssl/aes.h"
DigitalOut myled(LED1);
aes_context aes;
Serial pc(USBTX, USBRX);
unsigned char key[32] = { 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31 };
unsigned char iv[16] = { 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31 };
unsigned char input[128] = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 };
unsigned char output[128];
size_t input_len = 40;
size_t output_len = 0;
int main() {
pc.baud(115200);
aes_setkey(&aes, key, 256);
aes_crypt_cbc(&aes, AES_ENCRYPT, 24, iv, input, output);
pc.printf("\r\n\r\nFirst run\r\n");
/*while(1) {
myled = 1;
wait(0.2);
myled = 0;
wait(0.2);
}*/
}
Looking at their source (https://tls.mbed.org/aes-source-code linked from the page you linked) I don't see any aes_setkey. But I do see aes_setkey_enc and aes_setkey_dec. So perhaps that example is wrong or outdated. You could try using those other functions and see if they do what you want.
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];
}