一 RSA简介
这种算法1978年就出现了,它是第一个既能用于数据加密也能用于数字签名的算法。它易于理解和操作,也很流行。算法的名字以发明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman。
这种加密算法的特点主要是密钥的变化,上文我们看到DES只有一个密钥。相当于只有一把钥匙,如果这把钥匙丢了,数据也就不安全了。RSA同时有两把钥匙,公钥与私钥。同时支持数字签名。数字签名的意义在于,对传输过来的数据进行校验。确保数据在传输工程中不被修改。
二 数字签名技术
数字签名技术是将摘要信息用发送者的私钥加密,与原文一起传送给接收者。接收者只有用发送者的公钥才能解密被加密的摘要信息,然后用HASH函数对收到的原文产生一个摘要信息,与解密的摘要信息对比。如果相同,则说明收到的信息是完整的,在传输过程中没有被修改,否则说明信息被修改过,因此数字签名能够验证信息的完整性。
数字签名是个加密的过程,数字签名验证是个解密的过程。
3、乙方使用公钥加密数据,向甲方发送经过加密后的数据;甲方获得加密数据,通过私钥解密。
流程图如下图所示:
注:如果要建立更安全的加密消息传递模型,需要消息发送方和消息接收方各构建一套密钥对,并分别将各自的公钥暴露给对方,在进行消息传递时,A通过B的公钥对数据加密,B接收到消息通过B的私钥进行解密,反之,B通过A的公钥进行加密,A接收到消息后通过A的私钥进行解密。
4、 一般我认为RSA加解密共有两种方案,一种是通信双方共用一套公私密钥(公钥双方共有,私钥发送者保持);一种是通信双方一人一套公司密钥(通信时互换双方的公钥,安全性比较高)。显然第一种方式安全性低一些,并且复杂度低;第二种方式安全性高,但是复杂度高。
RSA加解密算法还有两种不同的方式,一种是使用对称密钥(比如DES等加解密方法)加密数据,然后使用非对称密钥(RSA加解密密钥)加密对称密钥;另一种是直接使用非对称密钥加密数据。第一种方式安全性高,复杂度也高,不存在加密数据长度限制问题,第二种方式安全性差一些,复杂度低,但是存在加密数据限制问题(即使用非对称密钥加密数据时,一次加密的数据长度是(密钥长度/8-11))。
因为公司业务功能需求限制,我下面展示的是双方采用一套公私密钥,并且采用公司密钥加解密数据的方法,其中还添加了对数据分段加密的方法。
5、实际代码实现
RSA_Encrypt类
主要就是包涵:加密方法、解密方法、生成密钥对方法、生成签名方法、验证签名方法
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class RSA_Encrypt {
/** 指定加密算法为RSA */
private static String ALGORITHM = "RSA";
/** 指定key的大小 */
private static int KEYSIZE = 1024;
/** 指定公钥存放文件 */
private static String PUBLIC_KEY_FILE = "PublicKey";
/** 指定私钥存放文件 */
private static String PRIVATE_KEY_FILE = "PrivateKey";
public static final String KEY_ALGORITHM = "RSA";
public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
/**
* 生成密钥对
*/
public static void generateKeyPair() throws Exception {
/** RSA算法要求有一个可信任的随机数源 */
SecureRandom sr = new SecureRandom();
/** 为RSA算法创建一个KeyPairGenerator对象 */
KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGORITHM);
/** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
kpg.initialize(KEYSIZE, sr);
/** 生成密匙对 */
KeyPair kp = kpg.generateKeyPair();
/** 得到公钥 */
Key publicKey = kp.getPublic();
/** 得到私钥 */
Key privateKey = kp.getPrivate();
/** 用对象流将生成的密钥写入文件 */
ObjectOutputStream oos1 = new ObjectOutputStream(new FileOutputStream(PUBLIC_KEY_FILE));
ObjectOutputStream oos2 = new ObjectOutputStream(new FileOutputStream(PRIVATE_KEY_FILE));
oos1.writeObject(publicKey);
oos2.writeObject(privateKey);
/** 清空缓存,关闭文件输出流 */
oos1.close();
oos2.close();
}
/**
* 产生签名
* @param data
* @param privateKey
* @return
* @throws Exception
*/
public static String sign(byte[] data, String privateKey) throws Exception {
// 解密由base64编码的私钥
byte[] keyBytes = decryptBASE64(privateKey);
// 构造PKCS8EncodedKeySpec对象
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
// KEY_ALGORITHM 指定的加密算法
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 取私钥对象
PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
// 用私钥对信息生成数字签名
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(priKey);
signature.update(data);
return encryptBASE64(signature.sign());
}
/**
* 验证签名
* @param data
* @param publicKey
* @param sign
* @return
* @throws Exception
*/
public static boolean verify(byte[] data, String publicKey, String sign)
throws Exception {
// 解密由base64编码的公钥
byte[] keyBytes = decryptBASE64(publicKey);
// 构造X509EncodedKeySpec对象
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
// KEY_ALGORITHM 指定的加密算法
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 取公钥匙对象
PublicKey pubKey = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(pubKey);
signature.update(data);
// 验证签名是否正常
return signature.verify(decryptBASE64(sign));
}
/**
* BASE64解密
* @param key
* @return
* @throws Exception
*/
public static byte[] decryptBASE64(String key) throws Exception{
return (new BASE64Decoder()).decodeBuffer(key);
}
/**
* BASE64加密
* @param key
* @return
* @throws Exception
*/
public static String encryptBASE64(byte[] key)throws Exception{
return (new BASE64Encoder()).encodeBuffer(key);
}
/**
* 加密方法 source: 源数据
*/
public static String encrypt(String source) throws Exception {
//generateKeyPair();
/** 将文件中的公钥对象读出 */
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(PUBLIC_KEY_FILE));
Key key = (Key) ois.readObject();
ois.close();
/** 得到Cipher对象来实现对源数据的RSA加密 */
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
int MaxBlockSize = KEYSIZE / 8 ;
String[] datas = splitString(source, MaxBlockSize - 11);
String mi = "";
for (String s : datas) {
mi += bcd2Str(cipher.doFinal(s.getBytes()));
}
return mi;
}
/**
*/
public static String[] splitString(String string, int len) {
int x = string.length() / len;
int y = string.length() % len;
int z = 0;
if (y != 0) {
z = 1;
}
String[] strings = new String[x + z];
String str = "";
for (int i=0; i<x+z; i++) {
if (i==x+z-1 && y!=0) {
str = string.substring(i*len, i*len+y);
}else{
str = string.substring(i*len, i*len+len);
}
strings[i] = str;
}
return strings;
}
/**
*/
public static String bcd2Str(byte[] bytes) {
char temp[] = new char[bytes.length * 2], val;
for (int i = 0; i < bytes.length; i++) {
val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f);
temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
val = (char) (bytes[i] & 0x0f);
temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
}
return new String(temp);
}
/**
* 解密算法 cryptograph:密文
*/
public static String decrypt(String cryptograph) throws Exception {
/** 将文件中的私钥对象读出 */
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(PRIVATE_KEY_FILE));
Key key = (Key) ois.readObject();
/** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
int key_len = KEYSIZE / 8 ;
byte[] bytes = cryptograph.getBytes();
byte[] bcd = ASCII_To_BCD(bytes, bytes.length);
System.err.println(bcd.length);
String ming = "";
byte[][] arrays = splitArray(bcd, key_len);
for(byte[] arr : arrays){
ming += new String(cipher.doFinal(arr));
}
return ming;
}
/**
*
*/
public static byte[] ASCII_To_BCD(byte[] ascii, int asc_len) {
byte[] bcd = new byte[asc_len / 2];
int j = 0;
for (int i = 0; i < (asc_len + 1) / 2; i++) {
bcd[i] = asc_to_bcd(ascii[j++]);
bcd[i] = (byte) (((j >= asc_len) ? 0x00 : asc_to_bcd(ascii[j++])) + (bcd[i] << 4));
}
return bcd;
}
public static byte asc_to_bcd(byte asc) {
byte bcd;
if ((asc >= '0') && (asc <= '9'))
bcd = (byte) (asc - '0');
else if ((asc >= 'A') && (asc <= 'F'))
bcd = (byte) (asc - 'A' + 10);
else if ((asc >= 'a') && (asc <= 'f'))
bcd = (byte) (asc - 'a' + 10);
else
bcd = (byte) (asc - 48);
return bcd;
}
/**
*/
public static byte[][] splitArray(byte[] data,int len){
int x = data.length / len;
int y = data.length % len;
int z = 0;
if(y!=0){
z = 1;
}
byte[][] arrays = new byte[x+z][];
byte[] arr;
for(int i=0; i<x+z; i++){
arr = new byte[len];
if(i==x+z-1 && y!=0){
System.arraycopy(data, i*len, arr, 0, y);
}else{
System.arraycopy(data, i*len, arr, 0, len);
}
arrays[i] = arr;
}
return arrays;
}
public static String getpublickey() throws Exception{
/** 将文件中的公钥对象读出 */
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(PUBLIC_KEY_FILE));
Key key = (Key) ois.readObject();
String publickey=encryptBASE64(key.getEncoded());
return publickey;
}
public static String getprivatekey() throws Exception{
/** 将文件中的私钥对象读出 */
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(PRIVATE_KEY_FILE));
Key key = (Key) ois.readObject();
String privatekey=encryptBASE64(key.getEncoded());
return privatekey;
}
}
Test2_Main类,这是一个测试类
public class Test2_Main {
publicstaticvoid main(String[] args)throws Exception {
RSA_Encrypt.generateKeyPair();
String source ="Hello World!";// 要加密的字符串
String cryptograph = RSA_Encrypt.encrypt(source);// 生成的密文
String target = RSA_Encrypt.decrypt(cryptograph);// 解密密文
System.out.println("解密之后的明文是:"+target);
byte[]bytes =source.getBytes();
// 产生签名
String sign = RSA_Encrypt.sign(bytes, RSA_Encrypt.getprivatekey());
System.err.println("签名:" +sign);
// 验证签名
boolean status = RSA_Encrypt.verify(bytes, RSA_Encrypt.getpublickey(),sign);
System.err.println("状态:" +status);
}
}
以上就是根据查找的资料,我自己整理的关于RSA加解密算法java代码实现。