RSA簽名和驗籤 Demo

RSA

RSA是一種非對稱加密的算法,是很早之前就出來的,聽說是法國的發明。

算法的核心思想是:加解密  、 驗籤

加解密是爲了數據傳遞的安全性,驗籤是爲了數據傳遞過程中防止被篡改

1、加解密

說明:加解密

-------------私鑰加密,公鑰解密;      公鑰加密,私鑰解密;---------------

解釋:RSA算法,會生成一對密鑰,包括私鑰和公鑰;私鑰和公鑰一般甲方和乙方只保留一個,甲方擁有公鑰,乙方就持有私鑰,  反之亦然。

具體實現過程:設:甲方持有私鑰,乙方持有公鑰。

甲方先將數據用私鑰加密之後,通過互聯網傳送給乙方。(加密後的數據一般是base64格式)。乙方收到數據後,用公鑰解密,得到想要的數據。。乙方得到數據後,經過處理,把處理後的數據經過公鑰加密,通過互聯網傳遞給甲方,甲方用私鑰解密,得到數據。。這樣,就實現了數據傳遞的安全性,因爲即便黑客得到的傳遞的數據,也不過是加密的數據,沒有解密的密鑰,是得不到有用的數據的。但是問題來了:

              黑客得不到數據,氣急敗壞,將錯誤的數據發送給甲方或者乙方,怎麼辦,甲方或者乙方還以爲是正常的數據,正常處理了,這樣不是導致數據錯誤了嗎?

 這時候,驗籤功能很好的解決了這個問題

2、簽名 、驗證簽名

說明:驗籤

-----------私鑰簽名,公鑰驗籤;   公鑰簽名,私鑰驗籤  -------------------------

解釋:簽名和驗證簽名 通俗易懂,就是驗證傳過來的數據是不是原始的,沒有被改動過的。。具體的原理不懂,實現還是明白的

具體實現:設:甲方持有私鑰,乙方持有公鑰

甲方通過 (私鑰 + 原始數據 ) 得到 簽名 sign , 之後,把 加密數據 、sign 發送給乙方。。。乙方收到之後,解密數據之後,得到原始數據,通過(公鑰 + 原始數據 + sign) 判斷數據是否被改動過。

true 表示驗籤通過 ,false 表示失敗

3、code

(1)簽名和驗籤

package com.zd.test;


import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
 
public class JavaMD5RSASign {
	
	private static String src = "i look";
	
	public static void main(String[] args) {
		MD5RSASign();
	}
	
	
	
	
	
	public static void MD5RSASign(){
		
		try {
			
			// 生成一對密鑰
			KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");  //獲取密鑰生成器實例
			keyPairGenerator.initialize(512);  // 初始化長度
			KeyPair keyPair = keyPairGenerator.generateKeyPair();  
			RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();//生成公鑰
			RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();  // 生成私鑰
			
			//用私鑰進行簽名
			PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());  //私鑰轉換成pkcs8格式
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); // 用key工廠對象生成私鑰
			Signature signature = Signature.getInstance("MD5withRSA");  //  md5 RSA簽名對象
			signature.initSign(privateKey);  //初始化簽名
			signature.update(src.getBytes());
			byte[] result = signature.sign();  //對消息進行簽名
			System.out.println("簽名結果:"+result);
			
			
			//用公鑰進行驗證
			X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
			PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
			signature.initVerify(publicKey);
			signature.update(src.getBytes());
			boolean verify = signature.verify(result);
			System.out.println("驗證結果:"+verify);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

(2)RSAUtil.java  工具類

package com.zd.util;

import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by huangxp on 2017/8/15 0015.
 */

import javax.crypto.Cipher;


public class RsaUtil {
    /**
     * 定義加密方式
     */
    private final static String KEY_RSA = "RSA";

    public static final String ECB_PKCS1_PADDING = "RSA/ECB/PKCS1Padding";//加密填充方式
    /**
     * 定義簽名算法
     */
    private final static String KEY_RSA_SIGNATURE = "MD5withRSA";
    /**
     * 定義公鑰算法
     */
    private final static String KEY_RSA_PUBLICKEY = "RSAPublicKey";
    /**
     * 定義私鑰算法
     */
    private final static String KEY_RSA_PRIVATEKEY = "RSAPrivateKey";

    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;


    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK_256 = 256;

    private RsaUtil() {
    }

    /**
     * 創建密鑰
     *
     * @return
     */
    public static Map<String, Object> generateKey() {
        Map<String, Object> map = null;
        try {
            KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_RSA);
            generator.initialize(1024);
            KeyPair keyPair = generator.generateKeyPair();
            // 公鑰
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            // 私鑰
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
            // 將密鑰封裝爲map
            map = new HashMap<String, Object>();
            map.put(KEY_RSA_PUBLICKEY, publicKey);
            map.put(KEY_RSA_PRIVATEKEY, privateKey);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
        return map;
    }

    /**
     * 用私鑰對信息生成數字簽名
     *
     * @param data       加密數據
     * @param privateKey 私鑰
     * @return
     */
    public static String sign(String privateKey, byte[] data) {
        String str = "";
        try {
            // 解密由base64編碼的私鑰
            byte[] bytes = decryptBase64(privateKey);
            // 構造PKCS8EncodedKeySpec對象
            PKCS8EncodedKeySpec pkcs = new PKCS8EncodedKeySpec(bytes);
            // 指定的加密算法
            KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
            // 取私鑰對象
            PrivateKey key = factory.generatePrivate(pkcs);
            // 用私鑰對信息生成數字簽名
            Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
            signature.initSign(key);
            signature.update(data);
            str = encryptBase64(signature.sign());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return str;
    }


    /**
     * 用私鑰對信息生成數字簽名
     *
     * @param privateKey
     * @param dataStr
     * @return
     */
    public static String sign(String privateKey, String dataStr) {
        String str = "";
        try {
            byte[] data = dataStr.getBytes("UTF-8");
            return sign(privateKey, data);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public static String signPublicKey(String publicKey, String dataStr) {
        String str = "";
        try {
            byte[] data = dataStr.getBytes("UTF-8");
            return signPublicKey(publicKey, data);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 用私鑰對信息生成數字簽名
     *
     * @param data       加密數據
     * @param publicKey 私鑰
     * @return
     */
    public static String signPublicKey(String publicKey, byte[] data) {
        String str = "";
        try {

            // 對公鑰解密
            byte[] bytes = decryptBase64(publicKey);
            // 取得公鑰
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
            KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
            PublicKey key = factory.generatePublic(keySpec);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return str;
    }
    /**
     * 校驗數字簽名
     *
     * @param data      加密數據
     * @param publicKey 公鑰
     * @param sign      數字簽名
     * @return 校驗成功返回true,失敗返回false
     */
    public static boolean verify(String publicKey, byte[] data, String sign) {
        boolean flag = false;
        try {
            // 解密由base64編碼的公鑰
            byte[] bytes = decryptBase64(publicKey);
            // 構造X509EncodedKeySpec對象
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
            // 指定的加密算法
            KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
            // 取公鑰對象
            PublicKey key = factory.generatePublic(keySpec);
            // 用公鑰驗證數字簽名
            Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
            signature.initVerify(key);
            signature.update(data);
            flag = signature.verify(decryptBase64(sign));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return flag;
    }


    public static boolean verify(String publicKey, String dataStr, String sign) {

        try {
            byte[] data = dataStr.getBytes("UTF-8");
            return verify(publicKey, data, sign);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 公鑰加密
     *
     * @param key  公鑰
     * @param data 待加密數據
     * @return
     */
    public static byte[] encryptByPublicKey(String key, byte[] data) {
        byte[] result = null;
        try {
            // 獲取公鑰字符串時,進行了encryptBase64操作,因此此處需對公鑰鑰解密
            byte[] bytes = decryptBase64(key);
            // 取得公鑰
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
            KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
            PublicKey publicKey = factory.generatePublic(keySpec);
            // 對數據加密
            Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            int inputLen = data.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 對數據分段加密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }
            byte[] encryptedData = out.toByteArray();
            out.close();
            return encryptedData;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static String encryptByPublicKey(String key, String dataStr) {
        try {
            byte[] result = encryptByPublicKey(key, dataStr.getBytes("UTF-8"));
            return encryptBase64(result);

        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }


    /**
     * 私鑰解密
     *
     * @param data 加密數據
     * @param key  私鑰
     * @return
     */
    public static byte[] decryptByPrivateKey(String key, byte[] data,int maxDecryptBlock) {
        byte[] result = null;
        try {
            // 獲取私鑰字符串時,進行了encryptBase64操作,因此此處需對私鑰解密
            byte[] bytes = decryptBase64(key);
            // 取得私鑰
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
            KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
            PrivateKey privateKey = factory.generatePrivate(keySpec);
            // 對數據解密
            Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);

            int inputLen = data.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 對數據分段解密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > maxDecryptBlock) {
                    cache = cipher
                            .doFinal(data, offSet, maxDecryptBlock);
                } else {
                    cache = cipher
                            .doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * maxDecryptBlock;
            }
            byte[] decryptedData = out.toByteArray();
            out.close();
            return decryptedData;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    public static String decryptByPrivateKey256(String key, String dataStr) {
        try {
            byte[] result = decryptByPrivateKey(key, decryptBase64(dataStr),MAX_DECRYPT_BLOCK_256);
            return new String(result);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    public static String decryptByPrivateKey(String key, String dataStr) {
        try {
            byte[] result = decryptByPrivateKey(key, decryptBase64(dataStr),MAX_DECRYPT_BLOCK);
            return new String(result);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * 私鑰加密
     *
     * @param data 待加密數據
     * @param key  私鑰
     * @return
     */
    public static byte[] encryptByPrivateKey(String key, byte[] data) {
        byte[] result = null;
        try {
            byte[] bytes = decryptBase64(key);
            // 取得私鑰
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
            KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
            PrivateKey privateKey = factory.generatePrivate(keySpec);
            // 對數據加密
            Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);

            int inputLen = data.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 對數據分段加密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }
            byte[] encryptedData = out.toByteArray();
            out.close();
            return encryptedData;

        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    public static String encryptByPrivateKey(String key, String dataStr) {
        try {
            byte[] result = encryptByPrivateKey(key, dataStr.getBytes("UTF-8"));
            return encryptBase64(result).replace("\n","");
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * 公鑰鑰解密
     *
     * @param key  公鑰
     * @param data 加密數據
     * @return
     */
    public static byte[] decryptByPublicKey(String key, byte[] data) {
        byte[] result = null;
        try {
            // 對公鑰解密
            byte[] bytes = decryptBase64(key);
            // 取得公鑰
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
            KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
            PublicKey publicKey = factory.generatePublic(keySpec);
            // 對數據解密
            Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, publicKey);

            int inputLen = data.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 對數據分段解密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                    cache = cipher
                            .doFinal(data, offSet, MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher
                            .doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_DECRYPT_BLOCK;
            }
            byte[] decryptedData = out.toByteArray();
            out.close();
            return decryptedData;
            //result = cipher.doFinal(data);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        // return result;
    }

    public static String decryptByPublicKey(String key, String dataStr) {
        try {
            byte[] result = decryptByPublicKey(key, decryptBase64(dataStr));
            return new String(result,"UTF-8");
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * 獲取公鑰
     *
     * @param map
     * @return
     */
    public static String getPublicKey(Map<String, Object> map) {
        String str = "";
        try {
            Key key = (Key) map.get(KEY_RSA_PUBLICKEY);
            str = encryptBase64(key.getEncoded());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return str;
    }

    /**
     * 獲取私鑰
     *
     * @param map
     * @return
     */
    public static String getPrivateKey(Map<String, Object> map) {
        String str = "";
        try {
            Key key = (Key) map.get(KEY_RSA_PRIVATEKEY);
            str = encryptBase64(key.getEncoded());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return str;
    }

    /**
     * BASE64 解密
     *
     * @param key 需要解密的字符串
     * @return 字節數組
     * @throws Exception
     */
    public static byte[] decryptBase64(String key) {
        //  return javax.xml.bind.DatatypeConverter.parseBase64Binary(key);
//        return Base64.decode(key, Base64.DEFAULT);
    	return Base64.getDecoder().decode(key);

    }

    /**
     * BASE64 加密
     *
     * @param key 需要加密的字節數組
     * @return 字符串
     * @throws Exception
     */
    public static String encryptBase64(byte[] key) {
    	
        return Base64.getEncoder().encodeToString(key);
    }

}

 總結:數據如果敏感,建議使用RSA加密,比較安全。。設置初始的字節爲1024很安全,聽說一般人破解不了。2048,賊安全

送給自己:人總要有點理想,就算沒有用,起碼算個信仰,這個信仰在一些時候總會莫名其妙的給你一股力量。堅持你走完最難的路。。即便感動不了別人,也能感動自己。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章