OpenSSL编程-DES编程详解

转自 : http://www.qmailer.net/archives/188.html


一. DES加密原理

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

二. DES API

1. 基本数据结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typedefunsigned charDES_cblock[8];
typedef/* const */ unsigned charconst_DES_cblock[8];
 
typedefstruct 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. 基本宏定义

1
2
#define DES_ENCRYPT 1
#define DES_DECRYPT 0

3. 设置密钥函数

1
2
3
4
5
6
7
8
9
10
11
//根据字符串生成key
voidDES_string_to_key(constchar *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
//设置密码表,并进行校验
intDES_set_key_checked(const_DES_cblock *key, DES_key_schedule *schedule);
 
//设置密码表,不需要校验
voidDES_set_key_unchecked(const_DES_cblock *key, DES_key_schedule *schedule);

4. DES ECB模式加解密API

1
2
3
4
5
6
7
voidDES_ecb_encrypt(const_DES_cblock *input, DES_cblock *output, DES_key_schedule *ks,intenc);
 
参数说明:
    input:输入数据,8字节
    output:输出数据,8字节
    ks:密钥
    enc:加密-DES_ENCRYPT,解密-DES_DECRYPT

5. DES CBC模式加解密API

1
2
3
4
5
6
7
8
9
voidDES_ncbc_encrypt(constunsigned char*input, unsigned char*output, longlength, DES_key_schedule *schedule, DES_cblock *ivec, intenc);
 
参数说明:
    input: 输入参数,8字节倍数
    output: 输出参数,8字节倍数
    length: input的长度
    schedule: 密钥
    ivec: 初始向量, 8字节
    enc: 加密-DES_ENCRYPT,解密-DES_DECRYPT

三. DES 示例

1. DES ECB模式示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/des.h>
 
#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
 ************************************************************************/
intmain(intargc, char*argv[])
{
    DES_key_schedule ks;
 
    inti = 0;
    intlen = 0;
    intnlen = 0;
    intcount = 0;
 
    char*data = "12345678123456781234567812345678"/* 原始明文, 十六进制字符串 */
    char*okey = "0000000000000000";                 /* 原始密钥, 十六进制字符串 */
 
    unsignedcharch = '\0';
    unsignedchar*ptr = NULL;
 
    unsignedcharsrc[16] = {0}; /* 补齐后的明文, data补齐后的1/2长度 */
    unsignedchardst[16] = {0}; /* 解密后的明文, data补齐后的1/2长度 */
 
    unsignedcharout[8] = {0};
    unsignedchartmp[8] = {0};
    unsignedcharblock[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");
 
    return0;
}

2. DES CBC模式示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/des.h>
 
#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
 ************************************************************************/
intmain(intargc, char*argv[])
{
    DES_key_schedule ks;
    DES_cblock ivec = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 
    inti = 0;
    intlen = 0;
    intnlen = 0;
 
    char*data = "12345678123456781234567812345678"/* 原始明文, 十六进制字符串 */
    char*okey = "0000000000000000";                 /* 原始密钥, 十六进制字符串 */
 
    unsignedcharch = '\0';
    unsignedchar*ptr = NULL;
 
    unsignedcharsrc[16] = {0}; /* 补齐后的明文, data补齐后的1/2长度 */
    unsignedchardst[16] = {0}; /* 解密后的明文, data补齐后的1/2长度 */
 
    unsignedcharblock[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");
 
    return0;
}

3. 输出结果

1
2
3
4
5
6
7
# ECB 模式
加密之前: 12345678123456781234567812345678
加密之后: 4A438AC15D8074B54A438AC15D8074B5
 
# CBC模式
加密之前: 12345678123456781234567812345678
加密之后: 4A438AC15D8074B58244AE0E7477AF78

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

四. HEX转换函数

1. HEX头文件 hex.h

1
2
3
4
5
6
7
8
#ifndef _HEX_H_
#define _HEX_H_
 
char*bin2hex(unsigned char*data, intsize);
 
unsignedchar*hex2bin(constchar *data, intsize, int*outlen);
 
#endif

1. HEX定义文件 hex.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
/************************************************************************
 * 二进制字节数组转换十六进制字符串函数
 * 输入:
 *       data 二进制字节数组
 *       size 二进制字节数组长度
 * 输出:
 *       十六进制字符串,需要free函数释放空间,失败返回NULL
 *
 * author: tonglulin@gmail.com by www.qmailer.net
 ************************************************************************/
char*bin2hex(unsigned char*data, intsize)
{
    int i = 0;
    int v = 0;
    char*p = NULL;
    char*buf = NULL;
    charbase_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';
    returnbuf;
}
 
/************************************************************************
 * 十六进制字符串转换二进制字节数组
 * 输入:
 *       data 十六进制字符串
 *       size 十六进制字符串长度,2的倍数
 *       outlen 转换后的二进制字符数组长度
 * 输出:
 *       二进制字符数组,需要free函数释放空间,失败返回NULL
 *
 * author: tonglulin@gmail.com by www.qmailer.net
 ************************************************************************/
unsignedchar*hex2bin(constchar *data, intsize, int*outlen)
{
    inti = 0;
    intlen = 0;
    charchar1 = '\0';
    charchar2 = '\0';
    unsignedcharvalue = 0;
    unsignedchar*out = NULL;
 
    if(size % 2 != 0) {
        returnNULL;
    }
 
    len = size / 2;
    out = (unsigned char*)malloc(len * sizeof(char) + 1);
    if(out == NULL) {
        returnNULL;
    }
 
    while(i < len) {
        char1 = *data;
        if(char1 >= '0'&& char1 <= '9') {
            value = (char1 - '0') << 4;
        }
        elseif (char1 >= 'a'&& char1 <= 'f') {
            value = (char1 - 'a'+ 10) << 4;
        }
        elseif (char1 >= 'A'&& char1 <= 'F') {
            value = (char1 - 'A'+ 10) << 4;
        }
        else{
            free(out);
            returnNULL;
        }
        data++;
 
        char2 = *data;
        if(char2 >= '0'&& char2 <= '9') {
            value |= char2 - '0';
        }
        elseif (char2 >= 'a'&& char2 <= 'f') {
            value |= char2 - 'a'+ 10;
        }
        elseif (char2 >= 'A'&& char2 <= 'F') {
            value |= char2 - 'A'+ 10;
        }
        else{
            free(out);
            returnNULL;
        }
 
        data++;
        *(out + i++) = value;
    }
    *(out + i) = '\0';
 
    if(outlen != NULL) {
        *outlen = i;
    }
 
    returnout;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值