blob: 359526eeb9c406c52fa751bbbff518e69857e41e [file] [log] [blame]
/****************************************************************************
* arch/arm/src/sam34/sam_aes.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/crypto/crypto.h>
#include <nuttx/arch.h>
#include <nuttx/mutex.h>
#include <arch/board/board.h>
#include "arm_internal.h"
#include "chip.h"
#include "sam_periphclks.h"
#include "sam_aes.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define AES_BLOCK_SIZE 16
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
static mutex_t g_samaes_lock = NXMUTEX_INITIALIZER;
static bool g_samaes_initdone = false;
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
static void samaes_memcpy(void *out, const void *in, size_t size)
{
size_t i;
size_t wcount = size / 4;
for (i = 0; i < wcount;
i++, out = (uint8_t *)out + 4, in = (uint8_t *)in + 4)
{
*(uint32_t *)out = *(uint32_t *)in;
}
}
static void samaes_encryptblock(void *out, const void *in)
{
samaes_memcpy((void *)SAM_AES_IDATAR, in, AES_BLOCK_SIZE);
putreg32(AES_CR_START, SAM_AES_CR);
while (!(getreg32(SAM_AES_ISR) & AES_ISR_DATRDY));
if (out)
{
samaes_memcpy(out, (void *)SAM_AES_ODATAR, AES_BLOCK_SIZE);
}
}
static int samaes_setup_mr(uint32_t keysize, int mode, int encrypt)
{
uint32_t regval = AES_MR_SMOD_MANUAL_START | AES_MR_CKEY;
if (encrypt)
{
regval |= AES_MR_CIPHER_ENCRYPT;
}
else
{
regval |= AES_MR_CIPHER_DECRYPT;
}
switch (keysize)
{
case 16:
regval |= AES_MR_KEYSIZE_AES128;
break;
case 24:
regval |= AES_MR_KEYSIZE_AES192;
break;
case 32:
regval |= AES_MR_KEYSIZE_AES256;
break;
default:
return -EINVAL;
}
switch (mode)
{
case AES_MODE_ECB:
regval |= AES_MR_OPMOD_ECB;
break;
case AES_MODE_CBC:
regval |= AES_MR_OPMOD_CBC;
break;
case AES_MODE_CTR:
regval |= AES_MR_OPMOD_CTR;
break;
case AES_MODE_CFB:
regval |= AES_MR_OPMOD_CFB;
break;
default:
return -EINVAL;
}
putreg32(regval, SAM_AES_MR);
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
static int samaes_initialize(void)
{
sam_aes_enableclk();
putreg32(AES_CR_SWRST, SAM_AES_CR);
return OK;
}
int aes_cypher(void *out, const void *in, size_t size,
const void *iv, const void *key, size_t keysize,
int mode, int encrypt)
{
int ret = OK;
if (!g_samaes_initdone)
{
ret = samaes_initialize();
if (ret != OK)
{
return ret;
}
g_samaes_initdone = true;
}
if (size % 16)
{
return -EINVAL;
}
nxmutex_lock(&g_samaes_lock);
ret = samaes_setup_mr(keysize, mode & AES_MODE_MASK, encrypt);
if (ret < 0)
{
nxmutex_unlock(&g_samaes_lock);
return ret;
}
samaes_memcpy((void *)SAM_AES_KEYWR, key, keysize);
if (iv != NULL)
{
samaes_memcpy((void *)SAM_AES_IVR, iv, AES_BLOCK_SIZE);
}
while (size)
{
if ((mode & AES_MODE_MAC) == 0)
{
samaes_encryptblock(out, in);
out = (char *)out + AES_BLOCK_SIZE;
}
else if (size == AES_BLOCK_SIZE)
{
samaes_encryptblock(out, in);
}
else
{
samaes_encryptblock(NULL, in);
}
in = (char *)in + AES_BLOCK_SIZE;
size -= AES_BLOCK_SIZE;
}
nxmutex_unlock(&g_samaes_lock);
return ret;
}