數據安全管理:RSA加密算法,簽名驗籤流程詳解

本文源碼:GitHub·點這裏 || GitEE·點這裏java

1、RSA算法簡介

一、加密解密

RSA加密是一種非對稱加密,在公開密鑰加密和電子商業中RSA被普遍使用。能夠在不直接傳遞密鑰的狀況下,完成加解密操做。這可以確保信息的安全性,避免了直接傳遞密鑰所形成的被破解的風險。是由一對密鑰來進行加解密的過程,分別稱爲公鑰和私鑰。該加密算法的原理就是對一極大整數作因數分解的困難性來保證安全性。

二、簽名驗籤

數字簽名就是信息的來源添加一段沒法被僞造的加密字符串,這段數字串做爲對信息的來源真實性的一個有效證實。這個過程稱爲簽名和驗籤。

2、場景描述

  • 消息發送方:甲方,持有公鑰
  • 消息接收方:乙方,持有私鑰

一、加密解密過程

(1)、乙方生成一對密鑰即公鑰和私鑰,私鑰不公開,乙方本身持有,公鑰爲公開,甲方持有。git

(2)、乙方收到甲方加密的消息,使用私鑰對消息進行解密,獲取明文。github

二、簽名驗簽過程

(1)、乙方收到消息後,須要回覆甲方,用私鑰對回覆消息簽名,並將消息明文和消息簽名回覆甲方。算法

(2)、甲方收到消息後,使用公鑰進行驗籤,若是驗簽結果是正確的,則證實消息是乙方回覆的。segmentfault

3、源代碼實現

一、密鑰字符串獲取

  • 代碼生成
private static HashMap<String, String> getTheKeys() {
    HashMap<String, String> keyPairMap = new HashMap<String, String>();
    KeyPairGenerator keyPairGen = null;
    try {
        keyPairGen = KeyPairGenerator.getInstance("RSA");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    // 密鑰大小:1024 位
    keyPairGen.initialize(1024);
    KeyPair keyPair = keyPairGen.generateKeyPair();
    String publicKey = printBase64Binary(keyPair.getPublic().getEncoded());
    String privateKey = printBase64Binary(keyPair.getPrivate().getEncoded());
    keyPairMap.put("publicKey", publicKey);
    keyPairMap.put("privateKey", privateKey);
    return keyPairMap ;
}
  • 讀取文件

01-1.png

文件位置數組

public static final String PUB_KEY = "rsaKey/public.key" ;
public static final String PRI_KEY = "rsaKey/private.key" ;

文件加載安全

public static String getKey (String keyPlace) throws Exception {
    BufferedReader br= null;
    try {
        br= new BufferedReader(new InputStreamReader(RsaCryptUtil.class.getClassLoader().
                                                     getResourceAsStream(keyPlace)));
        String readLine= null;
        StringBuilder keyValue = new StringBuilder();
        while((readLine= br.readLine())!=null){
            if(!(readLine.charAt(0)=='-')){
                keyValue.append(readLine);
            }
        }
        return keyValue.toString();
    } catch (Exception e) {
        throw new Exception("RSA密鑰讀取錯誤",e) ;
    } finally{
        if (br != null) {
            try {
                br.close();
            } catch (Exception e) {
                System.out.println("密鑰讀取流關閉異常");
            }
        }
    }
}

二、公鑰和私鑰

  • 公鑰字符串生成公鑰
public static RSAPublicKey createPublicKey(String publicKeyValue) throws Exception {
    try {
        byte[] buffer = DatatypeConverter.parseBase64Binary(publicKeyValue);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
        return (RSAPublicKey) keyFactory.generatePublic(keySpec);
    } catch (Exception e) {
        throw new Exception("公鑰建立失敗", e);
    }
}
  • 私鑰字符串生成私鑰
public static RSAPrivateKey createPrivateKey(String privateKeyValue) throws Exception {
    try {
        byte[] buffer = javax.xml.bind.DatatypeConverter.parseBase64Binary(privateKeyValue);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
    } catch (Exception e) {
        throw new Exception("私鑰建立失敗", e);
    }
}

三、加密和解密

  • 公鑰加密
public static String encrypt(RSAPublicKey publicKey, byte[] clearData) throws Exception {
    if (publicKey == null) {
        throw new Exception("加密公鑰爲空, 沒法加密");
    }
    try {
        Cipher cipher = Cipher.getInstance("RSA") ;
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] output = cipher.doFinal(clearData);
        return printBase64Binary(output);
    } catch (Exception e) {
        throw new Exception("公鑰加密失敗",e);
    }
}
  • 私鑰解密
public static String decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception {
    if (privateKey == null) {
        throw new Exception("解密私鑰爲空, 沒法解密");
    }
    try {
        Cipher cipher = Cipher.getInstance("RSA") ;
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] output = cipher.doFinal(cipherData);
        return new String(output);
    } catch (BadPaddingException e) {
        throw new Exception("私鑰解密失敗",e);
    }
}

四、簽名和驗籤

  • 私鑰簽名
public static String sign (String signData, PrivateKey privateKey) throws Exception {
    byte[] keyBytes = privateKey.getEncoded();
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PrivateKey key = keyFactory.generatePrivate(keySpec);
    Signature signature = Signature.getInstance("MD5withRSA");
    signature.initSign(key);
    signature.update(signData.getBytes());
    return printBase64Binary(signature.sign());
}
  • 公鑰驗籤
public static boolean verify(String srcData, PublicKey publicKey, String sign) throws Exception {
    byte[] keyBytes = publicKey.getEncoded();
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PublicKey key = keyFactory.generatePublic(keySpec);
    Signature signature = Signature.getInstance("MD5withRSA");
    signature.initVerify(key);
    signature.update(srcData.getBytes());
    return signature.verify(parseBase64Binary(sign));
}

五、編碼和解碼

/**
 * 字節數組轉字符
 */
public static String printBase64Binary(byte[] bytes) {
    return DatatypeConverter.printBase64Binary(bytes);
}
/**
 * 字符轉字節數組
 */
public static byte[] parseBase64Binary(String value) {
    return DatatypeConverter.parseBase64Binary(value);
}

六、測試代碼塊

  • 密鑰生成測試
public static void testCreateKey () throws Exception {
    HashMap<String, String> map = RsaCryptUtil.getTheKeys();
    String privateKeyStr=map.get("privateKey");
    String publicKeyStr=map.get("publicKey");
    System.out.println("私鑰:"+privateKeyStr);
    System.out.println("公鑰:"+publicKeyStr);
    //消息發送方
    String originData="cicada-smile";
    System.out.println("原文:"+originData);
    String encryptData = RsaCryptUtil.encrypt(RsaCryptUtil.createPublicKey(publicKeyStr),
                                              originData.getBytes());
    System.out.println("加密:"+encryptData);
    //消息接收方
    String decryptData=RsaCryptUtil.decrypt(RsaCryptUtil.createPrivateKey(privateKeyStr),
                                            RsaCryptUtil.parseBase64Binary(encryptData));
    System.out.println("解密:"+decryptData);
}
  • 密鑰讀取測試
public static void testReadKey () throws Exception {
    String value = getKey("rsaKey/public.key");
    System.out.println(value);
    String privateKeyStr = getKey(RsaCryptUtil.PRI_KEY) ;
    String publicKeyStr = getKey(RsaCryptUtil.PUB_KEY) ;
    //消息發送方
    String originData="cicada-smile";
    System.out.println("原文:"+originData);
    String encryptData = RsaCryptUtil.encrypt(RsaCryptUtil.createPublicKey(publicKeyStr),
                                              originData.getBytes());
    System.out.println("加密:"+encryptData);
    //消息接收方
    String decryptData=RsaCryptUtil.decrypt(RsaCryptUtil.createPrivateKey(privateKeyStr),
                                            RsaCryptUtil.parseBase64Binary(encryptData));
    System.out.println("解密:"+decryptData);
}
  • 簽名驗籤測試
public static void testSignVerify () throws Exception {
    String signData = "cicada-smile" ;
    String privateKeyStr = getKey(RsaCryptUtil.PRI_KEY) ;
    String publicKeyStr = getKey(RsaCryptUtil.PUB_KEY) ;
    String signValue = sign(signData,RsaCryptUtil.createPrivateKey(privateKeyStr)) ;
    boolean flag = verify(signData,RsaCryptUtil.createPublicKey(publicKeyStr),signValue);
    System.out.println("原文:"+signData);
    System.out.println("簽名:"+signValue);
    System.out.println("驗籤:"+flag);
}

4、源代碼地址

GitHub·地址
https://github.com/cicadasmile
GitEE·地址
https://gitee.com/cicadasmile

相關文章
相關標籤/搜索