zoukankan      html  css  js  c++  java
  • 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加密保持一致的方式。这个文档我找不到原始作者,只看到很多转载,所以不写超链接了。

  • 相关阅读:
    字符编码相关
    函数之形参与实参
    文件操作模式
    函数对象,名称空间,作用域,和闭包
    吴裕雄天生自然SPRINGBOOT开发实战处理'spring.datasource.url' is not specified and no embedded datasource could be autoconfigured
    吴裕雄天生自然SPRINGBOOT开发实战处理XXXX that could not be found.
    吴裕雄天生自然SPRINGBOOT开发实战SpringBoot HTML表单登录
    吴裕雄天生自然SPRINGBOOT开发实战SpringBoot REST示例
    吴裕雄天生自然SpringBoot开发实战学习笔记处理 Could not write metadata for '/Servers'.metadata\.plugins\org.eclipse.core.resources\.projects\Servers\.markers.snap (系统找不到指定的路径。)
    吴裕雄天生自然SPRINGBOOT开发实战SpringBoot Tomcat部署
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3037365.html
Copyright © 2011-2022 走看看