zoukankan      html  css  js  c++  java
  • Java加密与解密笔记(三) 非对称加密

    非对称的特点是加密和解密时使用的是不同的钥匙。密钥分为公钥和私钥,用公钥加密的数据只能用私钥进行解密,反之亦然。

    另外,密钥还可以用于数字签名。数字签名跟上文说的消息摘要是一个道理,通过一定方法对数据内容进行处理得到一个签名,查看这个签名是否与对方传递的签名一致。

    在非对称加密中用密钥来指公钥和私钥。

     

    RSA

    RAS是最早的非对称签名,是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。1987年7月首次在美国公布,当时他们三人都在麻省理工学院工作实习。RSA就是他们三人姓氏开头字母拼在一起组成的。

    对于非对称加密,在Java中可以用KeyPairGenerator工具类来负责生成密钥对:

    public class RSAUtil {
        
        public final static String ALGORITHM = "RSA";
    
        public static KeyPair getKey() throws Exception{
            KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM);
            return generator.generateKeyPair();
        }
        
        public static void main(String[] args) throws Exception{
            KeyPair keyPair = getKey();
            RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate();
            RSAPublicKey  publicKey = (RSAPublicKey)keyPair.getPublic();
            
            String privateKeyStr = Base64.encode(privateKey.getEncoded());
            String publicKeyStr = Base64.encode(publicKey.getEncoded());
            
            System.out.println("私钥:" + privateKeyStr);
            System.out.println("公钥:" + publicKeyStr);
        }
        
    } 

    使用公钥加密:

        public static String encryptByPublicKey(String data,String key)throws Exception{
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64Util.decode(key));
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
            
            Key k = keyFactory.generatePublic(keySpec);
            
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, k);
            
            byte[] bytes = cipher.doFinal(data.getBytes("UTF-8"));
            
            return Base64Util.encode(bytes);
        } 

    加密的时候用X509EncodedKeySpec来获取公钥,不要害怕X509,其实没有别的X508或者X609,就这么一个X509。X.509是一种非常通用的证书格式。所有的证书都符合ITU-T X.509国际标准。

    和之前的DES类似,使用私钥解密的代码如下:

        public static String decryptByPrivateKey(String data,String key)throws Exception{
            
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64Util.decode(key));
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
            
            Key k = keyFactory.generatePrivate(keySpec);
            
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, k);
            
            byte[] bytes = cipher.doFinal(Base64Util.decode(data));
            
            return new String(bytes,"UTF-8");
        } 

    还用X509去读私钥就不行了,会报下面这个错误:

    Exception in thread "main" java.security.spec.InvalidKeySpecException: Only RSAPrivate(Crt)KeySpec and PKCS8EncodedKeySpec supported for RSA private keys

    意思是只能用RSAPrivate(Crt)KeySpec 或者 PKCS8EncodedKeySpec去读私钥,改成下面这样就好了:

        public static String decryptByPrivateKey(String data,String key)throws Exception{
            
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64Util.decode(key));
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
            
            Key k = keyFactory.generatePrivate(keySpec);
            
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, k);
            
            byte[] bytes = cipher.doFinal(Base64Util.decode(data));
            
            return new String(bytes,"UTF-8");
        }

    使用私钥加密和公钥解密的方法就不用多说了,只需要在加密和解密时换成另外一个钥匙就行了。

    签名和签名验证

    /**
         * 使用私钥进行签名
         * @param data
         * @param key
         * @return
         * @throws Exception
         */
        public static String sign(String data,String key)throws Exception{
            PrivateKey k = (PrivateKey)getPrivateKey(key);
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);  
            signature.initSign(k);  
            signature.update(data.getBytes("UTF-8"));  
            return Base64.encode(signature.sign());
        }
        
        /**
         * 使用公钥进行签名验证
         * @param data
         * @param key
         * @return
         * @throws Exception
         */
        public static boolean signVerify(String data,String key,String sign)throws Exception{
            PublicKey k = (PublicKey)getPublicKey(key);
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);  
            signature.initVerify(k);  
            signature.update(data.getBytes("UTF-8"));
            return signature.verify(Base64.decode(sign));  
        }

    JDK中有专门用于签名的工具类Signature,可用的签名算法如下:

    完整代码重构如下:

    public class RSAUtil {
        
        public final static String ALGORITHM = "RSA";
        public final static String SIGNATURE_ALGORITHM = "MD5withRSA";
    
        /**
         * 获取公钥密钥对
         * @return
         * @throws Exception
         */
        public static KeyPair getKey() throws Exception{
            KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM);
            return generator.generateKeyPair();
        }
        
        private static Key getPublicKey(String key)throws Exception{
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64Util.decode(key));
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
            Key k = keyFactory.generatePublic(keySpec);
            return k;
        }
        
        private static Key getPrivateKey(String key)throws Exception{
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64Util.decode(key));
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
            Key k = keyFactory.generatePrivate(keySpec);
            return k;
        }
        
        /**
         * 使用公钥进行加密
         * @param data
         * @param key
         * @return
         * @throws Exception
         */
        public static String encryptByPublicKey(String data,String key)throws Exception{
            
            Key k = getPublicKey(key);
            
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, k);
            
            byte[] bytes = cipher.doFinal(data.getBytes("UTF-8"));
            
            return Base64Util.encode(bytes);
        }
        
        /**
         * 使用私钥进行加密
         * @param data
         * @param key
         * @return
         * @throws Exception
         */
        public static String encryptByPrivateKey(String data,String key)throws Exception{
            
            Key k = getPrivateKey(key);
            
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, k);
            
            byte[] bytes = cipher.doFinal(data.getBytes("UTF-8"));
            
            return Base64Util.encode(bytes);
        }
        
        /**
         * 使用密钥进行解密
         * @param data
         * @param key
         * @return
         * @throws Exception
         */
        public static String decryptByPrivateKey(String data,String key)throws Exception{
            Key k = getPrivateKey(key);
            
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, k);
            
            byte[] bytes = cipher.doFinal(Base64Util.decode(data));
            
            return new String(bytes,"UTF-8");
        }
        
        /**
         * 使用公钥进行解密
         * @param data
         * @param key
         * @return
         * @throws Exception
         */
        public static String decryptByPublicKey(String data,String key)throws Exception{
            Key k = getPublicKey(key);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, k);
            
            byte[] bytes = cipher.doFinal(Base64Util.decode(data));
            
            return new String(bytes,"UTF-8");
        }
        
        /**
         * 使用私钥进行签名
         * @param data
         * @param key
         * @return
         * @throws Exception
         */
        public static String sign(String data,String key)throws Exception{
            PrivateKey k = (PrivateKey)getPrivateKey(key);
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);  
            signature.initSign(k);  
            signature.update(data.getBytes("UTF-8"));  
            return Base64.encode(signature.sign());
        }
        
        /**
         * 使用公钥进行签名验证
         * @param data
         * @param key
         * @return
         * @throws Exception
         */
        public static boolean signVerify(String data,String key,String sign)throws Exception{
            PublicKey k = (PublicKey)getPublicKey(key);
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);  
            signature.initVerify(k);  
            signature.update(data.getBytes("UTF-8"));
            return signature.verify(Base64.decode(sign));  
        }
        
        public static void main(String[] args) throws Exception{
            KeyPair keyPair = getKey();
            RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate();
            RSAPublicKey  publicKey = (RSAPublicKey)keyPair.getPublic();
            
            String privateKeyStr = Base64.encode(privateKey.getEncoded());
            String publicKeyStr = Base64.encode(publicKey.getEncoded());
            
            System.out.println("私钥:" + privateKeyStr);
            System.out.println("公钥:" + publicKeyStr);
            
            String data = "Hello,RSA,Hello,RSAHello,RSAHello,RSAHello,RSAHello,RSAHello,RSA";
            System.out.println("---------------公钥加密,私钥解密-----------------");
            String encryptedData = encryptByPublicKey(data,publicKeyStr);
            System.out.println("加密后:" + encryptedData);
            
            String decryptedData = decryptByPrivateKey(encryptedData, privateKeyStr);
            System.out.println("解密后:" + decryptedData);
            System.out.println("---------------私钥加密,公钥解密-----------------");
            
            encryptedData = encryptByPrivateKey(data,privateKeyStr);
            System.out.println("加密后:" + encryptedData);
            decryptedData = decryptByPublicKey(encryptedData, publicKeyStr);
            System.out.println("解密后:" + decryptedData);
            
            String sign = sign(data,privateKeyStr);
            System.out.println("签名:" + sign);
            System.out.println("签名验证:" + signVerify(data,publicKeyStr,sign));
            
            
        }
        
    }

     DH(Diffie-Hellman)

    非对称加密的算法比较耗时,所以不能用它来传输大数据。通常情况下会是这样:

    1. 因为对称加密算法中没法安全传递密钥,所以用非对称加密算法来传递对称加密的密钥;
    2. 等对称加密的秘钥传递成功之后,正式的数据就用对称加密算法来传递了。

    DH算法就是为了实现这个目的而产生的。DH能实现甲乙双方的密钥沟通。

    假设客户端要发送数据到服务端,在Java中DH加密的完整步骤:

    服务端先生成自己的密钥对:

    /**
     * 数据处理服务端*/
    public class Server {
    
        private String publicKey;
        private String privateKey;
        private SecretKey key;
        
        public Server(){
            try {
                String[] keyPair = DHUtil.getStringKeyPair();
                publicKey = keyPair[0];
                privateKey = keyPair[1];
            } catch (Exception e) {
                e.printStackTrace();
            }
            
        }
       ...

    服务端的私钥自己保持,公布公钥,客户端则需要根据服务端的公钥生成自己的密钥对:

    /**
     * 数据传输客户端*/
    public class Client {
        
        private String publicKey;
        private String privateKey;private Server server;
        
        public Client(Server server){
            this.server = server;
            String serverPublicKey = server.getPublicKey();//明文获取到公钥
            try{
                String[] keyPair = DHUtil.getStringKeyPair(serverPublicKey);
                publicKey = keyPair[0];
                privateKey = keyPair[1];
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        ...

    客户端在和服务端通信时,使用的加密算法是对称加密。对称加密的密钥是根据服务端的公钥和客户端的私钥生成的。

    public class Client {
        
        private String publicKey;
        private String privateKey;
        private SecretKey key;
        
        private Server server;
        
        public Client(Server server){
            this.server = server;
            String serverPublicKey = server.getPublicKey();
            try{
                String[] keyPair = DHUtil.getStringKeyPair(serverPublicKey);
                publicKey = keyPair[0];
                privateKey = keyPair[1];
                key = DHUtil.getAgreementSecretKey(serverPublicKey, privateKey);
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    ...

    好了,现在可以往服务端发送数据了,比如有一个登录操作:

    public class Client {
        ...
        public boolean login(String user,String pwd){
            String data = "user=" + user + "&pwd=" + pwd;
            try {
                data = DHUtil.encrypt(data, key);
            } catch (Exception e) {
                e.printStackTrace();
            }
            String response = server.service(data,publicKey);
            System.out.println("Login Response:" + response);
            return response.equals("OK");
        }
    }

     可见,公钥是通过明文的形式发送给服务端的。服务端对数据进行处理:

    /**
     * 数据处理服务端
     * @author huqiao
     */
    public class Server {
    
        ...
    
        public String service(String data,String clientPublicKey){try {
                key = DHUtil.getAgreementSecretKey(clientPublicKey, privateKey);//根据客户端的publicKey生成本地密钥
                String decryptedData = DHUtil.decrypt(data, key);
                System.out.println("Data decryped:" + decryptedData);
                if(verfiy(decryptedData)){
                    return "OK";
                }else{
                    return "Error";
                    
                }
            } catch (Exception e) {
                e.printStackTrace();
                return e.getMessage();
            }
        }
        ... 

    服务器拿到客户端的公钥之后生成本地的密钥,然后对数据进行解密。为了简单起见,这里服务器往客户度返回数据时没有做加密。

    非常重要的DHUtil.java完整代码:

    public class DHUtil {
        
        public final static String ALGORITHM = "DH";
        public final static String SYMMETRIC_SECRET_ALGORITHM = "AES";//对称加密算法名称
    
        /**
         * 产生密钥对
         * @return
         * @throws Exception
         */
        public static KeyPair getKeyPair()throws Exception{
            KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM);
            generator.initialize(1024);
            return generator.generateKeyPair();
        }
        
        /**
         * 获取字符串类型的密钥对
         * @return
         * @throws Exception
         */
        public static String[] getStringKeyPair()throws Exception{
            KeyPair keyPair = getKeyPair();
            return keyPairToStringArray(keyPair);
        }
        
        public static String[] getStringKeyPair(String publicKey)throws Exception{
            KeyPair keyPair = getKeyPairByPublicKey(publicKey);
            return keyPairToStringArray(keyPair);
        }
        
        private static String[] keyPairToStringArray(KeyPair keyPair){
            String[] res = new String[2];
            PublicKey pubKey = keyPair.getPublic(); 
            PrivateKey priKey = keyPair.getPrivate();
            
            res[0] = Base64Util.encode(pubKey.getEncoded());
            res[1] = Base64Util.encode(priKey.getEncoded());
            
            return res;
        }
        
        
        /**
         * 由一个公钥产生密钥对
         * @param publicKey
         * @return
         * @throws Exception
         */
        public static KeyPair getKeyPairByPublicKey(String publicKey)throws Exception{
            
            PublicKey pKey = getPublicKey(publicKey);
            
            KeyPairGenerator generator = KeyPairGenerator.getInstance(pKey.getAlgorithm());
            
            DHParameterSpec dhGenParam = ((DHPublicKey) pKey).getParams();
            generator.initialize(dhGenParam);
            
            return generator.generateKeyPair();
        }
        
        private static PublicKey getPublicKey(String key)throws Exception{
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64Util.decode(key));
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
            PublicKey k = keyFactory.generatePublic(keySpec);
            return k;
        }
        
        private static PrivateKey getPrivateKey(String key)throws Exception{
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64Util.decode(key));
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
            PrivateKey k = keyFactory.generatePrivate(keySpec);
            return k;
        }
        
        /**
         * 根据一方公钥和另外一方私钥构建本地密钥
         * @param publicKey
         * @param privateKey
         * @return
         * @throws Exception
         */
        public static SecretKey getAgreementSecretKey(String publicKey,String privateKey)throws Exception{
            PublicKey pubKey = getPublicKey(publicKey);
            PrivateKey priKey = getPrivateKey(privateKey);
            
            return getAgreementSecretKey(pubKey,priKey);
            
        }
        
        public static SecretKey getAgreementSecretKey(PublicKey pubKey,PrivateKey priKey)throws Exception{
            KeyAgreement argeement = KeyAgreement.getInstance(pubKey.getAlgorithm());
            argeement.init(priKey);
            argeement.doPhase(pubKey, true);
            
            SecretKey secretKey = argeement.generateSecret(SYMMETRIC_SECRET_ALGORITHM);
            return secretKey;
        }
        
        /**
         * 加密
         * @param data
         * @param key
         * @return
         * @throws Exception
         */
        public static String encrypt(String data,SecretKey key)throws Exception{
            Cipher cipher = Cipher.getInstance(key.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] encryptedData = cipher.doFinal(data.getBytes("UTF-8"));
            return Base64Util.encode(encryptedData);
        }
        
        /**
         * 解密
         * @param data
         * @param key
         * @return
         * @throws Exception
         */
        public static String decrypt(String data,SecretKey key)throws Exception{
            byte[] encryptedData = Base64Util.decode(data);
            Cipher cipher = Cipher.getInstance(key.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] decryptedData = cipher.doFinal(encryptedData);
            return new String(decryptedData,"UTF-8");
        }
    } 

    不要被它的长度吓到,它做的事情其实很简单,就是生成密钥对和加密解密。生成密钥对,加密和解密在之前都见过,这里最重要的方法是使用来自两方的公钥和私钥生成一个本地密钥:

        /**
         * 根据一方公钥和另外一方私钥构建本地密钥
         * @param publicKey
         * @param privateKey
         * @return
         * @throws Exception
         */
        public static SecretKey getAgreementSecretKey(String publicKey,String privateKey)throws Exception{
            PublicKey pubKey = getPublicKey(publicKey);
            PrivateKey priKey = getPrivateKey(privateKey);
            
            return getAgreementSecretKey(pubKey,priKey);
            
        }
        
        public static SecretKey getAgreementSecretKey(PublicKey pubKey,PrivateKey priKey)throws Exception{
            KeyAgreement argeement = KeyAgreement.getInstance(pubKey.getAlgorithm());
            argeement.init(priKey);
            argeement.doPhase(pubKey, true);
            
            SecretKey secretKey = argeement.generateSecret(SYMMETRIC_SECRET_ALGORITHM);
            return secretKey;
        } 

    完整客户端和服务端代码如下:

    /**
     * 数据传输客户端
     * @author huqiao
     */
    public class Client {
        
        private String publicKey;
        private String privateKey;
        private SecretKey key;
        
        private Server server;
        
        public Client(Server server){
            this.server = server;
            String serverPublicKey = server.getPublicKey();
            try{
                String[] keyPair = DHUtil.getStringKeyPair(serverPublicKey);
                publicKey = keyPair[0];
                privateKey = keyPair[1];
                key = DHUtil.getAgreementSecretKey(serverPublicKey, privateKey);
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        
        public boolean login(String user,String pwd){
            String data = "user=" + user + "&pwd=" + pwd;
            try {
                data = DHUtil.encrypt(data, key);
            } catch (Exception e) {
                e.printStackTrace();
            }
            String response = server.service(data,publicKey);
            System.out.println("Login Response:" + response);
            return response.equals("OK");
        }
    }
    /**
     * 数据处理服务端
     * @author huqiao
     */
    public class Server {
    
        private String publicKey;
        private String privateKey;
        private SecretKey key;
        
        public Server(){
            try {
                String[] keyPair = DHUtil.getStringKeyPair();
                publicKey = keyPair[0];
                privateKey = keyPair[1];
            } catch (Exception e) {
                e.printStackTrace();
            }
            
        }
        
        public String service(String data,String clientPublicKey){
            System.out.println("----------------Data received at Server:----------------
    "+ data);
            System.out.println("----------------Client PublicKey received at Server:----------------
    "+clientPublicKey);
            try {
                key = DHUtil.getAgreementSecretKey(clientPublicKey, privateKey);
                String decryptedData = DHUtil.decrypt(data, key);
                System.out.println("Data decryped:" + decryptedData);
                if(verfiy(decryptedData)){
                    return "OK";
                }else{
                    return "Error";
                    
                }
            } catch (Exception e) {
                e.printStackTrace();
                return e.getMessage();
            }
        }
        
        private boolean verfiy(String decryptedData) {
            //解析用户名和密码,进行验证
            return true;
        }
    
        /**
         * 明文拿到服务端公钥
         * @return
         */
        public String getPublicKey(){
            return publicKey;
        }
    }

    测试:

    public class DHTest {
        
        public static void main(String[] args) {
            Server server = new Server();
            
            Client client = new Client(server);
            boolean loginSuccess = client.login("admin", "123456");
            
            System.out.println("login success:" + loginSuccess);
        }
    }

    测试结果:

    ----------------Data received at Server:----------------
    pVWbVMP57wkLftZN3bXx1mf4631yTMlxJ+hnMm4Dwmg=
    ----------------Client PublicKey received at Server:----------------
    MIIBpzCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YRt1I870QAwx4/gLZR
    JmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7
    V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HXKu/yIgMZndFIAccCgYEA9+GghdabPd7LvKtc
    NrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotU
    fI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7P
    SSoCAgIAA4GFAAKBgQC+WT4qNq/Yay1WFA89n5IOy+hJa8JQh4R0uyy5Yfo2ckgQ4cjh/u5GPKev
    Ua2B3vQVFEifKSn7tfP5bmYMQ5IZLPJ3JrP2m/QAjQ1T7swG/Kbtfc4eTgq+wpnb2LbDoznKGN28
    Mcrbf4HkwZ8QK0M26CySSEQCFliWydd6u/vl0A==
    Data decryped:user=admin&pwd=123456
    Login Response:OK
    login success:true

    DSA

     DSA的全称为数字签名算法(Digital Signature Algorithm),它与RSA的区别在于它只用于签名,并且它的速度比RSA要快。在安全性上两者差不多。

    因为在RSA中已经说到过签名以及验证的过程,DSA和它完全类似:

    public class DSAUtil {
    
        static final String ALGORITHM = "DSA";
        
        private static KeyPair getKeyPair()throws Exception{
            KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM);
            generator.initialize(1024);
            return generator.genKeyPair();
        }
        
    
        
        /**
         * 用私钥签名
         * @param data
         * @param privateKey
         * @return
         */
        public static String sign(String data,String privateKey)throws Exception{
            PrivateKey priKey = getPrivateKey(privateKey);
            Signature sign = Signature.getInstance(ALGORITHM);
            sign.initSign(priKey);
            sign.update(data.getBytes("UTF-8"));
            byte[] signBytes = sign.sign();
            return Base64Util.encode(signBytes);
        }
        
        /**
         * 用公钥进行签名验证
         * @param data
         * @param publicKey
         * @param signData
         * @return
         * @throws Exception
         */
        public static boolean verify(String data,String publicKey,String signData)throws Exception{
            PublicKey pubKey = getPublicKey(publicKey);
            Signature sign = Signature.getInstance(ALGORITHM);
            sign.initVerify(pubKey);
            sign.update(data.getBytes("UTF-8"));
            return sign.verify(Base64Util.decode(signData));
        }
        
        
        private static PublicKey getPublicKey(String key)throws Exception{
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64Util.decode(key));
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
            PublicKey k = keyFactory.generatePublic(keySpec);
            return k;
        }
        
        private static PrivateKey getPrivateKey(String key)throws Exception{
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64Util.decode(key));
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
            PrivateKey k = keyFactory.generatePrivate(keySpec);
            return k;
        }
        
        /**
         * 获取字符串类型的密钥对
         * @return
         * @throws Exception
         */
        public static String[] getStringKeyPair()throws Exception{
            KeyPair keyPair = getKeyPair();
            return keyPairToStringArray(keyPair);
        }
        
        private static String[] keyPairToStringArray(KeyPair keyPair){
            String[] res = new String[2];
            PublicKey pubKey = keyPair.getPublic(); 
            PrivateKey priKey = keyPair.getPrivate();
            
            res[0] = Base64Util.encode(pubKey.getEncoded());
            res[1] = Base64Util.encode(priKey.getEncoded());
            
            return res;
        }
        
        public static void main(String[] args) throws Exception{
            String data = "Hello,DSA";
            String[] keyPair = getStringKeyPair();
            String pubKey = keyPair[0];
            String priKey = keyPair[1];
            System.out.println("原文:" + data);
            System.out.println("---------Public Key----------");
            System.out.println(pubKey);
            System.out.println("---------Private Key----------");
            System.out.println(priKey);
            System.out.println();
            
            String signData = sign(data, priKey);
            System.out.println("Sign Data:" + signData);
            System.out.println("Verify Result:" + verify(data, pubKey, signData));
            
        }
    }

    ECC

    ECC-Elliptic Curves Cryptography,椭圆曲线密码编码学,是目前已知的公钥体制中,对每比特所提供加密强度最高的一种体制。ECC算法相当耗费资源,如果单纯使用CPU进行加密/解密,效率低下。目前JDK9都没有实现ECC的加密解密,仅仅提供ECC的秘钥生成。

    可以自己去实现ECC的Provider。因为Java的安全框架(JCA)提供了密钥生成的扩展机制(JCE)。参考这里如何实现一个Provider:

    How to Implement a Provider in the Java Cryptography Architecture

    其他相关文章:

    参考资料:

    http://snowolf.iteye.com/blog/381767

    http://snowolf.iteye.com/blog/382422

    http://snowolf.iteye.com/blog/382749

  • 相关阅读:
    第六十篇、音视频采集硬编码(H264+ACC)
    第十三篇、Swift_Nav自定义返回按钮后或者隐藏导航栏,Pop返回手势失效的解决方法 Pop全局返回添加的方法
    第五十九篇、OC录制小视频
    第五十八篇、iOS 微信聊天发送小视频的秘密
    第五十七篇、AVAssetReader和AVAssetWrite 对视频进行编码
    第五十六篇、OC打开本地和网络上的word、ppt、excel、text等文件
    Objective-C 编码建议
    在block中使用self
    纯代码TableView自适应高度(很老的使用方法)
    iOS应用架构谈 网络层设计方案
  • 原文地址:https://www.cnblogs.com/at0x7c00/p/7688124.html
Copyright © 2011-2022 走看看