zoukankan      html  css  js  c++  java
  • 【Java】聊聊常用的非对称加密算法之一RSA的使用(Java)

    参考的优秀文章

    Java加密技术(四)——非对称加密算法RSA

    RSA算法原理(一)RSA算法原理(二)

    RSA的公钥和私钥到底哪个才是用来加密和哪个用来解密?

    简单的介绍

    RSA是有名的非对称加密算法。

     

    RSA有两个密钥,一个是公开的,称为公开密钥;一个是私密的,称为私密密钥。

    特点:

    • 公开密钥是对大众公开的,私密密钥是服务器私有的,两者不能互推得出。
    • 用公开密钥对数据进行加密,私密密钥可解密;私密密钥对数据加密,公开密钥可解密。
    • 速度较对称加密慢。

    RSA是一个支持加密、签名的算法。

    加密:

    一般来说,我们通过公开密钥对信息加密,然后发送给服务端,服务端再用私密密钥解密,获取保密的信息。(而RSA中通过私密密钥加密,然后通过公开密钥正确地解密获取信息,但这个过程对于加密来说没有意义,因为公开密钥是公开的,也就是说大家都可以解密。所以私密密钥加密、公开密钥解密用于签名功能)

    签名:

    签名的目的在于证明给大伙看这份信息是本人所发,并且发送过程中没被篡改。

    服务端对于将要发送的信息进行摘要操作(比如MD5),然后对其摘要值用私密密钥加密,形成签名值,将发送的信息与签名值发送出去。客户端收到信息和签名值后,用公开密钥将签名值解密,然后将信息进行摘要操作,再比对两者的摘要值,就可知该信息是否服务端所发,发送过程是否有篡改。

    疑问与解答 

    为什么叫RSA呢?

    答:看一下它的发明者们的名字就知道了:Ron Rivest、Adi Shamir、Leonard Adleman。

    非对称加密算法是什么呢?

    答:比如,信息通过公开密钥加密,然后不能通过公开密钥解密,只能通过私密密钥去解密。同样的,信息通过私密密钥加密,只能由公开密钥解密。当然,公开密钥与私密密钥之间无法通过计算互推。

    RSA运用在哪里呢?

    答:比如HTTPS。

    简单的RSA使用演示

    import sun.misc.BASE64Decoder;
    import sun.misc.BASE64Encoder;
    
    public class Base64Util {
        
        /**
         * Base64加密
         */
        public static String encryptBASE64(byte[] key) throws Exception {
            return (new BASE64Encoder()).encodeBuffer(key);
        }
    
        /**
         * Base64解密
         */
        public static byte[] decryptBASE64(String key) throws Exception {
            return (new BASE64Decoder()).decodeBuffer(key);
        }
    
    }
    View Code
    import java.security.Key;
    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;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.crypto.Cipher;
    
    public class RSAUtil {
        public static final String ENCRYPTION_ALGORITHM = "RSA";
        public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
    
        /**
         * 生成密钥
         */
        public static Map<String, Object> initKey() throws Exception {
            /* 初始化密钥生成器 */
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ENCRYPTION_ALGORITHM);
            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>(2);
            keyMap.put("PublicKey", publicKey);
            keyMap.put("PrivateKey", privateKey);
            return keyMap;
        }
        
        /**
         * 取得公钥
         */
        public static String getPublicKey(Map<String, Object> keyMap)
                throws Exception {
            Key key = (Key) keyMap.get("PublicKey");
            return Base64Util.encryptBASE64(key.getEncoded());
        }
        
        /**
         * 取得私钥
         */
        public static String getPrivateKey(Map<String, Object> keyMap)
                throws Exception {
            Key key = (Key) keyMap.get("PrivateKey");
            return Base64Util.encryptBASE64(key.getEncoded());
        }
        
        /**
         * 加密
         */
        public static byte[] encrypt(byte[] data, String keyString, boolean isPublic) throws Exception {
            Map<String, Object> keyAndFactoryMap = RSAUtil.generateKeyAndFactory(keyString, isPublic);
            KeyFactory keyFactory = RSAUtil.getKeyFactory(keyAndFactoryMap);
            Key key = RSAUtil.getKey(keyAndFactoryMap);
            
            // 对数据加密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, key);
    
            return cipher.doFinal(data);
        }
        
        /**
         * 解密
         */
        public static byte[] decrypt(byte[] data, String keyString, boolean isPublic) throws Exception {
            Map<String, Object> keyAndFactoryMap = RSAUtil.generateKeyAndFactory(keyString, isPublic);
            KeyFactory keyFactory = RSAUtil.getKeyFactory(keyAndFactoryMap);
            Key key = RSAUtil.getKey(keyAndFactoryMap);
            
            // 对数据加密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, key);
    
            return cipher.doFinal(data);
        }
        
        /**
         * 生成钥匙
         */
        public static Map<String, Object> generateKeyAndFactory(String keyString, boolean isPublic) throws Exception {
            byte[] keyBytes = Base64Util.decryptBASE64(keyString);
            
            KeyFactory keyFactory = KeyFactory.getInstance(ENCRYPTION_ALGORITHM);
            Key key = null;
            if (isPublic) {
                X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
                key = keyFactory.generatePublic(x509KeySpec);
            } else {
                PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
                key = keyFactory.generatePrivate(pkcs8KeySpec);
            }
            
            Map<String, Object> keyAndFactoryMap = new HashMap<String, Object>(2);
            keyAndFactoryMap.put("key", key);
            keyAndFactoryMap.put("keyFactory", keyFactory);
            
            return keyAndFactoryMap;
        }
        
        /**
         * 从指定对象中获取钥匙
         */
        public static Key getKey(Map<String, Object> map) {
            if (map.get("key") == null) {
                return null;
            }
            return (Key)map.get("key");
        }
    
        /**
         * 从指定对象中获取钥匙工厂
         */
        public static KeyFactory getKeyFactory(Map<String, Object> map) {
            if (map.get("keyFactory") == null) {
                return null;
            }
            return (KeyFactory)map.get("keyFactory");
        }
        
        /**
         * 对信息生成数字签名(用私钥)
         */
        public static String sign(byte[] data, String keyString) throws Exception {
            Map<String, Object> keyAndFactoryMap = RSAUtil.generateKeyAndFactory(keyString, false);
            Key key = RSAUtil.getKey(keyAndFactoryMap);
            
            PrivateKey privateKey = (PrivateKey)key;
    
            // 用私钥对信息生成数字签名
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
            signature.initSign(privateKey);
            signature.update(data);
    
            return Base64Util.encryptBASE64(signature.sign());
        }
    
        /**
         * 校验数字签名(用公钥)
         */
        public static boolean verify(byte[] data, String keyString, String sign)
                throws Exception {
            Map<String, Object> keyAndFactoryMap = RSAUtil.generateKeyAndFactory(keyString, true);
            Key key = RSAUtil.getKey(keyAndFactoryMap);
            
            PublicKey publicKey = (PublicKey)key;
    
            // 取公钥匙对象
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
            signature.initVerify(publicKey);
            signature.update(data);
    
            // 验证签名是否正常
            return signature.verify(Base64Util.decryptBASE64(sign));
        }
    
    }
    View Code
    import static org.junit.Assert.*;
    
    import org.junit.Before;
    import org.junit.Test;
    
    import java.util.Map;
    
    public class HowToUse {
        private String publicKey = null;
        private String privateKey = null;
    
        @Before
        public void setUp() throws Exception {
            Map<String, Object> keyMap = RSAUtil.initKey();
            publicKey = RSAUtil.getPublicKey(keyMap);
            privateKey = RSAUtil.getPrivateKey(keyMap);
            
            System.out.println("公钥 -> " + publicKey);
            System.out.println("私钥 -> " + privateKey);
        }
        
        @Test
        public void test() throws Exception {
            System.out.println("公钥加密,私钥解密");
            String sourceString = "hi, RSA";
    
            byte[] encodedData = RSAUtil.encrypt(sourceString.getBytes(), publicKey, true);
            byte[] decodedData = RSAUtil.decrypt(encodedData, privateKey, false);
    
            String targetString = new String(decodedData);
            System.out.println("加密前: " + sourceString + ",解密后: " + targetString);
            assertEquals(sourceString, targetString);
        }
    
        @Test
        public void test2() throws Exception {
            System.out.println("私钥签名,公钥验证签名");
            String sourceString = "hello, RSA sign";
            byte[] data = sourceString.getBytes();
            
            // 产生签名
            String sign = RSAUtil.sign(data, privateKey);
            System.out.println("签名 -> " + sign);
    
            // 验证签名
            boolean status = RSAUtil.verify(data, publicKey, sign);
            System.out.println("状态 -> " + status);
            assertTrue(status);
        }
        
        @Test
        public void test3() throws Exception {
            System.out.println("私钥加密,公钥解密");
            String sourceString = "hello, reRSA";
            byte[] data = sourceString.getBytes();
    
            byte[] encodedData = RSAUtil.encrypt(data, privateKey, false);
            byte[] decodedData = RSAUtil.decrypt(encodedData, publicKey, true);
    
            String targetString = new String(decodedData);
            System.out.println("加密前: " + sourceString + ",解密后: " + targetString);
            assertEquals(sourceString, targetString);
        }
        
    }
    View Code
  • 相关阅读:
    走向变态的人生
    HDWIKI 4.0.2绿色版(含运行环境)(V1)
    centos7 安装python3.7.1
    一种高并发流控程序的简单轻量实现
    编写JDBC框架优化CRUD操作
    一段阻塞队列代码的纠错与优化
    一次请求在同一个事务实现
    创建Java内部类的编译错误处理
    C++模板简单分析与举例
    java.lang.OutOfMemoryError处理错误
  • 原文地址:https://www.cnblogs.com/nick-huang/p/5066574.html
Copyright © 2011-2022 走看看