RSA加密解密的使用

/ 技术 / 无站内评论 / 372浏览

什么是RSA?

RSA算法是现今使用最广泛的公钥密码算法,也是号称地球上最安全的加密算法。在了解RSA算法之前,先熟悉下几个术语 
根据密钥的使用方法,可以将密码分为对称密码和公钥密码 
对称密码:加密和解密使用同一种密钥的方式 
公钥密码:加密和解密使用不同的密码的方式,因此公钥密码通常也称为非对称密码。

一、公钥加密
假设一下,我找了两个数字,一个是1,一个是2。我喜欢2这个数字,就保留起来,不告诉你们(私钥),然后我告诉大家,1是我的公钥。

我有一个文件,不能让别人看,我就用1加密了。别人找到了这个文件,但是他不知道2就是解密的私钥啊,所以他解不开,只有我可以用
数字2,就是我的私钥,来解密。这样我就可以保护数据了。

我的好朋友x用我的公钥1加密了字符a,加密后成了b,放在网上。别人偷到了这个文件,但是别人解不开,因为别人不知道2就是我的私钥,
只有我才能解密,解密后就得到a。这样,我们就可以传送加密的数据了。

二、私钥签名
如果我用私钥加密一段数据(当然只有我可以用私钥加密,因为只有我知道2是我的私钥),结果所有的人都看到我的内容了,因为他们都知
道我的公钥是1,那么这种加密有什么用处呢?

但是我的好朋友x说有人冒充我给他发信。怎么办呢?我把我要发的信,内容是c,用我的私钥2,加密,加密后的内容是d,发给x,再告诉他
解密看是不是c。他用我的公钥1解密,发现果然是c。
这个时候,他会想到,能够用我的公钥解密的数据,必然是用我的私钥加的密。只有我知道我得私钥,因此他就可以确认确实是我发的东西。
这样我们就能确认发送方身份了。这个过程叫做数字签名。当然具体的过程要稍微复杂一些。用私钥来加密数据,用途就是数字签名

总结:公钥和私钥是成对的,它们互相解密。

公钥加密,私钥解密。

私钥数字签名,公钥验证。

举例

比如有两个用户Alice和Bob,Alice想把一段明文通过双钥加密的技术发送给Bob,Bob有一对公钥和私钥,那么加密解密的过程如下:

  1. Bob将他的公开密钥传送给Alice。
  2. Alice用Bob的公开密钥加密她的消息,然后传送给Bob。
  3. Bob用他的私人密钥解密Alice的消息。

  上面的过程可以用下图表示,Alice使用Bob的公钥进行加密,Bob用自己的私钥进行解密。


例子和图出自《网络安全基础 应用与标准第二版》

工具类

import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RSACryptography {

public static String data = "hello world";
public static String publicKeyString = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCISLP98M/56HexX/9FDM8iuIEQozy6kn2JMcbZS5/BhJ+U4PZIChJfggYlWnd8NWn4BYr2kxxyO8Qgvc8rpRZCkN0OSLqLgZGmNvoSlDw80UXq90ZsVHDTOHuSFHw8Bv//B4evUNJBB8g9tpVxr6P5EJ6FMoR/kY2dVFQCQM4+5QIDAQAB";
public static String privateKeyString = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAIhIs/3wz/nod7Ff/0UMzyK4gRCjPLqSfYkxxtlLn8GEn5Tg9kgKEl+CBiVad3w1afgFivaTHHI7xCC9zyulFkKQ3Q5IuouBkaY2+hKUPDzRRer3RmxUcNM4e5IUfDwG//8Hh69Q0kEHyD22lXGvo/kQnoUyhH+RjZ1UVAJAzj7lAgMBAAECgYAVh26vsggY0Yl/Asw/qztZn837w93HF3cvYiaokxLErl/LVBJz5OtsHQ09f2IaxBFedfmy5CB9R0W/aly851JxrI8WAkx2W2FNllzhha01fmlNlOSumoiRF++JcbsAjDcrcIiR8eSVNuB6ymBCrx/FqhdX3+t/VUbSAFXYT9tsgQJBALsHurnovZS1qjCTl6pkNS0V5qio88SzYP7lzgq0eYGlvfupdlLX8/MrSdi4DherMTcutUcaTzgQU20uAI0EMyECQQC6il1Kdkw8Peeb0JZMHbs+cMCsbGATiAt4pfo1b/i9/BO0QnRgDqYcjt3J9Ux22dPYbDpDtMjMRNrAKFb4BJdFAkBMrdWTZOVc88IL2mcC98SJcII5wdL3YSeyOZto7icmzUH/zLFzM5CTsLq8/HDiqVArNJ4jwZia/q6Fg6e8KO2hAkB0EK1VLF/ox7e5GkK533Hmuu8XGWN6I5bHnbYd06qYQyTbbtHMBrFSaY4UH91Qwd3u9gAWqoCZoGnfT/o03V5lAkBqq8jZd2lHifey+9cf1hsHD5WQbjJKPPIb57CK08hn7vUlX5ePJ02Q8AhdZKETaW+EsqJWpNgsu5wPqsy2UynO";

public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub

//获取公钥
PublicKey publicKey = getPublicKey(publicKeyString);
//获取私钥
PrivateKey privateKey = getPrivateKey(privateKeyString);
//公钥加密
byte[] encryptedBytes = encrypt(data.getBytes(), publicKey);
System.out.println("加密后:" + new String(encryptedBytes));
//私钥解密
byte[] decryptedBytes = decrypt(encryptedBytes, privateKey);
System.out.println("解密后:" + new String(decryptedBytes));
}

//base64编码后的公钥字符串转成PublicKey实例
public static PublicKey getPublicKey(String publicKey) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(publicKey.getBytes());
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(keySpec);
}

//base64编码后的私钥字符串转成PrivateKey实例
public static PrivateKey getPrivateKey(String privateKey) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(privateKey.getBytes());
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(keySpec);
}

//公钥加密
public static byte[] encrypt(byte[] content, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");//java默认"RSA"="RSA/ECB/PKCS1Padding"
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(content);
}

//私钥解密
public static byte[] decrypt(byte[] content, PrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(content);
}

上面的工具类代码也是我精挑细选的哦~!

注意:这里的公钥与密钥都是成对的。

RSA公钥加密

得到公钥

        PublicKey publicKey = getPublicKey(publicKeyString);

根据公钥加密

data是我们就是加密的数据,比如:hello world

        byte[] encryptedBytes = encrypt(data.getBytes(), publicKey);

输出结果

加密后:5��t� p'��$�:��Ͽ��S�`h�,�P]���Oo@+c��gE���%S�p�JF�+6?d P��g����PW��Q�E�o�U0o?��G�p|��d�Y��q�� ���|���4Mp

RSA密钥解密

得到私钥

        PrivateKey privateKey = getPrivateKey(privateKeyString);

根据密钥解密

注意第一个参数是通过公钥加密的字节数组

        byte[] decryptedBytes = decrypt(data.getBytes(), privateKey);

输出结果

解密后:hello world

生成密钥对

工具类里面的公钥与密钥是我们提前生成写死的去使用,如果需要每次都不一样呢?

我们可以根据工具类的实现来反推出来。

代码

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;

public class generate {
public static void main(String[] args) throws Exception {
//初始化密钥对生成器RSA算法
KeyPairGenerator rsa = KeyPairGenerator.getInstance("RSA");
//生成密钥对长度 1024位 位数越长越安全,但是对CPU加密解密耗时更长
rsa.initialize(1024);

KeyPair pair = rsa.generateKeyPair();

//得到密钥
PrivateKey pairPrivate = pair.getPrivate();
//得到公钥
PublicKey pairPublic = pair.getPublic();
//得到密钥字节数组
byte[] privateEncoded = pairPrivate.getEncoded();
//得到公钥字节数组
byte[] publicEncoded = pairPublic.getEncoded();

//使用Base64加密得到我们的最终密钥&公钥字符串
String pri = new String(Base64.getEncoder().encode(privateEncoded));
String pul = new String(Base64.getEncoder().encode(publicEncoded));
System.out.println("公钥:"+ pul);
System.out.println("密钥:"+ pri);

//通过公钥字符串得到公钥实例
PublicKey publicKey = RSACryptography.getPublicKey(pul);
//通过密钥字符串得到密钥字实例
PrivateKey privateKey = RSACryptography.getPrivateKey(pri);

//公钥加密
byte[] encrypt = RSACryptography.encrypt("hello world".getBytes(), publicKey);
//密钥解密
byte[] decrypt = RSACryptography.decrypt(encrypt, privateKey);

System.out.println("公钥加密结果:"+new String(encrypt));
System.out.println("私钥解密结果:"+new String(decrypt));

}
}

输出结果


召唤蕾姆
琼ICP备18000156号

鄂公网安备 42011502000211号