Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Java中的非對稱加密算法

Java中的非對稱加密算法

編輯:關於Android編程

上篇博文中我們講了Java中的對稱加密,還沒有看過的童鞋可以打開鏈接查看對稱加密,今天我們重點講一下Java中的非對稱加密。

對於非對稱加密,它需要兩個密鑰來進行加密和解密,分別為公鑰和私鑰,其相對於對稱加密而言安全性更高;在Java中的非對稱加密算法主要有DH算法和RSA算法。

DH算法加密:

package com.example.asiatravel.learndes.dh_util;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;

/**
 * Created by kuangxiaoguo on 16/9/14.
 *
 * DH加密工具類
 */
public class DHUtil {

    public static final String PUBLIC_KEY = "DHPublicKey";
    public static final String PRIVATE_KEY = "DHPrivateKey";

    /**
     * 甲方初始化並返回密鑰
     *
     * @return 甲方的公鑰和私鑰
     * @throws Exception
     */
    public static Map initKey() throws Exception {
        //初始化密鑰對生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH");
        keyPairGenerator.initialize(1024);// 默認是1024, 516-1024且是64的倍數
        //生成密鑰對
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        //得到公鑰和私鑰
        DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
        DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
        Map keyMap = new HashMap<>();
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /**
     * 乙方根據甲方公鑰初始化並返回密鑰對
     *
     * @param key 甲方的公鑰
     * @return 乙方的公鑰和私鑰
     * @throws Exception
     */
    public static Map initKey(byte[] key) throws Exception {
        //將甲方公鑰從字節數組轉化為publicKey
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(key);
        //實例化密鑰工廠
        KeyFactory keyFactory = KeyFactory.getInstance("DH");
        //產出甲方公鑰
        DHPublicKey dhPublicKey = (DHPublicKey) keyFactory.generatePublic(keySpec);
        //剖析甲方公鑰獲取其參數
        DHParameterSpec dhParameterSpec = dhPublicKey.getParams();
        //實例化密鑰對生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH");
        //用甲方公鑰初始化密鑰生成器
        keyPairGenerator.initialize(dhParameterSpec);
        //獲取密鑰對
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        //獲取乙方公鑰和私鑰
        DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
        DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
        //將乙方的公鑰和私鑰存入map集合中
        Map keyMap = new HashMap<>();
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /**
     * 根據對方的公鑰和自己的私鑰生成本地密鑰
     *
     * @param publicKey  對方公鑰
     * @param privateKey 自己私鑰
     * @return 本地密鑰
     * @throws Exception
     */
    public static byte[] getSecretKey(byte[] publicKey, byte[] privateKey) throws Exception {
        //實例化密鑰工廠
        KeyFactory keyFactory = KeyFactory.getInstance("DH");
        //將公鑰從字節數組轉化為publicKey
        X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKey);
        PublicKey pubKey = keyFactory.generatePublic(publicKeySpec);
        //將私鑰從字節數組轉化為privateKey
        PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKey);
        PrivateKey priKey = keyFactory.generatePrivate(privateKeySpec);
        //根據以上公鑰和私鑰生成本地的密鑰secretKey
        //實例化keyAgreement
        KeyAgreement keyAgreement = KeyAgreement.getInstance("DH");
        //用自己的私鑰初始化keyAgreement
        keyAgreement.init(priKey);
        //結合對方的公鑰進行運算
        keyAgreement.doPhase(pubKey, true);
        //開始生成本地密鑰secretKey,密鑰算法為對稱加密算法
        SecretKey secretKey = keyAgreement.generateSecret("AES");//DES 3DES AES
        return secretKey.getEncoded();
    }

    /**
     * 從Map中獲取公鑰
     *
     * @param keyMap 存放公鑰和密鑰的Map
     * @return 公鑰
     */
    public static byte[] getPublicKey(Map keyMap) {
        DHPublicKey key = (DHPublicKey) keyMap.get(PUBLIC_KEY);
        return key.getEncoded();
    }

    /**
     * 從Map中獲取私鑰
     *
     * @param keyMap 存放公鑰和密鑰的Map
     * @return 私鑰
     */
    public static byte[] getPrivateKey(Map keyMap) {
        DHPrivateKey key = (DHPrivateKey) keyMap.get(PRIVATE_KEY);
        return key.getEncoded();
    }
}

RSA算法加密:

package com.example.asiatravel.learndes.rsa_util;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

/**
 * Created by kuangxiaoguo on 16/9/14.
 *
 * RAS加密工具類
 */
public class RSAUtil {

    public static final String PUBLIC_KEY = "RSAPublicKey";
    public static final String PRIVATE_KEY = "RSAPrivateKey";

    /**
     * 生成RSA公鑰和私鑰
     *
     * @return RSA公鑰和私鑰的Map集合
     * @throws Exception
     */
    public static Map initKey() throws Exception {
        //初始化密鑰生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024);
        //獲取密鑰對
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        //獲取公鑰和私鑰
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        //把公鑰和私鑰存入map集合
        Map keyMap = new HashMap<>();
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /**
     * 使用公鑰加密
     *
     * @param data      需要加密的數據
     * @param publicKey 公鑰
     * @return 加密後的字節數組
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data, RSAPublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }

    /**
     * 使用私鑰解密
     *
     * @param data       被公鑰加密後的數據
     * @param privateKey 解密用的私鑰
     * @return 解密後的數據的字節數組
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data, RSAPrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 從Map集合中獲取公鑰
     *
     * @param keyMap 存儲公鑰和私鑰的map集合
     * @return 返回公鑰
     */
    public static RSAPublicKey getPublicKey(Map keyMap) {
        return (RSAPublicKey) keyMap.get(PUBLIC_KEY);
    }

    /**
     * 從Map集合中獲取私鑰
     *
     * @param keyMap 存儲公鑰和私鑰的map
     * @return 返回私鑰
     */
    public static RSAPrivateKey getPrivateKey(Map keyMap) {
        return (RSAPrivateKey) keyMap.get(PRIVATE_KEY);
    }
}

非對稱加密的測試代碼:

package com.example.asiatravel.learndes;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import com.example.asiatravel.learndes.dh_util.DHUtil;
import com.example.asiatravel.learndes.rsa_util.RSAUtil;
import com.example.asiatravel.learndes.util.ByteToHexUtil;

import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;

public class MainActivity extends AppCompatActivity {

    private static final String DATA = "asiatravel";
    private static final String TAG = "TAG";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        try {
            testDH();
        } catch (Exception e) {
            Log.e(TAG, "onCreate: " + e.getMessage());
        }
        try {
            testRSA();
        } catch (Exception e) {
            Log.e(TAG, "onCreate: " + e.getMessage());
        }
    }

    /**
     * 測試RSA加密-->非對稱加密
     */
    private void testRSA() throws Exception {
        Map keyMap = RSAUtil.initKey();
        RSAPublicKey publicKey = RSAUtil.getPublicKey(keyMap);
        RSAPrivateKey privateKey = RSAUtil.getPrivateKey(keyMap);
        System.out.println("RSA publicKey: " + publicKey);
        System.out.println("RSA privateKey: " + privateKey);

        //加密後的數據
        byte[] encryptResult = RSAUtil.encrypt(DATA.getBytes(), publicKey);
        System.out.println(DATA + " RSA 加密: " + ByteToHexUtil.fromByteToHex(encryptResult));

        //解密後的數據
        byte[] decryptResult = RSAUtil.decrypt(encryptResult, privateKey);
        System.out.println(DATA + " RSA 解密: " + new String(decryptResult));
    }

    /**
     * 測試DH加密-->非對稱加密
     */
    private void testDH() throws Exception {
        //甲方公鑰
        byte[] publicKeyA;
        //甲方私鑰
        byte[] privateKeyA;
        //甲方本地密鑰
        byte[] secretKeyA;
        //乙方公鑰
        byte[] publicKeyB;
        //乙方私鑰
        byte[] privateKeyB;
        //乙方本地密鑰
        byte[] secretKeyB;

        //初始化密鑰並生成甲方密鑰對
        Map keyMapA = DHUtil.initKey();
        publicKeyA = DHUtil.getPublicKey(keyMapA);
        privateKeyA = DHUtil.getPrivateKey(keyMapA);
        System.out.println("DH 甲方公鑰: " + ByteToHexUtil.fromByteToHex(publicKeyA));
        System.out.println("DH 甲方私鑰: " + ByteToHexUtil.fromByteToHex(privateKeyA));

        //乙方根據甲方公鑰生成乙方密鑰對
        Map keyMapB = DHUtil.initKey(publicKeyA);
        publicKeyB = DHUtil.getPublicKey(keyMapB);
        privateKeyB = DHUtil.getPrivateKey(keyMapB);
        System.out.println("DH 乙方公鑰: " + ByteToHexUtil.fromByteToHex(publicKeyB));
        System.out.println("DH 乙方私鑰: " + ByteToHexUtil.fromByteToHex(privateKeyB));

        //對於甲方,根據乙方公鑰和自己的私鑰生成本地密鑰 secretKeyA
        secretKeyA = DHUtil.getSecretKey(publicKeyB, privateKeyA);
        //對於乙方,根據其甲公鑰和自己的私鑰生成本地密鑰 secretKeyB
        secretKeyB = DHUtil.getSecretKey(publicKeyA, privateKeyB);

        System.out.println("DH 甲方本地密鑰: " + ByteToHexUtil.fromByteToHex(secretKeyA));
        System.out.println("DH 乙方本地密鑰: " + ByteToHexUtil.fromByteToHex(secretKeyB));
    }

}
總結:非對稱加密想對於對稱加密來講更加安全,其代碼邏輯方面相對於對稱加密來講也更為復雜,所以大家需要理解著去記憶,另外注釋我在代碼裡都寫上了,不明白的童鞋可以在下面留言。 最後,附上github源碼地址:點擊查看非對稱加密源碼,希望大家多多star!
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved