您的位置 首页 java

非对称加密下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[] key bytes = 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>

“`

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

## 总结

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

## 关于我自己

这些技巧和总结都是来自于实际的工作,欢迎大家反馈和提出自己的意见。

文章也会同步发在CSDN的个人博客上,木小鱼的笔记()。

文章来源:智云一二三科技

文章标题:非对称加密下RSA在Java的简明教程

文章地址:https://www.zhihuclub.com/186838.shtml

关于作者: 智云科技

热门文章

网站地图