======================================================
注:本文源代码点此下载
======================================================
在 java 中,从 j2ee1.4 开始,sun 提供了 jce( java crypto engine ),其中包含有 des 算法,在 java 中使用 des 算法的代码示例如下:
java crypto example
import java.security.key;
import java.security.security;
import javax.crypto.cipher;
public class desplus
{
static string strdefaultkey = "initkey";
static cipher encryptcipher = null;
static cipher decryptcipher = null;
static {
security.addprovider(new com.sun.crypto.provider.sunjce());
key key = null;
try {
key = getkey(strdefaultkey.getbytes());
encryptcipher = cipher.getinstance("des");
encryptcipher.init(cipher.encrypt_mode, key);
decryptcipher = cipher.getinstance("des");
decryptcipher.init(cipher.decrypt_mode, key);
}catch(exception e){
e.printstacktrace();
}
}
public desplus(){
}
public static byte[] encrypt(byte[] arrb) throws exception {
return encryptcipher.dofinal(arrb);
}
public static byte[] decrypt(byte[] arrb) throws exception {
return decryptcipher.dofinal(arrb);
}
private statickey getkey(byte[] arrbtmp) throws exception {
byte[] arrb = new byte[8];
for (int i = 0; iarrbtmp.length && iarrb.length; i++) {
arrb[i] = arrbtmp[i];
}
key key = new javax.crypto.spec.secretkeyspec(arrb, "des");
return key;
}
}
需要注意的是,加密后的结果是字节数组,一般情况下可以使用 base64 进行编码,以方便存储在字符串形的数据库字段中,当然亦可以采用原始的字节流或者是十六进制编码字符串;同样需要注意的是,在上面的代码示例中,java 的 des 算法可以指定加密的模式和填充方式,如果不指定,则默认的就是 ecb 加密模式和 pkcs#5 填充方式,关于加密模式和填充方式之后将进行介绍,现在我们来看 opensll 的 des 算法,还是先给一段代码示例:
c++ crypto example
int encrypt( unsigned char * inbuf , unsigned char * * outbuf , int inlen , unsigned char * key, unsigned char * iv )
{
bio *bio, *mbio, *cbio;
unsigned char *dst;
int outlen;
mbio = bio_new( bio_s_mem( ) );
cbio = bio_new( bio_f_cipher( ) );
bio_set_cipher( cbio , evp_des_ecb( ) , key , iv , 1 );
bio = bio_push( cbio , mbio );
bio_write( bio , inbuf , inlen );
bio_flush( bio );
outlen = bio_get_mem_data( mbio , (unsigned char **) & dst );
* outbuf = ( unsigned char * ) malloc( outlen );
memcpy( * outbuf , dst , outlen );
bio_free_all( bio );
return outlen;
}
该段代码使用了 openssl 库,该函数返回加密结果的长度,同时将加密的结果放置在 outbuf 中,需要注意的是,bio_set_chiper 这一行,最后两个参数:iv 参数在 ecb 加密模式下是不起作用的,仅 cbc 模式才会使用该变量,该变量要求必须是一个八字节的数组,enc 参数,如果是 1 则表明是进行加密,如果是 0 则表明是解密,-1 则表明使用最后一次操作的方式,只需要修改最后一个参数为0,就是解密了,所以解密的代码就不再重复了;
另外补充一点,这个加密方式是最古老的 des ,不是 3des ,输入参数 key 的长度要求至少是 8 个字节,如果不够,补 '\0',例如:unsigned char key[ ] = { "key\0\0\0\0\0" },如果超过八个字节,那么后面的不使用;如果你不愿意补零,那么需要保证和 java 的对应,否则不能互相加解密;
哦,还有一点,请注意在使用完后释放 outbuf 内存块,保证没有内存泄露;
下面来说一下加密模式,常见的加密模式有 ecb / cbc / cfb / ofb 四种,这也是 openssl 提供的四种,加密模式的主要意义就是,加密算法是按块进行加密的,例如 des ,是 64bit 一个块的进行加密,就是每次加密 8 个字节,因此每次输入八个字节的明文输出八个字节密文,如果是 16 个字节,那么分成两个块依次进行加密,问题就出现在这里,如果明文是 1234567812345678,分块分别进行加密,那么加密的结果类似“c4132737962c519c c4132737962c519c”,可以看出明文的规律,这就是 ecb 加密模式,密文可以看出明文的规律;为了解决这个问题,有了其他的加密模式:cbc 加密模式(密码分组连接),cfb加密模式(密码反馈模式),ofb加密模式(输出反馈模式)cbc 是要求给一个初始化的向量,然后将每个输出与该向量作运算,并将运算的结果作为下一个加密块的初始化向量,cfb 和 ofb 则不需要提供初始化向量,直接将密码或者输出作为初始化向量进行运算;这样就避免了明文的规律出现在密文中;当然缺点是解密时需要保证密文的正确性,如果网络传输时发生了一部分错误,则后面的解密结果就可能是错误的;(ecb模式仅影响传输错误的那个块);
密码算法基本上都是分组(按快)进行加密的,如果密文长度不是刚刚好可以进行分组,怎么办?只能进行填充,填充的方法有很多中,常用的是 pkcs#7,该填充方法是将每一个补充的字节内容填充为填充的字节个数;例如明文长度是 100 , 分组的大小是32个字节,那么需要分为四组,补充28个字节,那么补充的字节全部补充为'\0x28',如果分组的大小是 8 个字节,那么 pkcs#7 的填充方式和 pkcs#5 是完全一致的;另外还有一个规定,就是如果明文刚刚好进行分组,那么需要补充一个独立的分组出来,例如 des ,如果明文为 8 个字节,那么需要补充为 16 个字节进行运算,这样的好处是进行解密后,将解密出来的最后一个字节取出来,并将解密结果的长度减去该值,就是原来明文的长度;
更多的信息可以参考:http://en.wikipedia.org/wiki/block_cipher_modes_of_operation
======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/