Linux AES Driver for Zynq Ultrascale+ MPSoC & Versal
...
HW IP Features
- Supports Symmetric key algorithm.
Features supported in driver
- Supports Symmetric key algorithm.
PLM Configuration
For Versal, in order to use this driver, the BSP of PLM must be configured to enable XSECURE_NONSECURE_IPI_ACCESS macro in XilSecure library.
...
Code Block | ||||
---|---|---|---|---|
| ||||
/****************************************************************************** * Copyright (c) 2021 Xilinx, Inc. All rights reserved. * SPDX-License-Identifier: MIT ******************************************************************************/ #include <stdio.h> #include <unistd.h> #include <sys/socket.h> #include <linux/if_alg.h> #include <linux/socket.h> #include <string.h> #ifndef SOL_ALG #define SOL_ALG 279 #endif #ifndef#define ALG_SET_KEY_TYPE #define ALG_SET_KEY_TYPE 6 #endif_SIZE 1 #define KEY_SIZE 32 #define IV_SIZE 12 #define GCM_TAG_SIZE 16 #define DATA_SIZE 68 #define AES_KUP_KEY 0 #define AES_DEVICE_KEY 1 #define AES_PUF_KEY 2 int main(void) { int len = DATA_SIZE + GCM_TAG_SIZE; int opfd; int tfmfd; struct sockaddr_alg sa = { .salg_family = AF_ALG, .salg_type = "aead", .salg_name = "gcm(aes)" }; struct msghdr msg = {}; struct cmsghdr *cmsg; char cbuf[CMSG_SPACE(4) + CMSG_SPACE(1024)] = {0}; char buf[len]; struct af_alg_iv *iv; struct iovec iov; int i; __u8 key[] = { /* Key to be used for the AES encryption and decryption */ 0xF8, 0x78, 0xB8, 0x38, 0xD8, 0x58, 0x98, 0x18, 0xE8, 0x68, 0xA8, 0x28, 0xC8, 0x48, 0x88, 0x08, 0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00 }; __u8 key_type[] = {AES_KUP_KEY}; __u8 usr_iv[] = { /* Initialization Vector for the AES encryption and decryption */ 0xD2, 0x45, 0x0E, 0x07, 0xEA, 0x5D, 0xE0, 0x42, 0x6C, 0x0F, 0xA1, 0x33 }; __u8 input[DATA_SIZE] = { /* The Input Data should be multiples of 4 bytes */ 0x12, 0x34, 0x56, 0x78, 0x08, 0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00, 0xA5, 0xDE, 0x08, 0xD8, 0x58, 0x98, 0xA5, 0xA5, 0xFE, 0xDC, 0xA1, 0x01, 0x34, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0x09, 0x87, 0x65, 0x43, 0x21, 0x12, 0x34, 0x87, 0x65, 0x41, 0x24, 0x45, 0x66, 0x79, 0x87, 0x43, 0x09, 0x71, 0x36, 0x27, 0x46, 0x38, 0x01, 0xAD, 0x10, 0x56 }; tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0); bind(tfmfd, (struct sockaddr *)&sa, sizeof(sa)); /* Set key type to use for AES operation */ setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY_TYPE, key_type, 0 KEY_TYPE_SIZE); /* Set key for AES operation */ setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, key, KEY_SIZE); opfd = accept(tfmfd, NULL, 0); msg.msg_control = cbuf; msg.msg_controllen = sizeof(cbuf); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_ALG; cmsg->cmsg_type = ALG_SET_OP; cmsg->cmsg_len = CMSG_LEN(4); /* Set the AES operation type Encrption/Decryption */ *(__u32 *)CMSG_DATA(cmsg) = ALG_OP_ENCRYPT; cmsg = CMSG_NXTHDR(&msg, cmsg); cmsg->cmsg_level = SOL_ALG; cmsg->cmsg_type = ALG_SET_IV; cmsg->cmsg_len = CMSG_LEN(1024); iv = (void *)CMSG_DATA(cmsg); iv->ivlen = IV_SIZE; memcpy(iv->iv, usr_iv, IV_SIZE); iov.iov_base = input; iov.iov_len = len; msg.msg_iov = &iov; msg.msg_iovlen = 1; /* Send AES encryption request to AES driver */ sendmsg(opfd, &msg, 0); /* Read the output buffer for encrypted data and gcm-tag */ read(opfd, buf, len); printf("Data Out:\r\n"); for (i = 0; i < len - GCM_TAG_SIZE; i++) { printf("%02x", (unsigned char)buf[i]); } printf("\n"); printf("GCM TAG:\r\n"); for (i = len - GCM_TAG_SIZE; i < len; i++) { printf("%02x", (unsigned char)buf[i]); } printf("\n"); printf("Input:\r\n"); for (i = 0; i < len - GCM_TAG_SIZE; i++) { printf("%02x", (unsigned char)input[i]); } close(opfd); close(tfmfd); return 0; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
/****************************************************************************** * Copyright (c) 2021 Xilinx, Inc. All rights reserved. * SPDX-License-Identifier: MIT ******************************************************************************/ #include <stdio.h> #include <unistd.h> #include <sys/socket.h> #include <linux/if_alg.h> #include <linux/socket.h> #include <string.h> #ifndef SOL_ALG #define SOL_ALG 279 #endif #ifndef ALG_SET_KEY_TYPE #define ALG_SET_KEY_TYPE 6 #endif _SIZE 1 #define KEY_SIZE 32 #define IV_SIZE 12 #define GCM_TAG_SIZE 16 #define DATA_SIZE 68 #define AES_KUP_KEY 0 #define AES_DEVICE_KEY 1 #define AES_PUF_KEY 2 int main(void) { int len = DATA_SIZE + GCM_TAG_SIZE; int opfd; int tfmfd; struct sockaddr_alg sa = { .salg_family = AF_ALG, .salg_type = "aead", .salg_name = "gcm(aes)" }; struct msghdr msg = {}; struct cmsghdr *cmsg; char cbuf[CMSG_SPACE(4) + CMSG_SPACE(1024)] = {0}; char buf[len]; struct af_alg_iv *iv; struct iovec iov; int i; __u8 key[] = { /* Key to be used for the AES encryption and decryption */ 0xF8, 0x78, 0xB8, 0x38, 0xD8, 0x58, 0x98, 0x18, 0xE8, 0x68, 0xA8, 0x28, 0xC8, 0x48, 0x88, 0x08, 0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00 }; __u8 key_type[] = {AES_KUP_KEY}; __u8 usr_iv[] = { /* Initialization Vector for the AES encryption and decryption */ 0xD2, 0x45, 0x0E, 0x07, 0xEA, 0x5D, 0xE0, 0x42, 0x6C, 0x0F, 0xA1, 0x33 }; __u8 input[DATA_SIZE + GCM_TAG_SIZE] = { /* The Input Data should be multiples of 4 bytes */ 0xed, 0xaa, 0xe8, 0x26, 0xb6, 0xb4, 0x16, 0xbb, 0xd2, 0x81, 0x58, 0x79, 0x69, 0x20, 0x58, 0xf1, 0x6d, 0xf1, 0x13, 0x3c, 0x72, 0x22, 0xd5, 0x49, 0x14, 0x1d, 0xcf, 0xef, 0x0f, 0xaf, 0x01, 0xaf, 0xd6, 0x43, 0x3f, 0x9d, 0xc6, 0xbb, 0x7d, 0x32, 0x07, 0xd4, 0xa5, 0x31, 0xcd, 0xf5, 0xe6, 0xeb, 0xf5, 0x96, 0xbd, 0x4a, 0x0c, 0x3d, 0x43, 0x03, 0x13, 0xce, 0x88, 0xe2, 0xb9, 0xe1, 0x6c, 0x08, 0x6e, 0x63, 0x3d, 0x24, 0xb5, 0x2b, 0x80, 0xcd, 0x51, 0x17, 0xaf, 0xb4, 0x7b, 0x11, 0x6d, 0x4a, 0x8f, 0x89, 0xcf, 0x75 }; tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0); bind(tfmfd, (struct sockaddr *)&sa, sizeof(sa)); /* Set key type to use for AES operation */ setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY_TYPE, key_type, 0KEY_TYPE_SIZE); /* Set key for AES operation */ setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, key, KEY_SIZE); opfd = accept(tfmfd, NULL, 0); msg.msg_control = cbuf; msg.msg_controllen = sizeof(cbuf); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_ALG; cmsg->cmsg_type = ALG_SET_OP; cmsg->cmsg_len = CMSG_LEN(4); /* Set the AES operation type Encrption/Decryption */ *(__u32 *)CMSG_DATA(cmsg) = ALG_OP_DECRYPT; cmsg = CMSG_NXTHDR(&msg, cmsg); cmsg->cmsg_level = SOL_ALG; cmsg->cmsg_type = ALG_SET_IV; cmsg->cmsg_len = CMSG_LEN(1024); iv = (void *)CMSG_DATA(cmsg); iv->ivlen = IV_SIZE; memcpy(iv->iv, usr_iv, IV_SIZE); iov.iov_base = input; iov.iov_len = len; msg.msg_iov = &iov; msg.msg_iovlen = 1; /* Send AES decryption request to AES driver */ sendmsg(opfd, &msg, 0); /* Read the output buffer for decrypted data */ read(opfd, buf, len - GCM_TAG_SIZE); printf("Data Out:\r\n"); for (i = 0; i < len - GCM_TAG_SIZE; i++) { printf("%02x", (unsigned char)buf[i]); } printf("\n"); close(opfd); close(tfmfd); return 0; } |
...
for device key and puf key respectively.
And In set socket options like belowcalls, second function call is optional for device key/puf key usage.
/* Set key type to use for AES operation */
setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY_TYPE, key_type, 0KEY_TYPE_SIZE);
/* Set key for AES operation */
setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, NULLkey, 0KEY_SIZE);
Expected Output
Code Block | ||
---|---|---|
| ||
root@xilinx-zcu102-2019_1:/run/media/mmcblk0# ./Enc Data Out: edaae826b6b416bbd2815879692058f16df1133c7222d549141dcfef0faf01afd6433f9dc6bb7d3207d4a531cdf5e6ebf596bd4a0c3d430313ce88e2b9e16c086e633d24 GCM TAG: b52b80cd5117afb47b116d4a8f89cf75 Input: 1234567808f070b030d0509010e060a020c0408000a5de08d85898a5a5fedca10134abcdef12345678900987654321123487654124456679874309713627463801ad1056root@xilinx-zcu102-2019_1:/run/media/mmcblk0# ./Dec Data Out: 1234567808f070b030d0509010e060a020c0408000a5de08d85898a5a5fedca10134abcdef12345678900987654321123487654124456679874309713627463801ad1056 |
Please note as the data provided in user space will be located in virtual space, linux driver before handing off to ATF converts the data buffers to physical address.
Userspace examples for Versal
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> #include <unistd.h> #include <sys/socket.h> #include <linux/if_alg.h> #include <linux/socket.h> #include <string.h> #ifndef SOL_ALG #define SOL_ALG 279 #endif #define KEY_SIZE 32 #define AAD_SIZE 16 #define IV_SIZE 12 #define GCM_TAG_SIZE 16 #define DATA_SIZE 68 #define VERSAL_AES_USER_KEY_0 12 int main(void) { int len = AAD_SIZE + DATA_SIZE + GCM_TAG_SIZE; int opfd; int tfmfd; struct sockaddr_alg sa = { .salg_family = AF_ALG, .salg_type = "aead", .salg_name = "gcm(aes)" }; struct msghdr msg = {}; struct cmsghdr *cmsg; char cbuf[CMSG_SPACE(4) + CMSG_SPACE(1024) + CMSG_SPACE(1024)] = {0}; char buf[len]; struct af_alg_iv *iv; struct iovec iov; int i; __u8 key[] = { 0xF8, 0x78, 0xB8, 0x38, 0xD8, 0x58, 0x98, 0x18, 0xE8, 0x68, 0xA8, 0x28, 0xC8, 0x48, 0x88, 0x08, 0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00 }; __u8 key_type[] = {VERSAL_AES_USER_KEY_0}; __u8 usr_iv[] = { 0xD2, 0x45, 0x0E, 0x07, 0xEA, 0x5D, 0xE0, 0x42, 0x6C, 0x0F, 0xA1, 0x33 }; __u8 input[] = { /* First1bytes are AAD data */ 0x67, 0xe2, 0x1c, 0xf3, 0xcb, 0x29, 0xe0, 0xdc, 0xbc, 0x4d, 0x8b, 0x1d, 0x0c, 0xc5, 0x33, 0x4b, /* Cipher text */ 0xed, 0xaa, 0xe8, 0x26, 0xb6, 0xb4, 0x16, 0xbb, 0xd2, 0x81, 0x58, 0x79, 0x69, 0x20, 0x58, 0xf1, 0x6d, 0xf1, 0x13, 0x3c, 0x72, 0x22, 0xd5, 0x49, 0x14, 0x1d, 0xcf, 0xef, 0x0f, 0xaf, 0x01, 0xaf, 0xd6, 0x43, 0x3f, 0x9d, 0xc6, 0xbb, 0x7d, 0x32, 0x07, 0xd4, 0xa5, 0x31, 0xcd, 0xf5, 0xe6, 0xeb, 0xf5, 0x96, 0xbd, 0x4a, 0x0c, 0x3d, 0x43, 0x03, 0x13, 0xce, 0x88, 0xe2, 0xb9, 0xe1, 0x6c, 0x08, 0x6e, 0x63, 0x3d, 0x24, /* GCM TAG */ 0xec, 0x5a, 0xfd, 0x6b, 0x11, 0x8c, 0xff, 0x14, 0xfb, 0x63, 0x16, 0x75, 0xa5, 0x84, 0x0b, 0x4c }; tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0); printf("BIND \n"); bind(tfmfd, (struct sockaddr *)&sa, sizeof(sa)); printf("SET KEY \n"); setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, key, KEY_SIZE); printf("SET auth size \n"); setsockopt(tfmfd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, 16); printf("ACCEPT \n"); opfd = accept(tfmfd, NULL, 0); msg.msg_control = cbuf; msg.msg_controllen = sizeof(cbuf); printf("SET OP \n"); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_ALG; cmsg->cmsg_type = ALG_SET_OP; cmsg->cmsg_len = CMSG_LEN(4); *(__u32 *)CMSG_DATA(cmsg) = ALG_OP_DECRYPT; printf("SET IV \n"); cmsg = CMSG_NXTHDR(&msg, cmsg); cmsg->cmsg_level = SOL_ALG; cmsg->cmsg_type = ALG_SET_IV; cmsg->cmsg_len = CMSG_LEN(1024); iv = (void *)CMSG_DATA(cmsg); iv->ivlen = IV_SIZE; memcpy(iv->iv, usr_iv, IV_SIZE); cmsg = CMSG_NXTHDR(&msg, cmsg); cmsg->cmsg_level = SOL_ALG; cmsg->cmsg_type = ALG_SET_AEAD_ASSOCLEN; cmsg->cmsg_len = CMSG_LEN(1024); iv = (void *)CMSG_DATA(cmsg); iv->ivlen = AAD_SIZE; iov.iov_base = input; iov.iov_len = len; printf("SET INPUT \n"); msg.msg_iov = &iov; msg.msg_iovlen = 1; printf("SEND MSG \n"); sendmsg(opfd, &msg, 0); printf("READ \n"); read(opfd, buf, len - GCM_TAG_SIZE); close(opfd); printf("CLOSE OPFD \n"); close(tfmfd); printf("CLOSE TFMFD \n"); printf("Data Out:\r\n"); for (i = AAD_SIZE; i < len - GCM_TAG_SIZE; i++) { printf("%02x", (unsigned char)buf[i]); } printf("\n"); return 0; } |
Mainline status
- The driver is available in mainline kernel (https://github.com/torvalds/linux/blob/master/drivers/crypto/xilinx/zynqmp-aes-gcm.c)
Change Log
2018.3
Summary
- crypto: zynqmp-aes: Adds zynqmp-aes driver
Commits
Initial commit
- c7e7089 crypto: synqmp-aes: Adds zynqmp-aes driver
Bug fixes
- 6c6033a crypto: zynqmp-aes: Fix for segfault seen with large sets of data
- c1a602d crypto: zynqmp-aes: Adds an error code for zynqmp-aes driver
2023.1
- Userspace interface for AEAD algorithms(CONFIG_CRYPTO_USER_API_AEAD) and the driver(CONFIG_CRYPTO_DEV_ZYNQMP_AES) are enabled by default in the xilinx_defconfig and xilinx_zynqmp_defconfig
- Existing driver is replaced with new driver written using aead framework
- Added support for Versal
Related Links
Driver Code : https://github.com/Xilinx/linux-xlnx/blob/master/drivers/crypto/xilinx/zynqmp-aes-gcm.c
...