AES、RSA加密解密方法实现

摘要:AES、RSA加密解密方法在Java和JavaScript中的实现代码

1. AES加密解密(Java)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

import lombok.extern.slf4j.Slf4j;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
* @author duqian
*/
@Slf4j
public class AESEncryptUtils {
/**
* AES加密
*
* @param input 明文
* @param keyString 密钥,16位英文+数字
* @param ivString 偏移量,16位英文+数字
* @return
*/
public static String encrypt(String input, String keyString, String ivString) {
try {
SecretKey key = new SecretKeySpec(keyString.getBytes(StandardCharsets.UTF_8), "AES");
IvParameterSpec iv = new IvParameterSpec(ivString.getBytes(StandardCharsets.UTF_8));

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] cipherText = cipher.doFinal(input.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(cipherText);
} catch (InvalidAlgorithmParameterException | NoSuchPaddingException | IllegalBlockSizeException |
NoSuchAlgorithmException | BadPaddingException | InvalidKeyException e) {
throw new RuntimeException(e);
}
}

/**
* AES解密
*
* @param cipherText 密文
* @param keyString 密钥,16位英文+数字
* @param ivString 偏移量,16位英文+数字
* @return
*/
public static String decrypt(String cipherText, String keyString, String ivString) {
try {
SecretKey key = new SecretKeySpec(keyString.getBytes(StandardCharsets.UTF_8), "AES");
IvParameterSpec iv = new IvParameterSpec(ivString.getBytes(StandardCharsets.UTF_8));

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, iv);
byte[] plainText = cipher.doFinal(Base64.getDecoder().decode(cipherText));
return new String(plainText, StandardCharsets.UTF_8);
} catch (InvalidAlgorithmParameterException | NoSuchPaddingException | IllegalBlockSizeException |
NoSuchAlgorithmException | BadPaddingException | InvalidKeyException e) {
throw new RuntimeException(e);
}
}


public static void main(String[] args) {
// 密钥-16位字符串形式
String keyString = "1234EFghiJklmn56";
// 偏移量-16位字符串形式
String ivString = "abcdEFG890123456";
// 明文字符串
String plainText = "阿斯蒂芬中文www.baeldung.com符号!@#%……)(*&… …%-——+=)(&^%$#/*-\\|123a阿斯蒂芬";
log.info("plainText:\t\t\t\t{}", plainText);
// 加密
String cipherText = AESEncryptUtils.encrypt(plainText, keyString, ivString);
log.info("cipherText:\t\t\t{}", cipherText);
// 解密
String decryptedCipherText = AESEncryptUtils.decrypt(cipherText, keyString, ivString);
log.info("decryptedCipherText:\t{}", decryptedCipherText);
}

}

2. AES加密解密(JavaScript)

安装依赖

1
npm install crypto-js

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
* AES加密
* @param word 需要加密的字符
* @param key 秘钥
* @param iv 偏移量
*/
function aesEncrypt(word, key, iv) {
const _word = CryptoJS.enc.Utf8.parse(word);
const _key = CryptoJS.enc.Utf8.parse(key);
const _iv = CryptoJS.enc.Utf8.parse(iv);
const encrypted = CryptoJS.AES.encrypt(_word, _key, {
iv: _iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
}

/**
* AES解密
* @param word 需要解密的字符
* @param key 秘钥
* @param iv 偏移量
*/
function aesDecrypt(word, key, iv) {
const _word = {ciphertext: CryptoJS.enc.Base64.parse(word)};
const _key = CryptoJS.enc.Utf8.parse(key);
const _iv = CryptoJS.enc.Utf8.parse(iv);
const decrypted = CryptoJS.AES.decrypt(_word, _key, {
iv: _iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return decrypted.toString(CryptoJS.enc.Utf8);
}

function aesMain() {
const key = '1234EFghiJklmn56';
const iv = 'abcdEFG890123456';

const text = "阿什顿发asdfa1231@#$%^&*(阿道夫(*……%¥%……&asd安抚";
console.log('[AES]明文: ' + text);

const encrypted = aesEncrypt(text, key, iv);
console.log('[AES]密文: ' + encrypted);

const decrypted = aesDecrypt(encrypted, key, iv);
console.log('[AES]解密: ' + decrypted);

}

aesMain();

3. RSA密钥生成(Linux命令行)

详见:https://www.jianshu.com/p/c93a993f8997

生成私钥(PKCS#1)

1
openssl genrsa -out private_key.pem 1024

提取公钥

1
openssl rsa -pubout -in private_key.pem -out public_key.pem

RSA私钥格式转换(PKCS#1 ==> PKCS#8)

1
openssl pkcs8 -topk8 -inform PEM -in private_key.pem -outform PEM -out private_key_pkcs8.pem -nocrypt

4. RSA加密解密(Java)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144

import lombok.extern.slf4j.Slf4j;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
* @author duqian
* <p>
* 命令行生成RSA密钥
* <p>
* 生成私钥(PKCS#1):
* openssl genrsa -out private_key.pem 1024
* <p>
* 提取公钥:
* openssl rsa -pubout -in private_key.pem -out public_key.pem
* <p>
* RSA私钥格式转换(PKCS#1 ==> PKCS#8):
* openssl pkcs8 -topk8 -inform PEM -in private_key.pem -outform PEM -out private_key_pkcs8.pem -nocrypt
*/
@Slf4j
public class RSAEncryptUtils {

/**
* RSA公钥加密
*
* @param str 加密字符串
* @param publicKey 公钥
* @return 密文
*/
public static String encrypt(String str, String publicKey) {
try {
// base64编码的公钥
byte[] decoded = Base64.getDecoder().decode(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
// RSA加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherText = cipher.doFinal(str.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(cipherText);
} catch (IndexOutOfBoundsException | NoSuchPaddingException | IllegalBlockSizeException |
InvalidKeySpecException | NoSuchAlgorithmException | BadPaddingException | InvalidKeyException e) {
throw new RuntimeException(e);
}
}

/**
* RSA私钥解密
*
* @param str 加密字符串
* @param privateKey 私钥
* @return 明文
*/
public static String decrypt(String str, String privateKey) {
try {
// base64编码的私钥
byte[] decoded = Base64.getDecoder().decode(privateKey);
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
// RSA解密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, priKey);
byte[] plainText = cipher.doFinal(Base64.getDecoder().decode(str));
return new String(plainText, StandardCharsets.UTF_8);
} catch (IndexOutOfBoundsException | NoSuchPaddingException | IllegalBlockSizeException |
InvalidKeySpecException | NoSuchAlgorithmException | BadPaddingException | InvalidKeyException e) {
throw new RuntimeException(e);
}
}


/**
* 随机生成密钥对
*
* @throws NoSuchAlgorithmException
*/
public static String[] genKeyPair() throws NoSuchAlgorithmException {
// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
// 初始化密钥对生成器
keyPairGen.initialize(1024);
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
// 得到私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// 得到公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

String publicKeyString = new String(Base64.getEncoder().encode(publicKey.getEncoded()));
// 得到私钥字符串
String privateKeyString = new String(Base64.getEncoder().encode((privateKey.getEncoded())));
// 将公钥和私钥保存到数组,0表示公钥,1表示私钥
return new String[]{publicKeyString, privateKeyString};
}

public static void main(String[] args) throws Exception {
// 生成公钥和私钥
// String[] keyPair = genKeyPair();
// String pubKey = keyPair[0];
// String priKey = keyPair[1];
// log.info("随机生成的公钥为: {}", pubKey);
// log.info("随机生成的私钥为: {}", priKey);

// 使用已生成的公钥和私钥,需要为PCKS#8格式,不要换行符\n
String pubKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCYahMu3WfdCHyyReESS9dP737U" +
"ZeVsdLHofO7X8oKpM1QN2rk+mJKRgY58D5RS/UVAVWvHRH9E5hK8SWpiLRdbcWRP" +
"bTYWO7EXokLN78QJXNfcA5HDnMBEaGi0FQp0cnY4DhlHcoov9luZzGWrnF6FJ6zV" +
"aBY3fSnd0rpcifbtTwIDAQAB";
String priKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJhqEy7dZ90IfLJF" +
"4RJL10/vftRl5Wx0seh87tfygqkzVA3auT6YkpGBjnwPlFL9RUBVa8dEf0TmErxJ" +
"amItF1txZE9tNhY7sReiQs3vxAlc19wDkcOcwERoaLQVCnRydjgOGUdyii/2W5nM" +
"ZaucXoUnrNVoFjd9Kd3SulyJ9u1PAgMBAAECgYBS0MBfpJo89dGbpHCpWmBB5OZL" +
"TpqclcPdiZTV7cWlXmh7pq8lHg311imvq19ywH+Sd1e6zLNCoqjnehS+B7Y6ePAJ" +
"747l/SsLG4LBNO/D1ofS/d6RJv9SLGoE/7Q8q4qi8AqSPjI273jL+F4Zy6cwqzNP" +
"UnMMrmzOsrmNLO2W0QJBAMi2vl0U28JmZnsCD7WzJfeuts0w7bYSE1JKKiHSc0Pn" +
"Ih2GCk8qEbmvhTiUhVBqhlDT500Q4WxVC8FDSrm8VwUCQQDCZYMl5F6iSlSghI8R" +
"uo6p4CMsRhIehWhJDyFAZ8BPXC8nYzbdJmzuEdZesJi/SUTbctBb9qmbCUNtd9Fl" +
"hjtDAkEApg3qeH/lQHQPnP0bmivY4Y1+V0x/nf5eVdpd+RVvn2H964cVyGD5wTHh" +
"eeoGUX2QGhb2ad/pYAMMcpwFmpyjMQJAWXO2xp/wgANuL7Lv1rue3EKcTMotmkfP" +
"Nhc1ONrFHn+P3zMDUv5Uj7Q7jbT7hMIlYknR4Q9++i1oDp5dB7ed2wJAevVQ5LSH" +
"5dNtsB8UE0vxiRXD0TYfSB2tcSIJ7TycB1GQFwdgqoouqRZ0SL5aV26xSDWvgCAz" +
"qcGTGRvZN6c1jg==";

// 加密字符串
String message = "撒旦法多少发df阿斯蒂芬%… … !@#¥%……&*()/*-!@#$%^&*()爱的色放820";
log.info("明文: {}", message);

String messageEn = encrypt(message, pubKey);
log.info("密文: {}", messageEn);

String messageDe = decrypt(messageEn, priKey);
log.info("解密: {}", messageDe);
}

}

5. RSA加密解密(JavaScript)

安装依赖

1
npm install jsencrypt

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
* RSA加密
* @param str 明文
* @param pubKey 公钥
* @returns {string | false}
*/
function rsaEncrypt(str, pubKey) {
const jsEncrypt = new JSEncrypt();
jsEncrypt.setPublicKey(pubKey);
return jsEncrypt.encrypt(str);
}

/**
* RSA解密
* @param str 密文
* @param priKey 私钥
* @returns {string | false}
*/
function rsaDecrypt(str, priKey) {
const jsEncrypt = new JSEncrypt();
jsEncrypt.setPrivateKey(priKey);
return jsEncrypt.decrypt(str);
}

function rsaMain() {
// 使用生成好的公钥和私钥,格式为PKCS#1或PKCS#8均可
const pubKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCYahMu3WfdCHyyReESS9dP737U' +
'ZeVsdLHofO7X8oKpM1QN2rk+mJKRgY58D5RS/UVAVWvHRH9E5hK8SWpiLRdbcWRP' +
'bTYWO7EXokLN78QJXNfcA5HDnMBEaGi0FQp0cnY4DhlHcoov9luZzGWrnF6FJ6zV' +
'aBY3fSnd0rpcifbtTwIDAQAB';
const priKey = 'MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJhqEy7dZ90IfLJF' +
'4RJL10/vftRl5Wx0seh87tfygqkzVA3auT6YkpGBjnwPlFL9RUBVa8dEf0TmErxJ' +
'amItF1txZE9tNhY7sReiQs3vxAlc19wDkcOcwERoaLQVCnRydjgOGUdyii/2W5nM' +
'ZaucXoUnrNVoFjd9Kd3SulyJ9u1PAgMBAAECgYBS0MBfpJo89dGbpHCpWmBB5OZL' +
'TpqclcPdiZTV7cWlXmh7pq8lHg311imvq19ywH+Sd1e6zLNCoqjnehS+B7Y6ePAJ' +
'747l/SsLG4LBNO/D1ofS/d6RJv9SLGoE/7Q8q4qi8AqSPjI273jL+F4Zy6cwqzNP' +
'UnMMrmzOsrmNLO2W0QJBAMi2vl0U28JmZnsCD7WzJfeuts0w7bYSE1JKKiHSc0Pn' +
'Ih2GCk8qEbmvhTiUhVBqhlDT500Q4WxVC8FDSrm8VwUCQQDCZYMl5F6iSlSghI8R' +
'uo6p4CMsRhIehWhJDyFAZ8BPXC8nYzbdJmzuEdZesJi/SUTbctBb9qmbCUNtd9Fl' +
'hjtDAkEApg3qeH/lQHQPnP0bmivY4Y1+V0x/nf5eVdpd+RVvn2H964cVyGD5wTHh' +
'eeoGUX2QGhb2ad/pYAMMcpwFmpyjMQJAWXO2xp/wgANuL7Lv1rue3EKcTMotmkfP' +
'Nhc1ONrFHn+P3zMDUv5Uj7Q7jbT7hMIlYknR4Q9++i1oDp5dB7ed2wJAevVQ5LSH' +
'5dNtsB8UE0vxiRXD0TYfSB2tcSIJ7TycB1GQFwdgqoouqRZ0SL5aV26xSDWvgCAz' +
'qcGTGRvZN6c1jg==';

const text = "阿什顿发asdfa1231@#$%^&*(阿道夫(*……%¥%……&asd安抚";
console.log('[RSA]明文: ' + text);

// 公钥加密
const encrypted = rsaEncrypt(text, pubKey);
console.log('[RSA]密文: ' + encrypted);

// 私钥解密
const decrypted = rsaDecrypt(encrypted, priKey);
console.log('[RSA]解密: ' + decrypted);
}

rsaMain();