Java和ObjectiveC中字符编码及DES加密解密

1.概述

在基于互联网的应用中,发送端将字符采用某种方式加密后传输;而接受端根据事先约定的密钥进行解密,这样即使传输的字符被截获,也不会轻易被识别。而且,现在很多应用环境都很复杂,服务端是JAVA应用,客户端有JAVA应用、智能手机应用。我们以服务端为JAVA应用,客户端为智能手机IOS应用为例,实现在服务端加密一段字符,传输到客户端解密;在客户端又加密一段字符,传输到服务端解密,这样一个较为复杂的过程。

对于这种需求,有很多实现方式,如采用https加安全数字证书来实现,它在金融行业用得比较多。

这里采用DES算法完成这种字符安全传输的需求。首先声明一下,DES算法我也了解不多,下面的论述肯定有遗漏、错误等等不足之处,请参考性阅读,发现错误等请告诉我。在此先行谢过。

2.Java字符编码

所有计算机的字符都是按照某种字符集进行编码的,在网络中真正传输的是字节。

在客户端发送某串字符如”miki西游:mikixiyou@126.com”,它会按照客户端的字符集进行编码,形成字节流,在传输到某个服务端前,还需要使用BASE64进行编码,然后传到服务端。

服务端接收到之后,使用BASE64进行解码,然后按照它的默认字符集进行解码,形成字符串。如果客户端和服务端使用的默认字符集是一致的,如都是GBK,那么就会正确显示这段字符文字。如果不正确,如客户端用GBK编码,而服务器端用UTF8编码,那么就会出现乱码。我们经常在浏览器上见到乱码啊问号号等字符,就是这样字符集不一致所导致的。

   public static void main(String args[]) throws Exception {

 

       String source = “miki西游| mikixiyou@126.com”;

      

       StringcharsetName=System.getProperty(“file.encoding”);

       System.out.println(“file.encodingis “+charsetName);

       System.out.println(“source=”+source);

       System.out.println(parseByte2HexStr(source.getBytes(“GBK”)));

       System.out.println(parseByte2HexStr(source.getBytes()));

              

       System.out.println(parseByte2HexStr(source.getBytes(“UTF-8”)));

       String source_utf8=newString (source.getBytes(“UTF-8″),”UTF-8”);

       System.out.println(“source_utf8=”+source_utf8);

       String source_gbk=newString (source.getBytes(“GBK”),”GBK”);       

       System.out.println(“source_gbk=”+source_gbk);

   }

一般我们使用这个方法source.getBytes()的source字符串默认字符集的编码。

String source = “西游abc@126.com”;

System.out.println(parseByte2HexStr(source.getBytes()));

输出结果为

CEF7D3CE616263403132362E636F6D

前两个字节CEF7表示“西”,后两个字节D3CE表示“游”。GBK字符集对于汉字采用两字节编码的。

字符串source的默认字符集可以通过系统属性得到,它是每一个JAVA的文件编码。获取的方法如下:

       StringcharsetName=System.getProperty(“file.encoding”);

       System.out.println(“file.encodingis “+charsetName);

输出结果为

file.encoding is GBK

如果按照UTF-8字符集获取编码,那么输出的字节流将按照UTF-8编码方式进行输出。

       System.out.println(parseByte2HexStr(source.getBytes(“UTF-8”)));

       String source_utf8=newString (source.getBytes(“UTF-8″),”UTF-8”);

输出结果为

E8A5BFE6B8B8616263403132362E636F6D

前三个字节E8A5BF表示“西”,后三个字节E6B8B8表示“游”。UTF-8字符集对于汉字采用三字节编码的。

在互联网中,传输的字节流还需要进行BASE64编码。我不知道是不是因为字节流太长了什么的,需要BASE64编码压缩一下,还是其他什么目的。

BASE64的使用很简单,网上源代码很多。基本是使用这两个方法,“String encode(byte[] data)“将字节数组编码成字符串,“byte[]decode(String s)”将字符串还原成字节数组。

3.Java字节加密

在JAVA类中导入 javax.crypto.Cipher;包,使用Cipher.getInstance(“DES/CBC/PKCS5Padding”);方法实现加密。

注意,这里使用PKCS5Padding算法,密钥只能是8个字节。

因为在ios中,支持的DES加密算法是kCCOptionPKCS7Padding |kCCOptionECBMode。在使用PKCS7Padding,它的密钥可以是8个字节,也可以不是。如果密钥不是8个字节的话,那么JAVA端的PKCS5Padding算法就不能解密了。

我对DES算法也了解甚少,这里只说一下自己的理解。在密钥都是8个字节的前提下,PKCS7Padding和PKCS5Padding的加密和解密是通用的。因此,不必纠结于两个算法不一样怎么办,如何让IOS也支持JAVA的加密算法,甚至不用DES了等等。

我觉得都没必要,我们做的是工程,一种需求的实现方法。只要遵守密钥为8个字节的约定,就能实现需求,又何必去找其他的算法。好吧,我理解你觉得这样不安全,其实也没绝对的安全。

回到正题,JAVA中DES加密实现方法如下:

private static byte[] iv = {1, 2, 3, 4, 5, 6, 7, 8};

 

   public static byte[]encryptDES(String encryptString, String encryptKey)

           throws Exception {

 

       System.out.println(“willencryptedData with UTF-8 encoding =” + parseByte2HexStr(encryptString.getBytes(“UTF-8”)));

      

       IvParameterSpec zeroIv =new IvParameterSpec(iv);

       SecretKeySpec key = newSecretKeySpec(encryptKey.getBytes(), “DES”);

       Cipher cipher = Cipher.getInstance(“DES/CBC/PKCS5Padding”);

       cipher.init(Cipher.ENCRYPT_MODE,key, zeroIv);

       byte[] encryptedData =cipher.doFinal(encryptString.getBytes(“UTF-8”));

       System.out.println(“didencryptedData  =” + parseByte2HexStr(encryptedData));

       return encryptedData;

   }

 

   public static StringencryptDESwithBase64(String encryptString,String encryptKey) throws Exception

   {

       return XYBase64.encode(encryptDES(encryptString,encryptKey));

   }

JAVA中DES解密实现方法如下:

   public static String decryptDES(byte[] encryptedData, StringdecryptKey)

           throws Exception {

       System.out.println(“willdecryptedData =” + parseByte2HexStr(encryptedData));

      

       IvParameterSpec zeroIv =new IvParameterSpec(iv);

       SecretKeySpec key = newSecretKeySpec(decryptKey.getBytes(“UTF-8”), “DES”);

       Cipher cipher = Cipher.getInstance(“DES/CBC/PKCS5Padding”);

       cipher.init(Cipher.DECRYPT_MODE,key, zeroIv);

       byte decryptedData[] =cipher.doFinal(encryptedData);

 

       System.out.println(“diddecryptedData with UTF-8 encoding =” + parseByte2HexStr(decryptedData));

 

       String decryptedString =new String(decryptedData, “UTF-8”);

       System.out.println(“diddecryptedString with UTF-8 encoding =” + decryptedString);

       return decryptedString;

   }

   public static StringdecryptDESwithBase64(String encryptedString, String decryptKey)  throws Exception

   {

       byte[]encryptedData=XYBase64.decode(encryptedString);

       return decryptDES(encryptedData,decryptKey);      

   }  

在main()中调试一下,结果符合预期。

   public static void main(String[] args) throws Exception {

       String plainText = “abcdefghihjjjkelaemn”;

       String keyText = “20120401”;

 

       plainText = “miki西游| mikixiyou@126.com”;

       keyText = “abcd1234”;

 

       byte[] encryptedData = encryptDES(plainText,keyText);

       String decryptedString=decryptDES(encryptedData,keyText);

      

       String cipherText = parseByte2HexStr(encryptedData);

      

       System.out.println(“明文:” + plainText);

       System.out.println(“密钥:” + keyText);

       System.out.println(“密文 Base64 编码:” + cipherText);

       System.out.println(“解密后:” + decryptedString);    

      

       String encryptedString =encryptDESwithBase64(plainText, keyText);

       decryptedString=decryptDESwithBase64(encryptedString,keyText);

      

       System.out.println(“明文:” + plainText);

       System.out.println(“密钥:” + keyText);

       System.out.println(“密文:” + encryptedString);

       System.out.println(“解密后:” + decryptedString);

   }

输出结果如下:

will encryptedData with UTF-8 encoding=E8A5BFE6B8B8616263403132362E636F6D

did encryptedData =A69C602B3F74BD6273DE730D6214026B8FE538E4AB9F8547

will decryptedData =A69C602B3F74BD6273DE730D6214026B8FE538E4AB9F8547

did decryptedData with UTF-8 encoding =E8A5BFE6B8B8616263403132362E636F6D

did decryptedString with UTF-8 encoding =miki西游| mikixiyou@126.com

明文:miki西游| mikixiyou@126.com

密钥:abcd1234

密文 Base64 编码:A69C602B3F74BD6273DE730D6214026B8FE538E4AB9F8547

解密后:miki西游| mikixiyou@126.com

will encryptedData with UTF-8 encoding =E8A5BFE6B8B8616263403132362E636F6D

did encryptedData =A69C602B3F74BD6273DE730D6214026B8FE538E4AB9F8547

will decryptedData =A69C602B3F74BD6273DE730D6214026B8FE538E4AB9F8547

did decryptedData with UTF-8 encoding=E8A5BFE6B8B8616263403132362E636F6D

did decryptedString with UTF-8 encoding =miki西游| mikixiyou@126.com

明文:miki西游| mikixiyou@126.com

密钥:abcd1234

密文:ppxgKz90vWJz3nMNYhQCa4/lOOSrn4VH

解密后:miki西游| mikixiyou@126.com

这样,我们就实现了JAVA中的加密和解密。但要在客户端也实现这样的加密和解密算法才算最终完成任务。

4.Objective-C字符编码

 待续

5.Objective-C字节加密

  待续

6.参考资料

http://www.cnblogs.com/midea0978/articles/1437257.html

http://www.cnblogs.com/silentjesse/archive/2011/11/04/2235674.html

关于Objective-c和Java下DES加密保持一致的方式。这个文档我找不到原始作者,只看到很多转载,所以不写超链接了。