Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Linux AES Driver for Zynq Ultrascale+ MPSoC

Table of Contents

Table of Contents
excludeTable of Contents

NOTE : 

This Linux AES driver is written using symmetric key framework. However as ZynqMP supports AES-GCM mode, the driver is migrated to more appropriate AEAD framework in release 2019.2. The old symmetric key framework based AES driver will be deprecated in release 2021.2

Introduction

The Zynq UltraScale+ MPSoC includes an AES-GCM engine for symmetric key encryption and decryption. This block performs the modulus math based on Rivest-Shamir-Adelman (RSA)-4096 algorithm.
It is an symmetric algorithm. 
This block uses AES-GCM algorithm to encrypt or decrypt the provided data. It requires a key of size 256 bits and initialization vector(IV) of size 96 bits.

HW IP Features

  • Supports Symmetric key algorithm.

Features supported in driver

  • Supports Symmetric key algorithm.

Kernel Configuration

Cryptographic API  -→

Code Block
themeMidnight
< >  User-space interface for hash algorithms
<*>  User-space interface for symmetric key cipher algorithms
< >  User-space interface for random number generator algorithms
< >  User-space interface for AEAD algorithms
Code Block
themeMidnight
--- Hardware crypto device
[ ]  Support for AMD Secure Processor (NEW)
< >  Support for Cavium CNN55XX driver (NEW)
< >  Cavium ZIP driver (NEW)
< >  Support for Xilinx ZynqMP SHA3 hw accelerator (NEW)
< >  Support for Xilinx ZynqMP RSA hw accelerator (NEW)
<*>  Support for Xilinx ZynqMP AES hw accelerator 
<M>  VirtIO crypto driver (NEW)

Devicetree

Code Block
themeMidnight
xlnx_aes: zynqmp_aes {
                compatible = "xlnx,zynqmp-aes";
        };

TC Execution: Cross compile the below example and Need to create the executable file to test the AES functionality.

AF ALG AES Encrypt example

 With KUP key

Code Block
languagecpp
/******************************************************************************
* 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
#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 = "skcipher",
    .salg_name = "xilinx-zynqmp-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);
  /* 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;
}

AF ALG AES Decrypt example

With KUP key

...

languagecpp

...

Linux AES Driver for Zynq Ultrascale+ MPSoC & Versal

Table of Contents

Table of Contents
excludeTable of Contents



Introduction

The Zynq UltraScale+ MPSoC includes an AES-GCM engine for symmetric key encryption and decryption. It is an symmetric algorithm. 
This block uses AES-GCM algorithm to encrypt or decrypt the provided data. It requires a key of size 256 bits and initialization vector(IV) of size 96 bits.
This driver is supported for ZynqMP and 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.

This configuration in PLM shall be deprecated and removed in 2023.2 release. 

Kernel Configuration

For ZynqMP, the ZynqMP AES driver and the userspace interface for AEAD algorithms are enabled by default. So there is no need for kernel configuration.

For Versal, the driver and the userspace interface is not enabled by default. Enabling the driver shall enable the userspace interface as well.

To enable the driver follow this path in menuconfig:

Cryptographic API -> Hardware crypto devices → <*> Support for Xilinx ZynqMP AES hardware accelerator

Image Added

Userspace examples for ZynqMP

AF ALG AES Encrypt example with KUP key

The below example demonstrate how to use user provided key or KUP key for AES encryption : 

Code Block
languagecpp
themeMidnight
/******************************************************************************
* 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

#define KEY_TYPE_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, key_type, 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;
}


AF ALG AES Decrypt example with KUP key

The below example demonstrate how to use user provided key or KUP key for AES decryption : 

Code Block
languagecpp
themeMidnight
/******************************************************************************
* 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

#define KEY_TYPE_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, key_type, 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_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;
}

With Device/PUF key :

To use Device key or PUF key for data blob encryption/decryption , Create a primary boot image with PMU_FW (built with SECURE_ENVIRONMENT flag set).

To use device/puf key encryption/decryption, above applications remain same but with minor changes. Those changes should be as follows

__u8 key_type[] = {AES_DEVICE_KEY};

                       (or)

__u8 key_type[] = {AES_PUF_KEY};

for device key and puf key respectively.

In set socket options calls, 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, key_type, KEY_TYPE_SIZE);

/* Set key for AES operation */ 

setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, key, KEY_SIZE);


Expected Output

Code Block
themeMidnight
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

The examples provided in Userspace examples for ZynqMP shall work for Versal as well.

However Versal also supports Additional Authenticated Data (AAD). Below examples demonstrate the support for AAD in Versal.


AF ALG AES Encrypt example with AAD using KUP key


Code Block
languagecpp
themeMidnight
#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 IV_SIZE         12
#define AAD_SIZE	16
#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[DATA_SIZE + AAD_SIZE] = {
		/* First 16Bytes are AAD data */
		0x67, 0xe2, 0x1c, 0xf3, 0xcb, 0x29, 0xe0, 0xdc,
		0xbc, 0x4d, 0x8b, 0x1d, 0x0c, 0xc5, 0x33, 0x4b,
		/* Plain text */
		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));
	setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, key, KEY_SIZE);
	setsockopt(tfmfd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, 16);
	//setsockopt(tfmfd, SOL_ALG, ALG_SET_AEAD_ASSOCLEN, aad, AAD_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);
	*(__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);

	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;

	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;

	sendmsg(opfd, &msg, 0);
	read(opfd, buf, len);
	close(opfd);
	printf("Data Out:\r\n");
	for (i = AAD_SIZE; 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 = AAD_SIZE; i < len - GCM_TAG_SIZE; i++) {
		printf("%02x", (unsigned char)input[i]);
	}
	close(opfd);
	close(tfmfd);


	return 0;
}


AF ALG AES Decrypt example with AAD using KUP key


Code Block
languagecpp
themeMidnight
#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_TYPEKEY_SIZE        32
#define AAD_SIZE	16
#define ALG_SET_KEY_TYPE 6
#endifIV_SIZE    #define KEY_SIZE        32 #define IV_SIZE         12
#define GCM_TAG_SIZE   SIZE    16
#define DATA_SIZE 68SIZE	68

#define AES_KUP_KEY     0
#define VERSAL_AES_DEVICE_KEY  1
#define AES_PUF_KEY     2USER_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 = "skcipheraead",
    		.salg_name = "xilinx-zynqmp-aesgcm(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[] = {
/* 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
		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[] = {
		/* InitializationFirst1bytes Vectorare forAAD thedata 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*/
		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		0x22, 0xd5, 0x49, 0x14, 0x1d, 0xcf, 0xef, 0x0f, 0xaf, 0x01, 0xaf, 0xd6, 0x43, 0x3f, 0x9d, 0xc6, 0xbb, 0x7d, 0x32, 0x07, 0xd4,
 0xa5		0xa5, 0x31, 0xcd, 0xf5, 0xe6, 0xeb, 0xf5, 0x96, 0xbd, 0x4a, 0x0c, 0x3d, 0x43, 0x03, 0x13, 0xce, 0x88, 0xe2, 0xb9, 0xe1, 0x6c,
 0x08		0x08, 0x6e, 0x63, 0x3d, 0x24,
 
 0xb5, 0x2b, 0x80, 0xcd, 0x51, 0x17, 0xaf, 0xb4, 0x7b, 0x11, 0x6d, 0x4a, 0x8f, 0x89, 0xcf, 0x75
};
  , 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));
  /* Set key type to use for AES operation */
  , sizeof(sa));
	printf("SET KEY \n");
	setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY_TYPE, key_type, 0KEY_SIZE);
	printf("SET auth /* Set key for AES operation */
  size \n");
	setsockopt(tfmfd, SOL_ALG, ALG_SET_KEYAEAD_AUTHSIZE, key,KEY_SIZENULL, 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);
  /* Set the AES operation type Encrption/Decryption */
  *	*(__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);
  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, 
	cmsg = CMSG_NXTHDR(&msg, 0cmsg);
	cmsg->cmsg_level  /* Read the output buffer for decrypted data */
  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("= 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");

  close(opfd);
  close(tfmfd);

  return 0;
}

  • The above applications demonstrate how to use user provided key or KUP key for AES encryption/decryption.

With Device/PUF key :

To use Device key or PUF key for data blob encryption/decryption , Create a primary boot image with PMU_FW (built with SECURE_ENVIRONMENT flag set).

To use device/puf key encryption/decryption, above applications remain same but with minor changes. Those changes should be as follows

__u8 key_type[] = {AES_DEVICE_KEY};

                       (or)

__u8 key_type[] = {AES_PUF_KEY};

for device key and puf key respectively.

And set socket options like below

setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY_TYPE, key_type, 0);

setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, NULL, 0);

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.

Mainline status

...

	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

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