jdk和android的DES加密

前段时间负责开发了javaweb后台与android端的通信接口,其中传递了一些重要信息需要加密处理,我们使用了最常见的DES,加解密的核心代码如下:
/**
* 加密方法
*/
private byte [] encryptByte(byte[] byteS) {
byte[] byteFina = null ;
Cipher cipher;
try {
cipher = Cipher.getInstance ( "DES" );
cipher.init(Cipher.ENCRYPT_MODE,key);
byteFina = cipher.doFinal(byteS);
} catch (Exception e) {
throw new RuntimeException(
"Error initializing SqlMap class. Cause: " + e);
} finally {
cipher = null ;
}
return byteFina;
}
public String encryptStr(String strMing) {
byte [] byteMi = null ;
byte [] byteMing = null ;
String strMi = "" ;
BASE64Encoder base64en = new BASE64Encoder();
try {
byteMing = strMing.getBytes( "UTF8" );
byteMi = this .encryptByte(byteMing);
strMi = base64en.encode(byteMi);
} catch (Exception e) {
throw new RuntimeException(
"Error initializing SqlMap class. Cause: " + e);
} finally {
base64en = null ;
byteMing = null ;
byteMi = null ;
}
return strMi;
}
/**
* 解密方法
*
* @param strMi
* @return
*/
private byte [] decryptByte( byte [] byteD) {
Cipher cipher;
byte [] byteFina = null ;
try {
cipher = Cipher.getInstance ( "DES" );
cipher.init(Cipher. DECRYPT_MODE , key );
byteFina = cipher.doFinal(byteD);
} catch (Exception e) {
throw new RuntimeException(
"Error initializing SqlMap class. Cause: " + e);
} finally {
cipher = null ;
}
return byteFina;
}
public String decryptStr(String strMi) {
BASE64Decoder base64De = new BASE64Decoder();
byte [] byteMing = null ;
byte [] byteMi = null ;
String strMing = "" ;
try {
byteMi = base64De.decodeBuffer(strMi);
byteMing = this .decryptByte(byteMi);
strMing = new String(byteMing, "UTF8" );
} catch (Exception e) {
throw new RuntimeException(
"Error initializing SqlMap class. Cause: " + e);
} finally {
base64De = null ;
byteMing = null ;
byteMi = null ;
}
return strMing;
}
/**
* 使用方式
*/
public static void main(String[] args) throws Exception {
DesTester des = new DesTester( "key" );
String str1 = "这是用来加密的文字" ;
String str2 = des.encryptStr(str1);
String deStr = des.decryptStr(str2);
System. out .println( " 加密前: " + str1);
System. out .println( " 加密后: " + str2);
System. out .println( " 解密后: " + deStr);
}

令人始料未及的是,对于同一串加密信息(一般是字符串),jdk与android sdk加密出来的东西完全不一样,以至于无法对交互中接收到的数据进行解密。
百度了一些资料,了解了一下大概原因,原文解释如下(参考出处:http://www.docin.com/p-438365141.html):

调用DES加密算法最精要的就是下面两句话:
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);
CBC是工作模式,DES一共有电子密码本模式(ECB)、加密分组链接模式(CBC)、加密反馈模式(CFB)和输出反馈模式(OFB),
PKCS5Padding是填充模式,还有其他的填充模式:
然后,cipher.init()一共有三个参数:Cipher.ENCRYPT_MODE、key、zeroIv,zeroIv就是初始化向量,一个8位字符数组。
工作模式、填充模式、初始化向量这三种因素一个都不能少。否则,如果你不制定的话,那么程序就要调用默认实现。问题就来了,这就与平台有关了。

这两段话把原理解释的非常清楚,不过有一些细节还可以深挖一下。
1、工作模式的机制,度娘到一个可参考文章:http://wenku.baidu.com/view/8e329bc50c22590102029d3d.html
2、初始化向量的作用;
找到这样一个解释:初始化向量那是PBE密钥加密,没有向量的那是普通的加密,对安全方面来说PBE更安全些。

根据以上的分析,把加解密方法再重新修改一下:
/**
* DES加密
*/
public static String encryptDES(String encryptString){
IvParameterSpec zeroIv = new IvParameterSpec(iv);
SecretKeySpec key = new SecretKeySpec(keyStr.getBytes(), "DES");
Cipher cipher;
try {
cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);
byte[] encryptedData = cipher.doFinal(encryptString.getBytes("utf-8"));
return Base64.encode(encryptedData);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* DeS解密
*/
public static String decryptDES(String decryptString){
byte[] byteMi = Base64.decode(decryptString);
IvParameterSpec zeroIv = new IvParameterSpec(iv);
SecretKeySpec key = new SecretKeySpec(keyStr.getBytes(), "DES");
Cipher cipher;
try {
cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, zeroIv);
byte decryptedData[] = cipher.doFinal(byteMi);
return new String(decryptedData,"utf-8");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* 使用方式
*/
public static void main(String[] args) {
String str = "这是一个待加密的信息";
String jiamiStr = DESUtil.encryptDES(str);
String jiemiStr = DESUtil.decryptDES(jiamiStr);
System.out.println("未加密:"+str);
System.out.println("加密:"+jiamiStr);
System.out.println("解密:"+jiemiStr);
}

开发的环境是eclipse+jetty,以上代码在与android端联调时可正常通信。但打成war包部署到win2003+tomcat上之后,解密的信息却出现了乱码,可笑的是部分乱码而另一部分正常。又折腾了好一阵子,把编码从"utf-8"修改为"gb2312",这才能正常加解密。

一直到现在也没有完全搞清楚,为什么能win2003服务器在"utf-8"的编码设置下,能正常显示web页面,却不能支持加解密通信。

你可能感兴趣的:(android)