Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2105486
  • 博文数量: 389
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4126
  • 用 户 组: 普通用户
  • 注册时间: 2016-07-04 13:04
文章分类

全部博文(389)

文章存档

2020年(4)

2019年(24)

2018年(135)

2017年(158)

2016年(68)

我的朋友

分类: 嵌入式

2018-11-22 16:49:48

一. DES加密原理

DES 使用一个 56 位的密钥以及附加的 8 位奇偶校验位(每组的第8位作为奇偶校验位),产生最大 64 位的分组大小。这是一个迭代的分组密码,使用称为 Feistel 的技术,其中将加密的文本块分成两半。使用子密钥对其中一半应用循环功能,然后将输出与另一半进行“异或”运算;接着交换这两半,这一过程会继续下去,但最后一个循环不交换。DES 使用 16 轮循环,使用异或,置换,代换,移位操作四种基本运算。

二. DES API

typedef unsigned char DES_cblock[8]; 
typedef /* const */ unsigned char const_DES_cblock[8]; 
typedef struct DES_ks 
{ union { DES_cblock cblock; DES_LONG deslong[2]; }
 ks[16];
 } DES_key_schedule; 
sizeof(DES_cblock) = 8字节 
sizeof(const_DES_cblock ) = 8字节 
sizeof(DES_key_schedule) = 128字节

2. 基本宏定义

#define DES_ENCRYPT 1 #define DES_DECRYPT 0

3. 设置密钥函数

//根据字符串生成
key void DES_string_to_key(const char *str, DES_cblock *key);  
//will check that the key passed is of odd parity and is not a week or semi-weak key. 
//If the parity is wrong, then -1 is returned. If the key is a weak key, then -2 is returned. 
//If an error is returned, the key schedule is not generated  
//设置密码表,并进行校验  int DES_set_key_checked(const_DES_cblock *key, DES_key_schedule *schedule); 
//设置密码表,不需要校验 void DES_set_key_unchecked(const_DES_cblock *key, DES_key_schedule *schedule);

4. DES ECB模式加解密API

void DES_ecb_encrypt(const_DES_cblock *input, DES_cblock *output, DES_key_schedule *ks, int enc); 
参数说明: input
输入数据,8字节 output
输出数据,8字节 ks
密钥 enc
加密-DES_ENCRYPT
解密-DES_DECRYPT

5. DES CBC模式加解密API

void DES_ncbc_encrypt(const unsigned char *input, unsigned char *output, long length, DES_key_schedule *schedule, DES_cblock *ivec, int enc); 
参数说明: input: 
输入参数,8字节倍数 output: 
输出参数,8字节倍数 length: 
input的长度 schedule: 
密钥 ivec: 初始向量, 8字节 enc: 加密-DES_ENCRYPT,解密-DES_DECRYPT

三. DES 示例

1. DES ECB模式示例

#include   #include  #include  #include  #include "hex.h"
 /************************************************************************
 * DES-ECB加密方式
 * 8位密钥,加密内容8位补齐,补齐方式为:PKCS7。
 *
 * file: test_des_ecb.c
 * gcc -Wall -O2 -o test_des_ecb test_des_ecb.c hex.c -lcrypto
 *
 * author: tonglulin@gmail.com by www.qmailer.net
 ************************************************************************
/ int main(int argc, char *argv[]) 
{
 DES_key_schedule ks; 
int i = 0;
 int len = 0;
 int nlen = 0;
 int count = 0;
 char *data = "12345678123456781234567812345678"; 
/* 原始明文, 十六进制字符串 */ 
char *okey = "0000000000000000"; 
/* 原始密钥, 十六进制字符串 */ 
unsigned char ch = '\0'; 
unsigned char *ptr = NULL; 
unsigned char src[16] = {0}; 
/* 补齐后的明文, data补齐后的1/2长度 */
 unsigned char dst[16] = {0}; 
/* 解密后的明文, data补齐后的1/2长度 */
 unsigned char out[8] = {0};
 unsigned char tmp[8] = {0}; 
unsigned char block[8] = {0}; 
/* 设置密码表 */
 ptr = hex2bin(okey, strlen(okey), &nlen); 
memcpy(block, ptr, 8); free(ptr); 
DES_set_key_unchecked((const_DES_cblock*)block, &ks); 
/* 分析补齐明文所需空间及补齐填充数据 */
len = strlen((char *)data);
 ptr = hex2bin(data, len, &nlen); 
len = (nlen / 8 + (nlen % 8 ? 1: 0)) * 8;
 memcpy(src, ptr, len);
 free(ptr);
 ch = 8 - nlen % 8; 
memset(src + nlen, ch, 8 - nlen % 8); 
printf("加密之前: "); 
for (i = 0; i < len; i++) 
{ 
printf("%.2X", *(src + i));
 } 
printf("\n");
 /* 分组加密,每8字节一组 */ 
count = len / 8; 
for (i = 0; i < count; i++) 
{
 memcpy(tmp, src + 8 * i, 8); 
DES_ecb_encrypt((const_DES_cblock*)tmp, (DES_cblock*)out, &ks, DES_ENCRYPT);
 memcpy(dst + 8 * i, out, 8); 
} 
printf("加密之后: "); 
for (i = 0; i < len; i++) 
{ printf("%.2X", *(dst + i)); } 
printf("\n"); 
return 0;
 }

2. DES CBC模式示例

#include  #include  #include  #include  #include "hex.h" 
/************************************************************************
 * DES-CBC加密方式
 * 8位密钥,加密内容8位补齐,补齐方式为:PKCS7。
 *
 * file: test_des_cbc.c
 * gcc -Wall -O2 -o test_des_cbc test_des_cbc.c hex.c -lcrypto
 *
 * author: tonglulin@gmail.com by www.qmailer.net
 ************************************************************************/ 
int main(int argc, char *argv[]) 
{ 
DES_key_schedule ks;
 DES_cblock ivec = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 int i = 0;
 int len = 0; 
int nlen = 0; 
char *data = "12345678123456781234567812345678"; 
/* 原始明文, 十六进制字符串 */
 char *okey = "0000000000000000";
 /* 原始密钥, 十六进制字符串 */ 
unsigned char ch = '\0'; 
unsigned char *ptr = NULL; 
unsigned char src[16] = {0}; 
/* 补齐后的明文, data补齐后的1/2长度 */ 
unsigned char dst[16] = {0};
 /* 解密后的明文, data补齐后的1/2长度 */
 unsigned char block[8] = {0}; 
/* 设置密码表 */ 
ptr = hex2bin(okey, strlen(okey), &nlen); 
memcpy(block, ptr, 8); free(ptr); 
DES_set_key_unchecked((const_DES_cblock*)block, &ks);
 /* 分析补齐明文所需空间及补齐填充数据 */
 len = strlen((char *)data); 
ptr = hex2bin(data, len, &nlen); 
len = (nlen / 8 + (nlen % 8 ? 1: 0)) * 8; 
memcpy(src, ptr, len); free(ptr); 
ch = 8 - nlen % 8; 
memset(src + nlen, ch, 8 - nlen % 8);
 printf("加密之前: "); 
for (i = 0; i < len; i++) 
{
 printf("%.2X", *(src + i));
 } 
printf("\n"); 
/* 加密块链式加密 */ 
DES_ncbc_encrypt(src, dst, sizeof(src), &ks, &ivec, DES_ENCRYPT); 
printf("加密之后: "); 
for (i = 0; i < len; i++) 
{ printf("%.2X", *(dst + i)); } 
printf("\n"); 
return 0; }

3. 输出结果

# ECB 模式 
加密之前: 12345678123456781234567812345678 
加密之后: 4A438AC15D8074B54A438AC15D8074B5 
# CBC模式 加密之前: 12345678123456781234567812345678
 加密之后: 4A438AC15D8074B58244AE0E7477AF78

由结果可见,ECB和CBC模式的第一个8字节分组结果是一致的

四. HEX转换函数

1. HEX头文件 hex.h

#ifndef _HEX_H_
 #define _HEX_H_ 
char *bin2hex(unsigned char *data, int size); 
unsigned char *hex2bin(const char *data, int size, int *outlen);
 #endif

1. HEX定义文件 hex.c

#include  #include  #include 
 /************************************************************************
 * 二进制字节数组转换十六进制字符串函数
 * 输入: 
 *       data 二进制字节数组
 *       size 二进制字节数组长度
 * 输出:
 *       十六进制字符串,需要free函数释放空间,失败返回NULL
 *
 * author: tonglulin@gmail.com by www.qmailer.net
 ************************************************************************/ 
char *bin2hex(unsigned char *data, int size) 
{ int i = 0;
 int v = 0; 
char *p = NULL;
 char *buf = NULL; 
char base_char = 'A';
 buf = p = (char *)malloc(size * 2 + 1); 
for (i = 0; i < size; i++) {
 v = data[i] >> 4; 
*p++ = v < 10 ? v + '0' : v - 10 + base_char; 
v = data[i] & 0x0f; *p++ = v < 10 ? v + '0' : v - 10 + base_char; 
} 
*p = '\0'; return buf; } 
/************************************************************************
 * 十六进制字符串转换二进制字节数组
 * 输入: 
 *       data 十六进制字符串
 *       size 十六进制字符串长度,2的倍数
 *       outlen 转换后的二进制字符数组长度
 * 输出:
 *       二进制字符数组,需要free函数释放空间,失败返回NULL
 *
 * author: tonglulin@gmail.com by www.qmailer.net
 ************************************************************************/ 
unsigned char *hex2bin(const char *data, int size, int *outlen)
 {
 int i = 0; 
int len = 0; 
char char1 = '\0'; 
char char2 = '\0'; 
unsigned char value = 0;
 unsigned char *out = NULL; 
if (size % 2 != 0)
 { 
return NULL; 
} 
len = size / 2; 
out = (unsigned char *)malloc(len * sizeof(char) + 1); 
if (out == NULL) 
{ return NULL; } 
while (i < len) {
char1 = *data;
 if (char1 >= '0' && char1 <= '9') 
{ 
value = (char1 - '0') << 4;
 } 
else if (char1 >= 'a' && char1 <= 'f') 
{
 value = (char1 - 'a' + 10) << 4;
 } 
else if (char1 >= 'A' && char1 <= 'F')
 { 
value = (char1 - 'A' + 10) << 4;
 }
 else { free(out); return NULL; } data++;
char2 = *data; 
if (char2 >= '0' && char2 <= '9') 
{ value |= char2 - '0'; } 
else if (char2 >= 'a' && char2 <= 'f') 
{ value |= char2 - 'a' + 10; }
 else if (char2 >= 'A' && char2 <= 'F')
 { value |= char2 - 'A' + 10; } 
else { free(out); 
return NULL; 
} 
data++; *(out + i++) = value; } 
*(out + i) = '\0'; if (outlen != NULL) { *outlen = i; } return out; }
阅读(1015) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~