非对称密码的编程使用

非对称密码的概念:
1.对称密码中的密钥配送问题
对称密码传输模型
一旦黑客截取到你的密钥,你的数据也就泄露了。

2.非对称密码通信模型
这里写图片描述
说明:接收方已生成自己的公钥和私钥,私钥自己保存,而私钥则广播出去,发送方甲收到乙方的公钥,对需要传输的数据用公钥进行加密,乙方收到数据后用私钥进行解密恢复到原始数据。经过公钥加密过的数据只有私钥才能破解,所以即使加密过后的数据被截取到没有私钥也不能破解。

3.非对称密码的特征
(1)需要两个密钥来进行加密和解密,分别为公钥和私钥
(2)公钥和私钥相互配对,称为 KeyPair

4.非对称密码的优缺点
(1)优点:相比于对称密码,安全性更高
(2)缺点:加解密花费时间长、速度慢

常用非对称密码
(1)DH 密钥交换算法
(2)RSA 算法
(3)EIGamal 算法

非对称密码的作用
1.密钥交换(DH)
2.加密/解密(RSA)
3.数字签名(RSA)

DH 算法介绍
1.DH算法
一种适基于密钥一致协议的加密算法。
2.流程分析
1)甲方构建密钥对儿,将公钥公布给乙方,将私钥保留;双方约定数据加密算法;乙方通过甲方公钥构建密钥对儿,将公钥公布给甲方,将私钥保留。
2)甲方使用私钥、乙方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥加密数据,发送给乙方加密后的数据;乙方使用私钥、甲方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥对数据解密。
3)乙方使用私钥、甲方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥加密数据,发送给甲方加密后的数据;甲方使用私钥、乙方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥对数据解密
3.DH算法的数学原理
DH算法的数学原理
4.JDK实现
密钥长度:512-1024(64的整数倍)
默认密钥长度:1024
工作模式:无
填充方式:无

5.代码实现

package key.base64;
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;

public class DHUtil {
    public static final String PUBLIC_KEY = "DHPublicKey";
    public static final String PRIVATE_KEY = "DHPrivateKey";

    /**
     * 甲方初始化返回秘钥对
     */
    public static Map<String, Object> initKey() throws Exception {
        // 实例化秘钥对生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH");
        // 初始化秘钥生成器,默认是1024 512-1024& 64的倍数
        keyPairGenerator.initialize(1024);
        // 生成秘钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // 得到甲方的公钥
        DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
        // 得到甲方的私钥
        DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
        // 将公约和私钥封装在Map中,方便以后使用
        Map<String, Object> keyMap = new HashMap<String, Object>();
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /**
     * 乙方根据甲方公约初始化并返回秘钥对
     */
    public static Map<String, Object> 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<String, Object> keyMap = new HashMap<String, Object>();
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /**
     * 根据对方的公钥和自己私钥生成对称密码本地秘钥
     */
    public static byte[] getSecretKey(byte[] publicKey,byte[] privateKey) throws Exception {
        //实例化秘钥工厂
        KeyFactory keyFactory=KeyFactory.getInstance("DH");
        //将公约从字节数组转化为PublicKey
        X509EncodedKeySpec pubKeySpec=new X509EncodedKeySpec(publicKey);
        PublicKey pubKey=keyFactory.generatePublic(pubKeySpec);
        //将私钥从字节数组转化为PrivateKey
        PKCS8EncodedKeySpec priKeySpec=new PKCS8EncodedKeySpec(privateKey);
        PrivateKey priKey= keyFactory.generatePrivate(priKeySpec);

        //准备以上公钥和私钥生成本地秘钥
        //先实例化KeyAgreement
        KeyAgreement keyAgreement=KeyAgreement.getInstance("DH");
        //用自己的私钥初始化KeyAgreement
        keyAgreement.init(priKey);
        //结合对方公钥进行运算
        keyAgreement.doPhase(pubKey, true);
        //生成本地秘钥SecretKey秘钥算法为对称密码算法
        SecretKey secretKey=keyAgreement.generateSecret("DES");//DES AES 3DES
        return secretKey.getEncoded();
    }

    /**
     * 从Map中取得公钥
     */
    public static byte[] getPublicKey(Map<String, Object> keyMap) {
        DHPublicKey key=(DHPublicKey) keyMap.get(PUBLIC_KEY);
        return key.getEncoded();
    }

    /**
     * 从Map中取得私钥
     */
    public static byte[] getPrivateKey(Map<String, Object> keyMap) {
        DHPrivateKey key=(DHPrivateKey) keyMap.get(PRIVATE_KEY);
        return key.getEncoded();
    }

    /**
    *Test
    */
    public static void main(String[] args){
        //Test DH
//      甲方公钥
        byte[] publicKey1;
//      甲方私钥
        byte[] privateKey1;
//      甲方本地秘钥
        byte[] secretKey1;
//      乙方公钥
        byte[] publicKey2;
//      乙方私钥
        byte[] privateKey2;
//      乙方本地秘钥
        byte[] secretKey2;

        //初始化并产生甲方秘钥对
        Map<String, Object>keyMap1= DHUtil.initKey();
        publicKey1=DHUtil.getPublicKey(keyMap1);
        privateKey1=DHUtil.getPrivateKey(keyMap1);
        System.out.println("DH 甲方公钥:"+BytesToHex.fromBytesToHex(publicKey1));
        System.out.println("DH 甲方私钥:"+BytesToHex.fromBytesToHex(privateKey1));

        //乙方根据甲方公钥产生乙方秘钥对
        Map<String, Object> keyMap2=DHUtil.initKey(publicKey1);
        publicKey2=DHUtil.getPublicKey(keyMap2);
        privateKey2=DHUtil.getPrivateKey(keyMap2);
        System.out.println("DH 乙方公钥:"+BytesToHex.fromBytesToHex(publicKey2));
        System.out.println("DH 乙方私钥:"+BytesToHex.fromBytesToHex(privateKey2));
    }
}

RSA 算法介绍
1. RSA:MIT 的 Ron Rivest、 Adi Shamir 和 Leonard Adleman三位学者提出的 非对称加密算法
2. 作用:数据加密和数字签名
3.RSA 数学原理
(1)加解密公式
RSA加密:密文 = 明文E mod N 公钥(E,N)
RSA解密:明文 = 密文D mod N 私钥(D,N)
(2)模拟生成密钥对
1)求N:p=17 q=19 N=p*q = 323
2)求L:L=lcm(p-1,q-1)=lcm(16,18) = 144
3)求E:gcd(E,L)=1 E=5
4)求D:E*D mod L = 1 D=29
公钥(5,323) 私钥(29,323)

公钥(5,323)     私钥(29,323)

(3)加密
密文 = 明文E mod N = 123^5 mod 323 = 225
(4)解密
明文 = 密文D mod N = 225^29 mod 323 = 123
4. JDK实现
密钥长度:512-65536(64的倍数)
默认密钥长度:1024
工作模式:ECB
填充方式:NoPadding、PKCS1Padding、
OAEPWITHMD5AndMGF1Padding、
OAEPWITHSHA1AndMGF1Padding、
OAEPWITHSHA256AndMGF1Padding、
OAEPWITHSHA384AndMGF1Padding、
OAEPWITHSHA512AndMGF1Padding

下面是代码实现:

package key.base64;

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

import javax.crypto.Cipher;

public class RSAUtil {
    private static final String PUBLIC_KEY="publicKey";
    private static final String PRIVATE_KEY="privateKey";

    /**
     * 生成RSA的公钥和私钥
     */
    public static Map<String , Object> 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<String , Object> keyMap=new HashMap<String, Object>();
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;

    }

    public static RSAPublicKey getPublicKey(Map<String, Object> keyMap) {
        RSAPublicKey publicKey=(RSAPublicKey) keyMap.get(PUBLIC_KEY);
        return publicKey;
    }

    public static RSAPrivateKey getPrivateKey(Map<String, Object> keyMap) {
        RSAPrivateKey privateKey=(RSAPrivateKey) keyMap.get(PRIVATE_KEY);
        return privateKey;
    }

    /**
     * 公钥加密
     */
    public static byte[] encrypt(byte[] data,RSAPublicKey publicKey) throws Exception{
        Cipher cipher=Cipher.getInstance("RSA") ;
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] cipherBytes=cipher.doFinal(data);
        return cipherBytes;
    }

    /**
     * 私钥解密
     */
    public static byte[]  decrypt(byte[] data,RSAPrivateKey privateKey) throws Exception {
        Cipher cipher=Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] plainBytes=cipher.doFinal(data);
        return plainBytes;
    }

    //Test
    public static void main(String[] args){
        //Test RSA
        Map<String , Object> keyMap=RSAUtil.initKey();
        RSAPublicKey rsaPublicKey=RSAUtil.getPublicKey(keyMap);
        RSAPrivateKey rsaPrivateKey=RSAUtil.getPrivateKey(keyMap);
        System.out.println("RSA PublicKey:"+rsaPublicKey);
        System.out.println("RSA PrivateKey:"+rsaPrivateKey);

        byte[] rsaResult=RSAUtil.encrypt(DATA.getBytes(), rsaPublicKey);
        System.out.println(DATA+">>>RSA加密>>>"+BytesToHex.fromBytesToHex(rsaResult));

        byte[] plainResult=RSAUtil.decrypt(rsaResult, rsaPrivateKey);
        System.out.println(DATA+">>>RSA 解密>>>"+new String(plainResult));
    }
}

BytesToHex 类:

package key.base64;
public class BytesToHex {

    public static String fromBytesToHex(byte[] resultBytes) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < resultBytes.length; i++) {
            if (Integer.toHexString(0xFF & resultBytes[i]).length() == 1) {
                builder.append("0").append(
                        Integer.toHexString(0xFF & resultBytes[i]));
            } else {
                builder.append(Integer.toHexString(0xFF & resultBytes[i]));
            }
        }
        return builder.toString();
    }

}

“`

猜你喜欢

转载自blog.csdn.net/dongfangjunqi/article/details/50810490