Java语言的非对称加密的实现

1 篇文章 0 订阅

众所周知,互联网上的安全是非常重要的一个课题,如何让我们的软件,通信协议更加安全,是每个程序员都需要思考的问题。
本文主要讨论三种非对称加密的情况。
1.私钥加密-公钥解密
2.公钥加密-私钥解密
3.私钥签名-公钥验证

产生密钥对

无论上述哪种情况,我们都需要产生一个密钥对。

使用Keytool生成

需要借助JDK中自带的keytool来生成。在命令行模式下输入keytool.

这里写图片描述

如果配置正常,应该显示以上内容,如果提示commend not found.那需要把JDK的路径加入到Path中。有不会的同学请自行百度。

我们使用-genkeypair命令。

在命令行中输入:

keytool -genkey -help

这里写图片描述

可以看到这里详细参数的用法。

我们创建一个密钥库(含密钥对),命令如下:

keytool -genkey -alias blogkey -keyalg RSA -validity 36500 -keystore h:\key\blogkey.keystore

这里写图片描述

-alias 密钥库的别名,用于识别这个密钥库
-keyalg 这里我们使用常见的RSA算法
-validity 有效期,这里我们填了100年
-keystore 生成的文件名

根据系统引导填完内容,我们就创建了一个密钥库。

接下来我们需要导出证书,里面包含公钥。
我们使用-export命令。
这里写图片描述

keytool -export -rfc -alias blogkey -file pubkey.cer -keystore h:\key\blogkey.keystore

我们把导出的证书存为pubkey.cer

到目前为止,我们获取一个blogkey.keystore的密钥库及pubkey.cer的证书,其中blogkey.keystore自用,pubkey.cer转给别人使用。

从keystore中提取privatekey

    private static PrivateKey getPrivateKey(String keyStorePath, String alias, String password)
            throws Exception {
        FileInputStream is = new FileInputStream(keyStorePath);
        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(is, password.toCharArray());
        is.close();
        PrivateKey key = (PrivateKey) ks.getKey(alias, password.toCharArray());
        return key;
    }

在pubkey.cer中获取publickey

    private static PublicKey getPublicKey(String certificatePath)
            throws Exception {

       CertificateFactory certificateFactory = CertificateFactory
                .getInstance("X.509");
        FileInputStream in = new FileInputStream(certificatePath);

        Certificate certificate = certificateFactory.generateCertificate(in);
        in.close();

        PublicKey key = certificate.getPublicKey();
        return key;
    }

使用KeyPairGenerator直接生成

        KeyPairGenerator keyPairGenerator =  KeyPairGenerator.getInstance("RSA");  
        //可支持DiffieHellman (1024), DSA (1024),RSA (1024, 2048)
        keyPairGenerator.initialize(1024);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();

私钥加密-公钥解密

前面的章节我们获得了privateKey及publicKey, 接下来的事情就简单了。

私钥加密

    private static byte[] encryptByPrivateKey(data[] plainData, PrivateKey privateKey )
            throws Exception {
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        return cipher.doFinal(plainData);
    }

公钥解密

public static byte[] decryptByPublicKey(byte[] data, PublicKey publicKey )
        throws Exception {
    Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
    cipher.init(Cipher.DECRYPT_MODE, publicKey);
    return cipher.doFinal(data);
}

公钥加密-私钥解密

公钥加密

  public static byte[] encryptByPublicKey(byte[] plainData, PublicKey publicKey)
            throws Exception {
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(plainData);

    }

私钥解密

  public static byte[] decryptByPrivateKey(byte[] data,  PrivateKey privateKey ) throws Exception {
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);

    }

私钥签名-公钥验证

私钥签名

利用私钥签名除了私钥之外,我们还需要一个证书,因此如果没有在第一步生成pubkey.cer,这部分是无法实验的。



    public static byte[] sign(byte[] sign, String keyStorePath, String alias,
                              String password) throws Exception {
        // 获得证书
        X509Certificate x509Certificate = (X509Certificate) getCertificate(
                keyStorePath, alias, password);
        // 获取私钥
        KeyStore ks = getKeyStore(keyStorePath, password);
        // 取得私钥
        PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password
                .toCharArray());

        // 构建签名
        Signature signature = Signature.getInstance(x509Certificate
                .getSigAlgName());
        signature.initSign(privateKey);
        signature.update(sign);
        return (signature.sign());
    }

  private static Certificate getCertificate(String keyStorePath,
                                              String alias, String password) throws Exception {
        KeyStore ks = getKeyStore(keyStorePath, password);
        Certificate certificate = ks.getCertificate(alias);

        return certificate;
    }

公钥验证

   public static boolean verify(byte[] data, byte[] sign,
                                 String certificatePath) throws Exception {
        // 获得证书
        X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);
        // 获得公钥
        PublicKey publicKey = x509Certificate.getPublicKey();
        // 构建签名
        Signature signature = Signature.getInstance(x509Certificate
                .getSigAlgName());
        signature.initVerify(publicKey);
        signature.update(data);

        return signature.verify((sign));

    }
    private static Certificate getCertificate(String certificatePath)
            throws Exception {
        CertificateFactory certificateFactory = CertificateFactory
                .getInstance(X509);
        FileInputStream in = new FileInputStream(certificatePath);

        Certificate certificate = certificateFactory.generateCertificate(in);
        in.close();

        return certificate;
    }

小结

本文讲述了利用公钥和私钥对通信过程的数据进行非对称加密。而在实际应用过程中,由于非对称加密比对称加密更加费CPU,因此,通常都是非对称加密与对称加密相结合。即对称加密使用的密钥通过非对称加密来传递。对于交换密钥,另一个算法叫DH和他的优化算法Oakley,专门用来处理这类任务,有兴趣的同学可以下去了解下。

加密的目的是为了提高破解门槛,要记住一句话,世界没有绝对安全,只有更加安全。

扩展,关于Key的序列化问题

通常,我们的Key是以byte[]的形式进行交换,因此,我们需要把PublicKey/PrivateKey的对象转换为byte[].
在Key的方法有一个getEncoded()能够将其转为byte[].

        byte[] dataprivate = privateKey.getEncoded();
        byte[] datapublic = publicKey.getEncoded();

在恢复时,则需要分别处理。
对于私钥,我们有

        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(dataprivate);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey1 = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

对于公钥,我们有

    X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(datapublic);
    keyFactory = KeyFactory.getInstance("RSA");
    PublicKey publicKey1 = keyFactory.generatePublic(x509EncodedKeySpec);

参考文章:

参考书目:Java加密与解密的艺术

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值