一、理论_来源于网上。
RSA公钥加密体制包含如下3个算法:KeyGen(密钥生成算法),Encrypt(加密算法)以及Decrypt(解密算法)。
所以,从算法描述中我们也可以看出:公钥用于对数据进行加密,私钥用于对数据进行解密。当然了,这个也可以很直观的理解:公钥就是公开的密钥,其公开了大家才能用它来加密数据。私钥是私有的密钥,谁有这个密钥才能够解密密文。否则大家都能看到私钥,就都能解密,那不就乱套了。
签名算法同样包含3个算法:KeyGen(密钥生成算法),Sign(签名算法),Verify(验证算法)。
所以,在签名算法中,私钥用于对数据进行签名,公钥用于对签名进行验证。这也可以直观地进行理解:对一个文件签名,当然要用私钥,因为我们希望只有自己才能完成签字。验证过程当然希望所有人都能够执行,大家看到签名都能通过验证证明确实是我自己签的。
二、工具类
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
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.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
public class RSAUtil{
public static final String SIGN_ALGORITHMS = "SHA1WithRSA";
/**加密算法RSA*/
public static final String KEY_ALGORITHM = "RSA";
/**RSA最大加密明文大小*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/**RSA最大解密密文大小*/
private static final int MAX_DECRYPT_BLOCK = 128;
/**
* RSA签名
* @param content 待签名数据
* @param privateKey 商户私钥
* @param input_charset 编码格式
*/
public static String sign(String content, String privateKey, String input_charset){
try {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64_.decode(privateKey) );
KeyFactory keyf = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey priKey = keyf.generatePrivate(priPKCS8);
java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
signature.initSign(priKey);
signature.update(content.getBytes(input_charset));
byte[] signed = signature.sign();
return Base64_.encode(signed);
}catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* RSA验签名检查
* @param content 待签名数据
* @param sign 签名值
* @param ali_public_key 支付宝公钥
* @param input_charset 编码格式
*/
public static boolean verify(String content, String sign, String ali_public_key, String input_charset){
try {
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
byte[] encodedKey = Base64_.decode(ali_public_key);
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
signature.initVerify(pubKey);
signature.update(content.getBytes(input_charset) );
boolean bverify = signature.verify( Base64_.decode(sign) );
return bverify;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 私钥解密
* @param content 密文
* @param private_key 商户私钥
* @param input_charset 编码格式
*/
public static String decrypt(String content, String private_key, String input_charset) throws Exception {
PrivateKey prikey = getPrivateKey(private_key);
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, prikey);
InputStream ins = new ByteArrayInputStream(Base64_.decode(content));
ByteArrayOutputStream writer = new ByteArrayOutputStream();
//rsa解密的字节大小最多是128,将需要解密的内容,按128位拆开解密
byte[] buf = new byte[128];
int bufl;
while ((bufl = ins.read(buf)) != -1) {
byte[] block = null;
if (buf.length == bufl) {
block = buf;
} else {
block = new byte[bufl];
for (int i = 0; i < bufl; i++) {
block[i] = buf[i];
}
}
writer.write(cipher.doFinal(block));
}
return new String(writer.toByteArray(), input_charset);
}
/**
* 公钥加密
* @param data 源数据
* @param publicKey 公钥(BASE64编码)
*/
public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
byte[] keyBytes = Base64_.decode(publicKey);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicK = keyFactory.generatePublic(x509KeySpec);
// 对数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicK);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
}
public static String encryptByPublicKeyToStr(byte[] data, String publicKey) throws Exception {
byte[] bytes = encryptByPublicKey(data, publicKey);
String result = Base64_.encode(bytes);
return result;
}
/**
* 得到私钥
* @param key 密钥字符串(经过base64编码)
* @throws Exception
*/
public static PrivateKey getPrivateKey(String key) throws Exception {
byte[] keyBytes;
keyBytes = Base64_.decode(key);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
}
public static class Base64_ {
private static final Base64.Decoder decoder = Base64.getDecoder();
private static final Base64.Encoder encoder = Base64.getEncoder();
public static byte[] decode(String key) {
if (key == null) { return null;}
byte[] decode = decoder.decode(key);
return decode;
}
public static String encode(byte[] content) {
if (content == null) {return null;}
String encode = encoder.encodeToString(content);
return encode;
}
}
/**
* 测试
*/
public static void main(String args[]) throws Exception{
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
String pubKey = Base64_.encode(publicKey.getEncoded()); //公钥
String priKey = Base64_.encode(privateKey.getEncoded()); //私钥
// System.out.println(pubKey);
// System.out.println(priKey);
//......................................公钥加密,私钥解密!
String sourceStr = "我是中国人啊!!!!!!!!!!!!!!!!!!!!!!!!!";
//公钥加密
byte[] ens = RSAUtil.encryptByPublicKey(sourceStr.getBytes(),pubKey);
String encodes = Base64_.encode(ens);
System.out.println(encodes);
//私钥解密
String res2 = RSAUtil.decrypt(encodes, priKey, "UTF-8");
System.out.println(res2);
//.......................................签名验证,私钥签名,公钥验证是否正确!
String source = "id=shoig&name=shoer&age=23dnjlegj;reg"; //模拟请求参数,然后对此请求参数进行签名。
String sign = RSAUtil.sign(source, priKey, "UTF-8");
System.out.println("签名是:"+sign);
// 公钥验证签名是否正确.
// 具体流程是,请求参数+sign发送给公钥方,然后公钥方过滤掉sign,用公钥验证其他参数是否通过。
boolean result = RSAUtil.verify(source, sign, pubKey, "UTF-8");
System.out.println(result);
}
}