转载

RSA加密使用方式及签名验证

RSA加密原理使用方式签名验证

加密是网络传输中非常重要的一环,它保证了信息的安全性,让他人无法通过抓包来获取通讯的信息也无法通过伪造信息而实现对系统的入侵。其中最为常用的信息传递加密方式就是RSA加密。

RSA加密原理

RSA与传统加密方式不同的是,他是非对称加密,可以在不直接传递密钥的情况下,完成解密。这能够确保信息的安全性,避免了直接传递密钥所造成的被破解的风险。 
RSA加密方式是: 
(1)乙方生成两把密钥(公钥和私钥)。公钥是公开的,任何人都可以获得,私钥则是保密的。 
(2)甲方获取乙方的公钥,然后用它对信息加密。 
(3)乙方得到加密后的信息,用私钥解密。 
RSA非对称加密算法的原理请参照下面两篇文章,本文主要讲述RSA加密在java程序中的使用。其概念是利用大整数的质数分解的困难性来保障密钥不被破解。

RSA算法原理part1 
RSA算法原理part2

RSA加密传输的实现

在加密前首先要生成秘钥,秘钥的生成可以使用java中的security包下的KeyPairGenerator来生成指定位数的秘钥。生成的秘钥为byte类型,一般可以用文件保存在使用的时候读取,但是为了方便写在程序里也可以用base64编码成字符串,在使用的时候用base64解码然后获得秘钥的对象。 
密钥生成:

/*创建非对称加密的公钥和私钥示例 将生成的公钥和私钥用Base64编码后打印出来*/
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048); //一般加密位数为1024 对安全要求较高的情况下可以使用2048
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
/*将公钥base64编码打印出来*/        System.out.println(Base64.encodeBase64String(publicKey.getEncoded()));
/*将私钥base64编码打印出来*/      System.out.println(Base64.encodeBase64String(privateKey.getEncoded()));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

加密我们需要先将密钥字符串base64解码然后生成密钥对象然后使用。 
在java提供的jdk1.5中已经提供了相关加密工具类Cipher类,使用起来也比较方便 
加密:

/*公钥字符串*/
String pubKey="base64编码的公钥";
/*X.509 标准中定义的公钥编码标准,使用这个类进行转换*/
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
//获得公钥对象
PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
String msg="需要加密的内容";
/*使用Cipher加密*/
/*定义加密方式*/
Cipher cipher = Cipher.getInstance("RSA");
/*使用公钥和加密模式初始化*/
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
/*获取加密内容以UTF-8为标准转化的字节进行加密后再使用base64编码成字符串*/
/*加密后的字符串*/
String enmsg=Base64.encodeBase64String(cipher.doFinal(plainText.getBytes("UTF-8")));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

然后同理反向解密 
解密:

String priKey="base64编码的私钥";
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(baiduPriKey));
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
String msg="加密后的内容";
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
/*解密后的内容*/
String demsg = new String(cipher.doFinal(Base64.decodeBase64(msg)), "UTF-8");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

以上就是加密解密的过程

RSA签名的实现

RSA加密生成的公钥和私钥实际上是一对互相可以加密解密的钥匙对,换句话说 你可以用私钥加密,用公钥解密。但是由于一些特定的加密工具为了方便加密传输位数而指定了公钥的秘钥值,私钥是根据公钥的值计算得出的,所以一般私钥比较大且安全性更高,留作自己系统去解密其他系统传来的数据。 
但是我们说道,公钥是可能给复数个其他系统的,你无法得知是哪个系统给你传输的这个数据,所以就有了签名这一说。现在有甲乙两个系统,甲系统要给乙系统传输数据,甲系统的数据使用自己的私钥对传递的信息进行加密,然后加一个签名字段放入要传输的数据中然后整体数据再使用公钥进行加密,传输给乙系统。乙系统拿到数据后,先使用自己的私钥解密数据,然后剔除签名字段,然后解密签名字段看与剔除签名字段的数据进行对比,这一步叫做验签,如果相等则代表此数据时由甲方传来且数据没有被篡改。 
java中也提供了相应的签名方法类Signature可以直接使用,现在假设使用json字符串传输做一次签名验签的案例 
签名:

/* 1. 准备发送的数据 为保证顺序正确这里使用TreeMap*/
TreeMap<String, String> map = new TreeMap<String, String>();
map.put("msg1", "1324679");
map.put("msg2", "A001");
map.put("msg3", "V1.0");
map.put("msg4", "");
/* 2. 计算验签字段, sign字段不参与签名 map转String方法可以自定义*/
String line = JSON.toJSONString(map);
PrivateKey privateKey="自己的私钥";
//设置签名加密方式
Signature signature = Signature.getInstance("RSA");
signature.initSign(privateKey);//设置私钥
//签名和加密一样 要以字节形式 utf-8字符集得到字节
signature.update(line.getBytes("UTF-8"));
//得到base64编码的签名后的字段
String sign = Base64.encodeBase64String(signature.sign());
//将签名放入map
map.put("sign", sign);
//将要传输的数据转成json
String request = JSON.toJSONString(map);
/*进行传输(可进行正常加密)*/
.......
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

验签:

...
/*获得请求过来的request(若加密请解密)并转换成map*/
TreeMap<String, String> map = JSON.parseObject(request, new TypeReference<TreeMap<String, String>>() {});
String sign = map2.get("sign");//获得签名
map2.remove("sign");//剔除签名
String line = JSON.toJSONString(map);//转化为字符串
PublicKey publicKey = "对方给的公钥";
//指定签名类型
Signature signature = Signature.getInstance("RSA");
signature.initVerify(publicKey);//放入公钥
signature.update(line .getBytes("UTF-8"));//放入数据
//验签结果
boolean isPassed= signature.verify(Base64.decodeBase64(sign));
System.out.println("验签结果 : " + isPassed);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

实际使用的优化方法

rsa算法是一种取模计算,当加密位数很大时(比如2048位生成密钥),实际上消耗的计算量还是很大的,而且由于有签名的存在,相当于传了两份数据过去,一正一反加密验签消耗的计算量就非常大了,为了优化加密传输及减少系统计算量,我们一般需要采取一些优化方法: 
1.采取散列算法简化签名 
签名实际上只需要验证数据是否没有被篡改/是否是对方系统发来的数据 实际上是没有必要吧整个数据都进行加密传输,可以使用散列算法来进行压缩验证,常用的有sha256和md5,然后将计算后的值进行签名,接收方使用同样的方法进行压缩验签。 
2.生成随机对称加密密钥,使用对称加密加密数据,然后将密钥进行RSA加密明文传输 
第一种优化虽然优化了签名,减少了数据传输和运算,但是数据本体还是很大,使用rsa加密仍然需要消耗大量的计算能力,于是就有了这种加密方式,生成随机的密钥对称加密数据,然后将对称的密钥进行rsa加密明文传输,对方接受到对称密钥的rsa加密后的字符串,再用私钥解密,得到对称加密的密钥对数据进行解密。

最后附上完整的加密案例及整理的加密解密工具类:

rsa+aes加密传输工具及案例


原文链接:https://blog.csdn.net/yowasa/article/details/72825866

正文到此结束
Loading...