本文主要面向想在javaweb/java应用 里面使用RSA的人。
一、RSA是个ShenMeGui:
其实一开始叫我用RSA加密我是拒绝的(屁),因为不可能你叫我用我就用,我得查查他是什么东西对不对。
RSA是目前最有影响力的公钥加密算法,属于非对称加密的,也就是用一个大家都知道的公钥来加密出来的密文,只有拥有私钥的人才能解开,目前听说1024比较安全,2048位那是相当安全,往上就更难破解了。
关于RSA的基本原理,百度百科里面提到“RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。”然后阮一峰先生的 《RSA算法原理(一)》和《RSA算法原理(二)》里面就解释的比较清楚,看完你大概就懂了(不愧是大牛吖)。阮先生提到了:
加密公式:
me ≡ c (mod n)
解密公式:
cd ≡ m (mod n)
n是公共的模数,也就是pq的乘积,e是公钥的指数,d是私钥的指数,下面会说到利用他们可以还原公钥和密钥。
如果你知道是怎么回事的话也就清楚了RSA是怎么回事, 不清楚的话请去看文章,这里主要是说如何去使用RSA而不是自己实现RSA。知道RSA的大概原理将会对我们抄写代码有帮助,不然你出了问题自己都搞不定,咋办?
二、使用RSA实现加密解密的思路:
说起思路比较简单。其实就是浏览器向服务器拿到公钥,在用户填完信息后,用公钥帮用户加密,然后提交后,服务器再用java解密就可以了…….吗?本来大体思路是这样没错,可是我找到的方法并没有办法直接传输可用的公钥,所以我们要用到上述的公式,先把e和n取出来,利用js把e和n还原成公钥,然后再用他给信息加密后提交,最后就是用服务器上的java解密。
三、伸手党时间:
说了那么多,福利呢干货呢别人写好的代码呢?没错我就知道你想要这个。
一开始我也是大概搞清楚RSA之后开始各种找代码来参考一下,于是在我不懈努力之下,让我找到了这个《用javascript与java进行RSA加密与解密》,总体还是可用的,而且总体思路和我一致,但是用起来问题还是多多的,你们可以先点开链接看看代码。以下把这个链接称为“伸手党”资料。(伸手党是说你跟我,不是说那文章作者)
四、javascript里面的RSA:
首先你需要三个js(这个在“伸手党时间”里面有)
BigInt.js – 用于生成一个大整型;(这是RSA算法的需要)
RSA.js – RSA的主要算法;
Barrett.js – RSA算法所需要用到的一个支持文件;
像上面提到的,你拥有公钥的n和e就能还原公钥,然后进行加密。关键代码如下:
5 |
key = new RSAKeyPair(e, "" ,n);
|
7 |
var result = encryptedString(key, document.getElementById( "pwd" ).value);
|
e和n哪里来?你可以先用着链接里面的来test一下,我认为正常来说应该是java读取了送到给js的,下面会讲到。
五、 java里面的RSA:
那java里面肯定也有RSA的相关类和API能用,我们需要些什么呢?我们需要的是JDK里面的java.security包和一个开源的加解密解决方案BouncyCastle的API。java.security自己import就可以,→bouncyCastle在这里← 要JDK15以上的,下最新的就可以,打不开或者找不到的就百度一下咯~
下面我们说说java里面的代码问题,“伸手党”链接中的方法我们都可以自己修改逻辑和参数列表后就直接用了。
先来说生成密钥,利用generateKeyPair()和saveKey(),可以很简单的生成一对密钥,你可以直接存到相应路径,也可以像我一样改一下saveKey()把公钥私钥分开储存,甚至你可以直接保存在session,这样你的网站就永远在用别人猜不到的密钥了(我估计这样服务器工作量略大,还不如定时线程来更新密钥),下面是我修改过的代码
01 |
public static KeyPair generateKeyPair() throws Exception {
|
03 |
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance( "RSA" , BouncyCastleProvider());
|
04 |
final int KEY_SIZE = 1024 ;
|
05 |
keyPairGen.initialize(KEY_SIZE, new SecureRandom());
|
06 |
KeyPair keyPair = keyPairGen.generateKeyPair();
|
08 |
} catch (Exception e) {
|
09 |
throw new Exception(e.getMessage());
|
再说取钥的问题,你可以使用getKeyPair()获取公钥和密钥,大概长这样(我同事帮忙修改了下,返回的object然后自自行强制转换即可)这里注意readObject其实和加密包会有关系。
01 |
public static Object getKey(String path) throws Exception{
|
02 |
FileInputStream fis = new FileInputStream(path);
|
03 |
ObjectInputStream oos = new ObjectInputStream(fis);
|
04 |
Object kp= oos.readObject();
|
10 |
KeyPair kp=(KeyPair)getKey( "D:/key.key" );
|
我们读取到公钥后,需要用到RSAPublicKey的getModulus()和getPublicExponent()方法取得公钥的e(Exponent)和n(Modulus)给到前端页面,前端可以用getparameter等方法接收,或者在页面初始化时用ajax请求。
1 |
String Modulus=RSAPublicKey.getModulus().toString( 16 );
|
2 |
String Exponent=RSAPublicKey.getPublicExponent().toString( 16 );
|
这里需要toString(16)把他转为16进制,供前端使用。
最后是最重要的解密部分(加密和解密的写法极其相似,有需要的同学可以先看看解密),网上最简单而典型的写法是这样的(raw是密文)
1 |
public static byte [] RSAdecrypt(PrivateKey pk, byte [] raw) throws Exception {
|
2 |
Cipher cipher = Cipher.getInstance( "RSA" , new BouncyCastleProvider());
|
3 |
cipher.init(Cipher.DECRYPT_MODE, pk);
|
4 |
return cipher.doFinal(raw);
|
然后我在“伸手党”资料找到demo是这样的
01 |
public static byte [] RSAdecrypt(PrivateKey pk, byte [] raw) throws Exception {
|
02 |
Cipher cipher = Cipher.getInstance( "RSA" , new BouncyCastleProvider());
|
03 |
cipher.init(Cipher.DECRYPT_MODE, pk);
|
04 |
ByteArrayOutputStream bout = null ;
|
06 |
bout = new ByteArrayOutputStream( 64 );
|
08 |
int blockSize = cipher.getBlockSize();
|
09 |
while (raw.length - j * blockSize > 0 ) {
|
10 |
bout.write(cipher.doFinal(raw, j * blockSize, blockSize));
|
13 |
return bout.toByteArray();
|
这样看貌似第二个安全一点,不过我不是很懂为什么要写的这么复杂,测了下运行时间貌似差不多。求各位指导。
这里用到加密算法最核心的类Cipher类,我觉得有必要大概了解一下它,它的加密和解密过程用到的都是doFinal()方法,至于是加密还是解密就取决于init时候的参数Cliper的MODE。然后如果没有我说的BouncyCastle API你就要用 Cipher.getInstance(keyFactory.getAlgorithm())来实例化Clipher了,会麻烦一点。
到这里加密解密就已经完成了~~~然后接下来可能会遇到一些问题,请看↓
六、遇到问题了吧,说好的售后服务呢?
(1)首先再提一下setMaxDigits(),要注意里面的参数,1024位对应130,2048位对应260。
(2)然后是java里面关于解密时参数发送异常的问题:如果完全按照上述方法,或者是“伸手党”资料里面的做法,在大量使用的情况下就会出现以下报错。
如果你是用精简版的RSAdecrypt
org.bouncycastle.crypto.DataLengthException: input too large for RSA cipher.
at org.bouncycastle.crypto.engines.RSACoreEngine.convertInput(Unknown Source)
at org.bouncycastle.crypto.engines.RSABlindedEngine.processBlock(Unknown Source)
at org.bouncycastle.jcajce.provider.asymmetric.rsa.CipherSpi.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(Cipher.java:2087)
如果你是用复杂版的RSAdecrypt
java.lang.IllegalArgumentException: Bad arguments
at javax.crypto.Cipher.doFinal(Cipher.java:2141)
at com.dimeng.p2p.yylh.util.SecurityHelper.RSAdecrypt(SecurityHelper.java:236)
at com.dimeng.p2p.yylh.util.SecurityHelper.getdecryptStr(SecurityHelper.java:262)
at com.dimeng.p2p.yylh.util.SecurityHelper.main(SecurityHelper.java:342)
Exception in thread "main" java.lang.IllegalArgumentException: Bad arguments
at javax.crypto.Cipher.doFinal(Cipher.java:2141)
原因是 “伸手党”资料里面的用法是这样的,问题就出在toByteArray()上面
2 |
byte [] en_result = new BigInteger(result, 16 ).toByteArray();
|
3 |
byte [] de_result = RSAUtil.decrypt(RSAUtil.getKeyPair().getPrivate(),en_result);
|
准确来说是因为js加密的时候会导致byte[]类型密文比指定的长,为什么呢?因为上面提到的三个JS在加密密码时,偶尔会得出正确的密文byte[]多出一byte,里面是0,不信等报错了你自己试试。网上提供的思路如下:
01 |
/** * 16进制 To byte[] * @param hexString * @return byte[] */ |
02 |
public static byte [] hexStringToBytes(String hexString) {
|
03 |
if (hexString == null || hexString.equals( "" )) {
|
06 |
hexString = hexString.toUpperCase();
|
07 |
int length = hexString.length() / 2 ;
|
08 |
char [] hexChars = hexString.toCharArray();
|
09 |
byte [] d = new byte [length];
|
10 |
for ( int i = 0 ; i < length; i++) {
|
12 |
d[i] = ( byte ) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1 ]));
|
17 |
/** * Convert char to byte * @param c char * @return byte */
|
18 |
private static byte charToByte( char c) {
|
19 |
return ( byte ) "0123456789ABCDEF" .indexOf(c);
|
22 |
byte [] en_result = hexStringToBytes(password_en);
|
不过比较烦的是我不太懂位运算= =看懂d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));的给我解释一下谢谢~~~
七、扩展一下,加量不加价!
有同学是用.NET的,有没有例子呢?有!→《用RSA加密实现Web登录密码加密传输》(.NET版)如果使用过程中遇到问题可以参考本文
然后《Java 进行 RSA 加解密时不得不考虑到的那些事儿》这篇文章里面提到一些需要注意的东西,比如说加密的质量啊之类的,值得一看。
另外我发现梁栋老师写的《Java加密与解密的艺术(第2版)》有在线版可以点开,还有我找到了他的博客,哇好多java安全方面东西可以学习 Snowolf的博客中的Java/Security
相关推荐
本文详细介绍了Java实现的RSA加密解密算法,包括密钥对生成、公钥和私钥的使用、加密和解密、密钥文件的生成等知识点。这些知识点对于Java开发者来说非常重要,可以帮助他们更好地理解和实现RSA加密解密算法。
### Java 实现 RSA ...通过上述分析,我们了解到Java中实现RSA加密的具体步骤,包括密钥对的生成、数据加密与签名、签名验证与数据解密等关键过程。这些步骤确保了数据传输的安全性和完整性,是网络安全通信的基础。
在IT行业中,PHP和Java是两种广泛使用的编程语言,它们分别在Web开发的前后端扮演着重要角色。而RSA是一种非对称加密算法,广泛应用于数据的安全传输和存储。本项目"PHP_JAVA_RSA互通加解密"实现了PHP和Java之间使用...
在这个场景下,前端代码可能使用了JavaScript库,如CryptoJS或Web Cryptography API,来实现RSA2048的加密。这些库允许在浏览器环境中生成RSA密钥对,并使用公钥对敏感数据进行加密,然后将加密后的数据发送到服务器...
2. **Java实现RSA**:在Java中,我们可以使用`java.security`包下的`KeyPairGenerator`和`Cipher`类来生成RSA密钥对并进行加密解密操作。首先,我们需要生成一对公钥和私钥,公钥用于加密,私钥用于解密。 3. **...
1. **生成RSA密钥对**:在Java中,我们可以使用`KeyPairGenerator`类的`generateKeyPair()`方法生成一对RSA密钥,包括一个公钥(PublicKey)和一个私钥(PrivateKey)。生成的密钥通常以X.509编码格式存储。 2. **...
Java RSA加密技术是一种广泛应用于网络通信安全中的非对称加密算法,主要特点是公钥和私钥成对出现,其中公钥用于加密,私钥用于解密。这种加密方式的安全性较高,因为即使加密数据被截获,没有相应的私钥也无法解密...
本文将详细介绍Java、Android和Web三端通用的RSA和AES工具类的使用,以及相关的JavaScript实现。RSA是一种非对称加密算法,而AES则是一种对称加密算法,它们在保护敏感信息方面发挥着关键作用。 首先,RSA(Rivest-...
在Web开发中,由于浏览器端不支持Java,而JavaScript则可以在客户端运行,因此,使用RSA在Java后端生成密钥对,并将公钥传递给JavaScript前端进行加密,再将加密后的数据发送回服务器,由Java后端使用私钥解密,是...
由于Java的RSA加解密一般都是用RSA/ECB/PKCS1PADDING,导致Python一般的RSA加密库的加解密结果与Java的不兼容,Python下目前能与之兼容的RSA的库目前发现的只有一个,就是m2crypto。 这个库目前的问题是在windows...
1. 导入相关库:Java中使用`javax.crypto`包,Android中同样使用Java的加密库,而Web开发可能依赖于如Spring Security这样的框架。 2. 公钥和私钥的生成:使用`KeyPairGenerator`类生成RSA的公钥和私钥对。 3. 加密...
`java.security.KeyPairGenerator`类可以用来生成RSA密钥对,`java.security.PublicKey`和`java.security.PrivateKey`接口代表公钥和私钥。加密和解密分别由`Cipher`类的`doFinal`方法完成,通过设置对应的加密模式...
在提供的压缩包文件"rsa"中,可能包含了JavaScript和Java的示例代码,以及一个HTML文件,演示了如何在Web环境中使用这些代码。这些资源可以帮助开发者快速理解和应用RSA加密技术。需要注意的是,由于RSA的加密速度较...
总之,RSA_JS_JAVA项目展示了如何在JavaScript和Java之间使用RSA加密技术进行安全通信,涵盖了公钥加密和私钥解密的过程,以及在不同开发环境下如何实施这些操作。理解并掌握这些知识点对于进行跨平台的安全编程至关...
在Java中,可以使用`java.security`包下的`KeyPairGenerator`、`Cipher`等类来生成密钥对并进行加解密操作。 接下来是Java的ZIP加密压缩。ZIP是一种广泛使用的文件压缩格式,支持对文件或文件夹进行压缩。在Java中...
3. **Java中的RSA加密**: 在Java中,我们可以使用`java.security`包下的`KeyPairGenerator`和`Cipher`类来生成RSA密钥对并进行加密和解密操作。`KeyPairGenerator`用于生成密钥对,`Cipher`负责实际的加密和解密工作...
在给出的压缩包文件中,`rsa.jar`可能是一个包含上述MD5和RSA实现的Java库,`readme.txt`可能是关于如何使用这些功能的说明,而`Test_WebSafe`可能是一个测试用例,用于演示如何在Web环境中安全地使用这些加密算法。...
在这个项目中,我们关注的是"AES+RSA加密解密",这是两种广泛使用的加密算法,适用于JavaScript和Java环境中的前后端数据交换。下面将详细介绍这两个加密算法以及如何实现它们的互通。 **AES(Advanced Encryption ...
在"rsa前端加密,java后台解密"的场景中,前端使用RSA公钥对数据进行加密,然后将加密后的数据发送给后端,后端用私钥进行解密。这样可以确保数据在传输过程中的安全性,因为即使数据被截获,没有私钥也无法解密。 ...
在Java中,`java.security`包提供了`KeyPairGenerator`和`Cipher`接口来生成RSA密钥对和执行加密/解密操作。 接下来,AES(Advanced Encryption Standard)是另一种常用的对称加密算法,它比RSA更快,但安全性稍弱...