当前位置:编程学习 > JAVA >>

Java和Objective-C中字符编码及DES加密解密

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

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

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

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

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

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

以Java代码为例,解释一下字符如何编码,如何转换的操作过程。

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

 

Stringsource = "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 = " miki西游| mikixiyou@126.com;

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

输出结果为

6D696B69 CEF7 D3CE 7C206D696B697869796F75403132362E636F6D

前两个字节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");

输出结果为

6D696B69 E8A5BF E6B8B8 7C206D696B697869796F75403132362E636F6D

三个字节E8A5BF表示“西”,三个字节E6B8B8表示“游”。UTF-8字符集对于汉字采用三字节编码的,对于英文字符及数字还是单字节编码。

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

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

不管字符是采用UTF-8字符集,还是GBK字符集,以及其他的字符集。这些字符都是一串二进制数字,和对应的字符集的对应,从而形成人眼能理解的字符。

在Objective-C中,也是遵循这个规则的。

    NSData* data=[plainTextdataUsingEncoding: NSUTF8StringEncoding];

   NSLog(@"plainTextBytes with UTF-8 encoding:%@",[XYDESdataToHex:data]);

这是将字符串plainText以UTF8字符串编码方式生成一个字节流。

它的输出结果如下:

plainTextBytes with UTF-8 encoding:6D696B69 E8A5BF E6B8B8 7C206D696B697869796F75403132362E636F6D

三个字节E8A5BF表示“西”,三个字节E6B8B8表示“游”。UTF-8字符集对于汉字采用三字节编码,对于英文字符及数字还是单字节编码。

从这里可以看到字符编码都是UTF8时,不管是Java还是Objective-C语言中,得到的字节流都是一样的。

在这个字节流的基础上,使用Base64再次进行编码。我在Objective-C中采用的是google提供的GTMBase64进行编码和解码。
在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

   {

       returnXYBase64.encode(encryptDES(encryptString,encryptKey));

   }

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

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

           throws Exception {

     

补充:软件开发 , Java ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,