OpenSSL编程-3DES编程详解

一. 3DES加密原理

3DES(或称为Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。它相当于是对每个数据块应用三次DES加密算法。由于计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解;3DES即是设计用来提供一种相对简单的方法,即通过增加DES的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法。

3DES(即Triple DES)是DES向AES过渡的加密算法(1999年,NIST将3-DES指定为过渡的加密标准),加密算法,其具体实现如下:设Ek()和Dk()代表DES算法的加密和解密过程,K代表DES算法使用的密钥,P代表明文,C代表密文,这样:
3DES加密(EDE)过程为:C=Ek3(Dk2(Ek1(P)))
3DES解密(DED)过程为:P=Dk1(EK2(Dk3(C)))

二. 3DES API

1. 基本数据结构

        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. 3DES ECB模式加解密API

        void DES_ecb3_encrypt(const_DES_cblock *input, DES_cblock *output,
              DES_key_schedule *ks1, DES_key_schedule *ks2, DES_key_schedule *ks3, int enc);

        参数说明:
            input:输入数据, 8字节
            output:输出数据, 8字节
            ks1:密钥1
            ks2:密钥2
            ks3:密钥3
            enc:加密-DES_ENCRYPT, 解密-DES_DECRYPT

5. 3DES CBC模式加解密API

        void DES_ede3_cbc_encrypt(const unsigned char *input,unsigned char *output, long length,
              DES_key_schedule *ks1, DES_key_schedule *ks2, DES_key_schedule *ks3, DES_cblock *ivec, int enc);

        参数说明:
            input: 输入参数, 8字节倍数
            output: 输出参数, 8字节倍数
            length: input的长度, 通常为8字节倍数
            ks1: 密钥1
            ks2: 密钥2
            ks3: 密钥3
            ivec: 初始向量, 8字节, 默认为全0
            enc: 加密-DES_ENCRYPT, 解密-DES_DECRYPT

三. 3DES 示例

1. 3DES ECB模式示例

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/des.h>
#include <openssl/rand.h>

#include "hex.h"

/************************************************************************
 * 3DES-ECB加密方式
 * 8字节密钥,加密内容8位补齐,补齐方式为:PKCS7。
 *
 * file: test_des3_ecb.c
 * gcc -Wall -O2 -o test_des3_ecb test_des3_ecb.c hex.c -lcrypto
 *
 * author: tonglulin@gmail.com by www.qmailer.net
 ************************************************************************/
int main(int argc, char *argv[])
{
    int i = 0;
    int len = 0;
    int nlen = 0;

    char ch = '\0';
    char *key1 = "0000000000000000";  /* 原始密钥, 十六进制字符串 */
    char *key2 = "0000000000000000";  /* 原始密钥, 十六进制字符串 */
    char *key3 = "0000000000000000";  /* 原始密钥, 十六进制字符串 */
    char *data = "12345678123456781234567812345678";  /* 原始明文, 十六进制字符串 */
    unsigned char src[64] = {0};
    unsigned char out[64] = {0};
    unsigned char tmp[64] = {0};

    unsigned char *ptr  = NULL;
    unsigned char block[8] = {0};
    DES_key_schedule ks1, ks2, ks3;

    /* 设置密码表 */
    ptr = hex2bin(key1, strlen(key1), &nlen);
    memcpy(block, ptr, sizeof(block));
    free(ptr);
    DES_set_key_unchecked((C_Block *)block, &ks1);

    ptr = hex2bin(key2, strlen(key2), &nlen);
    memcpy(block, ptr, sizeof(block));
    free(ptr);
    DES_set_key_unchecked((C_Block *)block, &ks2);

    ptr = hex2bin(key3, strlen(key3), &nlen);
    memcpy(block, ptr, sizeof(block));
    free(ptr);
    DES_set_key_unchecked((C_Block *)block, &ks3);

    ptr = hex2bin(data, strlen(data), &nlen);
    memcpy(src, ptr, nlen);
    free(ptr);

    len = (nlen / 8 + (nlen % 8 ? 1: 0)) * 8;

    ch = 8 - nlen % 8;
    memset(src + nlen, ch, (8 - nlen % 8) % 8);

    printf("加密前数据: ");
    for (i = 0; i < len; i++) {
        printf("%02X", *(src + i));
    }
    printf("\n");

    for (i = 0; i < len; i += 8) {
        DES_ecb3_encrypt((C_Block *)(src + i), (C_Block *)(out + i), &ks1, &ks2, &ks3, DES_ENCRYPT);
    }

    printf("加密后数据: ");
    for (i = 0; i < len; i++) {
        printf("%02X" , *(out + i));
    }
    printf("\n");

    for (i = 0; i < len; i += 8) {
        DES_ecb3_encrypt((C_Block *)(out + i), (C_Block *)(tmp + i), &ks1, &ks2, &ks3, DES_DECRYPT);
    }

    printf("解密后数据: ");
    for (i = 0; i < len; i++) {
        printf("%02X", *(tmp + i));
    }
    printf("\n");

    return 0;
}

2. 3DES CBC模式示例

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/des.h>
#include <openssl/rand.h>

#include "hex.h"

/************************************************************************
 * 3DES-ECB加密方式
 * 8字节密钥,加密内容8位补齐,补齐方式为:PKCS7。
 *
 * file: test_des3_ecb.c
 * gcc -Wall -O2 -o test_des3_cbc test_des3_cbc.c hex.c -lcrypto
 *
 * author: tonglulin@gmail.com by www.qmailer.net
 ************************************************************************/
int main(int argc, char *argv[])
{
    int i = 0;
    int len = 0;
    int nlen = 0;

    char ch = '\0';
    char *key1 = "0000000000000000";  /* 原始密钥, 十六进制字符串 */
    char *key2 = "0000000000000000";  /* 原始密钥, 十六进制字符串 */
    char *key3 = "0000000000000000";  /* 原始密钥, 十六进制字符串 */
    char *data = "12345678123456781234567812345678";  /* 原始明文, 十六进制字符串 */
    unsigned char src[64] = {0};
    unsigned char out[64] = {0};
    unsigned char tmp[64] = {0};

    unsigned char *ptr  = NULL;
    unsigned char block[8] = {0};
    DES_key_schedule ks1, ks2, ks3;
    DES_cblock ivec;
    DES_cblock ivsetup = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    /* 设置密码表 */
    ptr = hex2bin(key1, strlen(key1), &nlen);
    memcpy(block, ptr, sizeof(block));
    free(ptr);
    DES_set_key_unchecked((C_Block *)block, &ks1);

    ptr = hex2bin(key2, strlen(key2), &nlen);
    memcpy(block, ptr, sizeof(block));
    free(ptr);
    DES_set_key_unchecked((C_Block *)block, &ks2);

    ptr = hex2bin(key3, strlen(key3), &nlen);
    memcpy(block, ptr, sizeof(block));
    free(ptr);
    DES_set_key_unchecked((C_Block *)block, &ks3);

    ptr = hex2bin(data, strlen(data), &nlen);
    memcpy(src, ptr, nlen);
    free(ptr);

    len = (nlen / 8 + (nlen % 8 ? 1: 0)) * 8;

    ch = 8 - nlen % 8;
    memset(src + nlen, ch, (8 - nlen % 8) % 8);

    printf("加密前数据: ");
    for (i = 0; i < len; i++) {
        printf("%02X", *(src + i));
    }
    printf("\n");

    memcpy(ivec, ivsetup, sizeof(ivsetup));
    /* 按照8字节数据进行加密,length=8 */
    for (i = 0; i < len; i += 8) {
        DES_ede3_cbc_encrypt(src + i, out + i, 8, &ks1, &ks2, &ks3, &ivec, DES_ENCRYPT);
    }

    printf("加密后数据: ");
    for (i = 0; i < len; i++) {
        printf("%02X" , *(out + i));
    }
    printf("\n");

    memcpy(ivec, ivsetup, sizeof(ivsetup));
    /* 按照8字节数据进行解密,length=8 */
    for (i = 0; i < len; i += 8) {
        DES_ede3_cbc_encrypt(out + i, tmp + i, 8, &ks1, &ks2, &ks3, &ivec, DES_DECRYPT);
    }

    printf("解密后数据: ");
    for (i = 0; i < len; i++) {
        printf("%02X", *(tmp + i));
    }
    printf("\n");

    return 0;
}

3. 输出结果

# ECB模式
加密前数据: 12345678123456781234567812345678
加密后数据: 4A438AC15D8074B54A438AC15D8074B5
解密后数据: 12345678123456781234567812345678

# CBC模式
加密前数据: 12345678123456781234567812345678
加密后数据: 4A438AC15D8074B58244AE0E7477AF78
解密后数据: 12345678123456781234567812345678

由结果可见,ECB和CBC模式的第一个8字节加密结果一致,而CBC模式的第二个8字节起会不断变化,同时,如果k1=k2=k3,则加密结果和DES加密算法相同。

四. HEX转换函数

请参考前面的Blog:《OpenSSL编程-DES编程详解

原创声明:除非注明,本站文章均为原创!转载请注明来自 嗨!大佟! www.qmailer.net
本文链接:http://www.qmailer.net/archives/208.html

发表评论