非对称加密、数字签名JDK实现

非对称加密算法

● 算法特点

  1. 有2把秘钥,为公钥和私钥。
  2. 如果使用公钥加密,则必须使用私钥解密。
  3. 如果使用私钥解密,则必须使用公钥加密。
  4. 公钥和私钥是一对,成为密钥对。

对于此类加密算法的实现有 RSA,ECC等,也就是说 对称加密,消息摘要以及非对称加密 是一些算法思想,基于思想才有的实现。那么非对称加密的算法实现就是RSA和ECC等。

在JDK中当然也为RSA等算法提供了实现

public class RSATest {

    static {

        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
            KeyPair keyPair = keyPairGenerator.generateKeyPair();//密钥对
            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();

            String pub = new String(Base64.getEncoder().encodeToString(publicKey.getEncoded()));
            String pri = new String(Base64.getEncoder().encodeToString(privateKey.getEncoded()));

            System.out.println("公钥:" + pub);
            System.out.println("私钥:" + pri);

        }catch (Exception e){
            e.printStackTrace();
        }

    }

    @Test
    public void testKeyPari() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();
        System.out.println(Base64.getEncoder().encodeToString(publicKey.getEncoded()));
        System.out.println("===");
        System.out.println(Base64.getEncoder().encodeToString(privateKey.getEncoded()));

        String source = "Ja";
        System.out.println("加密后的密文:");
        String miwen = rsaEncode(source, publicKey);
        System.out.println(miwen);
        System.out.println("解密后的明文:");
        System.out.println(rsaDecode(miwen,privateKey));

    }

    private String rsaEncode(String source, Key key) throws Exception{
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(1,key);
        byte[] bytes = cipher.doFinal(source.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(bytes);
    }

    //RSA算法解密
    private String rsaDecode(String source, Key key) throws Exception{
        Cipher rsa = Cipher.getInstance("RSA");
        rsa.init(2,key);
        byte[] bytes = rsa.doFinal(Base64.getDecoder().decode(source.getBytes(StandardCharsets.UTF_8)));
        return new String(bytes);
    }

}

生成密钥对主要是 KeyPairGenerator 这个对象,可以生成RSA算法需要的公钥和私钥。最后还是需要Cipher 这个对象去实现加解密,同时还要注意,Cipher加解密的结果不一定是一堆完整的字符串,所以往往还需要结合Base64或者Base58等可读性算法来存储或者传输。

数字签名

 * 数字签名
  • 数字签名是一种验证数据在网络传输过程中完整性、真实性的一种手段。
  • 当传输的数据不需要加密而又不希望被篡改时,就可以使用到数字签名,数字签名的过程还是要用到非对称加密算法的,
    1. 首先发送方使用散列函数将发送的内容生成一个消息摘要,也就是一个固定长度的字符串。
    1. 发送方继续使用私钥对散列函数进行加密
    1. 接收方收到内容之后,使用自己的公钥进行解密。
    1. 接收方使用相同的散列函数再次对内容进行加密。
    1. 此时如果接收方计算出的签名结果和发送方相同,则证明没有被篡改过,反之则被篡改过。
public class DigestSign {

    @Test
    public void testSign() throws Exception {
        //生成密钥对
        KeyPairGenerator pairGenerator = KeyPairGenerator.getInstance("RSA");
        KeyPair keyPair = pairGenerator.generateKeyPair();
        PublicKey publicKey = keyPair.getPublic(); //公钥
        PrivateKey privateKey = keyPair.getPrivate(); //私钥

        String pub = Base64.encode(publicKey.getEncoded());
        String pri = Base64.encode(privateKey.getEncoded());

        System.out.println("公钥:" + pub);
        System.out.println("私钥:" + pri);

        String content = "南山老妖";

        String hashRule = "sha256withrsa";//消息摘要算法

        //获取签名
        String sign = getSign(privateKey,content,hashRule);
        System.out.println("消息的签名是:" + sign);

        //接收方验证消息与签名是否匹配
        boolean verify = verifySign(publicKey,content,hashRule,sign);
        System.out.println("验证签名:" + verify);
    }

    private boolean verifySign(PublicKey publicKey, String content, String hashRule, String sign) throws Exception {
        Signature signature = Signature.getInstance(hashRule);
        signature.initVerify(publicKey);
        signature.update(content.getBytes(StandardCharsets.UTF_8));
        //对比签名
        boolean verify = signature.verify(Base64.decode(sign));
        return verify;
    }

    private String getSign(PrivateKey privateKey, String content, String hashRule) throws Exception {
        //获取消息签名算法
        Signature signature = Signature.getInstance(hashRule);

        //设置公钥
        signature.initSign(privateKey);
        //设置消息摘要泛
        signature.update(content.getBytes());
        byte[] sign = signature.sign();
        return Base64.encode(sign);
    }

}

数字签名的过程和RSA的加密解密还有有些相似的,只不过就是在验证数字签名的时候这里要注意,一定是将原文和Base64转码后的签名字节数组去比较。

你可能感兴趣的:(密码学,java,安全,开发语言)