前段时间负责开发了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页面,却不能支持加解密通信。
分享到:
相关推荐
jdk7解除aes加密限制,java.security.InvalidKeyException:illegal Key Size
js加密后形成的密文base64和hex码大写都进行了展示。为什么要50字节?
DESServiceECB.jar 实现了DES的ECB模式下的算法,允许对字符串、字节、文件的加密.
Ubuntu12.04安装与JDK.android开发环境搭建
本文首先分析了Java源代码需要加密的原因,简要介绍了DES算法及Java密码体系和Java密码扩展,最后说明了利用DES加密算法保护Java源代码的方法及步骤。
JDK8 JCE 支持256位加密
jdk8解除aes加密限制 java.security.InvalidKeyException:illegal Key Size
ubuntu下jdk的搭建,android开发环境的搭建
Java加密与解密的艺术.pdf Java加密与解密的案例 sun.misc.BASE64Decoder.rar{BASE64Decoder.java BASE64Encoder.java CEFormatException.java CEStreamExhausted.java CharacterDecoder.java CharacterEncoder...
用Java加密类实现常规的DES、RSA及SHA的加密算法,代码完整,收藏一下。
包含java jdk android 环境变量配置
JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。
利用jdk自带算法实现的AES加解密工具类及Base64编解码工具类、 文件操作工具类、aes扩展无限制权限策略文件等。 在jdk1.7环境亲测通过。
Android Java Jdk1.8
内容:基于jdk1.4的加密算法的具体实现,算法包括MD5,SHA-1,DES,DESede,RSA等
用于替换jdk里的两个jar,解决无法使用AES192、256位加密解密的问题 jce7,jce8
安卓Android开发环境搭建全程演示(jdk+eclipse+android sdk)
java jdk和android sdk的安装以及环境变量的配置.pdf
javajdk和androidsdk的安装以及环境变量的配置.pdf