STM32L082xx AES128 CBC Hardware Encryption using ST's HAL - c

Decryption is not working as intended on STM32L082xx.
Here is my attempt: I'm using all zeros as iv and key and all 0x42 for plain text.
If I do the same thing in python I get a different result:
I get
{0x7c,0xA5,0xDA,0xBF,0x97,0x18....}
Note I'm using key and IV which are not influenced by endianness so the parameter CRYP_DATATYPE_8B should not be of influence. I have tested with CRYP_DATATYPE_16B, CRYP_DATATYPE_1B, CRYP_DATATYPE_32B with no success. Any ideas?
I've tried with EBC as well, without success.
void TEST_decryption(){
uint8_t encrypted[128]={0x00};
uint8_t decrypted[128]={0x00};
for(int i=0;i<128;i++){
decrypted[i]=0x42;
}
HAL_CRYP_AESCBC_Encrypt(&hcryp, decrypted, 128, encrypted, 10000);
if(encrypted[0]==0xbf){
while(1); //pass
}else{
while(1); //fail
}
}
uint8_t iv[16]={0x00};
uint8_t userKey[16]={0x00};
/* AES init function */
void MX_AES_Init(void)
{
hcryp.Instance = AES;
hcryp.Init.DataType = CRYP_DATATYPE_8B;
hcryp.Init.pKey = &userKey[0];
hcryp.Init.pInitVect = &iv[0];
if (HAL_CRYP_Init(&hcryp) != HAL_OK)
{
Error_Handler();
}
__HAL_RCC_AES_CLK_ENABLE();
}
Same thing in python:
from Crypto.Cipher import AES
key = binascii.unhexlify('0'*32)
IV = binascii.unhexlify('0'*32)
encryptor = AES.new(key, AES.MODE_CBC, IV=IV)
print(binascii.hexlify(encryptor.encrypt(binascii.unhexlify('42'*128))))
output:
b'bfdaa57cb812189713a950ad99478879ec40e0761ed6475fca829d311af9ab3c72099b8b728c5145dc58f99d4fd9f0466ea50ca1a42a98560407c8e716e32bab1db3b30baa48939e253343b3a20f519767bdbb0f9083540b0ba14d289673c8129ae4c31855bf8a35d8ee1a22ce26337c2987e46fde5b448d1021682f5999ab49'
see for live demo : https://repl.it/repls/ImpracticalWhitesmokeCodec
EDIT:
It was suggested to set the key size to 128bit, this is not possible in this lib:
/**
* #brief Writes the Key in Key registers.
* #param hcryp: pointer to a CRYP_HandleTypeDef structure that contains
* the configuration information for CRYP module
* #param Key: Pointer to Key buffer
* #note Key must be written as little endian.
* If Key pointer points at address n,
* n[15:0] contains key[96:127],
* (n+4)[15:0] contains key[64:95],
* (n+8)[15:0] contains key[32:63] and
* (n+12)[15:0] contains key[0:31]
* #retval None
*/
static void CRYP_SetKey(CRYP_HandleTypeDef *hcryp, uint8_t *Key)
{
uint32_t keyaddr = (uint32_t)Key;
hcryp->Instance->KEYR3 = __REV(*(uint32_t*)(keyaddr));
keyaddr+=4U;
hcryp->Instance->KEYR2 = __REV(*(uint32_t*)(keyaddr));
keyaddr+=4U;
hcryp->Instance->KEYR1 = __REV(*(uint32_t*)(keyaddr));
keyaddr+=4U;
hcryp->Instance->KEYR0 = __REV(*(uint32_t*)(keyaddr));
}

Related

In C code using OpenSSL 3, how do you convert DES_crypt to use EVP APIs?

As stated in OpenSSL 3, DES_crypt macro is deprecated.
We are encouraged to use the sequence EVP_EncryptInit_ex(3), EVP_EncryptUpdate(3) and EVP_EncryptFinal_ex(3) as stated here:
https://www.openssl.org/docs/manmaster/man3/DES_crypt.html
However, it doesn't state where the old parameters are going to be placed.
Where is the "buf" and "salt" going on which EVP API? Which is the *In, Key, IV value on the EVP APIs?
Which cipher should I use?
Sample of our old code:
char* theDESCrypt (const char *myBuf, const char *mySalt)
{
// some code here
// ...
return DES_crypt(myBuf, mySalt);
}
This is what I tried to use. Is the placement of buffer and salt correct on this one?
char* theDESCrypt (const char *myBuf, const char *mySalt)
{
int myRetLen = 0;
int myRetLenFinal = 0;
unsigned char *myRet = malloc(strlen(myBuf) + 1);
/* fetch cipher */
EVP_CIPHER *des_cipher = EVP_CIPHER_fetch(NULL, "DES", NULL);
/* setup context */
EVP_CIPHER_CTX *p_Ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(p_Ctx);
/* encrypt data */
EVP_EncryptInit_ex2(p_Ctx, des_cipher, NULL, mySalt, NULL);
EVP_EncryptUpdate(p_Ctx, myRet, &myRetLen, (unsigned char*)myBuf, strlen(myBuf)+1);
EVP_EncryptFinal_ex(p_Ctx, &myRet[myRetLen], &myRetLenFinal);
/* cleanup contexts*/
EVP_CIPHER_free(des_cipher);
EVP_CIPHER_CTX_free(p_Ctx);
return myBuf;
}
I tried using the above code and it fails our unit tests so I'm not sure if my changes are correct.

How can a callback function be executed within a driver on linux?

I have to modify a driver that runs on linux to add a callback function that is invoked from an external application. I already have the code implemented but when it is executed when the computer starts up, the system gives an error and is blocked.
This is my new code on the driver side:
typedef void (*callbackFunctionNoParams) ();
typedef struct T_EXI_CONFIGURE_BUS_
{
T_mode mode;
unsigned short NumeroRT;
T_SA_Enable SA_Enable;
unsigned short MINOR_CYCLE;
callbackFunctionNoParams callback;
} T_EXI_CONFIGURE_BUS;
typedef struct PciExiDev_
{
/**
* It represents a char device to read/write
*/
struct cdev charDevice;
/**
* IRQ assigned
*/
unsigned int irq;
/**
* Callback function to be invoked
*/
callbackFunctionNoParams callback;
/**
* Device control block
*/
EXI_DCB theDCB;
} PciExiDev;
Execution code on driver side:
static long exi_ioctl( struct file * filep, unsigned int cmd, unsigned long arg )
{
PciExiDev * aPciExiDev = (PciExiDev *) filep->private_data;
int result = SUCCESS;
int i, j;
long ret = 0;
//printk("Ioctl received %d.\n",cmd);
switch( cmd )
{
case FIO_EXI_CONFIGURE_BUS:
{
T_EXI_CONFIGURE_BUS config;
T_LISTA_TRANS *auxTrans1, *auxTrans2;
T_TRANSACTION_DCB *transDCB1;
T_OPI opi;
T_EXIS exis;
unsigned short dato;
unsigned short datolong[2];
unsigned short ControlBlock[12];
// printk("Exi configure bus initiated.\n");
printk("TNB. Exi ioctl CONFIGURE BUS.\n");
copy_from_user( &config, (T_EXI_CONFIGURE_BUS *) arg, sizeof(T_EXI_CONFIGURE_BUS) );
LeerDatos( &aPciExiDev->theDCB, OPI_ADDRESS, 1, (unsigned short *) &opi, 1 );
aPciExiDev->callback = config.callback;
aPciExiDev->theDCB.modo = config.mode;
aPciExiDev->theDCB.CicloMenor = config.MINOR_CYCLE;
(*aPciExiDev->callback)();
...
New code on client side:
if( theHWConfiguration.existExi() )
{
T_EXI_CONFIGURE_BUS bus_config;
// Configura la tarjega exi en modo Bus Controller.
bus_config.mode = BC;
bus_config.NumeroRT = 28;
bus_config.MINOR_CYCLE = 20;
bus_config.callback = &bcInterruptHandler2;
status = ioctl( A_fd_exi, FIO_EXI_CONFIGURE_BUS, reinterpret_cast<long>( &bus_config ) );
}
return status;
}
void C_EXI::bcInterruptHandler2()
{
std::cout<< "bcInterruptHandler2" << endl;
}
And this is the execution code result:
Crash Image
If someone could help me or propose an alternative way of doing this I would be very grateful.
Your callback is bound to run at kernel space and then you write it to std::cout. While going through your code, it tells that there is a conflict between kernel mode address space and userside process address space. This means that if the callback function is declared in the userside but instead called in the kernel space, there would be an error.
The crash image suggests that somewhere in your code you have an invalid pointer that you are trying to access. I am afraid I cannot debug your code with the little context provided, but I can give you some suggestions:
Try to avoid casting until is strictly necessary.
When you are casting to a pointer, double-check that this is exactly what you need to do.
In the error message there is also the call stack: take a look at it in order to identify where is the error.
You can simply add some printk("%p", pointer) in your code to debug the content of your variables.

how to use mbedtls_pk_verify to verify signature

How to use this function.
int mbedtls_pk_verify(mbedtls_pk_context * ctx, mbedtls_md_type_t md_alg, const unsigned char * hash, size_t hash_len, const unsigned char * sig, size_t sig_len)
So by calling the function like this mbedtls_pk_verify(&public_key_context, MBEDTLS_MD_SHA1, md, sizeof(md), signature, signature_lenght) how should I initialize md and how do I know what it is?
md is the message digest (usually a hash value).
To verify a signature, you have to feed the message through the same hash algorithm that was used when creating the signature. If the signature was created using SHA1, then you have to calculate the SHA1 hash value for the message you want to verify first. Then you pass this value together with its length (20 bytes in this case) to the function.
You can use the mbedtls library itself to calculate the message digest:
// Get the message digest info structure for SHA1
mbetdtls_md_info_t *mdinfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
char *md = malloc(mdinfo->size);
// Calculate the message digest for the data
mbedtls_md(mdinfo, data, datalen, md);
// Now verify the signature for the given hash of the data
int st = mbedtls_pk_verify(&public_key_context,
mdinfo->type, md, mdinfo->size,
signature, signature_length);
if (st != 0) {
// Signature invalid!
} else {
// Signature valid
}
free(md);
This should do what you need.

STM32 using callbacks to retrive data from USB CDC VCP

I have generated a project for USB CDC VCP using CubeMX and HAL and now I am trying to figure out how I can implement these two weak functions:
void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
These fuctions will be called inside HAL_PCD_IRQHandler. What I want to do is place some code inside them so I can retrive received data from host and also find out about end of transaction.
I have seen that CubeMX has reimplemented these weak functions inside usbd_conf.c like this:
/**
* #brief Data Out stage callback.
* #param hpcd: PCD handle
* #param epnum: Endpoint Number
* #retval None
*/
void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
{
USBD_LL_DataOutStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff);
}
/**
* #brief Data In stage callback..
* #param hpcd: PCD handle
* #param epnum: Endpoint Number
* #retval None
*/
void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
{
USBD_LL_DataInStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff);
}
I am wondered to know what do these two functions (USBD_LL_DataOutStage and USBD_LL_DataInStage) do? And how I can edit them to achieve my goal.
I encountered this same issue in STM32Cube_FW_L4_V1.10.0 and after looking at this and some other discussions decided to work around it by replacing the CDC DataIn handler with an alternate implementation that adds a call to CDC_TransmitReady_CB() to wake the transmit task:
// Modified CDC DataIn handler to invoke a callback (CDC_TransmitReady_CB) on TX ready
uint8_t altDataInHandler(USBD_HandleTypeDef *pdev, uint8_t epnum) {
USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
if (hcdc == NULL) return USBD_FAIL;
hcdc->TxState = 0;
CDC_TransmitReady_CB();
return USBD_OK;
}
void hackCdcClass() {
USBD_CDC.DataIn = altDataInHandler;
}
Ugly, but it works like a charm.

Structure to add a node id with correct type

I am trying to specify a node id on my server but don't understand the structure that I am supposed to follow. I followed the seemingly simple structure to change the node ID and didn't receive errors or warnings. I was successful in creating the nodes as seen below but not creating a node_id. I thought to add a simple node id I would follow the same structure and add the lines with $$$$ in them;
// opcua_server.c
#include "ua_types.h"
#define HANDLE_PDU1 15
const uint8_t EN_DISPLAYNAME_PDU1[] = "PDU1";
const UA_UTF8_string_t ENGLISH_TEXT[] = {
{0, 0}, {sizeof(EN_DISPLAYNAME_PDU1) - 1, EN_DISPLAYNAME_PDU1}};
void opcua_add_nodes(void) {
UA_Status_t status = 0;
// Add PDU1 Folder
UA_Folder_t PDU1;
UAServer_Init_config_structure_Folder(&PDU1);
PDU1.node_handle = HANDLE_PDU1;
PDU1.display_name_handle = HANDLE_PDU1;
UA_NodeId_Config_t randomHANDLE; // $$$$ Not creating node id
PDU1.node_id = randomHANDLE; // $$$$ Not creating node id
status = UAServer_Create_Folder(&PDU1);
if (status != 0) {
UA_SERVER_PRINTF("UAServer_Create_Folder returned: %d\n",
(uint16_t)status);
}
status = UAServer_Add_to_folder(folder.node_handle, PDU1.node_handle);
if (status != 0) {
UA_SERVER_PRINTF("UAServer_Add_to_objects_folder returned: %d\n",
(uint16_t)status);
}
}
// ua_types.h
typedef struct {
/**
* A mandatory unique identifier that identifies the node in the library.
* The value zero is invalid.
*/
uint32_t node_handle;
/**
* A mandatory unique identifier that allows the host to efficiently look up
* the
* node name text to display in a translate callback. The value zero is
* invalid.
*/
uint32_t display_name_handle;
/**
* An optional unique identifier that allows the host to efficiently look up
* the
* node description text to display in a translate callback. The value zero
* is
* invalid.
*/
uint32_t description_handle;
/**
* An optional visibility mask that restricts the visibility of the node
* depending
* on which user is logged in. The anonymous user is bit 0 and bits 1 - 15
* represent the corresponding users
*/
uint16_t user_visibility;
/**
* Specifies the namespace index for this node. The UA namespace is 0 and
* cannot
* be used. The default server namespace is 1. Other namespaces may be added
* to the configuration data structure.
*/
uint16_t namespace_index;
/**
* An optional parameter set that defines the NodeId for the node as a
* string
* or a GUID. If this parameter is set to default values then the SDK will
* assign
* an opaque node id to the node. Opaque node ids are easily decoded by the
* SDK
* and offer the best performance. Only populate this parameter set if your
* application requires it.
*/
UA_NodeId_Config_t node_id;
} UA_Base_t;
/*****************************************************************************/
/** \brief A configuration structure for Folder address space nodes.
*
*/
typedef UA_Base_t UA_Folder_t;
/*****************************************************************************/
/** \brief A configuration structure for View address space nodes.
*
*/
typedef UA_Folder_t UA_View_t;
/*****************************************************************************/
/** \brief A configuration structure for Method address space nodes.
*
*/
typedef struct {
/**
* Configuration common to all nodes
*/
UA_Base_t base_config;
/**
* The file size in bytes
*/
uint64_t size;
/**
* The file is writable
*/
bool_t writable;
/**
* An optional writable mask that restricts write access of the file
* depending
* on which user is logged in. The anonymous user is bit 0 and bits 1 - 15
* represent the corresponding users
*/
uint16_t user_writable;
} UA_File_t;
When you define PDU1, a node_id is already created and associated with it. You just need to access node_id and assign value for each of its elements.
Replace
UA_NodeId_Config_t randomHANDLE; // $$$$ Not creating node id
PDU1.node_id = randomHANDLE; // $$$$ Not creating node id
with
PDU1.node_id.identifier_type = xxxx; // xxxx, yyyy, zzz is whatever valid value for their type.
PDU1.node_id.string_identifier = yyyy;
PDU1.node_id.guid_identifier = zzzz;
Turns out I needed to specify the identifier type (which I did by looking at the identifier types) and set it equal to opcua_node_encoding_string. The result is a string node id that I set out to create.
//Add PDU1 Folder
UA_Folder_t PDU1;
UAServer_Init_config_structure_Folder(&PDU1);
PDU1.node_handle = HANDLE_PDU1;
PDU1.display_name_handle = HANDLE_PDU1;
PDU1.node_id.identifier_type = opcua_node_encoding_string;
const char TEST_STRING_ID2[] = "PDU1";
PDU1.node_id.string_identifier.length = sizeof(TEST_STRING_ID2) - 1;
PDU1.node_id.string_identifier.data = (uint8_t*)TEST_STRING_ID2;
status = UAServer_Create_Folder(&PDU1);
if (status != 0)
{
UA_SERVER_PRINTF("UAServer_Create_Folder returned: %d\n", (uint16_t)status);
}
status = UAServer_Add_to_folder(folder.node_handle, PDU1.node_handle);
if (status != 0)
{
UA_SERVER_PRINTF("UAServer_Add_to_objects_folder returned: %d\n", (uint16_t)status);
}

Resources