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

  • 相关阅读:
    2019.9.18 csp-s模拟测试46 反思总结
    2019.9.17 csp-s模拟测试45 反思总结
    矩阵求导(包含极大似然估计)
    sir
    Square into Squares. Protect trees!(平方数分解平方和)
    最小二乘法
    2.5&2.6 numpy&pandas 笔记
    2.4 python学习笔记
    2.3 python学习笔记
    2.1&2.2python学习笔记
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3037365.html
Copyright © 2011-2022 走看看