非对称加密下RSA在Java的简明教程

引言

在现实世界中,每个人都有自己的密码。在各种系统中都有各类加密和解密的需求。 本文将详细介绍一下RSA的前身后世,应用场景和在Java中的实现,从理论到实践,一步到位,触手可用。

非对称加密与对称加密

对称加密(Symmetric Cryptography)

对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key),这种方法在密码学中叫做对称加密算法。对称加密有很多种算法,由于它效率很高,所以被广泛使用在很多加密协议的核心当中。
关于对称加密的概念非常容易理解,在现实实际中应用广泛,具体的加密算法都是依赖于秘钥的长度和加解密所需的资源和时间,这里需要一个平衡的。
比如DES, 3DES, AES等等都属于对称加密算法。

非对称加密(Asymmetric Cryptography)

1976年,美国学者Dime和Henman为解决信息公开传送和密钥管理问题,提出一种新的密钥交换协议,允许在不安全的媒体上的通讯双方交换信息,安全地达成一致的密钥,这就是“公开密钥系统”。相对于“对称加密算法”这种方法也叫做“非对称加密算法”。
非对称加密为数据的加密与解密提供了一个非常安全的方法,它使用了一对密钥、公钥(public key)和私钥(private key)。私钥只能由一方安全保管,不能外泄。而公钥则可以发给任何请求它的人。非对称加密使用这对密钥中的一个进行加密,而解密则需要另一个密钥。比如,你向银行请求公钥,银行将公钥发给你,你使用公钥对消息加密,那么只有私钥的持有人–银行才能对你的消息解密。与对称加密不同的是,银行不需要将私钥通过网络发送出去,因此安全性大大提高。
公私钥体系很好地解决了陌生人通信中加密和解密的问题, 但是加密和解密速度比较慢,如果数据量比较大,则用其加解密不太现实,时间和资源所需都比较大。
非对称加密体系下的数据传输过程,可以参照下图:
这里写图片描述
在上图中,加密和解密分别使用不同的秘钥,从而很好地解决了秘钥传输的问题,不同的人可以使用不同的秘钥来加解密数据。 这里还有一个非常重要的概念是CA中心,Certificate Authority证书中心的概念。 由于公钥是可以被所有人任意获取的,公开使用的,证书之间也可以基于签名来建立一个信任的链条。从而针对证书建立起来一整套追踪和管理的体系。这里不再赘述这个内容,感兴趣的读者可以参照CA的证书体系获取更多信息。
这里写图片描述
在这幅图中,体现了CA的价值。CA主要是在商业系统中用以分发和管理证书的一套系统,默认情况下,也可以直接线下发送证书。这里仅仅是为大家普及一个CA概念。

RSA

在非对称加密算法中,存在着RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)等诸多算法,相比而言RSA是其中应用最为广泛的一种加密算法。
RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。1987年7月首次在美国公布,当时他们三人都在麻省理工学院工作实习。RSA就是他们三人姓氏开头字母拼在一起组成的。
RSA是目前最有影响力和最常用的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。今天只有短的RSA钥匙才可能被强力方式解破。到2008年为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。但在分布式计算和量子计算机理论日趋成熟的今天,RSA加密安全性受到了挑战和质疑。
RSA算法基于一个十分简单的数论事实:将两个大质数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
对于普通的开发者而言,对于这些信息仅需要了解即可,对于大家来说,了解其原理是为了更好地使用这些算法来服务于我们的系统。

RSA的应用场景(通信,签名和完整性)

通信加解密

由于非对称加密方法中存在加解密速度慢的问题,对于大的数据由于时间和资源的约束无法商业使用,则采取了这种的方法进行加密:
. 使用对称秘钥进行内容加密,比如DES之类的算法,速度快
. 使用非对称算法针对秘钥进行加密, 确保秘钥的安全
. 一事一秘, 每次通信可以采取动态的秘钥,每次都动态生成秘钥
目前来说,主流的通信机制都是采用这种方式,这个是原理上的方式,但不是实际商业上的方式,实际上的商业方式,相比这种方式会更复杂,具体的一种方式如下:

  • 通信双方A和B,各自持有一对公私钥对,且且持有对方的公钥
  • 基于公钥信息,加密通信认证信息,建立可信任连接
  • 在建立可信任连接之后,动态创建一套公私钥对C,在A和B之间共享
  • 使用动态生产呢个的公私钥对,来进行实际的通信。
    相比于原理上的非对称加密通信而言,实际中的通信机制往往会更复杂,考虑到强度和安全性的问题。

签名认证

除了加解密之外,还有在实际中广泛使用的签名认证。 签名证书的用途:加入有A用户向B用户发送了信息“A love you”,B接收到之后怎么确定就是A发送的呢(因为中间人攻击中,假如C截获了A发送的信息后,改成“C love you”,B是无法确定这两个信息的发送者,因他她们都同样用B的工要加密),于是产生了签名证书技术。
签名证书是由CA用自己的私钥对用户的信息进行加密,并把发给用户的,用户可以在发送信息的过程中附加上自己的签名证书,让接受者验证信息的来源。当接受者接受到发送者的签名证书后即可用ca的公钥解密验证发送者的身份信息。

RSA在Java的实现示例

主要的Java实现如下:

public class RSAUtil {
    public static final String RSA_ALGORITHM = "RSA";
        public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
    public static final Charset UTF8 = Charset.forName("UTF-8");

        /**
         *  入口的publicKey是基于Base64编码过的,需要解码
         *  data为实际的数据, sign:摘要信息
         */
        public static boolean verify(byte[] data, String publicKey, String sign)
            throws Exception {
        // 解密由base64编码的公钥
        byte[] keyBytes = base64Decode(publicKey);
        // 构造X509EncodedKeySpec对象
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        // KEY_ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        // 取公钥匙对象
        PublicKey pubKey = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(pubKey);
        signature.update(data);
        // 验证签名是否正常
        return signature.verify(base64Decode(sign));
    }

   /**
    *  基于字符数组,获取公钥信息。
    */
   public static PublicKey getPublicKey(byte[] publicKeyBytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(publicKeyBytes);
        RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(pubSpec);

        return publicKey;
    }
    /**
     *  基于字符数组获取privateKey私钥信息
     */
    public static PrivateKey getPrivatekey(byte[] privateKeyBytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory.generatePrivate(privSpec);

        return privateKey;
    }

        /**
         * 这里并未强制要求数据使用Base64进行编码或者解码操作,开发者自行决定。
         */
    public static byte[] encrypt(PrivateKey privateKey, byte[] bytes) throws Exception {
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);

        return cipher.doFinal(bytes);
    }
        /**
         * 这里并未强制要求数据使用Base64进行编码或者解码操作,开发者自行决定。
         */
    public static byte[] decrypt(PublicKey publicKey, byte[] encrypted) throws Exception {
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, publicKey);

        return cipher.doFinal(encrypted);
    }


    private static KeyPair buildKeyPair() throws NoSuchAlgorithmException {
        final int keySize = 2048;
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
        keyPairGenerator.initialize(keySize);
        return keyPairGenerator.genKeyPair();
    }

    /**
     * base64的编码
     */
    public static String base64Encode(byte[] data) {
        return new BASE64Encoder().encode(data);
    }
        /**
     * base64的解码
     */
    public static byte[] base64Decode(String data) throws IOException {
        return new BASE64Decoder().decodeBuffer(data);
    }
}
在上述的代码示例中,提供了加密和解密方法,但是都并未要求使用base64解码和编码实现,开发者可以自行决定是否使用,在外层方法嵌套或者将base64方法放入decrpt/encrpt方法之内实现。
在此实现中提供了verify方法用以验证sign是否正确,签名认证方法。
这里使用了JDK中rt.jar中内置的sun.misc中的Base64的编码和解码方法,如果不喜欢依赖于Oracle的JDK,可以选用Apache的codec包,在maven中配置如下依赖接口:
<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.11</version>
</dependency>

具体的使用方法,可以参考网上的相关资料。

总结

加解密的算法虽然其中涵盖了复杂的数据算法,但是使用起来还是非常简单方便的,只要了解其中的主要原理和应用场景,把握重要的算法关键点,即可满足我们的基本需求。

关于我自己

这些技巧和总结都是来自于实际的工作,欢迎大家反馈和提出自己的意见。
文章也会同步发在今日头条的头条号上,搜索 “程序加油站”,就可以找到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值