⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 padlock.c

📁 A Brief Guide to User/Hacker of VIA Padlock SDK
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * 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 + -