关于DES加解密揭秘

    最近一个项目用到DES,这里顺便介绍一下它:
    数据加密标准(DES)是一个古老的对称密钥加密算法,它不是一个很安全的算法。三重DES(Triple-DES)仍然是很安全的,但是也只是在别无他法的情况下的一个较好的选择。高级加密标准(AES)是一个更好的加密算法,NIST用AES代替Triple-DES作为他们的标准。高级加密标准(AES)是一个用来代替数据加密标准(DES)的算法。目前使用的一般为128,196和256位密钥,这三种密钥都是相当安全的。而且美国政府也是这样认为的。他们批准将128位密钥的AES算法用于一般数据加密,196位和256位密钥的AES算法用于秘密数据和绝密数据的加密。DESX是DES的一个改进版本。DESX的原理是利用一个随机的二进制数与加密前的数据以及解密后的数据异或。虽然也有人批评这种算法,但是与DES相比DESX确实更安全,不过DESX在许多情况下并不适用。有点扯远了 :)

这里有这样一个需求,使用perl语言使用DES加密一个文件,并用java语言进行解密,这里查了网络上很多资料,没有一个很好的例子或者帮助信息,同样是DES,但是会影响加密和解密的结果。有两个因素可能影响加密结果:
一是使用的填充方式,可以指定一些标准的填充模式,比如PKCS5;二是工作模式,如:ECB、CBC、OFB、CTR
perl加密一个文件:


#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;
use Crypt::CBC;
die "Need to specify a file" if(!(my $infile = shift));
my $key = (12345678);
my $iv = q(01234567);
my $bufsize = 16384;
my $cipher = Crypt::CBC->new({
'key' => $key,
'iv' => $iv,
'header' => 'none',
'cipher' => 'DES',
'literal_key' => '1',
});
open (FORIG,"$infile")|| die "can't open file: $!";
open (FCRYPT,">$infile.crypt")|| die "can't open file: $!";
$cipher->start('encrypting');
while(my $readsize = sysread(FORIG, my $buf, $bufsize)) {
print FCRYPT $cipher->crypt($buf);
}
print FCRYPT $cipher->finish();
close FCRYPT;
close FORIG;


此是将一个文件用DES方式加密,值得注意的是literal_key表示不要用md5的哈希键;对应的java解密版本如下:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;

public class DES {

Cipher ecipher;
Cipher dcipher;
byte[] buf = new byte[1024];

public DES() {
String strKey = "12345678";
byte[] keyBytes = null;
try {
keyBytes = strKey.getBytes("UTF-8");
} catch (java.io.UnsupportedEncodingException ex) {
ex.printStackTrace();
}
byte[] iv = "01234567".getBytes();
IvParameterSpec ivSpec = new IvParameterSpec(iv);
try {
ecipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
dcipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
try {
DESKeySpec dks = new DESKeySpec(keyBytes);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(dks);

ecipher.init(Cipher.ENCRYPT_MODE, securekey, ivSpec);
dcipher.init(Cipher.DECRYPT_MODE, securekey, ivSpec);
} catch (InvalidKeyException e1) {
e1.printStackTrace();
} catch (InvalidAlgorithmParameterException e1) {
e1.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
}

public void encrypt(InputStream in, OutputStream out) {
try {
out = new CipherOutputStream(out, ecipher);
int numRead = 0;
while ((numRead = in.read(buf)) >= 0) {
out.write(buf, 0, numRead);
}
out.close();
} catch (java.io.IOException e) {
e.printStackTrace();
}
}

public byte[] encrptyStr(byte[] bIn) {
try {
return ecipher.doFinal(bIn);
}catch (Exception e) {
e.printStackTrace();
}
return new byte[]{};
}

public void decrypt(InputStream in, OutputStream out) {
try {
out = new CipherOutputStream(out, dcipher);
int numRead = 0;
while ((numRead = in.read(buf)) >= 0) {
out.write(buf, 0, numRead);
}
out.close();
} catch (java.io.IOException e) {
e.printStackTrace();
}
}

public byte[] decrptyStr(byte[] bIn) {
try {
return dcipher.doFinal(bIn);
}catch (Exception e) {
e.printStackTrace();
}
return new byte[]{};
}

public static void main(String args[]) throws Exception {
if (args.length != 1) {
System.out.println("Usage: java AESEncrypter filename");
System.exit(0);
}

DES encrypter = new DES();
try {
encrypter.decrypt(new FileInputStream(args[0]),
new FileOutputStream("Java_decrypted.txt"));
} catch (java.io.FileNotFoundException ex) {
ex.printStackTrace();
}
}

}


值得注意的是perl中的key和java中的strKey变量,这里由于java的Cipher包的限制,只能使用8位的key,如果能够使用长度更长的key,则可能需要自己根据DES的算法或者等待更高的java版本。
如果是加解密字符串,perl加密代码如下:

#!/usr/bin/perl

use strict;
use warnings;
use Crypt::CBC;
die "Need a string!" if (@ARGV == 0);
my $key = q(12345678);
my $iv = q(01234567);
my $cipher = Crypt::CBC->new({
'key' => $key,
'header' => 'none',
'iv' => $iv,
'cipher' => 'DES',
'keysize' => '8', #forced - default is 32 bytes
'padding' => 'standard', #PKCS5
'blocksize' => '8',
'literal_key' => '1', #do not MD5 hash key
});
print $cipher->encrypt_hex($ARGV[0]) . "\n";


java字串解密如下:

import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;

public class DESSTR {

Cipher ecipher;
Cipher dcipher;
byte[] buf = new byte[1024];

public DESSTR() {
String strKey = "12345678";
byte[] keyBytes = null;
try {
keyBytes = strKey.getBytes("UTF-8");
} catch (java.io.UnsupportedEncodingException ex) {
ex.printStackTrace();
}
byte[] iv = "01234567".getBytes();
IvParameterSpec ivSpec = new IvParameterSpec(iv);
try {
ecipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
dcipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
try {
DESKeySpec dks = new DESKeySpec(keyBytes);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(dks);
ecipher.init(Cipher.ENCRYPT_MODE, securekey, ivSpec);
dcipher.init(Cipher.DECRYPT_MODE, securekey, ivSpec);
} catch (InvalidKeyException e1) {
e1.printStackTrace();
} catch (InvalidAlgorithmParameterException e1) {
e1.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
}

public void encrypt(InputStream in, OutputStream out) {
try {
out = new CipherOutputStream(out, ecipher);
int numRead = 0;
while ((numRead = in.read(buf)) >= 0) {
out.write(buf, 0, numRead);
}
out.close();
} catch (java.io.IOException e) {
e.printStackTrace();
}
}

public byte[] encrptyStr(byte[] bIn) {
try {
return ecipher.doFinal(bIn);
}catch (Exception e) {
e.printStackTrace();
}
return new byte[]{};
}

public void decrypt(InputStream in, OutputStream out) {
try {
out = new CipherOutputStream(out, dcipher);
int numRead = 0;
while ((numRead = in.read(buf)) >= 0) {
out.write(buf, 0, numRead);
}
out.close();
} catch (java.io.IOException e) {
e.printStackTrace();
}
}

public byte[] decrptyStr(byte[] bIn) {
try {
return dcipher.doFinal(bIn);
}catch (Exception e) {
e.printStackTrace();
}
return new byte[]{};
}

public static String byte2hex(byte[] b) {
String hs = "";
String stmp = "";
for (int n = 0; n < b.length; n++) {
stmp = (Integer.toHexString(b[n] & 0XFF));
if (stmp.length() == 1)
hs = hs + "0" + stmp;
else
hs = hs + stmp;
}
return hs.toUpperCase();
}

public static byte[] hex2byte(byte[] b) {
if ((b.length % 2) != 0)
throw new IllegalArgumentException("Length is not even");
byte[] b2 = new byte[b.length / 2];
for (int n = 0; n < b.length; n += 2) {
String item = new String(b, n, 2);
b2[n / 2] = (byte) Integer.parseInt(item, 16);
}
return b2;
}

public static String byte2String(byte[] b) {
String hs = "";
String stmp = "";
for (int n = 0; n < b.length; n++) {
stmp = (Integer.toHexString(b[n] & 0XFF));
hs += Character.valueOf((char)Integer.parseInt(stmp, 16)).toString();
}
return hs;
}

public static void main(String args[]) throws Exception {
if (args.length == 0) {
System.err.println("Need a string!");
System.exit(1);
}
DESSTR encrypter = new DESSTR();
byte[] in = hex2byte(args[0].getBytes("UTF-8"));
byte[] out = encrypter.decrptyStr(in);
System.out.println(new String(out));
}
}


同样注意一下key的关系。
在这里可以下载上述的代码
des_aes.tar.bz2
des_aes.tar.gz
包括AES算法的用例。


Monthly Archives

Pages

Powered by Movable Type 7.7.2

About this Entry

This page contains a single entry by Cnangel published on December 5, 2009 11:01 PM.

MT5.0即将发布 was the previous entry in this blog.

Linux应用心得(三) is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.