1. 程式人生 > >Android AES和RSA混合加密工具類實現

Android AES和RSA混合加密工具類實現

        這幾天研究了一下android方面的加密技術,有RSA,md5,base64,AES等以及這幾種加密的混合加密,其他還好,在RSA和AES混合加密的時候出現點問題,就拿出來說一下。

        遇到的問題是,從網上找到的AES工具類大多數時base64編碼輸出格式的,所以一般情況下,與後臺配合使用的時候,加密結果不一致,甚至是解密後臺傳過來的密文失敗,同樣的內容,同樣的金鑰,加密出來的結果卻一直在變化(是整個字串都在變,沒有固定不變的部分)這個一直沒找到原因,後來瞭解到還有hex編碼的輸出格式,就驗證了一下,問題就解決了,以下是兩個工具類程式碼:

base64編碼輸出:

/**
 * AES
 */
public class AESUtils {
	public static String encrypt(String encodeRules,String content){
        try {
            KeyGenerator keygen=KeyGenerator.getInstance("AES");
            keygen.init(128, new SecureRandom(encodeRules.getBytes()));
            SecretKey original_key=keygen.generateKey();
            byte [] raw=original_key.getEncoded();
            SecretKey key=new SecretKeySpec(raw, "AES");
            Cipher cipher=Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte [] byte_encode=content.getBytes("utf-8");
            byte [] byte_AES=cipher.doFinal(byte_encode);
            String AES_encode=new String(TranscoderUtils.encodeBase64(byte_AES));
            return AES_encode;
        } 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();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
       
        return null;         
    }
    
    public static String decrypt(String encodeRules,String content){
        try {
            KeyGenerator keygen=KeyGenerator.getInstance("AES");
            keygen.init(128, new SecureRandom(encodeRules.getBytes()));
            SecretKey original_key=keygen.generateKey();
            byte [] raw=original_key.getEncoded();
            SecretKey key=new SecretKeySpec(raw, "AES");
            Cipher cipher=Cipher.getInstance("AES");
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte [] byte_content= TranscoderUtils.decodeBase64(content);
            byte [] byte_decode=cipher.doFinal(byte_content);
            String AES_decode=new String(byte_decode,"utf-8");
            return AES_decode;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        
        return null;         
    }
}

這是hex格式編碼的AES加密工具類:
public class AES {

    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(128); //128位的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);
    }
    
    //測試用例
    public static void test1(){
        String content = "hello abcdefggsdfasdfasdf";
        String pStr = encode(content );
        System.out.println("加密前:"+content);
        System.out.println("加密後:" + pStr);
        
        String postStr = decode(pStr);
        System.out.println("解密後:"+ postStr );
    }
    
    public static void main(String[] args) {
        test1();
    }
}

hex這種是將加密後的byte陣列進行16進位制轉換,然後再轉換成字串的形式,這樣的話,就會與後臺加密的結果一致了,並且相關AES線上加密解密網站,也都能成功解密出對應內容

下面是demo連結


相關推薦

Android AESRSA混合加密工具實現

        這幾天研究了一下android方面的加密技術,有RSA,md5,base64,AES等以及這幾種加密的混合加密,其他還好,在RSA和AES混合加密的時候出現點問題,就拿出來說一下。         遇到的問題是,從網上找到的AES工具類大多數時base64編

檔案字串的加密工具md5

直接上演算法封裝的工具類程式碼: [html] view plain copy  print? package com.itydl.utils;   import java.io.File;   import java.io.FileInputStream

前後端API互動資料加密——AESRSA混合加密完整例項

  前言    前段時間看到一篇文章講如何保證API呼叫時資料的安全性(傳送門:https://blog.csdn.net/ityouknow/article/details/80603617),文中講到利用RSA來加密傳輸AES的祕鑰,用AES來加密資料,並提供如下思路:   說人話就是前

WebSocket資料加密——AESRSA混合加密

  前言   之前在寫“一套簡單的web即時通訊”,寫到第三版的時候沒什麼思路,正好微信公眾號看到一篇講API互動加密,於是就自己搞了一套AES與RSA混合加密,無意中產生應用在WebSocket想法,好在思路都差不多,稍微改動一下就能實現,特意寫這篇部落格記錄下來   WebSo

JAVA中使用MD5加密工具實現對數據的加密處理

歸納 ssa utf int 控制 nic this com nod 1.MD5工具類 package com.ssm.util; import java.security.MessageDigest; public class MD5Util { //將字

java 加密工具(MD5、RSAAES加密方式)

 MD5加密 import org.apache.commons.codec.digest.DigestUtils; /** * MD5加密元件 * * @version 1.0 * @since 1.0 */ public abstract class M

Java AES 加密工具

dom .com 生成器 ogg bytes commons level result exc package com.microwisdom.utils; import java.security.NoSuchAlgorithmException; import ja

php aesrsa加密的區別

php aes和rsa加密的區別RSA非對稱加密,公鑰加密,私鑰解密,反之亦然。由於需要大數的乘冪求模等算法,運行速度慢,不易於硬件實現。通常私鑰長度有512bit,1024bit,2048bit,4096bit,長度越長,越安全,但是生成密鑰越慢,加解密也越耗時。既然是加密,那肯定是不希望別人知道我的消息

RSA加密工具(Java)

乾貨 package com.hht.exchange.utils; import javax.crypto.Cipher; import java.security.*; import java.security.spec.PKCS8EncodedKeySp

AESUtil AES加密工具

AES加密工具類,其中匯入的jar包jdk引進去就可以用了,jdk的版本儘量大於1.5 package com.g.mavenspring.demo.util; /** * @Title: AESUtil.java * @Package com.g.maven

AESRSA加密演算法入門Demo

首先感謝博主開園精神,此部落格是個人結合博主博文來進行一次個人的總結,加深學習印象。博主已經總結的非常的不錯,大家可以參考博主原文博主部落格地址 資料參考: 博主原始碼下載 百度百科 Java中有對稱加密和非對稱加密。 對稱加密演算法在加密和解密時

java進階之對接安卓RSA加密工具

     1.什麼是RSA加密演算法        RSA公鑰加密演算法是1977年由Ron Rivest、Adi Shamirh和LenAdleman在(美國麻省理工學院)開發的。RSA取名來自開發他們三者

AESRSA加密演算法調研

一、AES(DES的升級版)(對稱加密)執行時間 [1]     測試資料 這裡以讀取純文字檔案,一行一行的方式對字串進行加密,並把加密後的內容儲存到另外一個檔案中,計算檔案的加密時間。待檔案加密完成

android中MD5加密工具

/**  * md5工具類  *   * @author xiaoke  *   */ public class MD5Util {/*** * @param psdMD5要加密的物件* @returnMD5加密後市返回一個32位數的字串,返回“”,代表加密異常*/pub

客戶端與伺服器互動使用AES+RSA混合加密原理詳解

前言 最近維護公司APP應用的登入模組,由於測試人員用Fiddler抓包工具抓取到了公司關於登入時候的明文登入資訊。雖然使用的是HTTPS的方式進行http請求的,但還是被Fiddler抓到了明文內容。因此,需要對之前未加密的登入資訊進行加密。在網上搜到一篇關於AES

AES加密工具

aes加密工具類 不用base64, 8.bin2hex(2進位制轉16進位制),解密hex2bin(16進位制轉2進位制),先轉換後再解密。 public class AESUtil {       private static final Logger logg

MD5用戶密碼加密工具 MD5Util

void 十六進制 i++ case per pri mms java 創建 一般記錄用戶密碼,我們都是通過MD5加密配置的形式。這裏記錄一下,MD5加密的工具類。 package com.mms.utils; import java.security.Me

根據文件名字獲取文件的前綴後綴的工具

oid pos pub style ava span bsp 字符串 als FileNameUtil.java package com.tyust.common; import org.junit.Test; /** * 獲取文件後綴前綴的工具類

JDBC的配置文件,郵件,密碼加密工具

協議 登錄驗證 substring mon smtp getc getclass authent protoc 配置文件 url=jdbc:mysql:///sysclassName=com.mysql.jdbc.Driverusername=rootpassword=

Android開發人員不得不收集的工具集合

一.Android開發人員不得不收集的工具類集合  ----收藏 https://github.com/RobertCow/RxTools 二.android 開發之listview工具集合框架 https://github.com/anzaizai/EasyRefresh