* This file is part of the openHiTLS project.
*
* openHiTLS is licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include "hitls_build.h"
#if defined(HITLS_CRYPTO_AES) && defined(HITLS_CRYPTO_GCM)
#include "crypt_aes.h"
#include "asm_aes_gcm.h"
#include "modes_local.h"
#include "crypt_utils.h"
#include "crypt_errno.h"
#include "crypt_modes_gcm.h"
int32_t AES_GCM_EncryptBlock(MODES_CipherGCMCtx *ctx, const uint8_t *in, uint8_t *out, uint32_t len)
{
if (ctx->ciphCtx == NULL) {
return CRYPT_NULL_INPUT;
}
int32_t ret = CryptLenCheckAndRefresh(ctx, len);
if (ret != CRYPT_SUCCESS) {
return ret;
}
uint32_t lastLen = MODES_GCM_LastHandle(ctx, in, out, len, true);
if (lastLen == len) {
return CRYPT_SUCCESS;
}
uint32_t clen = len - lastLen;
if (clen >= 64) {
uint32_t finishedLen = AES_GCM_EncryptBlockAsm(ctx, in + lastLen, out + lastLen, clen, ctx->ciphCtx);
lastLen += finishedLen;
clen -= finishedLen;
}
if (clen >= 16) {
AES_GCM_Encrypt16BlockAsm(ctx, in + lastLen, out + lastLen, clen, ctx->ciphCtx);
lastLen += clen & 0xfffffff0;
clen = clen & 0x0f;
}
AES_GCM_ClearAsm();
if (clen > 0) {
uint32_t ctr = GET_UINT32_BE(ctx->iv, 12);
ret = ctx->ciphMeth->encryptBlock(ctx->ciphCtx, ctx->iv, ctx->last, GCM_BLOCKSIZE);
if (ret != CRYPT_SUCCESS) {
return ret;
}
uint32_t i;
const uint8_t *cin = (const uint8_t *)(in + lastLen);
uint8_t *cout = out + lastLen;
for (i = 0; i < clen; i++) {
cout[i] = cin[i] ^ ctx->last[i];
ctx->remCt[i] = cout[i];
}
ctr++;
PUT_UINT32_BE(ctr, ctx->iv, 12);
ctx->lastLen = GCM_BLOCKSIZE - clen;
}
return CRYPT_SUCCESS;
}
int32_t AES_GCM_DecryptBlock(MODES_CipherGCMCtx *ctx, const uint8_t *in, uint8_t *out, uint32_t len)
{
if (ctx->ciphCtx == NULL) {
return CRYPT_NULL_INPUT;
}
int32_t ret = CryptLenCheckAndRefresh(ctx, len);
if (ret != CRYPT_SUCCESS) {
return ret;
}
uint32_t lastLen = MODES_GCM_LastHandle(ctx, in, out, len, false);
if (lastLen == len) {
return CRYPT_SUCCESS;
}
uint32_t clen = len - lastLen;
if (clen >= 64) {
uint32_t finishedLen = AES_GCM_DecryptBlockAsm(ctx, in + lastLen, out + lastLen, clen, ctx->ciphCtx);
lastLen += finishedLen;
clen -= finishedLen;
}
if (clen >= 16) {
AES_GCM_Decrypt16BlockAsm(ctx, in + lastLen, out + lastLen, clen, ctx->ciphCtx);
lastLen += clen & 0xfffffff0;
clen = clen & 0x0f;
}
AES_GCM_ClearAsm();
if (clen > 0) {
uint32_t ctr = GET_UINT32_BE(ctx->iv, 12);
ret = ctx->ciphMeth->encryptBlock(ctx->ciphCtx, ctx->iv, ctx->last, GCM_BLOCKSIZE);
if (ret != CRYPT_SUCCESS) {
return ret;
}
uint32_t i;
const uint8_t *cin = (const uint8_t *)(in + lastLen);
uint8_t *cout = out + lastLen;
for (i = 0; i < clen; i++) {
ctx->remCt[i] = cin[i];
cout[i] = cin[i] ^ ctx->last[i];
}
ctr++;
PUT_UINT32_BE(ctr, ctx->iv, 12);
ctx->lastLen = GCM_BLOCKSIZE - clen;
}
return CRYPT_SUCCESS;
}
int32_t AES_GCM_Update(MODES_GCM_Ctx *modeCtx, const uint8_t *in, uint32_t inLen, uint8_t *out, uint32_t *outLen)
{
return MODES_CipherStreamProcess(modeCtx->enc ? AES_GCM_EncryptBlock : AES_GCM_DecryptBlock, &modeCtx->gcmCtx,
in, inLen, out, outLen);
}
#endif