加解密 C语言实现

1.加密的基本原理

加密分为对称加密和非对称加密,对称加密就是加密方和解密放用同一个密钥。

加密是分组加密,即将明文数据分成多个密钥大小的块,依次和密钥运算,输出密文。

padding,由于加密需要分组,就要保证最后一组数据大小和密钥一样大,补齐方式有多种,常见的是缺几补几。

推荐博客:

https://www.cnblogs.com/adylee/archive/2007/09/14/893438.html

 

2.常用库

openssl 下 aes.h

/* crypto/aes/aes.h */
/* ====================================================================
 * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
 *
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    openssl-core@openssl.org.
 *
 * 5. Products derived from this software may not be called "OpenSSL"
 *    nor may "OpenSSL" appear in their names without prior written
 *    permission of the OpenSSL Project.
 *
 * 6. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
 *
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 *
 */

#ifndef HEADER_AES_H
# define HEADER_AES_H

# include <openssl/opensslconf.h>

# ifdef OPENSSL_NO_AES
#  error AES is disabled.
# endif

# include <stddef.h>

# define AES_ENCRYPT     1
# define AES_DECRYPT     0

/*
 * Because array size can't be a const in C, the following two are macros.
 * Both sizes are in bytes.
 */
# define AES_MAXNR 14
# define AES_BLOCK_SIZE 16

#ifdef  __cplusplus
extern "C" {
#endif

/* This should be a hidden type, but EVP requires that the size be known */
struct aes_key_st {
# ifdef AES_LONG
    unsigned long rd_key[4 * (AES_MAXNR + 1)];
# else
    unsigned int rd_key[4 * (AES_MAXNR + 1)];
# endif
    int rounds;
};
typedef struct aes_key_st AES_KEY;

const char *AES_options(void);

int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
                        AES_KEY *key);
int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
                        AES_KEY *key);

int private_AES_set_encrypt_key(const unsigned char *userKey, const int bits,
                                AES_KEY *key);
int private_AES_set_decrypt_key(const unsigned char *userKey, const int bits,
                                AES_KEY *key);

void AES_encrypt(const unsigned char *in, unsigned char *out,
                 const AES_KEY *key);
void AES_decrypt(const unsigned char *in, unsigned char *out,
                 const AES_KEY *key);

void AES_ecb_encrypt(const unsigned char *in, unsigned char *out,
                     const AES_KEY *key, const int enc);
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
                     size_t length, const AES_KEY *key,
                     unsigned char *ivec, const int enc);
void AES_cfb128_encrypt(const unsigned char *in, unsigned char *out,
                        size_t length, const AES_KEY *key,
                        unsigned char *ivec, int *num, const int enc);
void AES_cfb1_encrypt(const unsigned char *in, unsigned char *out,
                      size_t length, const AES_KEY *key,
                      unsigned char *ivec, int *num, const int enc);
void AES_cfb8_encrypt(const unsigned char *in, unsigned char *out,
                      size_t length, const AES_KEY *key,
                      unsigned char *ivec, int *num, const int enc);
void AES_ofb128_encrypt(const unsigned char *in, unsigned char *out,
                        size_t length, const AES_KEY *key,
                        unsigned char *ivec, int *num);
void AES_ctr128_encrypt(const unsigned char *in, unsigned char *out,
                        size_t length, const AES_KEY *key,
                        unsigned char ivec[AES_BLOCK_SIZE],
                        unsigned char ecount_buf[AES_BLOCK_SIZE],
                        unsigned int *num);
/* NB: the IV is _two_ blocks long */
void AES_ige_encrypt(const unsigned char *in, unsigned char *out,
                     size_t length, const AES_KEY *key,
                     unsigned char *ivec, const int enc);
/* NB: the IV is _four_ blocks long */
void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out,
                        size_t length, const AES_KEY *key,
                        const AES_KEY *key2, const unsigned char *ivec,
                        const int enc);

int AES_wrap_key(AES_KEY *key, const unsigned char *iv,
                 unsigned char *out,
                 const unsigned char *in, unsigned int inlen);
int AES_unwrap_key(AES_KEY *key, const unsigned char *iv,
                   unsigned char *out,
                   const unsigned char *in, unsigned int inlen);


#ifdef  __cplusplus
}
#endif

#endif                          /* !HEADER_AES_H */

 

3.使用

(1)下面以 aes-128-ecb 并使用base64的实现,aes表示对称加密,ceb是一种加密模式,128表示128bit即16Bytes的密钥长度,base64是一种编码方式,将不可见字符转为可见字符,详见百度百科。

 

#ifndef _AES_128_ECB_H_
#define _AES_128_ECB_H_

int base64_encode(char *in_str, int in_len, char *out_str);
int base64_decode(char *in_str, int in_len, char *out_str);
int aes_128_ecb_encode(char *in, int in_len, char *out, int *out_len, const unsigned char *key);
int aes_128_ecb_decode(char *in, int in_len, char *out, int *out_len, const unsigned char *key);

#endif

 

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include "openssl/pem.h"
#include "openssl/bio.h"
#include "openssl/evp.h"
#include "openssl/aes.h"
#include <string.h>
#include <stdio.h>

#define BUF_SIZE 1024

int base64_encode(char *in_str, int in_len, char *out_str);
int base64_decode(char *in_str, int in_len, char *out_str);
int aes_128_ecb_encode(char *in, int in_len, char *out, int *out_len, const unsigned char *key);
int aes_128_ecb_decode(char *in, int in_len, char *out, int *out_len, const unsigned char *key);

int main()
{
	//AES_KEY aes;
	struct aes_key_st enc_aes, dec_aes;
	const unsigned char *in, *key = (unsigned char *)"f29848221a51a2bb"; 
	unsigned char *out, buf2[BUF_SIZE] = {0}; 
	int i, len, out_len;
	int pading_begin, pading_end, pading;

	struct stat st;
	int fd;
	char *buf;
	stat("./tmp", &st);
	printf("size : %d\n", st.st_size);
	buf= (char *)malloc(st.st_size*2);
	fd = open("./tmp", O_RDONLY);
	int nbytes = read(fd, buf, st.st_size);
	printf("buf : \n%s\n", buf);
	//printf("nbytes : %d\n", nbytes);
	//printf("st_size : %d\n", st.st_size);

//	strncpy((char *)buf, "192.168.3.10", 1024);
//	out_len = sizeof(buf);
	out_len = st.st_size;
	int len2 = strlen(buf); 
	//aes_128_ecb_encode(buf, strlen(buf), buf, &out_len, key);
//	out_len = base64_encode(buf, out_len, buf);
//	printf("base64_encode : \n%s\n", buf);
	out_len = base64_decode(buf, out_len, buf);
	aes_128_ecb_decode(buf, out_len, buf, &out_len, key);
	printf("decode : \n%s\n", buf);

	printf("len = %d\n", st.st_size);
	printf("len2 = %d\n", len2);
#if 0
	printf("%s\n", AES_options());
	if (AES_set_encrypt_key(key, 128, &enc_aes) < 0) {
		printf("failed to set enc key");
		exit(-1);
	}
	strncpy((char *)buf, "192.168.3.10", 1024);
	in = buf;
	out = buf;
	printf("before encrypt : \n%s\n", buf);
	/*-----------------------------pading begin-----------------------------*/
	len = strlen((const char *)buf);
	i = len/AES_BLOCK_SIZE + 1;
	pading_end = i*AES_BLOCK_SIZE;
	pading_begin = len;
	printf("len = %d\n, i*AES_BLOCK_SIZE = %d\n", len, (i+1)*AES_BLOCK_SIZE);
	pading = pading_end - pading_begin;
	printf("pading : %d\n", pading);
	memset((void *)(in + pading_begin), pading, pading);
	len = i*AES_BLOCK_SIZE;
	/*-----------------------------pading end-----------------------------*/
	printf("after pading : \n%s\n", buf);

	/*-----------------------------encode begin-----------------------------*/
	for (i = 0; (i+1)*AES_BLOCK_SIZE <= len; i++) {
		AES_ecb_encrypt(in+i*AES_BLOCK_SIZE, out+i*AES_BLOCK_SIZE, &enc_aes, AES_ENCRYPT);
	}
	/*-----------------------------encode end-----------------------------*/
	printf("after encrypt : \n%s\n", buf);
	/*-----------------------------base64 encode begin-----------------------------*/
	base64_encode(buf, len, buf);
	printf("after base64 encode : \n%s\n", buf);
	/*-----------------------------base64 encode end-----------------------------*/
	/*-----------------------------base64 decode begin-----------------------------*/
	base64_decode(buf, strlen(buf), buf);
	printf("after base64 decode : \n%s\n", buf);
	/*-----------------------------base64 decode end-----------------------------*/
	if (AES_set_decrypt_key(key, 128, &dec_aes) < 0) {
		printf("failed to set dec key");
		exit(-1);
	}
	printf("before decrypt : \n%s\n", buf);
	for (i = 0; (i+1)*AES_BLOCK_SIZE <= len; i++) {
		AES_ecb_encrypt(in+i*AES_BLOCK_SIZE, out+i*AES_BLOCK_SIZE, &dec_aes, AES_DECRYPT);
	}
	pading = in[len-1];
	*(char *)(in + len - pading) = '\0';

	printf("after decrypt : \n%s\n", buf);
#endif

	return 0;
}

int base64_encode(char *in_str, int in_len, char *out_str)
{
	BIO *b64, *bio;
	BUF_MEM *bptr = NULL;
	size_t size = 0;

	if (in_str == NULL || out_str == NULL)
		return -1;

	b64 = BIO_new(BIO_f_base64());
	bio = BIO_new(BIO_s_mem());
	bio = BIO_push(b64, bio);
	BIO_write(bio, in_str, in_len);
	BIO_flush(bio);
	BIO_get_mem_ptr(bio, &bptr);
	memcpy(out_str, bptr->data, bptr->length);
	out_str[bptr->length] = '\0';
	size = bptr->length;
	BIO_free_all(bio);

	return size;
}

int base64_decode(char *in_str, int in_len, char *out_str)
{
	BIO *b64, *bio;
	BUF_MEM *bptr = NULL;
	int counts;
	int size = 0;

	if (in_str == NULL || out_str == NULL)
		return -1;
	b64 = BIO_new(BIO_f_base64());
	BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
	bio = BIO_new_mem_buf(in_str, in_len);
	bio = BIO_push(b64, bio);
	size = BIO_read(bio, out_str, in_len);
	out_str[size] = '\0';
	BIO_free_all(bio);

	return size;
}
int aes_128_ecb_encode(char *in, int in_len, char *out, int *out_len, const unsigned char *key)
{
	/*-----------------------------pading begin-----------------------------*/
	int i, pading_end, pading_begin, ret = 0, pading;
	struct aes_key_st enc_aes;
	if (in_len > *out_len) {
		printf("aes_128_ecb_encode err : in_len > out_len\n");
		ret = -1;
		goto __end__;
	}
	if (AES_set_encrypt_key(key, 128, &enc_aes) < 0) {
		printf("failed to set enc key");
		ret = -1;
		goto __end__;
	}
	memcpy(out, in, in_len);
	i = in_len/AES_BLOCK_SIZE + 1;
	pading_end = i*AES_BLOCK_SIZE;
	pading_begin = in_len;
	pading = pading_end - pading_begin;
	memset((void *)(out + pading_begin), pading, pading);
	*out_len = i*AES_BLOCK_SIZE;
	/*-----------------------------pading end-----------------------------*/
	/*-----------------------------encode begin-----------------------------*/
	for (i = 0; (i+1)*AES_BLOCK_SIZE <= *out_len; i++) {
		AES_ecb_encrypt(out+i*AES_BLOCK_SIZE, out+i*AES_BLOCK_SIZE, &enc_aes, AES_ENCRYPT);
	}
	/*-----------------------------encode end-----------------------------*/

__end__:

	return ret;
}

int aes_128_ecb_decode(char *in, int in_len, char *out, int *out_len, const unsigned char *key)
{
	int i = 0, pading, ret = 0;
	struct aes_key_st dec_aes;

	if (in_len == 0) {
		goto __end__;
	}
	if (in_len > *out_len) {
		printf("aes_128_ecb_decode err : in_len > out_len\n");
		ret = -1;
		goto __end__;
	}	
	if (AES_set_decrypt_key(key, 128, &dec_aes) < 0) {
		printf("failed to set dec key");
		ret = -1;
		goto __end__;
	}
	memcpy(out, in, in_len);
	*out_len = in_len;
	for (i = 0; (i+1)*AES_BLOCK_SIZE <= *out_len; i++) {
		AES_ecb_encrypt(out+i*AES_BLOCK_SIZE, out+i*AES_BLOCK_SIZE, &dec_aes, AES_DECRYPT);
	}
	pading = out[*out_len-1];
	*(char *)(out + *out_len - pading) = '\0';

__end__:

	return ret;
}

 

转载于:https://www.cnblogs.com/yangxinrui/p/11416275.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
某同学在宿舍公用计算机上面使用文本文件来记录每天的心情故事,但是宿舍公用计算机不能设置密码,同学担心自己的日记被偷看,特委托你来完成如下加密程序: 该程序是一个可加密数据的日记记录工具,具有如下功能要求: 1. 运行系统后,系统给出三个选项:1)新增日记;2)阅读日记;3)退出系统 2. 选择功能1)后,系统提示用户输入日记文件名称和路径,并创建文本文件;同时,用户输入两个字符a和b,作为密钥;创建文件后,用户开始输入日记内容,日记内容为文本形式,将日记内容加密,然后将加密后的内容写入文件中; 3. 选择功能2)后,系统提示用户输入要打开的日记文件的路径和名称,打开文件后,读取文件中的密文,解密后显示出来; 4. 加密算法推荐大家采用简单的文本加密算法来实现,算法思想如下,从明文读入一个字符(英文),使用密钥a与该字符做异或操作,将结果作为密文保存下来,再读入第二个字符,使用密钥b与该字符做异或操作,同样保存结果,以此类推加密全文;解密过程可将密文作为输入完成整个加密过程,返回就是明文。如果同学们有兴趣加密中文,那么可将中文的高八位使用密钥a加密,低八位使用密钥b加密,完成加密过程。 这个加密算法需要使用C语言的位运算运算符,包括:& 按位与、| 按位或、^ 按位异或、~ 取反、<> 右移。 那么本算法中的异或可用如下方法完成,c为明文中取得的一个字符,该字符加密(解密)指令如下: c = plaintext[i]; //i+1是奇数使用密钥a,是偶数采用密钥b cipher[i] = c ^ a; 那么在cipher[i]中保存的就是c的密文。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值