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異或
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 示例
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <openssl/des.h>
- /************************************************************************
- ** 本例採用:
- ** 3des-ecb加密方式;
- ** 24位金鑰,不足24位的右補0x00;
- ** 加密內容8位補齊,補齊方式為:少1位補一個0x01,少2位補兩個0x02,...
- ** 本身已8位對齊的,後面補八個0x08。
- ************************************************************************/
- int main(void)
- {
- int docontinue
= 1;
- char *data
= "hello world!";
/* 明文
*/
- int data_len;
- int data_rest;
- unsigned char ch;
- unsigned char *src
= NULL;
/* 補齊後的明文
*/
- unsigned char *dst
= NULL;
/* 解密後的明文
*/
- int len;
- unsigned char tmp[8];
- unsigned char in[8];
- unsigned char out[8];
- char *k =
"01234567899876543210";
/* 原始金鑰
*/
- int key_len;
- #define LEN_OF_KEY 24
- unsigned char key[LEN_OF_KEY];
/* 補齊後的金鑰
*/
- unsigned char block_key[9];
- DES_key_schedule ks,ks2,ks3;
- /* 構造補齊後的金鑰
*/
- key_len = strlen(k);
- memcpy(key, k, key_len);
- memset(key
+ key_len, 0x00, LEN_OF_KEY
- key_len);
- /* 分析補齊明文所需空間及補齊填充資料
*/
- data_len = strlen(data);
- data_rest = data_len
% 8;
- len = data_len
+ (8
- data_rest);
- ch = 8 - data_rest;
- src = (unsigned char
*)malloc(len);
- dst = (unsigned char
*)malloc(len);
- if (NULL
== src
|| NULL
== dst)
- {
- docontinue = 0;
- }
- if (docontinue)
- {
- int count;
- int i;
- /* 構造補齊後的加密內容
*/
- memset(src, 0,
len);
- memcpy(src, data, data_len);
- memset(src
+ data_len, ch, 8
- data_rest);
- /* 金鑰置換
*/
- memset(block_key, 0, sizeof(block_key));
- memcpy(block_key, key
+ 0, 8);
- DES_set_key_unchecked((const_DES_cblock*)block_key,
&ks);
- memcpy(block_key, key
+ 8, 8);
- DES_set_key_unchecked((const_DES_cblock*)block_key,
&ks2);
- memcpy(block_key, key
+ 16, 8);
- DES_set_key_unchecked((const_DES_cblock*)block_key,
&ks3);
- printf("before encrypt:\n");
- for (i
= 0; i
< len; i++)
- {
- printf("0x%.2X ",
*(src
+ i));
- }
- printf("\n");
- /* 迴圈加密/解密,每8位元組一次
*/
- count =
len / 8;
- for (i
= 0; i
< count; i++)
- {
- memset(tmp, 0, 8);
- memset(in, 0, 8);
- memset(out, 0, 8);
- memcpy(tmp, src
+ 8 * i, 8);
- /* 加密
*/
- DES_ecb3_encrypt((const_DES_cblock*)tmp,
(DES_cblock*)in,
&ks,
&ks2, &ks3, DES_ENCRYPT);
- /* 解密
*/
- DES_ecb3_encrypt((const_DES_cblock*)in,
(DES_cblock*)out,
&ks,
&ks2, &ks3, DES_DECRYPT);
- /* 將解密的內容拷貝到解密後的明文
*/
- memcpy(dst
+ 8 * i, out, 8);
- }
- printf("after decrypt :\n");
- for (i
= 0; i
< len; i++)
- {
- printf("0x%.2X ",
*(dst
+ i));
- }
- printf("\n");
- }
- if (NULL
!= src)
- {
- free(src);
- src =
NULL;
- }
- if (NULL
!= dst)
- {
- free(dst);
- dst =
NULL;
- }
- return 0;
- }