zoukankan      html  css  js  c++  java
  • Java实现RSA密钥对并在加解密、加签验签中应用的实例

    一.项目结构

    二.代码具体实现

    1.密钥对生成的两种方式:一种生成公钥私文件,一种生成公钥私串

    KeyPairGenUtil.java

    package com.wangjinxiang.genkey.util;
    
    import java.io.FileOutputStream;
    import java.io.ObjectOutputStream;
    import java.security.Key;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    
    import sun.misc.BASE64Encoder;
    
    public class KeyPairGenUtil {
    
        /** 指定加密算法为RSA */
        private static final String ALGORITHM = "RSA";
        /** 密钥长度,用来初始化 */
        private static final int KEYSIZE = 1024;
        /** 指定公钥存放文件 */
        private static String PUBLIC_KEY_FILE = "PublicKey";
        /** 指定私钥存放文件 */
        private static String PRIVATE_KEY_FILE = "PrivateKey";
    
        public static void main(String[] args) throws Exception {
            //generateKeyPair();
            genKeyPair();
        }
    
        /**
        * 生成密钥对文件
        * @throws Exception
        */
        private static void generateKeyPair() throws Exception {
    
            //     /** RSA算法要求有一个可信任的随机数源 */
            //     SecureRandom secureRandom = new SecureRandom();
            /** 为RSA算法创建一个KeyPairGenerator对象 */
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
    
            /** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
            //     keyPairGenerator.initialize(KEYSIZE, secureRandom);
            keyPairGenerator.initialize(KEYSIZE);
    
            /** 生成密匙对 */
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
    
            /** 得到公钥 */
            Key publicKey = keyPair.getPublic();
    
            /** 得到私钥 */
            Key privateKey = keyPair.getPrivate();
    
            ObjectOutputStream oos1 = null;
            ObjectOutputStream oos2 = null;
            try {
                /** 用对象流将生成的密钥写入文件 */
                oos1 = new ObjectOutputStream(new FileOutputStream(PUBLIC_KEY_FILE));
                oos2 = new ObjectOutputStream(new FileOutputStream(PRIVATE_KEY_FILE));
                oos1.writeObject(publicKey);
                oos2.writeObject(privateKey);
            } catch (Exception e) {
                throw e;
            } finally {
                /** 清空缓存,关闭文件输出流 */
                oos1.close();
                oos2.close();
            }
        }
    
        /**
         * 生成密钥对
         * @throws NoSuchAlgorithmException
         */
        private static void genKeyPair() throws NoSuchAlgorithmException {
            
            /** RSA算法要求有一个可信任的随机数源 */
            SecureRandom secureRandom = new SecureRandom();
            
            /** 为RSA算法创建一个KeyPairGenerator对象 */
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
    
            /** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
            keyPairGenerator.initialize(KEYSIZE, secureRandom);
            //keyPairGenerator.initialize(KEYSIZE);
    
            /** 生成密匙对 */
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
    
            /** 得到公钥 */
            Key publicKey = keyPair.getPublic();
    
            /** 得到私钥 */
            Key privateKey = keyPair.getPrivate();
    
            byte[] publicKeyBytes = publicKey.getEncoded();
            byte[] privateKeyBytes = privateKey.getEncoded();
    
            String publicKeyBase64 = new BASE64Encoder().encode(publicKeyBytes);
            String privateKeyBase64 = new BASE64Encoder().encode(privateKeyBytes);
    
            System.out.println("publicKeyBase64.length():" + publicKeyBase64.length());
            System.out.println("publicKeyBase64:" + publicKeyBase64);
    
            System.out.println("privateKeyBase64.length():" + privateKeyBase64.length());
            System.out.println("privateKeyBase64:" + privateKeyBase64);
        }
    }

    2.将密钥串生成方式的密钥对在常量类里定义,以便后面的应用使用

    Constants.java

    package com.wangjinxiang.constant;
    
    public class Constants {
    
      //#priKeyText
      public final static String priKeyText = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJg7beoxy+/SCkaz3ut+bEhOOPPmb+yNngmBi88Gz4kfAP9IK/tMkIQpWbhpdMQ9NdGQ3suBSNBOcQYZLUkFjjPKqmeYlx+k3Fal2ADIT/imgwnytxm+qbXgM6M0f7r2bCkh0mTJIe7NQLNC0wnwYbajA1z1+tM6lmjOVxRZsZZ9AgMBAAECgYAoGzAgDTJ/YkTWz7ihLlN00Tbr+v/twHmsY3bj+hVfOM3Yc7kyob9JMmOy1AWxVbcCGTq5PrxiNOhOBQALRu1pivDsGDm2wA+Jb4vSIwL8dFCnIMlFFPMUb5VwtNIdlEZDQdZoLV7185OJ4IEK//GuNTwCklZNIOZ0j0YMEUw7uQJBAN5C3QpRWfwRhDf1S5+RaQPZWKehuc3DU2T67/tIUOKkSnY/KUX4KxPxCXXRsrbzU4mwoW0npBO3mtuOFDsk788CQQCvVzdjz7TZXFcGOjhk1e+id/ElW69/nt6DQmwUnJYyNS4cYfKoGD/RAxN0xaAoXsl6u3FGzY7TjLsuf6Wn3vvzAkAmLGW6d+50lK2YztCGP3tB5fqMEALRjFKubUr6ZZk+0+jWFlMIaW88pZFyYunG8lPOuj9/d+d+W3KFcwmWfumRAkApho1OrSVWiQDvL6CleOk84A0TXOhuYBCwo213YDJOB7w46pWOa9fJR2I3OIqapQAwee3057/YqC64b3CrFiszAkEAttDMWhXlagXMjwZAjEuuHK3CVCqRPNhZlnoX5A5RWIg0+BpHNQDfVSlYBtki361zB8L3HR8YfJIOWk/4S+ORLg==";
      
      //#pubKeyText
      public final static String pubKeyText = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCYO23qMcvv0gpGs97rfmxITjjz5m/sjZ4JgYvPBs+JHwD/SCv7TJCEKVm4aXTEPTXRkN7LgUjQTnEGGS1JBY4zyqpnmJcfpNxWpdgAyE/4poMJ8rcZvqm14DOjNH+69mwpIdJkySHuzUCzQtMJ8GG2owNc9frTOpZozlcUWbGWfQIDAQAB";
    }

    DigestUtil.java

    package com.wangjinxiang.util;
    
    public class DigestUtil {
    
        /**
         * 字节转为十六进制字符串
         * @param字节
         * @return 十六进制字符串
         */
        public static String byte2hex(byte[] b) {
            String hs = "";
            String stmp = "";
            for (int n = 0; b != null && n < b.length; n++) {
                stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
                if (stmp.length() == 1)
                    hs = hs + "0" + stmp;
                else
                    hs = hs + stmp;
            }
            return hs;
        }
    
        /**
         * 十六进制字符转为字节
         * @param 十六进制字符
         * @return  字节
         */
        public static byte[] hex2byte(byte[] b) {
            if ((b.length % 2) != 0)
                throw new IllegalArgumentException("byte length is not correct");
            byte[] b2 = new byte[b.length / 2];
            for (int n = 0; n < b.length; n += 2) {
                String item = new String(b, n, 2);
                b2[n / 2] = (byte) Integer.parseInt(item, 16);
            }
            return b2;
        }
    
        /**
         * 字符串转换成十六进制值
         * @param bin String 我们看到的要转换成十六进制的字符串
         * @return
        */
        public static String bin2hex(String bin) {
            char[] digital = "0123456789ABCDEF".toCharArray();
            StringBuffer sb = new StringBuffer("");
            byte[] bs = bin.getBytes();
            int bit;
            for (int i = 0; i < bs.length; i++) {
                bit = (bs[i] & 0x0f0) >> 4;
                sb.append(digital[bit]);
                bit = bs[i] & 0x0f;
                sb.append(digital[bit]);
            }
            return sb.toString();
        }
    }

    3.加解密应用实例RSAUtil.java

    说明:加解密是用公钥加密,用私钥解密

    package com.wangjinxiang.util;
    
    import java.security.KeyFactory;
    import java.security.PrivateKey;
    import java.security.spec.PKCS8EncodedKeySpec;
    import javax.crypto.Cipher;
    import org.apache.commons.codec.binary.Base64;
    import com.wangjinxiang.constant.Constants;
    import sun.misc.BASE64Decoder;
    import sun.misc.BASE64Encoder;
    
    public class RSAUtil {
        
        /** 指定加密算法为RSA */
        private static final String ALGORITHM = "RSA";
    
        public static void main(String[] args) throws Exception {
            
            String source = "深圳,您好!";// 要加密的字符串
            System.out.println("准备用公钥加密的字符串为:" + source);
            
            String cryptograph = encrypt(source);// 生成的密文
            System.out.print("用公钥加密后的结果为:" + cryptograph);
            System.out.println();
           
            String target = decrypt(cryptograph);// 解密密文
            System.out.println("用私钥解密后的字符串为:" + target);
            System.out.println();   
        }
        
        /**
         * 加密方法
         * @param source 源数据
         * @return
         * @throws Exception
         */
        public static String encrypt(String source) throws Exception {
            
            java.security.spec.X509EncodedKeySpec x509KeySpec = new java.security.spec.X509EncodedKeySpec(Base64.decodeBase64(Constants.pubKeyText));
            // RSA算法
            java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("RSA");
            // 取公钥匙对象
            java.security.PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
            // 得到Cipher对象来实现对源数据的RSA加密
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] b = source.getBytes();
            /** 执行加密操作 */
            byte[] b1 = cipher.doFinal(b);
            BASE64Encoder encoder = new BASE64Encoder();
            return encoder.encode(b1);
        }
    
        /**
         * 解密算法
         * @param cryptograph    密文
         * @return
         * @throws Exception
         */
        public static String decrypt(String cryptograph) throws Exception {
            
            PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(Constants.priKeyText));
            KeyFactory keyf = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyf.generatePrivate(priPKCS8);
    
            /** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            BASE64Decoder decoder = new BASE64Decoder();
            byte[] b1 = decoder.decodeBuffer(cryptograph);
    
            /** 执行解密操作 */
            byte[] b = cipher.doFinal(b1);
            return new String(b);
        }
    }

    运行结果:

    准备用公钥加密的字符串为:深圳,您好!
    用公钥加密后的结果为:Q5bZjBlIIPII04NOCIwYDPYBGNSC5Hv7XKc8TlkCRbZyAK4M4nm9uYcEded0Nbj7HeLXNZY8XrQD
    l2+FsYjfL0DlioCoJQm7bnwlVwYmdNMXOB3bfepywpeFRDSNswJxueLqVtmIKcbuCuXBvdIqrfDq
    PVbCVfI59/GhqAcqM6U=
    用私钥解密后的字符串为:深圳,您好!

    4.加签验签实例SignUtil.java

    说明:加签是用私钥,验签是用公钥

    package com.wangjinxiang.util;
    
    import java.security.KeyFactory;
    import java.security.PrivateKey;
    import java.security.spec.PKCS8EncodedKeySpec;
    import org.apache.commons.codec.binary.Base64;
    import com.wangjinxiang.constant.Constants;
    
    public class SignUtil {
        
        private final static String CHARACTER_ENCODING_UTF_8 = "UTF-8";
        
        public static void main(String[] args) {
            
            String signString = "深圳,您好!";
            try {
                // 加签
                String localSignature = SignUtil.sign(Constants.priKeyText.getBytes(CHARACTER_ENCODING_UTF_8), signString);
                System.out.println(localSignature);
                //验签
                boolean verifyResult = SignUtil.verify(Constants.pubKeyText.getBytes(CHARACTER_ENCODING_UTF_8), signString, localSignature);
                System.out.println("verifyResult:" + verifyResult);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        /**
         * RSA私钥加签
         * @param priKeyText经过base64处理后的私钥
         * @param plainText明文内容
         * @return 十六进制的签名字符串
         * @throws Exception 
         */
        public static String sign(byte[] priKeyText, String plainText) throws Exception {
            try {
                PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(priKeyText));
                KeyFactory keyf = KeyFactory.getInstance("RSA");
                PrivateKey prikey = keyf.generatePrivate(priPKCS8);
    
                // 用私钥对信息生成数字签名
                java.security.Signature signet = java.security.Signature.getInstance("SHA256withRSA");
                signet.initSign(prikey);
                signet.update(plainText.getBytes("UTF-8"));
                return DigestUtil.byte2hex(signet.sign());
            } catch (Exception e) {
                throw e; 
            }
        }
        
        /**
         * 公钥验签
         * @param pubKeyText经过base64处理后的公钥
         * @param plainText明文内容
         * @param signText十六进制的签名字符串
         * @return 验签结果 true验证一致 false验证不一致
         */
        public static boolean verify(byte[] pubKeyText, String plainText, String signText) {
            try {
                // 解密由base64编码的公钥,并构造X509EncodedKeySpec对象
                java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec(
                        Base64.decodeBase64(pubKeyText));
                // RSA算法
                java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("RSA");
                // 取公钥匙对象
                java.security.PublicKey pubKey = keyFactory.generatePublic(bobPubKeySpec);
                // 十六进制数字签名转为字节
                byte[] signed = DigestUtil.hex2byte(signText.getBytes("UTF-8"));
                java.security.Signature signatureChecker = java.security.Signature.getInstance("SHA256withRSA");
                signatureChecker.initVerify(pubKey);
                signatureChecker.update(plainText.getBytes("UTF-8"));
                // 验证签名是否正常
                return signatureChecker.verify(signed);
            } catch (Throwable e) {
                return false;
            }
        }
    }

    运行结果:

    7ef0cd04a3dc41ae1396a90a3d8a8b799c68c65202361823dd3a71a05fc2bf57c09ebe2074ba49008cf58288297267d770137ee267c6c296a784c7d50c607c73e1d78799c7de5dadf183f011d604df7270ce5616e465ddc93a95df9095249702fc265e97ed7ab2adf4535d13237040653d7f000a3080a0c4f11f84bbe48849e7
    verifyResult:true

    5.从生成的密钥对文件中读取公私钥加解密实例RSAUtil02.java

    package com.wangjinxiang.util2;
    
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.security.Key;
    
    import javax.crypto.Cipher;
    
    import sun.misc.BASE64Decoder;
    import sun.misc.BASE64Encoder;
    
    public class RSAUtil02 {
        
        /** 指定加密算法为RSA */
        private static final String ALGORITHM = "RSA";
        /** 指定公钥存放文件 */
        private static String PUBLIC_KEY_FILE = "PublicKey";
        /** 指定私钥存放文件 */
        private static String PRIVATE_KEY_FILE = "PrivateKey";
    
        public static void main(String[] args) throws Exception {
            
            String source = "深圳,您好!";// 要加密的字符串
            System.out.println("准备用公钥加密的字符串为:" + source);
            
            String cryptograph = encrypt(source);// 生成的密文
            System.out.print("用公钥加密后的结果为:" + cryptograph);
            System.out.println();
           
            String target = decrypt(cryptograph);// 解密密文
            System.out.println("用私钥解密后的字符串为:" + target);
            System.out.println();   
        }
        
        /**
         * 加密方法
         * @param source 源数据
         * @return
         * @throws Exception
         */
        public static String encrypt(String source) throws Exception {
            
            Key publicKey = getKey(PUBLIC_KEY_FILE);
    
            /** 得到Cipher对象来实现对源数据的RSA加密 */
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] b = source.getBytes();
            /** 执行加密操作 */
            byte[] b1 = cipher.doFinal(b);
            BASE64Encoder encoder = new BASE64Encoder();
            return encoder.encode(b1);
        }
    
        /**
         * 解密算法
         * @param cryptograph    密文
         * @return
         * @throws Exception
         */
        public static String decrypt(String cryptograph) throws Exception {
            
            Key privateKey = getKey(PRIVATE_KEY_FILE);
    
            /** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            BASE64Decoder decoder = new BASE64Decoder();
            byte[] b1 = decoder.decodeBuffer(cryptograph);
    
            /** 执行解密操作 */
            byte[] b = cipher.doFinal(b1);
            return new String(b);
        }
        
        private static Key getKey(String fileName) throws Exception, IOException {
            Key key;
            ObjectInputStream ois = null;
            try {
                /** 将文件中的私钥对象读出 */
                ois = new ObjectInputStream(new FileInputStream(fileName));
                key = (Key) ois.readObject();
            } catch (Exception e) {
                throw e;
            } finally {
                ois.close();
            }
            return key;
        }
    }

    运行结果:

    准备用公钥加密的字符串为:深圳,您好!
    用公钥加密后的结果为:Ep2Y6EstlUWQnmVxsZ0/NIV1NFIPAlg8rJguRdQB+2uBD+/sunrPiVoCm3zbuj317CNG5hwijNBf
    qKETmd7HoftpnHxzYwn+lWqlVdUHIO+ZrFn2OB6omlA/aFHCZzIHtKDU72cNuiBiwONxCXyaWq4Z
    scDfvzbz3//UYOhlDs4=
    用私钥解密后的字符串为:深圳,您好!
  • 相关阅读:
    Android 使用EventBus进行Fragment和Activity通信
    Android 实现对多个EditText的监听
    Retrofit2.0动态url遇到的坑
    Android 轻松实现语音朗读
    Android 7.0 因为file://引起的FileUriExposedException异常
    Android拍照得到全尺寸图片并进行压缩/拍照或者图库选择 压缩后 图片 上传
    Toolbar自定义布局
    [致歉]2:05-6:35部分站点出现故障,给您带来麻烦,请谅解团队
    上周热点回顾(8.11-8.17)团队
    [网站公告]8月17日14:00-15:00(周日下午)发布新版站内短消息团队
  • 原文地址:https://www.cnblogs.com/wangjinxiang/p/10618577.html
Copyright © 2011-2022 走看看