java-信息安全(五)-非对称加密算法RSA

时间:2021-01-10 15:11:56

概述

信息安全基本概念:

  • 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