📄 padlock.c
字号:
/*
* Copyright 1998-2004 VIA Technologies, Inc. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sub license,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* VIA, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "padlock.h"
#include "via_ace.h"
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <inttypes.h>
#include <errno.h>
/////////////////////////////////////////////////////////////////////////////
// For unaligned ACE aes function
struct cipherbuf_info
{
unsigned char *temp_buf;
unsigned char *p_alignedbuf;
int chunk_size;
int chunk_num;
int need_plus;
int plus_size;
int alloc_failed;
};
static void
ace_try_alloc(int total_bytes, int chunk_size, struct cipherbuf_info *p_bufinfo)
{
p_bufinfo->temp_buf = (unsigned char *)malloc(chunk_size + 16);
if (p_bufinfo->temp_buf != NULL)
{
p_bufinfo->alloc_failed = 0;
p_bufinfo->p_alignedbuf = ALIGN16(p_bufinfo->temp_buf);
p_bufinfo->chunk_size = chunk_size;
p_bufinfo->chunk_num = total_bytes / chunk_size;
p_bufinfo->need_plus = total_bytes % chunk_size;
p_bufinfo->plus_size = total_bytes % chunk_size;
}
else
{
p_bufinfo->alloc_failed = 1;
}
}
static void
ace_free_buf(struct cipherbuf_info *p_bufinfo)
{
if (p_bufinfo->temp_buf != NULL)
{
free(p_bufinfo->temp_buf);
p_bufinfo->temp_buf = NULL;
p_bufinfo->p_alignedbuf = NULL;
}
}
static int
ace_alloc_buf(int total_bytes, struct cipherbuf_info *p_bufinfo)
{
if (total_bytes > MAX_CIPHER_BUFFER_SIZE)
{
ace_try_alloc(total_bytes, MAX_CIPHER_BUFFER_SIZE, p_bufinfo);
if (p_bufinfo->alloc_failed)
{
printf("cipher buffer allocation larger than 64kB failed!\n");
return -1;
}
}
else
{
ace_try_alloc(total_bytes, total_bytes, p_bufinfo);
if (p_bufinfo->alloc_failed)
{
printf("cipher buffer allocation for %d bytes failed!\n", total_bytes);
return -1;
}
}
return 0;
}
static AES_RESULT
ace_aes_unaligned_crypt(struct ace_aes_context *ctx, int enc, unsigned char *in, unsigned char *out, int nbytes)
{
AES_RESULT res;
struct cipherbuf_info cipher_buf_info;
unsigned char *p_last_iv;
unsigned char *p_last_src_block;
unsigned char *p_last_dst_block;
unsigned char last_src_block[16];
unsigned char last_dst_block[16];
int result;
int i,m;
if (!nbytes)
return AES_SUCCEEDED;
result = ace_alloc_buf(nbytes, &cipher_buf_info);
if (result != 0)
{
printf("system memory is insufficient!\n");
return AES_FAILED;
}
for (i = 1; i <= cipher_buf_info.chunk_num; i++)
{
memcpy(cipher_buf_info.p_alignedbuf, in, cipher_buf_info.chunk_size);
in = in + cipher_buf_info.chunk_size;
// For iv update of cbc and cfb mode decryption Because the hardware can update iv automatically
// We have to do it by software.
switch (ctx->mode)
{
case ACE_AES_ECB: break;
case ACE_AES_CBC:
case ACE_AES_CFB128: if(enc == 0)
{
p_last_iv = (unsigned char *)(cipher_buf_info.p_alignedbuf + cipher_buf_info.chunk_size - 16);
memcpy(ctx->last_iv,p_last_iv, 16);
}
break;
case ACE_AES_OFB128: p_last_src_block = (unsigned char *)(cipher_buf_info.p_alignedbuf + cipher_buf_info.chunk_size - 16);
memcpy(last_src_block, p_last_src_block, 16);
break;
}
// call the lowest level api to encrypt or decrypt data in the cipher buffer
// the addresses of src and dst are same.
res = ace_aes_atomic_crypt( ctx, enc, cipher_buf_info.p_alignedbuf, cipher_buf_info.p_alignedbuf, cipher_buf_info.chunk_size);
if(res != AES_SUCCEEDED)
{
return res;
}
// For iv update of cbc cfb mode encryption and the very special mode ofb whose iv update is same
// for both encryption and decryption Because the hardware can update iv automatically
// We have to do it by software.
switch (ctx->mode)
{
case ACE_AES_ECB: break;
case ACE_AES_CBC:
case ACE_AES_CFB128: if(enc == 1)
{
p_last_iv = (unsigned char *)(cipher_buf_info.p_alignedbuf + cipher_buf_info.chunk_size - 16);
memcpy(ctx->last_iv,p_last_iv, 16);
}
// Finally we update the intermediate iv here for both encryption and decryption
memcpy(ctx->iv, ctx->last_iv, 16);
break;
case ACE_AES_OFB128: // ofb mode iv update is very special we have to hold the last block of src and dst
// then xor them to get the last iv.
p_last_dst_block = (unsigned char *)(cipher_buf_info.p_alignedbuf + cipher_buf_info.chunk_size - 16);
memcpy(last_dst_block, p_last_dst_block, 16);
for(m = 0;m < 16;m++)
{
ctx->iv[m] = last_dst_block[m] ^ last_src_block[m];
}
break;
}
memcpy(out, cipher_buf_info.p_alignedbuf, cipher_buf_info.chunk_size);
out = out + cipher_buf_info.chunk_size;
}//!for
if (cipher_buf_info.need_plus != 0)
{
memcpy(cipher_buf_info.p_alignedbuf, in, cipher_buf_info.plus_size);
in = in + cipher_buf_info.plus_size;
// For iv update of cbc and cfb mode decryption Because the hardware can update iv automatically
// We have to do it by software.
switch (ctx->mode)
{
case ACE_AES_ECB: break;
case ACE_AES_CBC:
case ACE_AES_CFB128: if(enc == 0)
{
p_last_iv = (unsigned char *)(cipher_buf_info.p_alignedbuf + cipher_buf_info.plus_size - 16);
memcpy(ctx->last_iv,p_last_iv, 16);
}
break;
case ACE_AES_OFB128: p_last_src_block = (unsigned char *)(cipher_buf_info.p_alignedbuf + cipher_buf_info.plus_size - 16);
memcpy(last_src_block, p_last_src_block, 16);
break;
}
// call the lowest level api to encrypt or decrypt data in the cipher buffer
// the addresses of src and dst are same.
res = ace_aes_atomic_crypt( ctx, enc, cipher_buf_info.p_alignedbuf, cipher_buf_info.p_alignedbuf, cipher_buf_info.plus_size);
if(res != AES_SUCCEEDED)
{
return res;
}
// For iv update of cbc cfb mode encryption and the very special mode ofb whose iv update is same
// for both encryption and decryption Because the hardware can update iv automatically
// We have to do it by software.
switch (ctx->mode)
{
case ACE_AES_ECB: break;
case ACE_AES_CBC:
case ACE_AES_CFB128: if(enc == 1)
{
p_last_iv = (unsigned char *)(cipher_buf_info.p_alignedbuf + cipher_buf_info.plus_size - 16);
memcpy(ctx->last_iv,p_last_iv, 16);
}
// Finally we update the intermediate iv here
// for both encryption and decryption
memcpy(ctx->iv, ctx->last_iv, 16);
break;
case ACE_AES_OFB128: // ofb mode iv update is very special
// we have to hold the last block of src and dst
// then xor them to get the last iv.
p_last_dst_block = (unsigned char *)(cipher_buf_info.p_alignedbuf + cipher_buf_info.plus_size - 16);
memcpy(last_dst_block, p_last_dst_block, 16);
for(m = 0;m < 16;m++)
{
ctx->iv[m] = last_dst_block[m] ^ last_src_block[m];
}
break;
}
memcpy(out, cipher_buf_info.p_alignedbuf, cipher_buf_info.plus_size);
out = out + cipher_buf_info.plus_size;
}//!if need_plus
ace_free_buf(&cipher_buf_info);
return res;
}
static AES_RESULT
ace_aes_aligned_crypt(struct ace_aes_context *ctx, int enc, unsigned char *in, unsigned char *out, int nbytes)
{
AES_RESULT res;
unsigned char *p_last_iv;
unsigned char *p_last_src_block;
unsigned char *p_last_dst_block;
unsigned char last_src_block[16];
unsigned char last_dst_block[16];
int m;
// For iv update of cbc and cfb mode decryption Because the hardware can update iv automatically
// We have to do it by software.
switch (ctx->mode)
{
case ACE_AES_ECB: break;
case ACE_AES_CBC:
case ACE_AES_CFB128: if(enc == 0)
{
p_last_iv = (unsigned char *)(in + nbytes - 16);
memcpy(ctx->last_iv,p_last_iv, 16);
}
break;
case ACE_AES_OFB128: p_last_src_block = (unsigned char *)(in + nbytes - 16);
memcpy(last_src_block, p_last_src_block, 16);
break;
}
// because the addresses of in and out are aligned which can be accepted by ACE hardware
// we call the lowest level api directly here
res = ace_aes_atomic_crypt(ctx, enc, in, out, nbytes);
if(res != AES_SUCCEEDED)
{
return res;
}
// For iv update of cbc cfb mode encryption and the very special mode ofb whose iv update is same
// for both encryption and decryption Because the hardware can update iv automatically
// We have to do it by software.
switch (ctx->mode)
{
case ACE_AES_ECB: break;
case ACE_AES_CBC:
case ACE_AES_CFB128: // Finally we update the intermediate iv here
// for both encryption and decryption
if(enc == 1)
{
p_last_iv = (unsigned char *)(out + nbytes - 16);
memcpy(ctx->iv,p_last_iv, 16);
}
else
{
memcpy(ctx->iv, ctx->last_iv, 16);
}
break;
case ACE_AES_OFB128: // ofb mode iv update is very special we have to hold the
// last block of src and dst then xor them to get the last iv.
p_last_dst_block = (unsigned char *)(out + nbytes - 16);
memcpy(last_dst_block, p_last_dst_block, 16);
for(m = 0;m < 16;m++)
{
ctx->iv[m] = last_dst_block[m] ^ last_src_block[m];
}
memcpy(ctx->iv,ctx->last_iv, 16);
break;
}
return res;
}
/////////////////////////////////////////////////////////////////////////////////
// VIA Padlock SDK ACE AES API
// VIA Padlock SDK plain ACE AES API
int padlock_ace_available()
{
int result = 0;
PUSHREG
asm("movl $0xC0000000, %%eax\n \
cpuid\n \
cmpl $0xC0000001, %%eax\n \
jnz local_label\n \
cpuid\n \
andl $0xC0, %%edx\n \
jz local_label\n \
movl %1, %0 \n \
local_label:\n"
:"=m"(result)
:"i"(1));
POPREG
return result;
}
struct ace_aes_context *
padlock_aes_begin()
{
struct ace_aes_context *ctx;
ctx = (struct ace_aes_context *)malloc(sizeof(struct ace_aes_context));
if(ctx == NULL)
{
printf("\nFatal error : Fail to create ace_aes_ctx!\n");
exit;
}
return ctx;
}
AES_RESULT
padlock_aes_setmodeiv(struct ace_aes_context *ctx, ACE_AES_MODE mode, unsigned char *iv)
{
AES_RESULT res = AES_SUCCEEDED;
if(ctx == NULL)
{
printf("Fatal error : ace_aes_ctx NULL pointer error!\n");
res = AES_FAILED;
return res;
}
switch(mode)
{
case ACE_AES_ECB: ctx->mode = mode;
ctx->iv = NULL;
break;
case ACE_AES_CBC:
case ACE_AES_CFB128:
case ACE_AES_OFB128: ctx->mode = mode;
if(iv == NULL)
{
printf("Fatal error : iv NULL pointer error!\n");
res = AES_FAILED;
return res;
}
ctx->iv = iv;
break;
default: printf("Fatal error : invalid cipher mode!\n");
res = AES_MODE_NOT_SUPPORTED;
return res;
}
return res;
}
AES_RESULT
padlock_aes_encrypt(struct ace_aes_context *ctx, unsigned char *plaintxt, unsigned char *ciphertxt, int nbytes)
{
AES_RESULT res;
int enc = 1;
if(ctx == NULL)
{
printf("Fatal error : ace_aes_ctx NULL pointer error!\n");
res = AES_FAILED;
return res;
}
if((plaintxt == NULL)||(ciphertxt == NULL))
{
printf("Fatal error : key/plaintxt/ciphertxt NULL pointer error!\n");
res = AES_FAILED;
return res;
}
if(nbytes == 0)
{
printf("no data need to be processed!\n");
res = AES_SUCCEEDED;
return res;
}
if(nbytes % 16)
{
printf("Fatal error : the length of plaintxt/ciphertxt must be multiples of 16bytes\n");
res = AES_NOT_BLOCKED;
return res;
}
if((UNALIGNED(plaintxt))||(UNALIGNED(ciphertxt)))
{
res = ace_aes_unaligned_crypt(ctx, enc, plaintxt, ciphertxt, nbytes);
}
else
{
res = ace_aes_aligned_crypt(ctx, enc, plaintxt, ciphertxt, nbytes);
}
return res;
}
AES_RESULT
padlock_aes_decrypt(struct ace_aes_context *ctx, unsigned char *ciphertxt, unsigned char *plaintxt, int nbytes)
{
AES_RESULT res;
int enc = 0;
if(ctx == NULL)
{
printf("Fatal error : ace_aes_ctx NULL pointer error!\n");
res = AES_FAILED;
return res;
}
if((ciphertxt == NULL)||(plaintxt == NULL))
{
printf("Fatal error : key/plaintxt/ciphertxt NULL pointer error!\n");
res = AES_FAILED;
return res;
}
if(nbytes == 0)
{
printf("no data need to be processed!\n");
res = AES_SUCCEEDED;
return res;
}
if(nbytes % 16)
{
printf("Fatal error : the length of plaintxt/ciphertxt must be multiples of 16bytes\n");
res = AES_NOT_BLOCKED;
return res;
}
if((UNALIGNED(ciphertxt))||(UNALIGNED(plaintxt)))
{
res = ace_aes_unaligned_crypt(ctx, enc, ciphertxt, plaintxt, nbytes);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -