OpenSSL編程-3DES編程詳解

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. 基本數據結構

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

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. 基本宏定義

1

2

#define DES_ENCRYPT 1

#define DES_DECRYPT 0

3. 設置密鑰函數

1

2

3

4

5

6

7

8

9

10

11

//根據字符串生成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

1

2

3

4

5

6

7

8

9

10

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

1

2

3

4

5

6

7

8

9

10

11

12

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模式示例

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

#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: [email protected] 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模式示例

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

#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: [email protected] 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. 輸出結果

1

2

3

4

5

6

7

8

9

# ECB模式

加密前數據: 12345678123456781234567812345678

加密後數據: 4A438AC15D8074B54A438AC15D8074B5

解密後數據: 12345678123456781234567812345678

 

# CBC模式

加密前數據: 12345678123456781234567812345678

加密後數據: 4A438AC15D8074B58244AE0E7477AF78

解密後數據: 12345678123456781234567812345678

由結果可見,ECB和CBC模式的第一個8字節加密結果一致,而CBC模式的第二個8字節起會不斷變化,同時,如果k1=k2=k3,則加密結果和DES加密算法相同。

四. HEX轉換函數

請參考前面的Blog:《OpenSSL編程-DES編程詳解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章