1. 程式人生 > >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)))

二、加密模式

(1)ECB模式

     DES ECB(電子密本方式)其實非常簡單,就是將資料按照8個位元組一段進行DES加密或解密得到一段8個位元組的密文或者明文,最後一段不足8個位元組,按照需求補足8個位元組進行計算,之後按照順序將計算所得的資料連在一起即可,各段資料之間互不影響。

(2)CBC模式

      DES CBC(密文分組連結方式)有點麻煩,它的實現機制使加密的各段資料之間有了聯絡。其實現的機理如下:

  加密步驟如下:

1)首先將資料按照8個位元組一組進行分組得到D1D2......Dn(若資料不是8的整數倍,用指定的PADDING資料補位)

2)第一組資料D1與初始化向量I異或

後的結果進行DES加密得到第一組密文C1(初始化向量I為全零)

3)第二組資料D2與第一組的加密結果C1異或以後的結果進行DES加密,得到第二組密文C2

4)之後的資料以此類推,得到Cn

5)按順序連為C1C2C3......Cn即為加密結果。

解密是加密的逆過程,步驟如下:

1)首先將資料按照8個位元組一組進行分組得到C1C2C3......Cn

2)將第一組資料進行解密後與初始化向量I進行異或得到第一組明文D1(注意:一定是先解密再異或)

3)將第二組資料C2進行解密後與第一組密文資料進行異或得到第二組資料D2

4)之後依此類推,得到Dn

5)按順序連為D1D2D3......Dn即為解密結果。

這裡注意一點,解密的結果並不一定是我們原來的加密資料,可能還含有你補得位,一定要把補位去掉才是你的原來的資料。


三. 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; 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. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <openssl/des.h>
  5. /************************************************************************
  6. ** 本例採用:
  7. ** 3des-ecb加密方式;
  8. ** 24位金鑰,不足24位的右補0x00;
  9. ** 加密內容8位補齊,補齊方式為:少1位補一個0x01,少2位補兩個0x02,...
  10. ** 本身已8位對齊的,後面補八個0x08。
  11. ************************************************************************/
  12. int main(void)
  13. {
  14.     int docontinue = 1;
  15.     char *data = "hello world!"; /* 明文 */
  16.     int data_len;
  17.     int data_rest;
  18.     unsigned char ch;
  19.     unsigned char *src = NULL; /* 補齊後的明文 */
  20.     unsigned char *dst = NULL; /* 解密後的明文 */
  21.     int len;
  22.     unsigned char tmp[8];
  23.     unsigned char in[8];
  24.     unsigned char out[8];
  25.     char *k = "01234567899876543210"; /* 原始金鑰 */
  26.     int key_len;
  27.     #define LEN_OF_KEY 24
  28.     unsigned char key[LEN_OF_KEY]; /* 補齊後的金鑰 */
  29.     unsigned char block_key[9];
  30.     DES_key_schedule ks,ks2,ks3;
  31.     /* 構造補齊後的金鑰 */
  32.     key_len = strlen(k);
  33.     memcpy(key, k, key_len);
  34.     memset(key + key_len, 0x00, LEN_OF_KEY - key_len);
  35.     /* 分析補齊明文所需空間及補齊填充資料 */
  36.     data_len = strlen(data);
  37.     data_rest = data_len % 8;
  38.     len = data_len + (8 - data_rest);
  39.     ch = 8 - data_rest;
  40.     src = (unsigned char *)malloc(len);
  41.     dst = (unsigned char *)malloc(len);
  42.     if (NULL == src || NULL == dst)
  43.     {
  44.         docontinue = 0;
  45.     }
  46.     if (docontinue)
  47.     {
  48.         int count;
  49.         int i;
  50.         /* 構造補齊後的加密內容 */
  51.         memset(src, 0, len);
  52.         memcpy(src, data, data_len);
  53.         memset(src + data_len, ch, 8 - data_rest);
  54.         /* 金鑰置換 */
  55.         memset(block_key, 0, sizeof(block_key));
  56.         memcpy(block_key, key + 0, 8);
  57.         DES_set_key_unchecked((const_DES_cblock*)block_key, &ks);
  58.         memcpy(block_key, key + 8, 8);
  59.         DES_set_key_unchecked((const_DES_cblock*)block_key, &ks2);
  60.         memcpy(block_key, key + 16, 8);
  61.         DES_set_key_unchecked((const_DES_cblock*)block_key, &ks3);
  62.         printf("before encrypt:\n");
  63.         for (i = 0; i < len; i++)
  64.         {
  65.             printf("0x%.2X ", *(src + i));
  66.         }
  67.         printf("\n");
  68.         /* 迴圈加密/解密,每8位元組一次 */
  69.         count = len / 8;
  70.         for (i = 0; i < count; i++)
  71.         {
  72.             memset(tmp, 0, 8);
  73.             memset(in, 0, 8);
  74.             memset(out, 0, 8);
  75.             memcpy(tmp, src + 8 * i, 8);
  76.             /* 加密 */
  77.             DES_ecb3_encrypt((const_DES_cblock*)tmp, (DES_cblock*)in, &ks, &ks2, &ks3, DES_ENCRYPT);
  78.             /* 解密 */
  79.             DES_ecb3_encrypt((const_DES_cblock*)in, (DES_cblock*)out, &ks, &ks2, &ks3, DES_DECRYPT);
  80.             /* 將解密的內容拷貝到解密後的明文 */
  81.             memcpy(dst + 8 * i, out, 8);
  82.         }
  83.         printf("after decrypt :\n");
  84.         for (i = 0; i < len; i++)
  85.         {
  86.             printf("0x%.2X ", *(dst + i));
  87.         }
  88.         printf("\n");
  89.     }
  90.     if (NULL != src)
  91.     {
  92.         free(src);
  93.         src = NULL;
  94.     }
  95.     if (NULL != dst)
  96.     {
  97.         free(dst);
  98.         dst = NULL;
  99.     }
  100.     return 0;
  101. }