#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include "aes_hw.h"
#define CRYPTO_DEV_NAME "/dev/crypto"
int hw_crypto_ctx_init(cryptodev_ctx *ctx)
{
if(ctx->dev_fd>0)
close(ctx->dev_fd);
ctx->dev_fd = open(CRYPTO_DEV_NAME, O_RDWR, 0);
if (ctx->dev_fd < 0)
{
dbg_perror("open(%s)", CRYPTO_DEV_NAME);
return -1;
}
return 0;
}
void hw_crypto_sess_close(cryptodev_ctx *ctx)
{
if (ioctl(ctx->dev_fd, CIOCFSESSION, &ctx->sess.ses))
dbg_perror("ioctl(CIOCFSESSION)");
ctx->sess_opened = 0;
}
int hw_crypto_sess_open(cryptodev_ctx *ctx,
const unsigned char *key,
unsigned int key_size,
enum cryptodev_crypto_op_t alg)
{
session_info_op siop;
unsigned int i;
ctx->sess.cipher = alg;
ctx->sess.keylen = key_size;
ctx->sess.key = (uint8_t *)key;
if (ioctl(ctx->dev_fd, CIOCGSESSION, &ctx->sess))
{
dbg_perror("ioctl(CIOCGSESSION) err %d", errno);
dbg(" cipher=%d, keylen=%d, key=", alg, key_size);
for (i = 0; i < key_size; i++)
{
fprintf(stderr, "%x", key[i]);
}
printf("\n");
return -errno;
}
memset(&siop, 0, sizeof(siop));
siop.ses = ctx->sess.ses;
if (ioctl(ctx->dev_fd, CIOCGSESSINFO, &siop))
{
dbg_perror("ioctl(CIOCGSESSINFO)");
return -errno;
}
// dbg("Got %s with driver %s\n",
// siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
// dbg("Alignmask is %x\n", (unsigned int)siop.alignmask);
ctx->alignmask = siop.alignmask;
ctx->sess_opened = 1;
return 0;
}
int hw_crypto_setkey(cryptodev_ctx *ctx, const unsigned char *key, unsigned int key_size, enum cryptodev_crypto_op_t alg)
{
if(!ctx||ctx->dev_fd <= 0)
return -1;
if(ctx->sess_opened)
{
hw_crypto_sess_close(ctx);
}
return hw_crypto_sess_open(ctx, key, key_size, alg);
}
void hw_crypto_ctx_deinit(cryptodev_ctx *ctx)
{
if(!ctx||ctx->dev_fd <= 0)
return;
if(ctx->sess_opened)
{
hw_crypto_sess_close(ctx);
}
close(ctx->dev_fd);
ctx->dev_fd = 0;
return;
}
int hw_encrypt(cryptodev_ctx *ctx, void *iv, void *plaintext, void *ciphertext, size_t size)
{
crypt_op cryp;
void *p;
int ret = 0;
void *tmp_plain_buf = NULL, *tmp_cipher_buf = NULL;
void *tmp_plaintext = plaintext;
void *tmp_ciphertext = ciphertext;
/* check plaintext and ciphertext alignment */
if (ctx->alignmask)
{
p = (void *)(((unsigned long)plaintext + ctx->alignmask) & ~ctx->alignmask);
if (plaintext != p)
{
tmp_plain_buf = (void *)malloc(size + ctx->alignmask);
tmp_plaintext = (void *)(((unsigned long)tmp_plain_buf + ctx->alignmask) & ~ctx->alignmask);
memcpy(tmp_plaintext, plaintext, size);
}
p = (void *)(((unsigned long)ciphertext + ctx->alignmask) & ~ctx->alignmask);
if (ciphertext != p)
{
tmp_cipher_buf = (void *)malloc(size + ctx->alignmask);
tmp_ciphertext = (void *)(((unsigned long)tmp_cipher_buf + ctx->alignmask) & ~ctx->alignmask);
}
}
memset(&cryp, 0, sizeof(cryp));
/* Encrypt data.in to data.encrypted */
cryp.ses = ctx->sess.ses;
cryp.len = size;
cryp.src = (uint8_t *)tmp_plaintext;
cryp.dst = (uint8_t *)tmp_ciphertext;
cryp.iv = (uint8_t *)iv;
cryp.op = COP_ENCRYPT;
if (ioctl(ctx->dev_fd, CIOCCRYPT, &cryp))
{
dbg_perror("ioctl(CIOCCRYPT)");
ret = -errno;
}
if (tmp_plain_buf)
free(tmp_plain_buf);
if (tmp_cipher_buf)
{
memcpy(ciphertext, tmp_ciphertext, size);
free(tmp_cipher_buf);
}
memcpy(iv, ciphertext + size - 16, 16);
if (ret < 0)
{
dbg_perror("operation fail, size %d:", size);
}
return ret;
}
int hw_decrypt(cryptodev_ctx *ctx, void *iv, void *ciphertext, void *plaintext, size_t size)
{
crypt_op cryp;
void *p;
int ret = 0;
void *tmp_plain_buf = NULL, *tmp_cipher_buf = NULL;
void *tmp_plaintext = plaintext;
void *tmp_ciphertext = ciphertext;
uint8_t tmp[16];
memcpy(tmp, ciphertext + size - 16, 16);
/* check plaintext and ciphertext alignment */
if (ctx->alignmask)
{
p = (void *)(((unsigned long)plaintext + ctx->alignmask) & ~ctx->alignmask);
if (plaintext != p)
{
tmp_plain_buf = (void *)malloc(size + ctx->alignmask);
tmp_plaintext = (void *)(((unsigned long)tmp_plain_buf + ctx->alignmask) & ~ctx->alignmask);
}
p = (void *)(((unsigned long)ciphertext + ctx->alignmask) & ~ctx->alignmask);
if (ciphertext != p)
{
tmp_cipher_buf = (void *)malloc(size + ctx->alignmask);
tmp_ciphertext = (void *)(((unsigned long)tmp_cipher_buf + ctx->alignmask) & ~ctx->alignmask);
memcpy(tmp_ciphertext, ciphertext, size);
}
}
memset(&cryp, 0, sizeof(cryp));
/* Encrypt data.in to data.encrypted */
cryp.ses = ctx->sess.ses;
cryp.len = size;
cryp.src = (uint8_t *)tmp_ciphertext;
cryp.dst = (uint8_t *)tmp_plaintext;
cryp.iv = (uint8_t *)iv;
cryp.op = COP_DECRYPT;
if (ioctl(ctx->dev_fd, CIOCCRYPT, &cryp))
{
dbg_perror("ioctl(CIOCCRYPT)");
ret = -errno;
}
if (tmp_plain_buf)
{
memcpy(plaintext, tmp_plaintext, size);
free(tmp_plain_buf);
}
if (tmp_cipher_buf)
free(tmp_cipher_buf);
memcpy(iv, tmp, 16);
if (ret < 0)
{
dbg_perror("operation fail, size %d:", size);
}
return ret;
}
#define BLOCK_SIZE (8 * 1024)
int hw_encrypt_blocks_cbc(cryptodev_ctx *ctx, void *iv, void *plaintext, void *ciphertext, size_t size)
{
size_t remain = size;
int ret = 0;
uint8_t ori_iv[16];
uint8_t *plain_ptr, *cipher_ptr;
memcpy(ori_iv, iv, 16);
plain_ptr = (uint8_t *)plaintext;
cipher_ptr = (uint8_t *)ciphertext;
while (remain > 0)
{
size_t operate_size = BLOCK_SIZE;
if (operate_size > remain)
{
operate_size = remain;
}
ret = hw_encrypt(ctx, iv, plain_ptr, cipher_ptr, operate_size);
if (ret < 0)
return ret;
remain -= operate_size;
plain_ptr += operate_size;
cipher_ptr += operate_size;
}
return 0;
}
int hw_decrypt_blocks_cbc(cryptodev_ctx *ctx, void *iv, void *ciphertext, void *plaintext, size_t size)
{
size_t remain = size;
int ret = 0;
uint8_t *plain_ptr, *cipher_ptr;
cipher_ptr = (uint8_t *)ciphertext;
plain_ptr = (uint8_t *)plaintext;
while (remain > 0)
{
size_t operate_size = BLOCK_SIZE;
if (operate_size > remain)
{
operate_size = remain;
}
ret = hw_decrypt(ctx, iv, cipher_ptr, plain_ptr, operate_size);
if (ret < 0)
return ret;
remain -= operate_size;
cipher_ptr += operate_size;
plain_ptr += operate_size;
}
return 0;
}