java-信息安全(五)-非对称加密算法RSA
概述
信息安全基本概念:
- RSA算法(Ron Rivest、Adi Shamir、Leonard Adleman,人名组合)
RSA
RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。
RSA算法基于一个十分简单的数论事实:将两个大质数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
RSA公开密钥密码体制。所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。
在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,但却不能根据PK计算出SK。
正是基于这种理论,1978年出现了著名的RSA算法,它通常是先生成一对RSA 密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开,甚至可在网络服务器中注册。为提高保密强度,RSA密钥至少为500位长,一般推荐使用1024位。这就使加密的计算量很大。为减少计算量,在传送信息时,常采用传统加密方法与公开密钥加密方法相结合的方式,即信息采用改进的DES或IDEA对话密钥加密,然后使用RSA密钥加密对话密钥和信息摘要。对方收到信息后,用不同的密钥解密并可核对信息摘要。
RSA密钥长度随着保密级别提高,增加很快。下表列出了对同一安全级别所对应的密钥长度。
保密级别
|
对称密钥长度(bit)
|
RSA密钥长度(bit)
|
ECC密钥长度(bit)
|
保密年限
|
80
|
80
|
1024
|
160
|
2010
|
112
|
112
|
2048
|
224
|
2030
|
128
|
128
|
3072
|
256
|
2040
|
192
|
192
|
7680
|
384
|
2080
|
256
|
256
|
15360
|
512
|
2120
|
基本流程
(1)乙方生成两把密钥(公钥和私钥)。公钥是公开的,任何人都可以获得,私钥则是保密的。
(2)甲方获取乙方的公钥,然后用它对信息加密。
(3)乙方得到加密后的信息,用私钥解密。
算法分类
算法 | 密钥长度 | 默认长度 | 签名长度 | 实现的方 |
MD2withRSA | 512-65536 (64的整数倍) |
1024 | 同密钥 | JDK |
MD5withRSA | 同上 | 1024 | 同密钥 | JDK |
SHA1withRSA | ... | 1024 | 同密钥 | JDK |
SHA224withRSA | ... | 2048 | 同密钥 | BC |
SHA256withRSA | ... | 2048 | 同密钥 | BC |
SHA384withRSA | ... | 2048 | 同密钥 | BC |
SHA512withRSA | ... | 2048 | 同密钥 | BC |
RIPEMD128withRSA | 2048 | 同密钥 | BC | |
RIPEMD160withRSA | 同上 | 2048 | 同密钥 | BC |
签名
import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin; public class RSA { private static String src = "rsa security"; public static void main(String[] args) { jdkRSA(); } public static void jdkRSA(){ try { //1.初始化密钥 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(512); KeyPair keyPair = keyPairGenerator.generateKeyPair(); RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate(); //2.执行签名 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded()); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); java.security.Signature signature = java.security.Signature.getInstance("MD5withRSA"); signature.initSign(privateKey); signature.update(src.getBytes()); byte[] res = signature.sign(); System.out.println("签名:"+HexBin.encode(res)); //3.验证签名 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded()); keyFactory.getInstance("RSA"); PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); signature = Signature.getInstance("MD5withRSA"); signature.initVerify(publicKey); signature.update(src.getBytes()); boolean bool = signature.verify(res); System.out.println("验证:"+bool); } catch (Exception e) { e.printStackTrace(); } } }
加密解密示例代码
package com.jd.order.util.encryption; 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.Signature; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; import javax.crypto.Cipher; import org.apache.commons.codec.binary.Base64; /** * RSA 加密,签名,校验 * * @author 木子旭 * @since 2017年3月16日下午1:19:58 * @version %I%,%G% */ public class RSACoder { public static final String KEY_ALGORITHM = "RSA"; public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; private static final String PUBLIC_KEY = "RSAPublicKey"; private static final String PRIVATE_KEY = "RSAPrivateKey"; /** * 用私钥对信息生成数字签名 * * @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 校验成功返回true 失败返回false * @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)); } /** * 解密<br> * 用私钥解密 * * @param data * @param key * @return * @throws Exception */ public static byte[] decryptByPrivateKey(byte[] data, String key) throws Exception { // 对密钥解密 byte[] keyBytes = decryptBASE64(key); // 取得私钥 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec); // 对数据解密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateKey); return cipher.doFinal(data); } /** * 解密<br> * 用公钥解密 * * @param data * @param key * @return * @throws Exception */ public static byte[] decryptByPublicKey(byte[] data, String key) throws Exception { // 对密钥解密 byte[] keyBytes = decryptBASE64(key); // 取得公钥 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicKey = keyFactory.generatePublic(x509KeySpec); // 对数据解密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, publicKey); return cipher.doFinal(data); } /** * 加密<br> * 用公钥加密 * * @param data * @param key * @return * @throws Exception */ public static byte[] encryptByPublicKey(byte[] data, String key) throws Exception { // 对公钥解密 byte[] keyBytes = decryptBASE64(key); // 取得公钥 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicKey = keyFactory.generatePublic(x509KeySpec); // 对数据加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return cipher.doFinal(data); } /** * 加密<br> * 用私钥加密 * * @param data * @param key * @return * @throws Exception */ public static byte[] encryptByPrivateKey(byte[] data, String key) throws Exception { // 对密钥解密 byte[] keyBytes = decryptBASE64(key); // 取得私钥 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec); // 对数据加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateKey); return cipher.doFinal(data); } /** * 取得私钥 * * @param keyMap * @return * @throws Exception */ public static String getPrivateKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PRIVATE_KEY); return encryptBASE64(key.getEncoded()); } /** * 取得公钥 * * @param keyMap * @return * @throws Exception */ public static String getPublicKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PUBLIC_KEY); return encryptBASE64(key.getEncoded()); } /** * 初始化密钥 * * @return * @throws Exception */ public static Map<String, Object> initKey() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator .getInstance(KEY_ALGORITHM); keyPairGen.initialize(1024); KeyPair keyPair = keyPairGen.generateKeyPair(); // 公钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 私钥 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String, Object> keyMap = new HashMap<String, Object>(2); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; } public static byte[] decryptBASE64(String data) { return Base64.decodeBase64(data); } public static String encryptBASE64(byte[] data) { return new String(Base64.encodeBase64(data)); } }
测试示例
package com.jd.order.util.encryption; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.Map; import org.junit.Before; import org.junit.Test; public class RSACoderTest { private String publicKey; private String privateKey; @Before public void setUp() throws Exception { Map<String, Object> keyMap = RSACoder.initKey(); publicKey = RSACoder.getPublicKey(keyMap); privateKey = RSACoder.getPrivateKey(keyMap); System.err.println("公钥: \n\r" + publicKey); System.err.println("私钥: \n\r" + privateKey); } @Test public void test() throws Exception { System.err.println("公钥加密——私钥解密"); String inputStr = "abc"; byte[] data = inputStr.getBytes(); byte[] encodedData = RSACoder.encryptByPublicKey(data, publicKey); byte[] decodedData = RSACoder.decryptByPrivateKey(encodedData, privateKey); String outputStr = new String(decodedData); System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr); assertEquals(inputStr, outputStr); } }
输出
公钥: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChh7ZmniTadEijgM68v9cG4Er6jrnJHA0jMaJowJzr9ftm3hRsfVXnCDFP4KE3xZ5ZLZXI9L7pJnk6JwAVxmtfVnJhLPubfeDi2ekkirEUTVBrHH2N7nDK/dCoFALkySSrcBtU5mi/4A0VAoQvftZ6K7DXLQgRPluKgoJgICd8fwIDAQAB 私钥: MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKGHtmaeJNp0SKOAzry/1wbgSvqOuckcDSMxomjAnOv1+2beFGx9VecIMU/goTfFnlktlcj0vukmeTonABXGa19WcmEs+5t94OLZ6SSKsRRNUGscfY3ucMr90KgUAuTJJKtwG1TmaL/gDRUChC9+1norsNctCBE+W4qCgmAgJ3x/AgMBAAECgYBZYqoy+wxVvsd7gwnkNRyed3vGTzjL6zPx58OByCSOBp7J+9a9elYQ9N2k4B8Wp8rKeolKnPUQO/QVlANeCWDciL1GstrbAAFy4onLiCLCnM3LWIoXlUi49RhtDWfcB9Cz74F6oBC/7maDNMSvOXu8N9t6Eg7bgoD8cdYY+KE+gQJBAPxX6hRWDdhC+t7l2AMZlBKirFvD6brlvapEsfxf90tvwg+5GpC2FRf+qXi/X5hkPhyBH2A63vqwl4pZTrk5uOECQQCj3ut7vlEwH9rvh70QYM2HH9EW8nqvWuTod31CI5aRw1eF3vHM1+VkEfdoykaaM+f5159r8jdvnQIOPKwLYwFfAkEA3wLXRbezrp+rVNhuanbtjPalOshOxTUKxPLHFdK+G7YeHIUrfB7fT4Bpx+PhmS1mUwyubP46V/U/SC6bS0k/IQJAWlusCzKY/+lAxr1ZIfPOwIhpubaAsbpz6D8i4VpQRxWoaBfTyrjtMu25N535qkOe0SP1Mwd/S9sObB1GXIz+DwJBANKNEcwjB00U6Bz5zZjnRm22jRpVoHXY1f77Yiex8ZiTpRyxWdi/17lOv0AZYvnFC2uJS1pIfoeecKrcvRuHq1w= 公钥加密——私钥解密 加密前: abc 解密后: abc