RSA公钥私钥的简单实现

RSA算法是种能同时用于加密和数字签名的算法,也是被研究得最广泛的公钥算法。而公钥私钥的加密解密也会使一些小伙伴疑惑,这里稍微简单说一下,再简单地实现一下。

首先,公钥加密私钥可以解密。其次,私钥加密公钥可以解密。再深一步来说,公钥负责加密,私钥负责解密。私钥负责签名,公钥负责验证。公钥就是给大家用的,私钥就是给自己用的,必须小心保存。举个栗子,A想向B发送一条加密的信息,使用B的公钥加密,这样只有拥有对应私钥的B才能解密,确保了信息没有被别人看到,其次A可以用自己的私钥加密一条信息发送给B,B用A的公钥验证,因为只有A拥有私钥所以能证明此信息是A所发的。(如果A是在借钱B经过公钥验证后就知道是本人而不是骗子了)

RSAUtils

首先定义一些全局用的常量变量。

public static final int ENCRYPT_MODE = Cipher.ENCRYPT_MODE;

public static final int DECRYPT_MODE = Cipher.DECRYPT_MODE;
	
public static final Charset UTF8 = Charset.forName("UTF-8");
	
private static final String ALGORITHM = "RSA";
	
private Cipher cipher;
其次是调用公钥私钥的方法。

	private static Key getEncKey(String encKey){
		PublicKey publicKey = null;
		try {
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(encKey.getBytes(UTF8)));
			KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
			publicKey = keyFactory.generatePublic(keySpec);
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return publicKey;
	}
	
	private static Key getDecKey(String decKey){
		PrivateKey privateKey = null;
		try {
			PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(decKey.getBytes(UTF8)));
			KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
			privateKey = keyFactory.generatePrivate(keySpec);
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return privateKey;
	}
定义一下RSAUtils的init方法

	public boolean init(int mode, String key){
		//参数校验code
		try {
			cipher = Cipher.getInstance(ALGORITHM);
		} catch (NoSuchAlgorithmException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (NoSuchPaddingException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		Key secKey = null;
		//靠mode判断是加密还是解密
		if (mode == ENCRYPT_MODE) {
			secKey = getEncKey(key);
		}
		else if (mode == DECRYPT_MODE) {
			secKey = getDecKey(key);
		}
		if (secKey == null) {
			return false;
		}
		try {
			cipher.init(mode, secKey);
		} catch (InvalidKeyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
		return true;
	}
加解密的方法主体

	public String encrypt(String text){
		byte[] data = null;
		try {
			data = cipher.doFinal(text.getBytes(UTF8));
		} catch (IllegalBlockSizeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BadPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return new String(Base64.getEncoder().encode(data), UTF8);
	}
	
	public String decrypt(String text){
		byte[] data = null;
		try {
			data = cipher.doFinal(Base64.getDecoder().decode(text.getBytes(UTF8)));
		} catch (IllegalBlockSizeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BadPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return new String(data, UTF8);
	}

RSATest

测试代码

		String password = "HelloWorld!";
		RSAUtils rsaUtils = new RSAUtils();
		String enckey = pubkey;//公钥
		rsaUtils.init(Cipher.ENCRYPT_MODE, enckey);
		//得到密文
		String cipherText = rsaUtils.encrypt(password);
		System.out.println("cipherText: " + cipherText);
		String deckey = prikey;//私钥
		rsaUtils.init(Cipher.DECRYPT_MODE, deckey);
		//得到明文
		String plaintext = rsaUtils.decrypt(cipherText);
		System.out.println("plaintext: " + plaintext);
结果

cipherText: JF3tcjS2P552QJQQgu7mTTBS4NsW7pCZdbi3bKaDonyEqBXuRiM6Ctm4kSzw9fkb1dYciyOcS0I+KbS9sopGNTGjr9ExwB+/0OvNL9HPWlfG35NdQPK+0Vm4YD1oBrRap9EWGYyR6QC2vV4wesYOkXNn8gjosIew/4gSoMhL3E4=
plaintext: HelloWorld!

关于Base64
现在在Java 8中java.util包下面实现了Base64可以直接拿来用,本文用的也是java.util.Base64。Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。举个栗子,11111111, 11111111, 11111111 转换后 00111111, 00111111, 00111111, 00111111 (二进制)三个字节的是原文,四个字节的是转换后的Base64编码,其前两位均为0。再匹配Base64编码表得到对应的编码。

索引
对应字符
索引
对应字符
索引
对应字符
索引
对应字符
0
A
17
R
34
i
51
z
1
B
18
S
35
j
52
0
2
C
19
T
36
k
53
1
3
D
20
U
37
l
54
2
4
E
21
V
38
m
55
3
5
F
22
W
39
n
56
4
6
G
23
X
40
o
57
5
7
H
24
Y
41
p
58
6
8
I
25
Z
42
q
59
7
9
J
26
a
43
r
60
8
10
K
27
b
44
s
61
9
11
L
28
c
45
t
62
+
12
M
29
d
46
u
63
/
13
N
30
e
47
v
   
14
O
31
f
48
w
   
15
P
32
g
49
x
   
16
Q
33
h
50
y
   

二进制数据不可能每次都刚好平均地分为6位,这时候,就在数据末尾填充0,使二进制数据的长度成为24的倍数(6和8的最小公倍数)。末尾全部填充的就由"="表示。由于标准的Base64编码后可能出现字符+和/,这两个在URL中不能直接作为参数,这时候可以用UrlEncoder,可以把字符+和/分别变成-和_。

测试代码

		String encoded = null;
		try {
			encoded = Base64.getEncoder().encodeToString("Hello World!!!".getBytes("UTF-8"));
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(encoded);
		byte[] decoded = Base64.getDecoder().decode(encoded);
		try {
			System.out.println(new String(decoded, "UTF-8"));
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			encoded = Base64.getEncoder().encodeToString("He>lo?World!!!".getBytes("UTF-8"));
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(encoded);
		String urlEncoded = null;
		try {
			urlEncoded = Base64.getUrlEncoder().encodeToString("He>lo?World!!!".getBytes("UTF-8"));
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(urlEncoded);
结果

SGVsbG8gV29ybGQhISE=
Hello World!!!
SGU+bG8/V29ybGQhISE=
SGU-bG8_V29ybGQhISE=


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值