Java RSA格式 转换与运算(转)
来源:互联网 发布:淘宝会员俱乐部 编辑:程序博客网 时间:2024/05/21 08:02
RSA是目前最有影响力的公钥加密算法,该算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥,即公钥,而两个大素数组合成私钥。公钥是可发布的供任何人使用,私钥则为自己所有,供解密之用。
解密者拥有私钥,并且将由私钥计算生成的公钥发布给加密者。加密都使用公钥进行加密,并将密文发送到解密者,解密者用私钥解密将密文解码为明文。
以甲要把信息发给乙为例,首先确定角色:甲为加密者,乙为解密者。首先由乙随机确定一个KEY,称之为密匙,将这个KEY始终保存在机器B中而不发出来;然后,由这个 KEY计算出另一个KEY,称之为公匙。这个公钥的特性是几乎不可能通过它自身计算出生成它的私钥。接下来通过网络把这个公钥传给甲,甲收到公钥后,利用公钥对信息加密,并把密文通过网络发送到乙,最后乙利用已知的私钥,就对密文进行解码了。以上就是RSA算法的工作流程。
算法实现过程为:
1. 随意选择两个大的质数p和q,p不等于q,计算N=pq。
2. 根据欧拉函数,不大于N且与N互质的整数個数為(p-1)(q-1)。
3. 选择一个整数e与(p-1)(q-1)互质,并且e小于(p-1)(q-1)。
4. 用以下这个公式计算d:d× e ≡ 1 (mod (p-1)(q-1))。
5. 将p和q的记录销毁。
以上内容中,(N,e)是公钥,(N,d)是私钥。
下面讲解RSA算法的应用。
RSA的公钥和私钥是由KeyPairGenerator生成的,获取KeyPairGenerator的实例后还需要设置其密钥位数。设置密钥位数越高,加密过程越安全,一般使用1024位。如下代码:
[代码]java代码:
1
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA);
2
// 密钥位数
3
keyPairGen.initialize(
1024
);
公钥和私钥可以通过KeyPairGenerator执行generateKeyPair()后生成密钥对KeyPair,通过KeyPair.getPublic()和KeyPair.getPrivate()来获取。如下代码:
[代码]java代码:
1
// 动态生成密钥对,这是当前最耗时的操作,一般要2s以上。
2
KeyPair keyPair = keyPairGen.generateKeyPair();
3
// 公钥
4
PublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
5
// 私钥
6
PrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
7
byte
[] publicKeyData = publicKey.getEncoded();
8
byte
[] privateKeyData = publicKey.getEncoded();
公钥和私钥都有它们自己独特的比特编码,可以通过getEncoded()方法获取,返回类型为byte[]。通过byte[]可以再度将公钥或私钥还原出来。具体代码如下:
[代码]java代码:
01
// 通过公钥byte[]将公钥还原,适用于RSA算法
02
public
static
PublicKey getPublicKey(
byte
[] keyBytes)
throws
03
NoSuchAlgorithmException,InvalidKeySpecException {
04
X509EncodedKeySpec keySpec =
new
X509EncodedKeySpec(keyBytes);
05
KeyFactory keyFactory = KeyFactory.getInstance(
"RSA"
);
06
PublicKey publicKey = keyFactory.generatePublic(keySpec);
07
return
publicKey;
08
}
09
// 通过私钥byte[]将公钥还原,适用于RSA算法
10
public
static
PrivateKey getPrivateKey(
byte
[] keyBytes)
throws
11
NoSuchAlgorithmException,InvalidKeySpecException {
12
PKCS8EncodedKeySpec keySpec =
new
PKCS8EncodedKeySpec(keyBytes);
13
KeyFactory keyFactory = KeyFactory.getInstance(
"RSA"
);
14
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
15
return
privateKey;
16
}
在上文讲到的RSA算法实现过程中提到(N,e)是公钥,(N,d)是私钥。既然已经获取到了PublicKey和PrivateKey了,那如何取到N、e、d这三个值呢。要取到这三个值,首先要将PublicKey和PrivateKey强制转换成RSAPublicKey和RSAPrivateKey。共同的N值可以通过getModulus()获取。执行RSAPublicKey.getPublicExponent()可以获取到公钥中的e值,执行RSAPrivateKey.getPrivateExponent()可以获取私钥中的d值。这三者返回类型都是BigInteger。代码如下:
[代码]java代码:
01
// 打印公钥信息
02
public
static
void
printPublicKeyInfo(PublicKey key){
03
RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
04
Log.d(MainActivity.TAG,
"RSAPublicKey:"
);
05
Log.d(MainActivity.TAG,
"Modulus.length="
+
06
rsaPublicKey.getModulus().bitLength());
07
Log.d(MainActivity.TAG,
"Modulus="
+
08
rsaPublicKey.getModulus().toString());
09
Log.d(MainActivity.TAG,
"PublicExponent.length="
+
10
rsaPublicKey.getPublicExponent().bitLength());
11
Log.d(MainActivity.TAG,
"PublicExponent="
+
12
rsaPublicKey.getPublicExponent().toString());
13
}
14
15
// 打印私钥信息
16
public
static
void
printPublicKeyInfo(PrivateKey key){
17
RSAPrivateKey rsaPublicKey = (RSAPrivateKey) privateKey;
18
Log.d(MainActivity.TAG,
"RSAPrivateKey:"
);
19
Log.d(MainActivity.TAG,
"Modulus.length="
+
20
rsaPrivateKey.getModulus().bitLength());
21
Log.d(MainActivity.TAG,
"Modulus="
+
22
rsaPrivateKey.getModulus().toString());
23
Log.d(MainActivity.TAG,
"PublicExponent.length="
+
24
rsaPrivateKey.getPrivateExponent().bitLength());
25
Log.d(MainActivity.TAG,
"PublicExponent="
+
26
rsaPrivateKey.getPrivateExponent().toString());
27
}
由于程序中动态生成KeyPair对明文加密后生成的密文是不可测的,所以在实际开发中通常在生成一个KeyPair后将公钥和私钥的N、e、d这三个特征值记录下来,在真实的开发中使用这三个特征值再去将PublicKey和PrivateKey还原出来。还原方法如下:
[代码]java代码:
01
// 使用N、e值还原公钥
02
public
static
PublicKey getPublicKey(String modulus, String
03
publicExponent)
04
throws
NoSuchAlgorithmException, InvalidKeySpecException {
05
BigInteger bigIntModulus =
new
BigInteger(modulus);
06
BigInteger bigIntPrivateExponent =
new
BigInteger(publicExponent);
07
RSAPublicKeySpec keySpec =
new
RSAPublicKeySpec(bigIntModulus,
08
bigIntPrivateExponent);
09
KeyFactory keyFactory = KeyFactory.getInstance(
"RSA"
);
10
PublicKey publicKey = keyFactory.generatePublic(keySpec);
11
return
publicKey;
12
}
13
14
// 使用N、d值还原公钥
15
public
static
PrivateKey getPrivateKey(String modulus, String
16
privateExponent)
17
throws
NoSuchAlgorithmException, InvalidKeySpecException {
18
BigInteger bigIntModulus =
new
BigInteger(modulus);
19
BigInteger bigIntPrivateExponent =
new
BigInteger(privateExponent);
20
RSAPrivateKeySpec keySpec =
new
RSAPrivateKeySpec(bigIntModulus,
21
bigIntPrivateExponent);
22
KeyFactory keyFactory = KeyFactory.getInstance(
"RSA"
);
23
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
24
return
privateKey;
25
}
公钥和私钥都具备后,就可以使用加解密的工具类javax.crypto.Cipher对明文和密文进行处理了。与所有的引擎类一样,可以通过调用Cipher类中的getInstance(String transformation)静态工厂方法得到Cipher对象。该方法中的参数描述了由指定输入产生输出所进行的操作或操作集合,可以是下列两种形式之一:“algorithm/mode/padding”或“algorithm”。例如下面的例子就是有效的transformation形式:"DES/CBC/PKCS5Padding"或"DES"。如果没有指定模式或填充方式,就使用特定提供者指定的默认模式或默认填充方式。
Cipher的加密和解密方式所调用的方法和过程都一样,只是传参不同的区别。如下代码:
[代码]java代码:
1
// 编码前设定编码方式及密钥
2
cipher.init(mode, key);
3
// 传入编码数据并返回编码结果
4
byte
[] dataResult = cipher.doFinal(input);
Cipher.init(mode, key)方法中MODE指加密或解密模式,值为Cipher.ENCRYPT_MODE或Cipher.DECRYPT_MODE,参数key在加密时传入PublicKey,在解密时以PrivateKey传入。Cipher.doFinal(byte[] data)则是将待编码数据传入后并返回编码结果。为了将编码结果转为可读字符串,通常最后还使用BASE 64算法对最终的byte[]数据编码后显示给开发者。
转载于:http://blog.csdn.net/syptt100/article/details/50781275
0 0
- Java RSA格式 转换与运算(转)
- Java RSA格式 转换与运算
- RSA密钥之C#格式与Java格式转换
- RSA密钥之C#格式与Java格式转换
- RSA密钥之C#格式与Java格式转换
- RSA之格式转换
- RSA密钥,JAVA与.NET之间转换
- pkcs1与pkcs8格式RSA私钥互相转换
- pkcs1与pkcs8格式RSA私钥互相转换
- 《RSA与大数运算》
- RSA与大数运算
- RSA与大数运算
- RSA的密钥把JAVA格式转换成C#的格式(一)
- RSA的密钥把JAVA格式转换成C#的格式(二)
- JAVA日期格式转换与数据类型转换
- 转贴:RSA与大数运算
- RSA与大数运算(转载)
- RSA密钥,JAVA与.NET,IOS之间转换
- grails executeQuery in
- 内部类详解
- ScrollView嵌套TextView,让TextView可以滚动
- BZOJ 3240 构造矩阵+矩阵快速幂
- Latex使用小结
- Java RSA格式 转换与运算(转)
- linux安装部署git
- 【JAVA】设计模式之命令模式(Command模式)的使用分析
- bootstrap-table分页模板和获取表中的ID
- Java面试题大全(part_2)
- 好的博客地址
- 消息队列之JMS消息服务讲解
- Java File renameTo方法重命名文件
- 事件document.Ready里的函数和外面的函数的区别