<span style="font-size:18px;"> 在Android开发时经常涉及到客户端与服务端的交互,对于一些敏感数据需要进行加密处理。比如登录功能的密码加密,这里介绍 DES加密的一些实现代码和注意事项。 </span>
<span style="font-size:18px;"> 请原谅我匮乏表达能力,</span>如果你看不太懂,可以查看相关链接)由于不同的开发环境,在进行加密和解密的时候经常出 现结果不相同的情况,我遇到的是用Android 客户端进行DES加密,然后在服务器端用C#DES方法进行解密,结果。。。 </span>
<span style="font-size:18px;"> 先看一下Android端的DES加密算法:(来自网络粘贴:原址:</span><span style="font-size:14px;">http://www.it165.net/pro/html/201411/26957.html,http://www. it165.net/pro/html/201411/26957.html</span>
<span style="font-size:18px;"> public static final String ALGORITHM_DES = "DES/CBC/PKCS5Padding";
</span>
public static final String ALGORITHM_DES = "DES/CBC/PKCS5Padding"; private static byte[] IV={0x12,0x34,0x56,0x78,(byte) 0x90,(byte) 0xAB,(byte) 0xCD,(byte) 0xEF}; /** * DES算法,加密 * * @param data * 待加密字符串 * @param key * 加密私钥,长度不能够小于8位 * @return 加密后的字节数组,一般结合Base64编码使用 * @throws InvalidAlgorithmParameterException * @throws Exception */ public static String encode(String key, String data) { if (data == null) return null; try { DESKeySpec dks = new DESKeySpec(key.subString(0,8).getBytes()); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); // key的长度不能够小于8位字节 Key secretKey = keyFactory.generateSecret(dks); Cipher cipher = Cipher.getInstance(ALGORITHM_DES); IvParameterSpec iv = new IvParameterSpec(IV); AlgorithmParameterSpec paramSpec = iv; cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec); byte[] bytes = cipher.doFinal(data.getBytes());
byte[] str=Base64.encode(bytes,0, bytes.length, 0); return new String(str,"UTF-8"); } catch (Exception e) { e.printStackTrace(); return data; } } /** * DES算法,解密 * * @param data * 待解密字符串 * @param key * 解密私钥,长度不能够小于8位 * @return 解密后的字节数组 * @throws Exception * 异常 */ public static String decode(String key, String data) { if (data == null) return null; try { DESKeySpec dks = new DESKeySpec(key.getBytes()); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); // key的长度不能够小于8位字节 Key secretKey = keyFactory.generateSecret(dks); Cipher cipher = Cipher.getInstance(ALGORITHM_DES); IvParameterSpec iv = new IvParameterSpec("12345678".getBytes()); AlgorithmParameterSpec paramSpec = iv; cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec); return new String(cipher.doFinal(byte2hex(data.getBytes()))); } catch (Exception e) { e.printStackTrace(); return data; } }
我对他的代码进行了一些小的修改,首先就是加密方法的红色部分,我们来看一下都是什么东东:
要想知道第一行和第二行的意义,首先我们要先了解
调用DES加密算法包最精要的就是下面两句话:(来自摘抄:http://blog.csdn.net/randyjiawenjie/article/details/6617225,http://jingyan.baidu.com/article/f96699bbb1b3d6894f3c1b66.html)
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);
-
Cipher类为加密和解密提供密码功能,转换始终包括加密算法的名称(例如,DES),后面可能跟有一个加密模式和填充方案。Cipher.getInstance的参数格式:"加密算法/加密 模式/填充模式" 或 "算法"
-
其中的参数含义为:DES为加密算法,CBC为加密模式,PKCS5Padding为填充模式.
-
常用加密算法:DES、3DES、RC4、AES等
-
加密模式:ECB、CBC、CFB、OFB等;
- DES一共有电子密码本模式(ECB)、加密分组链接模式(CBC)、加密反馈模式(CFB)和输出反馈模式(OFB)四种模式
-
填充模式:NoPadding、PKCS1Padding、PKCS5Padding、PKCS7Padding
-
-
所以有
-
-
DES/CFB/PKCS5Padding,
-
DES/ECB/PKCS5Padding,
-
DES/OFB/PKCS5Padding,
-
DES/CFB/NoPadding,
-
DES/CBC/NoPadding,
-
DES/ECB/NoPadding,
-
DES/OFB/NoPadding,
-
........
-
我不会告诉你我是一个一个试出来哪一个能匹配上的。。。。。。
-
-
工作模式、填充模式、初始化向量这三种因素一个都不能少。否则,如果你不指定的话,那么就要程序就要调用默认实现。问题就来了,这就与平台有关了。
-
-
剩下代码中标红的就是将加密结果进行Base64编码,然后将字节数组转换为字符串返回
-
-
================================================================================================
-
接下来就是C#服务器端了,先看一下DES加密解密代码
-
这里唯一要注意的就是保证 private static byte[] Keys = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF } 和Android端的 private static byte[] IV={0x12,0x34,0x56,0x78,(byte) 0x90, (byte) 0xAB,(byte) 0xCD,(byte) 0xEF} 保持一致,以及是否对加密内容进行了字符串截取,当然最重要的是保证密匙相同。<span style="color:#ff0000;">private static byte[] Keys = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };</span> /** <summary> /// DES加密字符串 /// </summary> /// <param name="encryptString">待加密的字符串</param> /// <param name="encryptKey">加密密钥,要求为8位</param> /// <returns>加密成功返回加密后的字符串,失败返回源串</returns> public static string EncryptDES(string encryptString, string encryptKey) { try { <span style="color:#ff0000;">byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8));</span> byte[] rgbIV = Keys; byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString); DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider(); MemoryStream mStream = new MemoryStream(); CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write); cStream.Write(inputByteArray, 0, inputByteArray.Length); cStream.FlushFinalBlock(); return Convert.ToBase64String(mStream.ToArray()); } catch { return encryptString; } } /** <summary> /// DES解密字符串 /// </summary> /// <param name="decryptString">待解密的字符串</param> /// <param name="decryptKey">解密密钥,要求为8位,和加密密钥相同</param> /// <returns>解密成功返回解密后的字符串,失败返源串</returns> public static string DecryptDES(string decryptString, string decryptKey) { try { byte[] rgbKey = Encoding.UTF8.GetBytes(decryptKey); byte[] rgbIV = Keys; byte[] inputByteArray = Convert.FromBase64String(decryptString); DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider(); MemoryStream mStream = new MemoryStream(); CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write); cStream.Write(inputByteArray, 0, inputByteArray.Length); cStream.FlushFinalBlock(); return Encoding.UTF8.GetString(mStream.ToArray()); } catch { return decryptString; } }
-
传说:
-
a. 有些 明文加密后返回值为null,原来是明文的长度 必须为8的倍数 。增加一个while循环填充空格就可以了。当你处理其他系统间的加密数据交互时,也可以参考一下。
-
b. Android平台和Java平台的DES加密解密如果不这样处理也会出现加密解密结果不同的情况。
-
c. 谁能告诉我为啥在android中(Eclipse) private static byte[] IV={0x12,0x34,0x56,0x78,(byte) 0x90,(byte) 0xAB,(byte) 0xCD,(byte) 0xEF}里后面的数据要进行类型转换。
-
-