轉自:http://blog.csdn.net/duanxingheng/article/details/11655037
一、DES算法簡介
1、DES算法介紹
2、工作模式
1)ECB模式
DES ECB(電子密本方式)其實非常簡單,就是將數據按照8個字節一段進行DES加密或解密得到一段8個字節的密文或者明文,最後一段不足8個字節,按照需求補足8個字節進行計算,之後按照順序將計算所得的數據連在一起即可,各段數據之間互不影響。
2)CBC模式
DES CBC(密文分組鏈接方式)有點麻煩,它的實現機制使加密的各段數據之間有了聯繫。其實現的機理如下:
加密步驟如下:
a)首先將數據按照8個字節一組進行分組得到D1、D2......Dn(若數據不是8的整數倍,用指定的PADDING數據補位)
b)第一組數據D1與初始化向量I異或後的結果進行DES加密得到第一組密文C1(初始化向量I爲全零)
c)第二組數據D2與第一組的加密結果C1異或以後的結果進行DES加密,得到第二組密文C2
d)之後的數據以此類推,得到Cn
e)按順序連爲C1C2C3......Cn即爲加密結果。
解密是加密的逆過程,步驟如下:
a)首先將數據按照8個字節一組進行分組得到C1C2C3......Cn
b)將第一組數據進行解密後與初始化向量I進行異或得到第一組明文D1(注意:一定是先解密再異或)
c)將第二組數據C2進行解密後與第一組密文數據進行異或得到第二組數據D2
d)之後依此類推,得到Dn
e)按順序連爲D1D2D3......Dn即爲解密結果。
這裏注意一點,解密的結果並不一定是我們原來的加密數據,可能還含有你補得位,一定要把補位去掉纔是你的原來的數據。
3、3DES 算法
3DES算法顧名思義就是3次DES算法,其算法原理如下:
設Ek()和Dk()代表DES算法的加密和解密過程,K代表DES算法使用的密鑰,P代表明文,C代表密表,這樣,
3DES加密過程爲:C=Ek3(Dk2(Ek1(P)))
3DES解密過程爲:P=Dk1((EK2(Dk3(C)))
這裏可以K1=K3,但不能K1=K2=K3(如果相等的話就成了DES算法了)
3DES算法圖示如下:
3DES with 2 diffrent keys(K1=K3),可以是3DES-CBC,也可以是3DES-ECB,3DES-CBC整個算法的流程和DES-CBC一樣,但是在原來的加密或者解密處增加了異或運算的步驟,使用的密鑰是16字節長度的密鑰,將密鑰分成左8字節和右8字節的兩部分,即k1=左8字節,k2=右8字節,然後進行加密運算和解密運算。
3DES with 3 different keys,和3DES-CBC的流程完全一樣,只是使用的密鑰是24字節的,但在每個加密解密加密時候用的密鑰不一樣,將密鑰分爲3段8字節的密鑰分別爲密鑰1、密鑰2、密鑰3,在3DES加密時對加密解密加密依次使用密鑰1、密鑰2、密鑰3,在3DES解密時對解密加密解密依次使用密鑰3、密鑰2、密鑰1。
二、單DES算法ECB模式加解密
1、使用函數DES_set_key_unchecked設置密鑰。
備註:
1)自己指定密鑰時,切記勿使用函數DES_string_to_key,該函數是根據輸入的string隨機計算key,並不是將輸入的string當作key。
2)設置key必須使用DES_set_key_unchecked函數,而不能使用DES_set_key_check函數,否則計算出來的數據會不正確。
3)openssl在進行DES運算時,僅按8字節塊加密,所以必須自己進行數據拆分
2、使用函數DES_ecb_encrypt來進行數據加解密
void DES_ecb_encrypt(const_DES_cblock *input,DES_cblock *output,
DES_key_schedule *ks,int enc);
函數功能說明:DES ECB計算
參數說明:
input: 輸入數據;(8字節長度)
output: 輸出數據;(8字節長度)
ks: 密鑰;
enc:加密:DES_ENCRYPT , 解密:DES_DECRYPT;
三、單DES算法CBC模式加解密
1、使用函數DES_set_key_unchecked設置密鑰
2、使用函數DES_ncbc_encrypt來進行數據加解密
void DES_ncbc_encrypt(const unsigned char *input,unsigned char *output,
long length,DES_key_schedule *schedule,DES_cblock *ivec,
int enc);
參數說明:
input: 輸入數據;(8字節長度)
output: 輸出數據;(8字節長度)
length: 數據長度;(這裏數據長度不包含初始化向量長度)
schedule:密鑰;
ivec: 初始化向量;(一般爲8個字節0)
enc:加密:DES_ENCRYPT , 解密:DES_DECRYPT;
四、T-DES算法ECB模式加解密
1、使用函數DES_set_key_unchecked設置密鑰
2、使用函數DES_ecb3_encrypt來進行加解密
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);
函數說明:
3DES ECB算法
參數說明:
input: 輸入數據
output: 輸出數據
ks1,ks2,ks3, 3DES算法的三隻密鑰,實際應用中,大家更習慣於用兩隻密鑰,調用此函數時,只需在ks3處傳入ks1即可;
enc:加密:DES_ENCRYPT , 解密:DES_DECRYPT
五、T-DES算法CBC模式加解密
1、使用函數DES_set_key_unchecked設置密鑰
2、使用函數DES_ede3_cbc_encrypt來進行加解密
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);
函數功能說明:
3DES CBC模式計算;
參數說明:
input: 輸入數據;(8字節長度)
output: 輸出數據;(8字節長度)
length: 長度;(這裏數據長度不包含初始化向量長度)
ks1:密鑰1;(爲16字節密鑰的左邊8字節)
ks2:密鑰2;(爲16字節密鑰的右邊8字節)
ks3:密鑰3;(爲16字節密鑰的左邊8字節)
ivec:初始化向量;;(一般爲8個字節0)
enc:DES_ENCRYPT , 解密:DES_DECRYPT;
3、CBC模式簡介
數據加密採用3DES-CBC算法,初始向量爲16進制數“0000000000000000”,如圖所示:
數據塊長度爲8字節整數倍,則在此數據塊後附加一個8字節長的數據塊,附加的數據塊爲:16進制的“80 00 00 00 00 00 00 00”
六、示例代碼
1、加密實現:
void CPage1::OnButtonEncrypt()
{
// TODO: Add your control notification handler code here
DES_cblock key;
unsigned char key_hex[256] = {0};
unsigned char data_hex[256] = {0};
unsigned char initval_hex[256] = {0};
unsigned char temp[256] = {0};
int i = 0;
int keylen = 0;
int datalen = 0;
int InitialLen = 0;
DES_key_schedule schedule;
DES_key_schedule schedule2;
DES_key_schedule schedule3;
const_DES_cblock input;
DES_cblock output;
DES_cblock ivec;
UpdateData(TRUE);
m_key.Remove(' ');
m_data.Remove(' ');
m_initval.Remove(' ');
keylen = m_key.GetLength()/2;
datalen = m_data.GetLength()/2;
InitialLen = m_initval.GetLength()/2;
if (keylen%8!=0)
{
AfxMessageBox("輸入密鑰長度不是8的整數倍,請重新輸入!");
return;
}
if (datalen%8!=0)
{
AfxMessageBox("輸入數據長度不是8的整數倍,請重新輸入!");
return;
}
StrToHex(m_key,key_hex,keylen);
StrToHex(m_data,data_hex,datalen);
StrToHex(m_initval,initval_hex,InitialLen);
if (keylen == 8)
{
memcpy(key,key_hex,keylen);
DES_set_key_unchecked(&key, &schedule);
}
else if (keylen == 16)
{
memcpy(key,key_hex,8);
DES_set_key_unchecked(&key, &schedule);
memcpy(key,key_hex+8,8);
DES_set_key_unchecked(&key, &schedule2);
memcpy(key,key_hex,8);
DES_set_key_unchecked(&key, &schedule3);
}
memcpy(ivec,initval_hex,InitialLen);
//單DES算法
if (keylen == 8)
{
//ECB模式
if (((CButton*)GetDlgItem(IDC_RADIO1))->GetCheck())
{
for(i = 0;i < datalen/8;i++)
{
memcpy(input,data_hex+i*8,8);
DES_ecb_encrypt(&input, &output, &schedule, DES_ENCRYPT);
memcpy(temp+i*8,output,8);
}
}
//CBC模式
else if (((CButton*)GetDlgItem(IDC_RADIO2))->GetCheck())
{
memcpy(data_hex+datalen,"\x80\x00\x00\x00\x00\x00\x00\x00",8);
datalen += 8;
for(i = 0;i < datalen/8;i++)
{
DES_ncbc_encrypt(data_hex+i*8, temp+i*8,8,&schedule,&ivec, DES_ENCRYPT);
}
}
}
//TDES算法
else if (keylen == 16)
{
//ECB模式
if (((CButton*)GetDlgItem(IDC_RADIO1))->GetCheck())
{
for (i = 0;i < datalen/8;i++)
{
memcpy(input,data_hex+i*8,8);
DES_ecb3_encrypt(&input, &output, &schedule, &schedule2, &schedule3, DES_ENCRYPT);
memcpy(temp+i*8,output,8);
}
}
//CBC模式
else if (((CButton*)GetDlgItem(IDC_RADIO2))->GetCheck())
{
memcpy(data_hex+datalen,"\x80\x00\x00\x00\x00\x00\x00\x00",8);
datalen += 8;
for(i = 0;i < datalen/8;i++)
{
DES_ede3_cbc_encrypt(data_hex+i*8, temp+i*8,8,&schedule, &schedule2, &schedule3,&ivec, DES_ENCRYPT);
}
}
}
HexToStr(temp,datalen,m_result);
UpdateData(FALSE);
}
2、解密實現:
void CPage1::OnButtonDecrypt()
{
// TODO: Add your control notification handler code here
DES_cblock key;
unsigned char key_hex[256] = {0};
unsigned char data_hex[256] = {0};
unsigned char initval_hex[256] = {0};
unsigned char temp[256] = {0};
int i = 0;
int keylen = 0;
int datalen = 0;
int InitialLen = 0;
DES_key_schedule schedule;
DES_key_schedule schedule2;
DES_key_schedule schedule3;
const_DES_cblock input;
DES_cblock output;
DES_cblock ivec;
UpdateData(TRUE);
m_key.Remove(' ');
m_data.Remove(' ');
m_initval.Remove(' ');
keylen = m_key.GetLength()/2;
datalen = m_data.GetLength()/2;
InitialLen = m_initval.GetLength()/2;
if (keylen%8!=0)
{
AfxMessageBox("輸入密鑰長度不是8的整數倍,請重新輸入!");
return;
}
if (datalen%8!=0)
{
AfxMessageBox("輸入數據長度不是8的整數倍,請重新輸入!");
return;
}
StrToHex(m_key,key_hex,keylen);
StrToHex(m_data,data_hex,datalen);
StrToHex(m_initval,initval_hex,InitialLen);
if (keylen == 8)
{
memcpy(key,key_hex,keylen);
DES_set_key_unchecked(&key, &schedule);
}
else if (keylen == 16)
{
memcpy(key,key_hex,8);
DES_set_key_unchecked(&key, &schedule);
memcpy(key,key_hex+8,8);
DES_set_key_unchecked(&key, &schedule2);
memcpy(key,key_hex,8);
DES_set_key_unchecked(&key, &schedule3);
}
memcpy(ivec,initval_hex,InitialLen);
if (keylen == 8)
{
if (((CButton*)GetDlgItem(IDC_RADIO1))->GetCheck())
{
for(i = 0;i < datalen/8;i++)
{
memcpy(input,data_hex+i*8,8);
DES_ecb_encrypt(&input, &output, &schedule, DES_DECRYPT);
memcpy(temp+i*8,output,8);
}
}
else if (((CButton*)GetDlgItem(IDC_RADIO2))->GetCheck())
{
for(i = 0;i < datalen/8;i++)
{
DES_ncbc_encrypt(data_hex+i*8, temp+i*8,8,&schedule,&ivec, DES_DECRYPT);
}
}
}
else if (keylen == 16)
{
//ECB模式
if (((CButton*)GetDlgItem(IDC_RADIO1))->GetCheck())
{
for (i = 0;i < datalen/8;i++)
{
memcpy(input,data_hex+i*8,8);
DES_ecb3_encrypt(&input, &output, &schedule, &schedule2, &schedule3, DES_DECRYPT);
memcpy(temp+i*8,output,8);
}
}
//CBC模式
else if (((CButton*)GetDlgItem(IDC_RADIO2))->GetCheck())
{
for(i = 0;i < datalen/8;i++)
{
DES_ede3_cbc_encrypt(data_hex+i*8, temp+i*8,8,&schedule, &schedule2, &schedule3,&ivec, DES_DECRYPT);
}
}
}
HexToStr(temp,datalen,m_result);
UpdateData(FALSE);
}