Java加密与解密笔记(三) 非对称加密

摘要:
publicclassRSAUtil{publicfinalstaticStringALGORITHM=“RSA”;publicstaticKeyPairgetKey()throwsException{KeyPairGenerator=KeyPairGeneration.getInstance(ALGORITHM);

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

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

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

 

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,可用的签名算法如下:

Java加密与解密笔记(三) 非对称加密第1张

完整代码重构如下:

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

免责声明:文章转载自《Java加密与解密笔记(三) 非对称加密》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇特定条件下傅里叶变换的性质Echart 动态生成series数据下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

https、公钥,私钥,数字证书

前言 https是http与ssl的结合,为了解决http明文传输导致信息泄露的问题。ssl通过公钥和私钥保证客户端和服务器之间的通讯加密,由权威机构办法的数字证书杜绝了中间人攻击的可能。 http和ssl http是处于应用层的传输协议,ssl是处于与TCP同层的传输层和应用层之间的协议,由于http使用明文传输,就会导致数据在传输过程中泄露,为此将ht...

JAVA RSA私钥 加密(签名) 对应 C# RSA私钥 加密(签名)

非对称密钥RSA算法加解密在C#和Java之间交互的问题,这两天看了很多其他人写的文章,碰到了几个问题,最终解决问题。 参考地址:http://xw-z1985.iteye.com/blog/1837376 需求目的:完成c#请求端RSA加密(签名)问题,客户端采用C#开发,服务器端采用Java开发。服务器端给客户端提供私钥,进行数据加密(签名),客户端加...

RSA加密原理使用方式签名验证

  RSA加密原理使用方式签名验证 加密是网络传输中非常重要的一环,它保证了信息的安全性,让他人无法通过抓包来获取通讯的信息也无法通过伪造信息而实现对系统的入侵。其中最为常用的信息传递加密方式就是RSA加密。 RSA加密原理 RSA与传统加密方式不同的是,他是非对称加密,可以在不直接传递密钥的情况下,完成解密。这能够确保信息的安全性,避免了直接传递密钥...

GPG操作——签名验证

问题描述: 可能大家都遇到过软件在下载过程中由于网络原因导致下载的软件体积与实际软件体积不符。最常见的办法是对待下载文件附加一个摘要文件。这种做法比较常见,也比较容易实现。但是,还是会有一个问题:如果我篡改了网站,改变了文件的内容,并对该文件做了一次摘要,替换了原有的摘要文件。那用户下载的文件就失去了摘要验证的意义。如何避免这种问题呢? 解决方案: 软件提...

netty 解决TCP粘包与拆包问题(二)

TCP以流的方式进行数据传输,上层应用协议为了对消息的区分,采用了以下几种方法。 1.消息固定长度 2.第一篇讲的回车换行符形式 3.以特殊字符作为消息结束符的形式 4.通过消息头中定义长度字段来标识消息的总长度 一、采用指定分割符解决粘包与拆包问题 服务端 1 package com.ming.netty.nio.stickpack; 2...

关于Git GUI克隆代码

1.首先需要使用Git GUI生成一个SSH秘钥并将其拷贝到远程(码云或者GitHub)账号下的SSH公钥中(以码云为例) 将上一步生成的SSH密钥拷贝到下面的码云的公钥中 2.拷贝下码云上代码的SSH地址进行下载    注:拷贝下默认是Master分支,若要获取其它分支,直切切换到远程的其它分支即可...