RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。1973年,在英国政府通讯总部工作的数学家克利福德·柯克斯(Clifford Cocks)在一个内部文件中提出了一个相同的算法,但他的发现被列入机密,一直到1997年才被发表。对极大整数做因数分解的难度决定了RSA算法的可靠性。换言之,对一极大整数做因数分解愈困难,RSA算法愈可靠。假如有人找到一种快速因数分解的算法的话,那么用RSA加密的信息的可靠性就肯定会极度下降。但找到这样的算法的可能性是非常小的。今天只有短的RSA钥匙才可能被强力方式解破。到目前为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。
代码实现(Java)
package top.sencom.sencq.utils.encrypt;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
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 javax.crypto.Cipher;
/*
*
*由于RSA加密解密速度过慢,所以应当使用RSA来加密传输AES密钥,此后通信双方都使用AES。
*
* */
public class RSAEncrypt {
//生成密钥对
public static void genKeyPair() throws NoSuchAlgorithmException{
//KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
// 初始化密钥对生成器,密钥大小为96-1024位
keyPairGen.initialize(1024,new SecureRandom());
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到私钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 得到公钥
String publicKeyString = new String(java.util.Base64.getEncoder().encode((publicKey.getEncoded())));
// 得到私钥字符串
String privateKeyString = new String(java.util.Base64.getEncoder().encode((privateKey.getEncoded())));
// 得到公钥字符串
System.out.println(publicKeyString);
System.out.println(privateKeyString);
}
//RSA公钥加密
public static String encrypt( byte[] str, String publicKey ) throws Exception{
//base64编码的公钥
byte[] decoded = java.util.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);
String outStr = new String(java.util.Base64.getEncoder().encode(cipher.doFinal(str)));
//String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
return outStr;
}
//RSA私钥解密
public static String decrypt(byte[] str, String privateKey) throws Exception{
//BASE64解码加密后的字符串
byte[] inputByte = java.util.Base64.getDecoder().decode((str));
//BASE64解码私钥
byte[] decoded = java.util.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);
String outStr = new String(cipher.doFinal(inputByte));
return outStr;
}
public static void main(String[] args) throws Exception {
//生成RSA密钥对
//RSAEncrypt.genKeyPair();
String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCuIygC5H6eiZOkxJO5sHJXmxZ2hFe5BiarBPuXS4a4maFP7gSi7UUlTXsC06/vkuiREbqJ7ifHjRJopTTEm6bsWCXGqR4gjfNXviaaYwp5mfw2kdB0+5vVNDRWG6hlF1nQCJ2xlirgf0l1BKCv5vVGFfp+2ZxVwR+6T6GOtigwewIDAQAB";
String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAK4jKALkfp6Jk6TEk7mwclebFnaEV7kGJqsE+5dLhriZoU/uBKLtRSVNewLTr++S6JERuonuJ8eNEmilNMSbpuxYJcapHiCN81e+JppjCnmZ/DaR0HT7m9U0NFYbqGUXWdAInbGWKuB/SXUEoK/m9UYV+n7ZnFXBH7pPoY62KDB7AgMBAAECgYEAnKdZ3khKNDsVzFtffePi6TbGnXXvKK8E6EMCRpgWKUlj2fEI0L1cv/MU33UqR/7EI4VsZ5sMxDL/xY4hi2FvZpwF54gJzwia7bunsLSogi2g7qWFoJmfGH+uhoLvxZw/S2mKz67XjJ2bfl6zp/NaeF+QOvVYpY9jA/H3elkj+CECQQD4LzE8Wd0rO5v/Zs8B5wnIgMfL61g+xeCmAUeRTbvMG+J1Aq5M4xhe3EN53a+ReKa13a7zs896cjJLrScC504RAkEAs58DYIHd/GmbpTqCur33Qgnw2CyZ0QPZ7RELPiTVazI5G+Q7xlZr5hXAXy3yEMrN2ohN1dFpYzvRVSscRSO5ywJAU2ZQbk5ocynB306mC6ae9ADKoyz/54BJYJ+XdC2iCRHpxJZVCkNaIi50glRLtl/L7duD+iMXerc7TZDvRhuCcQJAONL8YYKUNK9AUzRAeU1xtI2qiOkLPEmInuv+b4l9ju0TjhRVKLjcZ6zH8BR7+P3/w7vNS/B087TP067Qwbq8owJAMcfHIRsjA5Vp2H0ZY5wUCTMWmTV+OB7xRgd1WmBUiMLmOkvrTe1l9LorGk4e/lhd64q27pTP35V+LV2nP9UOJg==";
String ciphertext = RSAEncrypt.encrypt("你好".getBytes("UTF-8"),publicKey);
System.out.println(ciphertext);
String plaintext = RSAEncrypt.decrypt(ciphertext.getBytes("UTF-8"), privateKey);
System.out.println(plaintext);
}
}
高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。
代码实现(Java)
package top.sencom.sencq.utils.encrypt;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
/**
* @version V1.0
* @desc AES 加密
*/
public class AESEncrypt {
private static final String KEY_ALGORITHM = "AES";
private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";//默认的加密算法
/**
* AES 加密操作
*
* @param content 待加密内容
* @param password 加密密码
* @return 返回Base64转码后的加密数据
*/
public static String encrypt(String content, String password) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);// 创建密码器
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));// 初始化为加密模式的密码器
byte[] result = cipher.doFinal(byteContent);// 加密
return Base64.encodeBase64String(result);//通过Base64转码返回
} catch (Exception ex) {
Logger.getLogger(AESEncrypt.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
/**
* AES 解密操作
*
* @param content
* @param password
* @return
*/
public static String decrypt(String content, String password) {
try {
//实例化
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
//使用密钥初始化,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password));
//执行操作
byte[] result = cipher.doFinal(Base64.decodeBase64(content));
return new String(result, "utf-8");
} catch (Exception ex) {
Logger.getLogger(AESEncrypt.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
/**
* 生成加密秘钥
*
* @return
*/
private static SecretKeySpec getSecretKey(final String password) {
//返回生成指定算法密钥生成器的 KeyGenerator 对象
KeyGenerator kg = null;
try {
kg = KeyGenerator.getInstance(KEY_ALGORITHM);
//AES 要求密钥长度为 128
kg.init(128, new SecureRandom(password.getBytes()));
//生成一个密钥
SecretKey secretKey = kg.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);// 转换为AES专用密钥
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(AESEncrypt.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
//测试
public static void main(String[] args) {
int radnum = (int)(1+Math.random()*(10000000-1+1));
String key = String.valueOf(radnum);
System.out.println(key);
String s = "hello,你好!";
System.out.println("s:" + s);
String s1 = AESEncrypt.encrypt(s, key);
System.out.println("s1:" + s1);
System.out.println("s2:"+AESEncrypt.decrypt(s1, key));
}
}
补充
6.1:对于上述的AES加密在windows环境测试工作正常;但搬到Linux生产环境就会报如下错误
javax.crypto.BadPaddingException:Given final block not properly padded
问题出在这里:
private static SecretKeySpec getSecretKey(final String password) {
//返回生成指定算法密钥生成器的 KeyGenerator 对象
KeyGenerator kg = null;
try {
kg = KeyGenerator.getInstance(KEY_ALGORITHM);
//AES 要求密钥长度为 128
kg.init(128, new SecureRandom(password.getBytes()));
//生成一个密钥
SecretKey secretKey = kg.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);// 转换为AES专用密钥
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(AESEncrypt.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
修改为:
private static SecretKeySpec getSecretKey(final String password) {
//返回生成指定算法密钥生成器的 KeyGenerator 对象
KeyGenerator kg = null;
try {
kg = KeyGenerator.getInstance(KEY_ALGORITHM);
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(secretKey.getBytes());
//AES 要求密钥长度为 128
kg.init(128, secureRandom);
//生成一个密钥
SecretKey secretKey = kg.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);// 转换为AES专用密钥
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(AESEncrypt.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
原因:SecureRandom 实现完全随操作系统本身的內部状态,除非调用方在调用 getInstance 方法,然后调用 setSeed 方法;该实现在 windows 上每次生成的 key 都相同,但是在 solaris 或部分 linux 系统上则不同。关于SecureRandom类的详细介绍,见 http://yangzb.iteye.com/blog/325264