安全
RSA
- RSA是最常用非对称加密算法。常用于消息签名。它的加解密的密钥是成对出现的。使用私钥加密只能用对应的公钥才能解密。这样防止了类似DES等对称加密算法的密钥传输的问题。其加密效率比DES慢。
- 详细内容请查看:http://zh.wikipedia.org/wiki/RSA%E5%8A%A0%E5%AF%86%E6%BC%94%E7%AE%97%E6%B3%95
/**
* RSA算法加密解密例子
* 注意:RSA加密对明文的长度是有限制的,RSA加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块进行。
*
*/
public class RSACoder extends TestCase {
/**
* 测试用私钥加密再用公钥解密
*
* @throws Exception
*/
public void test1() throws Exception {
byte[] arr = this.readFileIntoByteArr(new File("D:/data.txt"));
System.out.println("加密前的明文:" + new String(arr, "GBK"));
Map<String, Object> keyMap = this.initKey();
PrivateKey priKey = (PrivateKey) keyMap.get("PrivateKey");
PublicKey pubKey = (PublicKey) keyMap.get("PublicKey");
byte[] encryptData = this.encryptByPriKey(arr, priKey.getEncoded());
System.out.println("密文:" + Hex.encodeHexString(encryptData));
byte[] data = this.decryptByPubKey(encryptData, pubKey.getEncoded());
System.out.println("解密后的明文:" + new String(data, "GBK"));
}
/**
* 测试数字签名与验签
*
* @throws Exception
*/
public void test2() throws Exception {
byte[] arr = this.readFileIntoByteArr(new File("D:/data.txt"));
System.out.println("签名主体:" + new String(arr, "GBK"));
Map<String, Object> keyMap = this.initKey();
PrivateKey priKey = (PrivateKey) keyMap.get("PrivateKey");
PublicKey pubKey = (PublicKey) keyMap.get("PublicKey");
byte[] sign = this.sign(arr, priKey.getEncoded());
System.out.println("签名:" + Hex.encodeHexString(sign));
boolean b = this.verify(arr, pubKey.getEncoded(), sign);
System.out.println(b ? "验签成功" : "验签失败");
}
/**
* 测试直接对主体签名与先对主体加摘要再签名得到的签名是不一样的。
*
* @throws Exception
*/
public void test3() throws Exception {
byte[] arr = this.readFileIntoByteArr(new File("D:/data.txt"));
System.out.println("签名主体:" + new String(arr, "GBK"));
Map<String, Object> keyMap = this.initKey();
PrivateKey priKey = (PrivateKey) keyMap.get("PrivateKey");
PublicKey pubKey = (PublicKey) keyMap.get("PublicKey");
// 直接签名
byte[] sign1 = this.sign(arr, priKey.getEncoded());
System.out.println("签名:" + Hex.encodeHexString(sign1));
// 先得到MD5摘要再签名
byte[] md5 = DigestUtils.md5(arr);
byte[] sign2 = this.sign(md5, priKey.getEncoded());
System.out.println("签名:" + Hex.encodeHexString(sign2));
}
/**
* 生成密钥对
*
* @return
* @throws NoSuchAlgorithmException
*/
public Map<String, Object> initKey() throws NoSuchAlgorithmException {
// 实例化密钥对生成器
KeyPairGenerator gener = KeyPairGenerator.getInstance("RSA");
gener.initialize(1024);
KeyPair pair = gener.generateKeyPair();
PrivateKey priKey = pair.getPrivate();
PublicKey pubKey = pair.getPublic();
Map<String, Object> keyMap = new HashMap<String, Object>(2);
keyMap.put("PrivateKey", priKey);
keyMap.put("PublicKey", pubKey);
System.out.println("私钥:" + Hex.encodeHexString(priKey.getEncoded()));
System.out.println("公钥:" + Hex.encodeHexString(pubKey.getEncoded()));
return keyMap;
}
/**
* 读取文件内容到byte数组
*
* @param file
* @return
* @throws IOException
*/
public byte[] readFileIntoByteArr(File file) throws IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
try {
FileInputStream in = new FileInputStream(file);
byte[] tmpbuf = new byte[1024];
int count = 0;
while ((count = in.read(tmpbuf)) != -1) {
bout.write(tmpbuf, 0, count);
tmpbuf = new byte[1024];
}
in.close();
} catch (FileNotFoundException e) {
throw new FileNotFoundException("文件" + file.getPath() + "不存在");
} catch (IOException e) {
throw new IOException("读取文件内容到BYTE数组中出现IO异常", e);
}
return bout.toByteArray();
}
/**
* 私钥加密
*
* @param data
* @param priKeyByte
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws NoSuchPaddingException
* @throws InvalidKeyException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
public byte[] encryptByPriKey(byte[] data, byte[] priKeyByte) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
// 获取私钥
KeySpec spec = new PKCS8EncodedKeySpec(priKeyByte);
// 生成私钥
Key priKey = keyFactory.generatePrivate(spec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, priKey);
return cipher.doFinal(data);
}
/**
* 公钥解密
*
* @param data
* @param pubKeyByte
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws NoSuchPaddingException
* @throws InvalidKeyException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
public byte[] decryptByPubKey(byte[] data, byte[] pubKeyByte) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
// 获取公钥
KeySpec spec = new X509EncodedKeySpec(pubKeyByte);
// 生成公钥
Key pubKey = keyFactory.generatePublic(spec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, pubKey);
return cipher.doFinal(data);
}
/**
* 使用MD5withRSA算法,加签
*
* @param data
* @param priKeyByte
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws InvalidKeyException
* @throws SignatureException
*/
public byte[] sign(byte[] data, byte[] priKeyByte) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
// 获取私钥
KeySpec spec = new PKCS8EncodedKeySpec(priKeyByte);
// 生成私钥
PrivateKey priKey = keyFactory.generatePrivate(spec);
Signature signature = Signature.getInstance("MD5withRSA");
signature.initSign(priKey);
signature.update(data);
return signature.sign();
}
/**
* 使用MD5withRSA算法,解签
*
* @param data
* @param pubKeyByte
* @param sign
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws InvalidKeyException
* @throws SignatureException
*/
public boolean verify(byte[] data, byte[] pubKeyByte, byte[] sign) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException,
SignatureException {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
// 获取公钥
KeySpec spec = new X509EncodedKeySpec(pubKeyByte);
// 生成公钥
PublicKey pubKey = keyFactory.generatePublic(spec);
Signature signature = Signature.getInstance("MD5withRSA");
signature.initVerify(pubKey);
signature.update(data);
return signature.verify(sign);
}
}