条理清晰的入门:使用Java实现RSA加密解密

什么是RSA

翻一下以前的密码学笔记,找到了!

虽然字很潦草,但还是依稀可辨。简单的说就是基于大数分解的困难性,造就了RSA的难破解性。不想打字, l a t e x latex latex 太麻烦了。

使用Java

Java Doc里面有很多有用的东西,想详细了解可以直接看文档。可以直接在线看,也可以下载到本地看

需要导入的头文件

如果你要直接复制粘贴,那么会有很多错误,懒得一个个点击导入就直接复制导入吧。

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.UUID;
import javax.crypto.Cipher;

生成公钥、私钥

/* 生成公私钥 */
KeyPairGenerator keyPairGenerator = null;
try {
	keyPairGenerator = KeyPairGenerator.getInstance("RSA"); //NoSuchAlgorithmException
} catch (Exception e) {
	e.printStackTrace();
}
keyPairGenerator.initialize(2048); // 此处可以添加参数new SecureRandom(UUID.randomUUID().toString().getBytes())
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate();

上面几行代码已经产生了可以直接使用的公钥、私钥了。

进行加密解密

好了,有了密钥之后怎么进行加密、解密呢?以下为:

  1. 私钥加密 公钥解密
  2. 公钥加密 私钥解密
        /* 私钥加密 公钥解密 */
	try {
		Cipher cipher = Cipher.getInstance("RSA"); //NoSuchPaddingException
		cipher.init(Cipher.ENCRYPT_MODE,rsaPrivateKey); //InvalidKeyException
		byte[] b = cipher.doFinal("12345678".getBytes()); //BadPaddingException
		System.out.println(new String(b));

		cipher.init(Cipher.DECRYPT_MODE,rsaPublicKey);
		b = cipher.doFinal(b);
		System.out.println(new String(b));
	}catch (Exception e) {
		e.printStackTrace();
	}
        
        /* 公钥加密 私钥解密 */
	try {
		Cipher cipher = Cipher.getInstance("RSA"); //NoSuchPaddingException
		cipher.init(Cipher.ENCRYPT_MODE,rsaPublicKey); //InvalidKeyException
		byte[] b = cipher.doFinal("12345678".getBytes()); //BadPaddingException
		System.out.println(new String(b));
        	
		cipher.init(Cipher.DECRYPT_MODE,rsaPrivateKey);
		b = cipher.doFinal(b);
		System.out.println(new String(b));
	}catch (Exception e) {
		e.printStackTrace();
	}

这里需要注意的是,根据密钥位数不同,一次可被加密的长度也是不同的,在上面使用了2048的加密位数,那么一次加密只能256字节。
可能会看到有的加密长度是 “2048/8 - 11 ”,那么这个“ - 11 ”是什么意思呢?我们知道明文过长需要进行分组( padding ),既然要分组,就必然有分组标准:RSA_PKCS1_PADDING、RSA_PKCS1_OAEP_PADDING、RSA_NO_PADDING。而“ - 11 ”就是第一个标准的填充方式,详细了解就网上搜索吧。

        /* 根据长度判断是否需要分组 */
        System.out.println(rsaPrivateKey.getModulus().bitLength() / 8);
        System.out.println(rsaPublicKey.getModulus().bitLength() / 8);

密钥的存储

存储必然是使用文件来存储的,查询文档,发现密钥可以转化为字节,同时字节也能转化回密钥。到这里发现问题很简单了。
但是这里要注意的是,转化为字节存储到文件是简单的,但是从文件读取到字节( byte []),一次读取可能不能读取完整整个文件,需要多次读取,那么多次读取的字节放到哪里呢,在这里我使用了将读取的字节转换为字符串( String ),进行拼接之后再还原回字节。
那么问题就出现了,字节转到到字符串再转化回来,这个过程其实是会出现问题的,如图可以看到byte []原长度和转化后的长度是不一样的。这里的解决方式是,将字节进行Base64编码再转为字符串,转回的时候则进行相应的Base64解码操作。

        /* 公私钥与字符串的转换 */
try {
	Base64.Decoder decoder = Base64.getDecoder();
	Base64.Encoder encoder = Base64.getEncoder();
	String publicKeyString = encoder.encodeToString(rsaPublicKey.getEncoded());
	String privateKeyString = encoder.encodeToString(rsaPrivateKey.getEncoded());
	System.out.println(publicKeyString);
	System.out.println(privateKeyString);
	KeyFactory keyFactory = KeyFactory.getInstance("RSA"); //NoSuchAlgorithmException
 
	byte[] keyBytes = decoder.decode(publicKeyString);
	X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
	keyFactory.generatePublic(x509EncodedKeySpec); //InvalidKeySepcException

	keyBytes = decoder.decode(privateKeyString);
	PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
	keyFactory.generatePrivate(pkcs8EncodedKeySpec); //InvalidKeySepcException
} catch (Exception e) {
	e.printStackTrace();
}

以上代码只进行了到字符串的转换,如果需要存储到文件中,那么只需要

FileOutputStream fos = new FileOutputStream("C:\\Users\\XXX\\Desktop\\private");
fos.write(encoder.encodeToString(rsaPrivateKey.getEncoded()).getBytes());

密文的存储、读取

看到密钥的存储需要进行Base64的编码解码,那么不禁想,密文是不是也同样需要呢?
答案是可以需要,也可以不需要。
既然要对密文进行解密,那么私钥或者公钥是一定已经有的,在获取密钥之后,我们可以计算出每段加密完成之后密文的字节数,每次按照这个字节数进行文件的读取,读取后直接解密成字符串即可。

/* 写入 */
FileOutputStream fospass = new FileOutputStream("C:\\Users\\XXX\\Desktop\\password");
byte [] buffer = new byte[256];
b = cipher.doFinal( (“XXX" + "\r\n\r\n").getBytes());
fospass.write(b);
fospass.close();

/* 读取 */
FileInputStream fis = new FileInputStream("..\\password");
byte [] buffer = new byte[256];
fis.read(buffer);
fis.close();
s = new String(cipher.doFinal(buffer));

OK,到这里使用Java进行RSA加密、解密的整个流程就很清楚了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值