1. 程式人生 > >Android與Java服務端加密解密

Android與Java服務端加密解密

本篇部落格是使用Android端與Java服務端互動——SocketIO中的通訊方式連線Android客戶端和java伺服器端的。如果對這方面沒有了解過的,可以隨意去看看;如果對這方面沒有需求或者只關心加密操作的同志請繼續。

在Android端做資料加密操作以前在做畢業設計的時候就想把這個功能加進去,奈何時間有限,知識有限再加上這個需求並沒有那麼迫切,時間一長就沒有繼續糾纏下去了。現如今,專案中要求加上這個功能,沒辦法,只能硬著頭皮上咯。

一通google之後,搜了不少有用的資料作為存檔,貼出來也給大人們享受享受。

1.PHP,安卓,ios相互適用的AES加密演算法
    http://wangsigui.blog
.51cto.com/5362901/1340415 2.iOS,Android,WP, .NET通用AES加密演算法 http://www.cnblogs.com/mantgh/p/4244891.html 3.Android、iPhone和Java三個平臺一致的加密工具 http://www.iteye.com/topic/1127949 4.關於AES256演算法java端加密,ios端解密出現無法解密問題的解決方案 http://my.oschina.net/nicsun/blog/95632 5.Android與IOS通用AES加密解密方法 http://blog.csdn.net/yuxikuo_1/article/details/39476071
6.android、ios與伺服器端php使用rsa加密解密通訊 http://blog.csdn.net/xyxjn/article/details/17225809 7.PHP android ios相互相容的AES加密演算法 http://www.funboxpower.com/868.html 8.Android DES AES MD5加密 http://m.blog.csdn.net/blog/u014071669/39341689 9.Java Base64、AES、SHA1、MD5加密演算法 http://my.oschina.net/u/1447924/blog/377798 10.
在Java、Android、PHP實現AES加解密,並且互通的方式 http://magiclen.org/aes/ 11.AES Encryption : AES « Security « Android http://www.java2s.com/Code/Android/Security/AESEncryption.htm 12.Given final block not properly padded http://bbs.csdn.net/topics/80064751 13.android 和java平臺通用的AES加密解密(Android端與java端互相解密的解決方案) http://my.oschina.net/wangxnn/blog/390346

好了,以上就是我所蒐集的有關AES加密相關的資料了,因為在網上搜了一通發現目前AES加密這一塊安全效能還不錯,大部分人都推薦使用,so,跟著人民群眾走不會錯的,當然,如果你有更好的加密操作的話,可以分享給我,在此小生先謝謝各位了。

進入正題吧,先貼出程式碼:

package com.netty.server.util;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

public class AESUtils {

    static final String algorithmStr = "AES/ECB/PKCS5Padding";

    private static final Object TAG = "AES";

    static private KeyGenerator keyGen;

    static private Cipher cipher;

    static boolean isInited = false;

      private static  void init() {
        try { 
                /**為指定演算法生成一個 KeyGenerator 物件。
                *此類提供(對稱)金鑰生成器的功能。
                *金鑰生成器是使用此類的某個 getInstance 類方法構造的。
                *KeyGenerator 物件可重複使用,也就是說,在生成金鑰後,
                *可以重複使用同一 KeyGenerator 物件來生成進一步的金鑰。
                *生成金鑰的方式有兩種:與演算法無關的方式,以及特定於演算法的方式。
                *兩者之間的惟一不同是物件的初始化:
                *與演算法無關的初始化
                *所有金鑰生成器都具有金鑰長度 和隨機源 的概念。
                *此 KeyGenerator 類中有一個 init 方法,它可採用這兩個通用概念的引數。
                *還有一個只帶 keysize 引數的 init 方法,
                *它使用具有最高優先順序的提供程式的 SecureRandom 實現作為隨機源
                *(如果安裝的提供程式都不提供 SecureRandom 實現,則使用系統提供的隨機源)。
                *此 KeyGenerator 類還提供一個只帶隨機源引數的 inti 方法。
                *因為呼叫上述與演算法無關的 init 方法時未指定其他引數,
                *所以由提供程式決定如何處理將與每個金鑰相關的特定於演算法的引數(如果有)。
                *特定於演算法的初始化
                *在已經存在特定於演算法的引數集的情況下,
                *有兩個具有 AlgorithmParameterSpec 引數的 init 方法。
                *其中一個方法還有一個 SecureRandom 引數,
                *而另一個方法將已安裝的高優先順序提供程式的 SecureRandom 實現用作隨機源
                *(或者作為系統提供的隨機源,如果安裝的提供程式都不提供 SecureRandom 實現)。
                *如果客戶端沒有顯式地初始化 KeyGenerator(通過呼叫 init 方法),
                *每個提供程式必須提供(和記錄)預設初始化。
                */
            keyGen = KeyGenerator.getInstance("AES");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        // 初始化此金鑰生成器,使其具有確定的金鑰長度。
        keyGen.init(256); //256位的AES加密
        try {    
                // 生成一個實現指定轉換的 Cipher 物件。
            cipher = Cipher.getInstance(algorithmStr);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        }
        //標識已經初始化過了的欄位
        isInited = true;
    }

    private static byte[] genKey() {
        if (!isInited) {
            init();  
        }
        //首先 生成一個金鑰(SecretKey),
        //然後,通過這個祕鑰,返回基本編碼格式的金鑰,如果此金鑰不支援編碼,則返回 null。 
        return keyGen.generateKey().getEncoded();
    }

    private static byte[] encrypt(byte[] content, byte[] keyBytes) {
        byte[] encryptedText = null;
        if (!isInited) { 
            init();
        }
        /**
        *類 SecretKeySpec
        *可以使用此類來根據一個位元組陣列構造一個 SecretKey,
        *而無須通過一個(基於 provider 的)SecretKeyFactory。
        *此類僅對能表示為一個位元組陣列並且沒有任何與之相關聯的鑰引數的原始金鑰有用 
        *構造方法根據給定的位元組陣列構造一個金鑰。
        *此構造方法不檢查給定的位元組陣列是否指定了一個演算法的金鑰。
        */
        Key key = new SecretKeySpec(keyBytes, "AES");
        try {
                // 用金鑰初始化此 cipher。
            cipher.init(Cipher.ENCRYPT_MODE, key);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        try {
                //按單部分操作加密或解密資料,或者結束一個多部分操作。(不知道神馬意思)
            encryptedText = cipher.doFinal(content);
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        return encryptedText;
    }

    private static byte[] encrypt(String content, String password) {
        try {
            byte[] keyStr = getKey(password);
            SecretKeySpec key = new SecretKeySpec(keyStr, "AES");
            Cipher cipher = Cipher.getInstance(algorithmStr);//algorithmStr          
            byte[] byteContent = content.getBytes("utf-8");
            cipher.init(Cipher.ENCRYPT_MODE, key);//   ʼ  
            byte[] result = cipher.doFinal(byteContent);
            return result; //     
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static byte[] decrypt(byte[] content, String password) {
        try {
            byte[] keyStr = getKey(password);
            SecretKeySpec key = new SecretKeySpec(keyStr, "AES");
            Cipher cipher = Cipher.getInstance(algorithmStr);//algorithmStr           
            cipher.init(Cipher.DECRYPT_MODE, key);//   ʼ  
            byte[] result = cipher.doFinal(content);
            return result; //     
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static byte[] getKey(String password) {
        byte[] rByte = null;
        if (password!=null) {
            rByte = password.getBytes();
        }else{
            rByte = new byte[24];
        }
        return rByte;
    }

    /**
     * 將二進位制轉換成16進位制
     * @param buf
     * @return
     */
    public static String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 將16進位制轉換為二進位制
     * @param hexStr
     * @return
     */
    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1)
            return null; 
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2),
                    16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

        //注意: 這裡的password(祕鑰必須是16位的)
    private static final String keyBytes = "abcdefgabcdefg12"; 

    /**
    *加密
    */
    public static String encode(String content){
            //加密之後的位元組陣列,轉成16進位制的字串形式輸出
        return parseByte2HexStr(encrypt(content, keyBytes));
    }

    /**
    *解密
    */
    public static String decode(String content){
            //解密之前,先將輸入的字串按照16進位制轉成二進位制的位元組陣列,作為待解密的內容輸入
        byte[] b = decrypt(parseHexStr2Byte(content), keyBytes);
        return new String(b);
    }
}

對這一段程式碼的瞭解並不是很透徹,程式碼也是參照著android 和java平臺通用的AES加密解密完成的,在此感謝一下這位博主的經驗分享。

哦,需要注意的一點是中間有一段程式碼keyGen.init(256);這裡可能會出現異常Illegal key size or default parameters,各位請不要驚慌,這裡寫圖片描述。解決方案請參照這篇部落格中的方法AES加密時丟擲java.security.InvalidKeyException: Illegal key size or default parameters
我在這裡也簡單的總結一下步驟供大人們使用咯:

去orcale官網搜尋jce + " " + jdk版本,例如jce 6,找到相關的下載連結,下載後解壓選擇解壓後文件夾中的local_policy.jar和US_export_policy.jar替換掉你的jdk安裝目錄下的/jre/lib/security/目錄下的兩個同名檔案即可解決上述異常。

好了,本次的內容到此結束了,希望對您有點收穫。

原始碼由於和上次的幾乎一樣,只是加了一個加密工具類檔案,在資料傳輸的時候加了呼叫了加密工具類中的加密解密方法,貼上SocketIO通訊的原始碼,有需要的可以載下來,自己加上加密解密操作。

傳送門