DES 对称加密方式,在通信过程中经常用到。DES有四种加密模式:

 

1. ECB

Electronic Codebook

最古老简单的模式,加密数据长度必须为8的倍数(不足8位添加padding),密钥必须为8位。不依赖向量,易受到字典攻击。不推荐。

2. CBC

Cipher Block Chaining

引入初始化vector,可以使用不同的Vector产生不同的密文。缺点一个错误发生后,当前和以后的数据都会被影响。

3. CFB

Cipher Feedback 

加密反馈模式克服了需要等待8个字节才能加密的缺点,它采用了分组密码作为流密码的密钥流生成器。缺点一旦某位数据出错,会影响目前和其后8个块的数据;

4. OFB

Output Feedback 

 

其中以ECB模式最简单,不依赖向量,缺点也比较明显,易受到字典攻击。推荐使用CFB方式加密。

下面探讨一下ECB各语言下的实现。

 

一. C实现

C语言下可调用第三方库openssl实现DES加密。



#include <openssl/des.h>

/**
* @brief DES ECB加解密,暂时不选用CBC
* @param pSrc [in] 源字符串
* @param pLen 源字符串长度
* @param key [in] 密钥
* @param kLen 密钥长度
* @param enc 操作类型,DES_ENCRYPT加密,DES_DECRYPT解密
* @param cipher [out] 加密后的字符串
* @param oLen [out] 加密后的字符串长度
*
* @return 加密后的字符串
*/
std::string _DESCode( const char *pSrc,
int pLen,
char *key,
int kLen,
int *oLen,
int enc )
{
std::string strCipher;
std::vector<unsigned char> ciphers;

DES_cblock keyEncrypt;
memset( (void*)keyEncrypt,0,8 );

// 只取key的8位
memcpy( (void*)keyEncrypt,
(void*)key,
kLen >=8?8:kLen );

// 设置key
DES_key_schedule keySchedule;
DES_set_key_unchecked(&keyEncrypt, &keySchedule);

const_DES_cblock inputText; // 每次输入8位
DES_cblock outputText; // 每次输出8位
unsigned char tmp[8]; // 中间结果

// 每次加密8字节
for( int i = 0; i < pLen/8; i++ )
{
memcpy( inputText, pSrc + i*8,8 );
DES_ecb_encrypt( &inputText,&outputText,&keySchedule,enc );
memcpy( tmp,outputText,8 );

// 汇总
for( int j=0; j<8; j++ )
{
ciphers.push_back( tmp[j] );
}
}

// 不足8倍数补齐
if( pLen%8 )
{
int tmp1 = pLen/8*8;
int tmp2 = pLen - tmp1;
memset( (void*)inputText,0,8 ); // 填充0
memcpy( (void*)inputText,(void*)(pSrc + tmp1), tmp2 ); // 剩余部分

DES_ecb_encrypt( &inputText,&outputText,&keySchedule,enc );
memcpy( tmp,outputText,8 );

// 汇总
for( int j=0; j<8; j++ )
{
ciphers.push_back( tmp[j] );
}
}

// 复制结果
strCipher.clear();
strCipher.assign( ciphers.begin(),ciphers.end() );

// 密文长度
*oLen = ciphers.size();
if( enc == DES_DECRYPT )
{
*oLen = strCipher.size();
}

return strCipher;
}



 

2. java实现

public static final String ALGORITHM_DES = "DES/ECB/NoPadding"; // ECB

/**
* DES算法,加密
*
* @param data 待加密字符串,数据不足8位倍数会自动补全
* @param key 加密私钥,长度不能够小于8位
* @return 加密后的字节数组,一般结合Base64编码使用
* @throws InvalidAlgorithmParameterException
* @throws Exception
*/
public static byte[] encode(String key,String data) {
if(data == null)
return null;

// ECB模式下,待加密字符串长度必须为8的倍数
data = fillZero(data);

try{
DESKeySpec dks = new DESKeySpec(key.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");

// key的长度不能够小于8位字节
Key secretKey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance(ALGORITHM_DES);

// 加密
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] bytes = cipher.doFinal(data.getBytes());
return bytes;
}catch(Exception e){
System.out.println(e.getMessage());
}

return null;
}

/**
* DES算法,解密
*
* @param data 待解密字符串
* @param key 解密私钥,长度不能够小于8位
* @return 解密后的字节数组,数据不足8位倍数会自动补全,需去除\0
* @throws Exception 异常
*/
public static String decode(String key,byte[] data) {
if(data == null)
return null;

try {
DESKeySpec dks = new DESKeySpec(key.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");

// key的长度不能够小于8位字节
Key secretKey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance(ALGORITHM_DES);

// 解密
cipher.init(Cipher.DECRYPT_MODE, secretKey);

// 去除空格
byte[] output = cipher.doFinal(data);
int i = 0;
for( i=output.length-1; i>=0; i-- ){
if( output[i] != '\0' )
break;
}

return new String(output,0,i+1);
} catch (Exception e){
System.out.println(e.getMessage());
}

return null;
}

 

参考资料:

​https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation​