最近项目使用3des进行数据的加解密,服务器为java,客户端为android和ios。这一点,android显然具有先天优势,对jdk的基本算法都会支持,但ios就不能支持3des的所有加密模式了,那么为了ios也能适应java的多种加密模式才有了本文的探索。
1、des与3des
3des是对des进行3重加密后的结果,3des不同于des,其秘药必须为24位,然后以每8位为一个key来组成3个key,同时还要有一个8位的加密偏移向量来同时加密一组数据。
2、DESede/CFB/PKCS5Padding
在java中加密标示如上所述,java的加密协议串为 加密协议/加密模式/补位算法 三部分组成。在这里加密协议统称对称加密协议,主要分为三种DES/3DES/AES。
DES/3DES/AES区别于工作模式:
DES
1977年1月,美国政府颁布:采纳IBM公司设计的方案作为非机密数据的正式数据加密标准(DES Data Encryption Standard) 。
目前在国内,随着三金工程尤其是金卡工程的启动,DES算法在POS、ATM、磁卡及智能卡(IC卡)、加油站、高速公路收费站等领域被广泛应用,以此来实现关键数据的保密,如信用卡持卡人的PIN的加密传输,IC卡与POS间的双向认证、金融交易数据包的MAC校验等,均用到DES算法。
DES算法的入口参数有三个:Key、Data、Mode。
其中Key为8个字节共64位,是DES算法的工作密钥;
Data也为8个字节64位,是要被加密或被解密的数据;
Mode为DES的工作方式,有两种:加密或解密。
DES算法是这样工作的:
如Mode为加密,则用Key 去把数据Data进行加密, 生成Data的密码形式(64位)作为DES的输出结果;
如Mode为解密,则用Key去把密码形式的数据Data解密,还原为Data的明码形式(64位)作为DES的输出结果。
在通信网络的两端,双方约定一致的Key,在通信的源点用Key对核心数据进行DES加密,然后以密码形式在公共通信网(如电话网)中传输到通信网络的终点,数据到达目的地后,用同样的Key对密码数据进行解密,便再现了明码形式的核心数据。这样,便保证了核心数据(如PIN、MAC等)在公共通信网中传输的安全性和可靠性。
通过定期在通信网络的源端和目的端同时改用新的Key,便能更进一步提高数据的保密性,这正是现在金融交易网络的流行做法。
3DES
3DES是DES加密算法的一种模式,它使用3条64位的密钥对数据进行三次加密。数据加密标准(DES)是美国的一种由来已久的加密标准,它使用对称密钥加密法。
3DES(即Triple DES)是DES向AES过渡的加密算法(1999年,NIST将3-DES指定为过渡的加密标准),是DES的一个更安全的变形。它以DES为基本模块,通过组合分组方法设计出分组加密算法。
设Ek()和Dk()代表DES算法的加密和解密过程,K代表DES算法使用的密钥,P代表明文,C代表密表,这样,
3DES加密过程为:C=Ek3(Dk2(Ek1(P)))
3DES解密过程为:P=Dk1((EK2(Dk3(C)))
K1、K2、K3决定了算法的安全性,若三个密钥互不相同,本质上就相当于用一个长为168位的密钥进行加密。多年来,它在对付强力攻击时是比较安全的。若数据对安全性要求不那么高,K1可以等于K3。在这种情况下,密钥的有效长度为112位。
AES
AES(Advanced Encryption Standard):高级加密标准,是下一代的加密算法标准,速度快,安全级别高。
用AES加密2000年10月,NIST(美国国家标准和技术协会)宣布通过从15种候选算法中选出的一项新的密匙加密标准。Rijndael被选中成为将来的 AES。Rijndael是在1999年下半年,由研究员Joan Daemen 和 Vincent Rijmen 创建的。AES正日益成为加密各种形式的电子数据的实际标准。
美国标准与技术研究院(NIST)于2002年5月26日制定了新的高级加密标准(AES)规范。
AES算法基于排列和置换运算。排列是对数据重新进行安排,置换是将一个数据单元替换为另一个。
AES使用几种不同的方法来执行排列和置换运算。AES是一个迭代的、对称密钥分组的密码,它可以使用128、192和256位密钥,并且用128位(16字节)分组加密和解密数据。
与公共密钥加密使用密钥对不同,对称密钥密码使用相同的密钥加密和解密数据。通过分组密码返回的加密数据的位数与输入数据相同。迭代加密使用一个循环结构,在该循环中重复置换和替换输入数据。
3、加密模式
每个加密算法都分为四种加密模式:ECB,CBC,CFB,OFB。
其四种加密方式的优缺点如下:
ECB
优点:
1.简单;
2.有利于并行计算;
3.误差不会被传送;
缺点:
1.不能隐藏明文的模式;
2.可能对明文进行主动攻击;
CBC
优点:
1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。
缺点:
1.不利于并行计算;
2.误差传递;
3.需要初始化向量IV(其实这也不算缺点。。)
CFB
优点:
1.隐藏了明文模式;
2.分组密码转化为流模式;
3.可以及时加密传送小于分组的数据;
缺点:
1.不利于并行计算;
2.误差传送:一个明文单元损坏影响多个单元;
3.唯一的IV;
OFB
优点:
1.隐藏了明文模式;
2.分组密码转化为流模式;
3.可以及时加密传送小于分组的数据;
缺点:
1.不利于并行计算;
2.对明文的主动攻击是可能的;
3.误差传送:一个明文单元损坏影响多个单元;
4、补位算法
所谓补位算法,就是为了防止明文在加密是因为位数不够而导致加密失败的一种规避方法,java中使用最多的是PKCS5Padding补位算法,其PKCS5Padding的工作原理为,若明文的长度不为8的倍数位,则在末尾补齐,若明文长度为整8数位,则在末尾补齐8字节的数据,所以若java使用PKCS5Padding进行部位,则在c++中进行解密或加密需要对部位的部分进行添加或去除。
以下示例在加密串为DESede/CFB/PKCS5Padding下c++与java进行互相加解密。
#pragma hdrstop
#include
#include
#include
#include
#include
#include
#include
#pragma argsused
#define BUFSIZE 256
#define CFBMODE 64
using namespace std;
class Des {
public:
typedef vector<unsigned char> Bytes;
static Bytes encrypt(Bytes in) {
const unsigned char IV[] = { 48, 48, 48, 48, 48, 48, 48, 48 };
const unsigned char key[] = { 51, 57, 101, 49, 50, 48, 51, 48, 45, 49,
55, 49, 53, 45, 52, 97, 57, 101, 45, 57, 52, 49, 98, 45 };
DES_key_schedule schedule;
DES_key_schedule schedule2;
DES_key_schedule schedule3;
DES_cblock desKey = { 0 };
DES_cblock iv = { 0 };
memcpy(desKey, key, 8);
DES_set_key_unchecked(&desKey, &schedule);
memcpy(desKey, key + 8, 8);
DES_set_key_unchecked(&desKey, &schedule2);
memcpy(desKey, key + 16, 8);
DES_set_key_unchecked(&desKey, &schedule3);
copy(IV, IV + 8, iv);
int i = 0;
const size_t paddingLength = (8 - in.size() % 8);
const Bytes padding(paddingLength, 8 - in.size() % 8);
copy(padding.begin(), padding.end(), back_inserter(in));
Bytes result(in.size());
DES_ede3_cfb_encrypt(&in[0], &result[0], CFBMODE, in.size(), &schedule,
&schedule2, &schedule3, &iv,
DES_ENCRYPT);
return result;
}
static Bytes decrypt(Bytes in) {
//偏移向量
const unsigned char IV[] = { 48, 48, 48, 48, 48, 48, 48, 48 };
//24位加密key,3des下秘钥必须为24位
const unsigned char key[] = { 51, 57, 101, 49, 50, 48, 51, 48, 45, 49,
55, 49, 53, 45, 52, 97, 57, 101, 45, 57, 52, 49, 98, 45 };
DES_key_schedule schedule;
DES_key_schedule schedule2;
DES_key_schedule schedule3;
DES_cblock desKey = { 0 };
DES_cblock iv = { 0 };
memcpy(desKey, key, 8);
DES_set_key_unchecked(&desKey, &schedule);
memcpy(desKey, key + 8, 8);
DES_set_key_unchecked(&desKey, &schedule2);
memcpy(desKey, key + 16, 8);
DES_set_key_unchecked(&desKey, &schedule3);
copy(IV, IV + 8, iv);
int i = 0;
Bytes result(in.size());
DES_ede3_cfb_encrypt(&in[0], &result[0], CFBMODE, in.size(), &schedule,
&schedule2, &schedule3, &iv,
DES_DECRYPT);
int paddingLength = result.size() - result[result.size() - 1];
Bytes padding(0);
if (paddingLength > 0
&& result[result.size() - 1] == result[paddingLength])
copy(result.begin(), result.begin() + paddingLength,
back_inserter(padding));
else
padding = result;
return padding;
}
};
int main() {
string message = "111111111111";
Des::Bytes in(message.begin(), message.end());
Des::Bytes encr = Des::encrypt(in);
Des::Bytes decr = Des::decrypt(encr);
// size_t size = encr.size();
for (Des::Bytes::const_iterator byte = decr.begin(); byte != decr.end();
++byte) {
printf("%02X ", *byte);
}
printf("\n");
return 0;
}