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


    RSA 
        这样的算法1978年就出现了。它是第一个既能用于数据加密也能用于数字签名的算法。它易于理解和操作。也非常流行。算法的名字以发明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman。

     
        这样的加密算法的特点主要是密钥的变化,上文我们看到DES仅仅有一个密钥。相当于仅仅有一把钥匙。假设这把钥匙丢了,数据也就不安全了。RSA同一时候有两把钥匙,公钥与私钥。

    同一时候支持数字签名。

    数字签名的意义在于。对传输过来的数据进行校验。确保数据在传输project中不被改动。

    流程分析: 

    1. 甲方构建密钥对儿,将公钥发布给乙方,将私钥保留。
    2. 甲方使用私钥加密数据,然后用私钥对加密后的数据签名,发送给乙方签名以及加密后的数据。乙方使用公钥、签名来验证待解密数据是否有效,假设有效使用公钥对数据解密。
    3. 乙方使用公钥加密数据,向甲方发送经过加密后的数据。甲方获得加密数据,通过私钥解密。
    按如上步骤给出序列图,例如以下: 





    通过java代码实现例如以下:

    package com.somnus.cipher;
    
    import java.io.InputStream;
    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.Arrays;
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.crypto.Cipher;
    
    import org.apache.commons.codec.binary.Base64;
    import org.apache.commons.codec.binary.Hex;
    
    /** 非对称加密算法RSA
     * @Title: RsaEncrypt.java 
     * @Description: TODO
     * @author Somnus
     * @date 2015年6月5日 下午2:02:44 
     * @version V1.0 
     */
    public class RSAUtil {
        public static final String ALGORITHM = "RSA";  
        public static final String SIGNATURE_ALGORITHM = "MD5withRSA";  
      
        private static final String PUBLIC_KEY = "RSAPublicKey";  
        private static final String PRIVATE_KEY = "RSAPrivateKey";  
        
        private static final String PUBLIC_KEY_PATH = "public.cer";
        private static final String PRIVATE_KEY_PATH = "private.key";
        
        /** 
         * 用私钥对信息生成数字签名 
         *  
         * @param data 
         *            加密数据 
         * @param privateKey 
         *            私钥 
         * @return 
         * @throws Exception 
         */  
        public static String sign(String data) throws Exception { 
            // 解密由base64编码的私钥  
            byte[] keyBytes = Base64.decodeBase64(getPrivateKey());
            // 构造PKCS8EncodedKeySpec对象  
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);  
            // ALGORITHM 指定的加密算法  
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);  
            // 取私钥匙对象  
            PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);  
            // 用私钥对信息生成数字签名  
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);  
            signature.initSign(priKey);  
            signature.update(Hex.decodeHex(data.toCharArray()));  
            return Base64.encodeBase64String(signature.sign());
        }  
      
        /** 
         * 校验数字签名 
         *  
         * @param data 
         *            加密数据 
         * @param publicKey 
         *            公钥 
         * @param sign 
         *            数字签名 
         *  
         * @return 校验成功返回true 失败返回false 
         * @throws Exception 
         *  
         */  
        public static boolean verify(String data,String sign)throws Exception {  
            // 解密由base64编码的公钥  
            byte[] keyBytes = Base64.decodeBase64(getPublicKey());
            // 构造X509EncodedKeySpec对象  
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);  
            // ALGORITHM 指定的加密算法  
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);  
            // 取公钥匙对象  
            PublicKey pubKey = keyFactory.generatePublic(keySpec);  
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);  
            signature.initVerify(pubKey);  
            signature.update(Hex.decodeHex(data.toCharArray()));  
            // 验证签名是否正常  
            return signature.verify(Base64.decodeBase64(sign));  
        }  
      
        /** 
         * 解密<br> 
         * 用私钥解密 
         *  
         * @param data 
         * @return 
         * @throws Exception 
         */  
        public static String decryptByPrivateKey(String data)throws Exception {  
            // 对密钥解密  
            byte[] keyBytes = Base64.decodeBase64(getPrivateKey());
            // 取得私钥  
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);  
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);  
            Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);  
            //初始化Cipher对象,设置为解密模式
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());  
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            // 运行解密操作
            byte[] buff = cipher.doFinal(Hex.decodeHex(data.toCharArray()));
            System.out.println(Arrays.toString(buff));
            return new String(buff);
        }  
      
        /** 
         * 解密<br> 
         * 用公钥解密 
         *  
         * @param data 
         * @return 
         * @throws Exception 
         */  
        public static String decryptByPublicKey(String data)throws Exception {  
            // 对密钥解密  
            byte[] keyBytes = Base64.decodeBase64(getPublicKey()); 
            // 取得公钥  
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);  
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);  
            Key publicKey = keyFactory.generatePublic(x509KeySpec);  
            //初始化Cipher对象,设置为解密模式
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());  
            cipher.init(Cipher.DECRYPT_MODE, publicKey);  
            // 运行解密操作
            byte[] buff = cipher.doFinal(Hex.decodeHex(data.toCharArray()));
            System.out.println(Arrays.toString(buff));
            return new String(buff); 
        }  
      
        /** 
         * 加密<br> 
         * 用公钥加密 
         *  
         * @param data 
         * @return 
         * @throws Exception 
         */  
        public static String encryptByPublicKey(String data)throws Exception {  
            // 对公钥解密  
            byte[] keyBytes = Base64.decodeBase64(getPublicKey());
            // 取得公钥  
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);  
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);  
            Key publicKey = keyFactory.generatePublic(x509KeySpec);  
            // 实例化Cipher对象,它用于完毕实际的加密操作
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());  
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] buff = cipher.doFinal(data.getBytes());
            System.out.println(Arrays.toString(buff));
            // 运行加密操作。

    加密后的结果通常都会用Base64编码进行传输 return Hex.encodeHexString(buff); } /** * 加密<br> * 用私钥加密 * * @param data * @return * @throws Exception */ public static String encryptByPrivateKey(String data) throws Exception { // 对密钥解密 byte[] keyBytes = Base64.decodeBase64(getPrivateKey()); // 取得私钥 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM); Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec); // 对数据加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateKey); byte[] buff = cipher.doFinal(data.getBytes()); System.out.println(Arrays.toString(buff)); // 运行加密操作。

    加密后的结果通常都会用Base64编码进行传输 return Hex.encodeHexString(buff); } /** * 取得私钥 * * @param keyMap * @return * @throws Exception */ public static String getPrivateKey()throws Exception{ Key key = (Key)initKey().get(PRIVATE_KEY); return Base64.encodeBase64String(key.getEncoded()); } /** * 取得公钥 * * @param keyMap * @return * @throws Exception */ public static String getPublicKey()throws Exception { Key key = (Key) initKey().get(PUBLIC_KEY); return Base64.encodeBase64String(key.getEncoded()); } /** * 初始化密钥 * * @return * @throws Exception * @throws Exception */ public static Map<String, Object> initKey() throws Exception{ InputStream in1 = RSAUtil.class.getClassLoader().getResourceAsStream(PUBLIC_KEY_PATH); InputStream in2 = RSAUtil.class.getClassLoader().getResourceAsStream(PRIVATE_KEY_PATH); try { KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM); /*生成公钥*/ byte[] encodedpubkey = new byte[in1.available()]; in1.read(encodedpubkey); X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encodedpubkey); PublicKey publicKey = keyFactory.generatePublic(pubKeySpec); /*生成私钥*/ byte[] encodedprikey = new byte[in2.available()]; in2.read(encodedprikey); PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(encodedprikey); PrivateKey privateKey = keyFactory.generatePrivate(priKeySpec); /*封装进map*/ Map<String, Object> keyMap = new HashMap<String, Object>(); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; } catch(Exception e){ e.printStackTrace(); throw e; } finally { in1.close(); in2.close(); } } /** * 初始化密钥 2 * @return * @throws Exception */ public static Map<String, Object> initKey2() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(ALGORITHM); keyPairGen.initialize(1024); KeyPair keyPair = keyPairGen.generateKeyPair(); // 公钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 私钥 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String, Object> keyMap = new HashMap<String, Object>(2); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; } public static void main(String[] args) throws Exception { String publicKey = getPublicKey(); String privateKey = getPrivateKey(); System.out.println("公钥: " + publicKey); System.out.println("私钥: " + privateKey); System.out.println("公钥加密————————————————————私钥解密"); String data = "Somnus"; System.out.println("原文: " + data); String encryptData = encryptByPublicKey(data); System.out.println("加密后: " + encryptData); String decryptData = decryptByPrivateKey(encryptData); System.out.println("解密后: " + decryptData); System.out.println("私钥加密————————————————————公钥解密"); System.out.println("原文: " + data); String encryptData2 = encryptByPrivateKey(data); System.out.println("加密后: " + encryptData2); String decryptData2 = decryptByPublicKey(encryptData2); System.out.println("解密后: " + decryptData2); System.out.println("私钥签名——公钥验证签名"); // 产生签名 String sign = sign(encryptData2); System.out.println("签名: " + sign); // 验证签名 boolean status = verify(encryptData2,sign); System.out.println("状态:" + status); } }


    控制台输出: 

    公钥加密————————————————————私钥解密
    原文: Somnus
    [82, 112, 47, -49, -44, 28, 117, 87, -32, -5, -116, 56, -60, 87, -1, -36, 89, 84, -9, 17, -66, 64, -115, -114, 72, -86, 79, 63, -15, -35, -14, 40, -50, 16, -105, 73, 80, 7, -48, 75, -114, -64, 80, 74, 6, -74, 24, -59, -59, 31, 121, -63, 45, 93, 20, 25, -116, 51, -74, -40, 22, 55, -31, -106]
    加密后: 52702fcfd41c7557e0fb8c38c457ffdc5954f711be408d8e48aa4f3ff1ddf228ce1097495007d04b8ec0504a06b618c5c51f79c12d5d14198c33b6d81637e196
    [83, 111, 109, 110, 117, 115]
    解密后: Somnus
    私钥加密————————————————————公钥解密
    原文: Somnus
    [69, -38, -21, -84, -56, -1, 50, -33, -46, 11, 124, 37, -106, 53, 67, 81, -9, 39, -15, -89, 59, -49, 102, 71, 89, -7, 22, 42, 49, -29, 28, 114, -36, -1, -123, -7, 124, -104, -38, 83, 12, 76, 61, -117, 118, -54, 99, 99, 47, -118, 28, -119, 83, -5, 124, 122, -3, 109, 45, -38, -31, 98, 99, -107]
    加密后: 45daebacc8ff32dfd20b7c2596354351f727f1a73bcf664759f9162a31e31c72dcff85f97c98da530c4c3d8b76ca63632f8a1c8953fb7c7afd6d2ddae1626395
    [83, 111, 109, 110, 117, 115]
    解密后: Somnus
    私钥签名——公钥验证签名
    签名:
    GfLuZt88KdtRoTL7nJoeoRYGW0Lqu9eV4o9J8OVzH9jbHHGa/ZZDlCAjqS1jwkMYaXrut+W2a8v867mZDvQJtw==
    状态:true

        简要总结一下,使用公钥加密、私钥解密,完毕了乙方到甲方的一次数据传递,通过私钥加密、公钥解密,同一时候通过私钥签名、公钥验证签名。完毕了一次甲方到乙方的数据传递与验证,两次数据传递完毕一整套的数据交互!

    类似数字签名。数字信封是这样描写叙述的: 

    数字信封 
      数字信封用加密技术来保证仅仅有特定的收信人才干阅读信的内容。 
    流程: 
        信息发送方採用对称密钥来加密信息。然后再用接收方的公钥来加密此对称密钥(这部分称为数字信封)。再将它和信息一起发送给接收方。接收方先用对应的私钥打开数字信封,得到对称密钥,然后使用对称密钥再解开信息。

     

  • 相关阅读:
    【HDOJ】2267 How Many People Can Survive
    【HDOJ】2268 How To Use The Car
    【HDOJ】2266 How Many Equations Can You Find
    【POJ】2278 DNA Sequence
    【ZOJ】3430 Detect the Virus
    【HDOJ】2896 病毒侵袭
    求奇数的乘积
    平方和与立方和
    求数列的和
    水仙花数
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/6719616.html
Copyright © 2020-2023  润新知