RSA非对称加密、签名校验

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xybelieve1990/article/details/83088697

加密举例

比如有两个用户Alice和Bob,Alice想把一段明文通过双钥加密的技术发送给Bob,Bob有一对公钥和私钥,那么加密解密的过程如下:

  1. Bob将他的公开密钥传送给Alice。
  2. Alice用Bob的公开密钥加密她的消息,然后传送给Bob。
  3. Bob用他的私人密钥解密Alice的消息。

  上面的过程可以用下图表示,Alice使用Bob的公钥进行加密,Bob用自己的私钥进行解密。

例子和图出自《网络安全基础 应用与标准第二版》

RSA算法

RSA公钥加密算法是1977年由Ron Rivest、Adi Shamirh和LenAdleman在(美国麻省理工学院)开发的。RSA取名来自开发他们三者的名字。RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的所有密码攻击,已被ISO推荐为公钥数据加密标准。RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

编码实现

package encrypt;

import org.apache.tomcat.util.codec.binary.Base64;

import javax.crypto.Cipher;
import java.io.*;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * RSA加解密及签名校验
 * RSA签名算法:MD2withRSA、MD5withRSA、SHA1withRSA,为jdk实现
 * 1.秘钥长度为64的倍数,在512~65536之间,默认长度1024,签名长度和秘钥长度相同
 * 签名算法:SHA256withRSA,为BC实现,秘钥默认长度为2048
 */
public class RsaSecurity {

    //非对称加密算法
    public static final String KEY_ALGORITHM = "RSA";
    //签名算法
    public static final String SIGN_ALGORITHM = "SHA256withRSA";
    /**
     * 秘钥长度,必须是64的倍数,在512~65536之间
     */
    private static final int KEY_SIZE = 512;
    //公钥
    private static final String PUBLIC_KEY = "PUBLIC_KEY";
    //私钥
    private static final String PRIVATE_KEY = "PRIVATE_KEY";

    private static final String PUBLIC_PATH = "/Users/public.key";

    private static final String PRIVATE_PATH = "/Users/private.key";

    public static void main(String[] args) throws Exception{
        /**
         * 加解密验证
         */
        //初始化秘钥对
        Map<String, Object> keyMap = RsaSecurity.initKey();
        //私钥
        byte[] privateKey = RsaSecurity.getPrivateKey(keyMap);
        //公钥
        byte[] publicKey = RsaSecurity.getPublicKey(keyMap);
        System.out.println("私钥:" + Base64.encodeBase64String(privateKey));
        System.out.println("公钥:" + Base64.encodeBase64String(publicKey));

        String source = "Burning by Maria Arredondo";
        byte[] encryptData = RsaSecurity.encryptByPrivateKey(source.getBytes(), privateKey);
        System.out.println("私钥加密后数据:" + new String(encryptData));
        byte[] decryptData = RsaSecurity.decryptByPublicKey(encryptData, publicKey);
        System.out.println("公钥解密后数据:" + new String(decryptData));

        /**
         * 签名验证
         */
        String privateKeyStr = readKeyFromFile(PRIVATE_PATH);
        String publicKeyStr = readKeyFromFile(PUBLIC_PATH);

        String signSource = "Love Mail";
        String sign = signByPrivateKey(signSource, privateKeyStr);
        System.out.println("私钥签名值:" + sign);
        System.out.println("公钥签名校验结果:" + verifySignByPublic(signSource, publicKeyStr, sign));
    }

    /**
     * 初始化秘钥对
     * @return 秘钥map
     * @throws Exception
     */
    public static Map<String, Object> initKey() throws Exception{
        //实例化秘钥生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        //初始化秘钥生成器
        keyPairGenerator.initialize(KEY_SIZE);
        //生成秘钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        //公钥
        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
        //私钥
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();

        //保存公钥
        RsaSecurity.saveKeyForFile(PUBLIC_PATH, Base64.encodeBase64String(rsaPublicKey.getEncoded()));
        //保存私钥
        RsaSecurity.saveKeyForFile(PRIVATE_PATH, Base64.encodeBase64String(rsaPrivateKey.getEncoded()));

        //将秘钥存储在map中
        Map<String, Object> keyMap = new HashMap<>();
        keyMap.put(PUBLIC_KEY, rsaPublicKey);
        keyMap.put(PRIVATE_KEY, rsaPrivateKey);
        return keyMap;
    }

    /**
     * 私钥加密
     * @param data 待加密数据
     * @param key 秘钥
     * @return byte[] 加密数据
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception{
        //取得私钥
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key);
        //实例化秘钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        //私钥加密数据
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }


    /**
     * 公钥解密
     * @param data 待解密数据
     * @param key 秘钥
     * @return byte[] 解密数据
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] data, byte[] key) throws Exception{
        //取得公钥(材料转换)
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key);
        //实例化秘钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //生成公钥
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

        //解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }

    /**
     * 私钥签名
     * @param content 待签名数据
     * @param rsaPrivateKey 签名秘钥
     * @return 签名值
     * @throws Exception
     */
    public static String signByPrivateKey(String content, String rsaPrivateKey) throws Exception{
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(rsaPrivateKey));
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //获取秘钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        //实例化签名
        Signature signature = Signature.getInstance(SIGN_ALGORITHM);
        //初始化签名
        signature.initSign(privateKey);
        signature.update(content.getBytes());
        byte[] sign = signature.sign();
        return Base64.encodeBase64String(sign);

    }

    /**
     * 公钥验签
     * @param content 报文数据
     * @param rsaPublicKey 签名秘钥
     * @param sign 签名值
     * @return 验签是否通过
     * @throws Exception
     */
    public static boolean verifySignByPublic(String content, String rsaPublicKey, String sign) throws Exception{
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(rsaPublicKey));
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //获取公钥
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        //实例化签名
        Signature signature = Signature.getInstance(SIGN_ALGORITHM);
        //初始化验签
        signature.initVerify(publicKey);
        signature.update(content.getBytes());
        return signature.verify(Base64.decodeBase64(sign));

    }

    /**
     * 获取公钥
     * @param keyMap
     * @return
     */
    public static byte[] getPublicKey(Map<String, Object> keyMap){
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        return key.getEncoded();
    }

    /**
     * 获取私钥
     * @param keyMap
     * @return
     */
    public static byte[] getPrivateKey(Map<String, Object> keyMap){
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        return key.getEncoded();
    }

    /**
     * 生成文件保存秘钥
     * @param filePath
     * @param keyStr
     */
    public static void saveKeyForFile(String filePath, String keyStr){
        try{
            File file = new File(filePath);
            if(!file.exists()){
                file.mkdir();
            }
            BufferedWriter bw = new BufferedWriter(new FileWriter(file));
            bw.write(keyStr);
            bw.flush();
            bw.close();
        }catch(IOException e){
            e.printStackTrace();
        }
    }

    /**
     * 从文件中读取秘钥
     * @param filePath
     * @return
     */
    public static String readKeyFromFile(String filePath){
        try {
            BufferedReader br = new BufferedReader(new FileReader(new File(filePath)));
            String readLine = null;
            StringBuilder sb = new StringBuilder();
            while((readLine=br.readLine()) != null){
                sb.append(readLine);
            }
            br.close();
            return sb.toString();
        }catch (IOException e){
            e.printStackTrace();
        }
        return null;
    }


}

猜你喜欢

转载自blog.csdn.net/xybelieve1990/article/details/83088697