Java与VB之间的私钥加解密
Java与VB之间的私钥加解密
笔者在之前做项目过程中遇到如下的问题:
客户端开发语言:Microsoft Visual Basic
服务器端开发语言:Java SDK 1.5.0
客户端登录服务器时,需要传递用户名和密码到服务器,为了保证传输的安全,不能将密码使用明文传送,所以需要对密码进行加密,在服务器端再进行解密。虽然可以使用SSL协议保证传输过程的安全,但是由于环境的因素,有些时候没有办法是用SSL,所以需要使用私钥加密的方法。
初步方案为使用DES算法对用户密码进行加密。
Sun JCE Provider已经提供了一套加密解密方案。所以一个加密解密的例子如下:
package org.ly;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
// encrypt and decrypt using the DES private key algorithm
public class DESDemo {
public static void main(String[] args) throws Exception {
//DES算法密码的最大长度为8个bytes
//Invalid key length: 7 bytes
//Invalid key length: 9 bytes
byte[] keyBytes = “maxLen-8”.getBytes(“UTF-8”);
//私钥算法为DES
SecretKeySpec skeySpec = new SecretKeySpec(keyBytes, “DES”);
//密码信息–算法:DES、模式:ECB、填充方式:PKCS5Padding
Cipher encipher = Cipher.getInstance(“DES/ECB/PKCS5Padding”);
//初始化
encipher.init(Cipher.ENCRYPT_MODE, skeySpec);
//源数据
byte[] source = “password”.getBytes();
System.out.println(“Encypting with DES/ECB/PKCS5Padding…”);
//加密
byte[] enResult = encipher.doFinal(source);
//加密后的数据,加密后的数据为字节数组,打印出的字符串是乱码
//使用BASE64编码凡是进行编码,推荐使用Apache Common Codec
System.out.println(“cipherText:\n” new String(enResult));
System.out.println(“base64 encode cipher text:\n”
new sun.misc.BASE64Encoder().encode(enResult));
//在本程序中,可以使用同一个Cipher对象,只需要重新初始化
Cipher cipher = Cipher.getInstance(“DES/ECB/PKCS5Padding”);
//解密
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
System.out.println(“Decypting with DES/ECB/PKCS5Padding…”);
byte[] original = cipher.doFinal(enResult);
System.out.println(“plainText:\n” new String(original));
}
}
程序执行结果为:
Encypting with DES/ECB/PKCS5Padding…
cipherText:
?__き;?,H??*?_?k
base64 encode cipher text:
xEagqs7sixIwv8qtwTXaw==
Decypting with DES/ECB/PKCS5Padding…
plainText:
password
为了创建Cipher对象,需要调用Cipher类的getInstance方法,并传递一个transformation参数。Provider的名称是可选参数。其中在获取cipher实例的时候使用的方式的API为:
static Cipher getInstance(String transformation)
Returns a Cipher object that implements the specified transformation.
static Cipher getInstance(String transformation, Provider provider)
Returns a Cipher object that implements the specified transformation.
static Cipher getInstance(String transformation, String provider)
Returns a Cipher object that implements the specified transformation.
transformation是一个描述操作的字符串,它根据给定的输入,产生输出。一个典型的transformation包括加密算法名和可选的反馈模式以及填充模式。其形式如下:
- “algorithm/mode/padding” or
- “algorithm“
(在后这种,将使用provider默认的mode和padding scheme。)。例如,下面的例子是一个合法的transformation。
Cipher c = Cipher.getInstance(“DES/CBC/PKCS5Padding“);
使用CFB和OFB方式,块加密器可以加密小于cipher实际块大小的数据,当请求这种mode时,可以将处理的位数添加在模式后面,例如“DES/CFB8/NoPadding”和“DES/OFB32/PKCS5Padding”。如果没有设置的话,将使用provider默认的大小。例如SunJCE使用64位对于DES算法。
下面是SunJCE Provider支持的Cipher的详细信息:
在Microsoft Visual Basic 6.0中并没有一个built-in的加密解密API(在.Net中已经包含了这部分内容),所以笔者在网上下载了几个DES算法的VB实现代码,但是都不能够和Java提供的DES加密解密算法匹配,即如果使用SunJCE加密,那么VB端不能解密,VB端加密,SunJCE不能解密。主要的原因在于VB加密的结果(byte数组)和Java加密的结果(byte数组)是不一样的。开始以为是因为平台的原因(Java中byte类型的变量的值得范围是-128-127,而VB中是0-255),但是如果将其进行正常的转化,应该是没有问题的,因为一个数值00011011无论在Java中还是VB中都是同一个数,之所以有正负是因为第一位在Java中作为符号位使用了而已。所以根源在于网络中的DES加密算法的mode和padding scheme与SunJCE的实现不同,导致了同样的数据,使用同样的密码生成密钥,但是加密结果却不同,当然解密也就不正确了。
现在的目标是找到一种算法,使其和Sun提供的算法可以匹配,即加密后的数据和SunJCE加密后的数据是一致的。例如上面例子中SunJCE加密后的字节数组的值为:
[-5, 17, 26, -126, -85, 59, -78, 44, 72, -62, -1, 42, -73, 4, -41, 107]
那么在VB中对应的值应该为:
[251, 17, 26, 130, 171, 59, 178, 44, 72, 194, 255, 42, 183, 4, 215, 107]
但是,结果没有找到这样的算法。如果各位有找到的,请联系笔者。
所以笔者决定另寻它法,使用其他的算法是否会有解决的办法呢,首先查看SunJCE还支持哪些算法,毕竟SunJCE已经实现了很多算法,不需要服务器端在自己去网上查找算法了,SunJCE实现的算法可信度要比网络上的好一些吧。SunJCE实现的算法如下:
?
AES: Advanced Encryption Standard as specified by NIST in a draft FIPS. Based on the Rijndael algorithm by Joan Daemen and Vincent Rijmen, AES is a 128-bit block cipher supporting keys of 128, 192, and 256 bits.
?
ARCFOUR/RC4: A stream cipher developed by Ron Rivest. For more information, see K. Kaukonen and R. Thayer, “A Stream Cipher Encryption Algorithm ‘Arcfour'”, Internet Draft (expired),?draft-kaukonen-cipher-arcfour-03.txt.
?
Blowfish: The block cipher designed by Bruce Schneier.
?
DES: The Digital Encryption Standard as described in FIPS PUB 46-2.
?
DESede: Triple DES Encryption (DES-EDE).
?
ECIES (Elliptic Curve Integrated Encryption Scheme)
?
PBEWith<digest>And<encryption> or?PBEWith<prf>And<encryption>: The password-based encryption algorithm (PKCS #5), using the specified message digest (<digest>) or pseudo-random?function (<prf>) and encryption algorithm (<encryption>). Examples:
o
PBEWithMD5AndDES: The password-based encryption algorithm as defined in: RSA Laboratories, “PKCS #5: Password-Based Encryption Standard,” version 1.5, Nov 1993. Note that this algorithm implies [url=mk:@MSITStore:F:\books\JavaDoc\jdk150.chm::/jdk150/guide/security/jce/JCERefGuide.html#cbcMode#cbcMode]CBC[/url] as the cipher mode and [url=mk:@MSITStore:F:\books\JavaDoc\jdk150.chm::/jdk150/guide/security/jce/JCERefGuide.html#pkcs5Pad#pkcs5Pad]PKCS5Padding[/url] as the padding scheme and cannot be used with any other cipher modes or padding schemes.
o
PBEWithHmacSHA1AndDESede: The password-based encryption algorithm as defined in: RSA Laboratories, “PKCS #5: Password-Based Cryptography Standard,” version 2.0, March 1999.
?
RC2,?RC4, and?RC5: Variable-key-size encryption algorithms developed by Ron Rivest for RSA Data Security, Inc.
?
RSA: The RSA encryption algorithm as defined in PKCS #1.
其中AES、DES、DESede和DES都相似,在网络中没有找到和SunJCE对应的加密解密实现。但是找到了Blowfish算法的实现中讲到了mode和padding scheme。下面是Blowfish创始人的主页中对Blowfish算法的一个介绍:
- Block cipher: 64-bit block Variable key length: 32 bits to 448 bits Designed by Bruce Schneier Much faster than DES and IDEA Unpatented and royalty-free No license required
- Free source code available
其优点为密码的长度不仅仅是8bytes,可以从4bytes到56bytes不等,并且加密速度要比DES和IDEA快,不需要license就可以使用,并且有免费的源代码。
Blowfish算法已经有如下语言的实现,其中包含了Visual Basic语言。
- Reference source code from?SSLeay 0.6.6 C by Bruce Schneier C by Paul Kocher C (author unknown) C# and Java by Markus Hahn (very fast implementations) C by Jim Conger (note) C by Samuel Kabak Forth by Pierre Abbat Perl VHDL
- Visual Basic by David Ireland
在DI-Management网站下载Blowfish VB6.0的源代码,其中包含了示例的可执行程序(另外,对于加密解密的初学者,DI-Management网站提供了很多基础知识的介绍)。可执行程序的界面如下:
其中就包含了Mode和Padding的设置,这正是和SunJCE的transformation相匹配的模式。
修改Java的源代码,使用SunJCE的Blowfish/ECB/PKCS5Padding的transformation来获取Cipher实例。
package org.ly;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
// encrypt and decrypt using the DES private key algorithm
public class DESDemo {
public static void main(String[] args) throws Exception {
byte[] keyBytes = “maxLen-8”.getBytes(“UTF-8”);
SecretKeySpec skeySpec = new SecretKeySpec(keyBytes, “Blowfish”);
Cipher encipher = Cipher.getInstance(“Blowfish/ECB/PKCS5Padding”);
encipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] source = “password”.getBytes();
System.out.println(“Encypting with Blowfish/ECB/PKCS5Padding…”);
byte[]?enResult = encipher.doFinal(source);
System.out.println(“cipherText:\n” new String(enResult));
System.out.println(“base64 encode cipher text:\n”
new sun.misc.BASE64Encoder().encode(enResult));
Cipher cipher = Cipher.getInstance(“Blowfish/ECB/PKCS5Padding”);
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
System.out.println(“Decypting with Blowfish/ECB/PKCS5Padding…”);
byte[] original = cipher.doFinal(enResult);
System.out.println(“plainText:\n” new String(original));
}
}
其中加密后的enResult的值为:
[-47, -53, -8, 124, 126, 12, -7, 81, 112, 77, 93, -9, -74, -89, 27, -5]
如果对应的VB代码使用相同的密码maxlen-8和相同的加密transforamtion:Blowfish/ECB/PKCS5Padding以及相同的加密算法Blowfish加密的结果字节数组为下面的值,说明两者加密的结果是一致的,自然可以互相加解密。
[209,203,248,124,126,12,249,81,112,77,93,247,182,167,27,251]
事实正是如此,所以就解决了VB和Java之间的加解密问题。加密后的密码使用base64编码在网络上传输。
注:VB代码中可能需要修改一处判断语句,在源代码中好像有一处分支一直没有执行。
关于mode和padding的相关支持,可以参考DI-Management网站的介绍。www.maibu.ren