Android传输数据时Rsa加密解密详解
一、RSA加密算法
RSA加密算法是一种“非对称加密算法”。使用长度可以变化的密钥。 RSA 是第一个既能用于数据加密也能用于数字签名的算法。
RSA的安全性依赖于大数分解,小于 1024 位的 N 已经被证明是不安全的,而且由于 RSA 算法进行的都是大数计算,是的 RSA 最快的情况也比 DES 慢,因此通常 RSA 只能用于加密少量数据或者加密密钥。
RSA算法原理:
1. 随机选择两个大质数 p和 q ,计算 N = p*q;
2. 选择一个大于 1小于 N 的自然数 e , e 必须与 (p-1)(q-1) 互素
3. 用公式计算出 d: d*e = 1(mod(p-1)(q-1))
4. 销毁 p和 q
最终得到的 N和 e 就是“公钥”, d 就是“私钥”;发送方使用 N 去加密数据,接收方只有使用 d 才能解开数据内容。
二、加密注意事项
Android加密过的数据,服务端无法解密:
1. 加密填充方式不同
Android系统 RSA 实现是“ RSA/None/NoPadding ”
Java 的 JDK 实现是“ RSA/None/PKCS1Padding ”
注:加密填充方式选择 “RSA/None/PKCS1Padding ”
2. 实现分段加密
RSA非对称加密内容长度有限制, 1024 位 key 最多只能加密 127 位数据,否则会报错: javax.crypto.IllegalBlockSizeException:
input must be
und er
256 bytes , RSA是常用的非对称加密算法。出现“不正确长度”原因是待加密数据超长所致。
RSA算法规定:待加密的字节数不能超过密钥的长度值除以8再减去11,而加密后得到密文的字数,正好是密钥长度值除以8。
注:小数据可以不使用分段加密,一旦数据超过密钥支持最大字节数,使用分段加密。
3. 私钥加密和解密都很耗时,所以根据不同需求采用不同方案进行加解密。个人觉得因为服务器要求解密效率高,所以客户端私钥加密,服务器公钥解密比较好一点。加密之后数据大小差不多是加密前的 1.5倍。
三、RSA加密算法实例
1. 设置变量
/**
非对称加密密钥算法 */
public static final
String RSA
= "RSA" ;
/**
加密填充方式 */
public static final
String ECB_PKCS1_PADDING
= "RSA/ECB/PKCS1Padding" ;
/**
秘钥默认长度 */
public static final int
DEFAULT_KEY_SIZE = 2048;
/**
当要加密的内容超过 bufferSize ,则采用 partSplit 进行分块加密 */
public static final byte []
DEFAULT_SPLIT
= "#PART#" .getBytes();
/**
当前秘钥支持加密的最大字节数 */
public static final int
DEFAULT_BUFFERSIZE = ( DEFAULT_KEY_SIZE
/ 8) - 11;
2. 生成密钥对
/**
*
随机生成 RSA 密钥对
*
* @param keyLength
密钥长度,范围:512 ~ 2048 一般1024
* @return
*/
public static
KeyPair generateRSAKeyPair( int
keyLength) {
try
{
KeyPairGenerator kpg = KeyPairGenerator. getInstance ( RSA );
kpg.initialize(keyLength);
return
kpg.genKeyPair();
} catch
(NoSuchAlgorithmException e) {
e.printStackTrace();
return null ;
}
}
3. 公钥加密
/**
*
用公钥对字符串进行加密
*
* @param data
原文
*/
public static byte [] encryptByPublicKey( byte []
data, byte [] publicKey)
throws Exception {
//
得到公钥
X509EncodedKeySpec keySpec =
new X509EncodedKeySpec(publicKey);
KeyFactory kf = KeyFactory. getInstance ( RSA );
PublicKey keyPublic = kf.generatePublic(keySpec);
//
加密数据
Cipher cp = Cipher. getInstance ( ECB_PKCS1_PADDING );
cp.init(Cipher. ENCRYPT_MODE , keyPublic);
return
cp.doFinal(data);
}
4. 私钥解密
/**
*
使用私钥进行解密
*/
public static byte [] decryptByPrivateKey( byte []
encrypted, byte [] privateKey)
throws Exception {
//
得到私钥
PKCS8EncodedKeySpec keySpec =
new PKCS8EncodedKeySpec(privateKey);
KeyFactory kf = KeyFactory. getInstance ( RSA );
PrivateKey keyPrivate = kf.generatePrivate(keySpec);
//
解密数据
Cipher cp = Cipher. getInstance ( ECB_PKCS1_PADDING );
cp.init(Cipher. DECRYPT_MODE , keyPrivate);
byte [] arr = cp.doFinal(encrypted);
return
arr;
}
5. 私钥加密
/**
*
私钥加密
*
* @param data 待加密数据
* @param privateKey
密钥
* @return
byte[]
加密数据
*/
public static byte [] encryptByPrivateKey( byte []
data, byte [] privateKey)
throws Exception {
//
得到私钥
PKCS8EncodedKeySpec keySpec =
new PKCS8EncodedKeySpec(privateKey);
KeyFactory kf = KeyFactory. getInstance ( RSA );
PrivateKey keyPrivate = kf.generatePrivate(keySpec);
//
数据加密
Cipher cipher = Cipher. getInstance ( ECB_PKCS1_PADDING );
cipher.init(Cipher. ENCRYPT_MODE , keyPrivate);
return
cipher.doFinal(data);
}
6. 公钥解密
/**
*
公钥解密
*
* @param data 待解密数据
* @param publicKey
密钥
* @return
byte[]
解密数据
*/
public static byte [] decryptByPublicKey( byte []
data, byte [] publicKey)
throws Exception {
//
得到公钥
X509EncodedKeySpec keySpec =
new X509EncodedKeySpec(publicKey);
KeyFactory kf = KeyFactory. getInstance ( RSA );
PublicKey keyPublic = kf.generatePublic(keySpec);
//
数据解密
Cipher cipher = Cipher. getInstance ( ECB_PKCS1_PADDING );
cipher.init(Cipher. DECRYPT_MODE , keyPublic);
return
cipher.doFinal(data);
}
7. 加密解密实现
KeyPair keyPair =
generateRSAKeyPair ( DEFAULT_KEY_SIZE );
//
公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
//
私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
try {
//公钥加密
byte [] encryByte =
encryptByPublicKey ( "Lking" .getBytes(),publicKey.getEncoded());
String encryBase64 = Base64. encodeToString (encryByte,Base64. DEFAULT );
Log. e ( "Lking" , "RSA公钥加密 ---->" +encryBase64);
//私钥解密
byte [] encryBytepri =
decryptByPrivateKey (Base64. decode (encryBase64,Base64. DEFAULT ),
privateKey.getEncoded());
String pri = new
String(encryBytepri);
Log. e ( "Lking" , "RSA私钥解密 ---->" +pri);
} catch
(Exception e) {
e.printStackTrace();
}
四、分段 RSA加密算法实例
1. 设置变量
/**
非对称加密密钥算法 */
public static final
String RSA
= "RSA" ;
/**
加密填充方式 */
public static final
String ECB_PKCS1_PADDING
= "RSA/ECB/PKCS1Padding" ;
/**
秘钥默认长度 */
public static final int
DEFAULT_KEY_SIZE = 2048;
/**
当要加密的内容超过 bufferSize ,则采用 partSplit 进行分块加密 */
public static final byte []
DEFAULT_SPLIT
= "#PART#" .getBytes();
/**
当前秘钥支持加密的最大字节数 */
public static final int
DEFAULT_BUFFERSIZE = ( DEFAULT_KEY_SIZE
/ 8) - 11;
2. 生成密钥对
/**
*
随机生成 RSA 密钥对
*
* @param keyLength
密钥长度,范围:512 ~ 2048
* 一般 1024
* @return
*/
public static
KeyPair generateRSAKeyPair( int
keyLength) {
try
{
KeyPairGenerator kpg = KeyPairGenerator. getInstance ( RSA );
kpg.initialize(keyLength);
return
kpg.genKeyPair();
} catch
(NoSuchAlgorithmException e) {
e.printStackTrace();
return null ;
}
}
3. 公钥分段加密
/**
*
用公钥对字符串进行分段加密
*
*/
public static byte [] encryptByPublicKeyForSpilt( byte []
data, byte [] publicKey)
throws
Exception {
int
dataLen = data. length ;
if
(dataLen <=
DEFAULT_BUFFERSIZE ) {
return
encryptByPublicKey (data, publicKey);
}
List<Byte> allBytes =
new
ArrayList<Byte>( 2048 );
int
bufIndex =
0 ;
int
subDataLoop =
0 ;
byte [] buf =
new byte [ DEFAULT_BUFFERSIZE ];
for
( int
i =
0 ; i < dataLen; i++) {
buf[bufIndex] = data[i];
if
(++bufIndex ==
DEFAULT_BUFFERSIZE
|| i == dataLen -
1 ) {
subDataLoop++;
if
(subDataLoop !=
1 ) {
for
( byte
b :
DEFAULT_SPLIT ) {
allBytes.add(b);
}
}
byte [] encryptBytes =
encryptByPublicKey (buf, publicKey);
for
( byte
b : encryptBytes) {
allBytes.add(b);
}
bufIndex =
0 ;
if
(i == dataLen -
1 ) {
buf =
null ;
}
else {
buf =
new byte [Math. min ( DEFAULT_BUFFERSIZE ,
dataLen - i - 1 )];
}
}
}
byte [] bytes =
new byte [allBytes.size()];
{
int
i =
0 ;
for
(Byte b : allBytes) {
bytes[i++] = b.byteValue();
}
}
return
bytes;
}
4. 私钥分段解密
/**
*
使用私钥分段解密
*
*/
public static byte [] decryptByPrivateKeyForSpilt( byte []
encrypted, byte [] privateKey)
throws
Exception {
int
splitLen =
DEFAULT_SPLIT . length ;
if
(splitLen <=
0 ) {
return
decryptByPrivateKey (encrypted, privateKey);
}
int
dataLen = encrypted. length ;
List<Byte> allBytes =
new
ArrayList<Byte>( 1024 );
int
latestStartIndex =
0 ;
for
( int
i =
0 ; i < dataLen; i++) {
byte
bt = encrypted[i];
boolean
isMatchSplit =
false ;
if
(i == dataLen -
1 ) {
//
到 data 的最后了
byte [] part =
new byte [dataLen - latestStartIndex];
System. arraycopy (encrypted, latestStartIndex,
part, 0 , part. length );
byte [] decryptPart =
decryptByPrivateKey (part, privateKey);
for
( byte
b : decryptPart) {
allBytes.add(b);
}
latestStartIndex = i + splitLen;
i = latestStartIndex -
1 ;
}
else if (bt ==
DEFAULT_SPLIT [ 0 ])
{
//
这个是以 split[0] 开头
if
(splitLen >
1 ) {
if
(i + splitLen < dataLen) {
//
没有超出 data 的范围
for
( int
j =
1 ; j < splitLen; j++) {
if
( DEFAULT_SPLIT [j] != encrypted[i
+ j]) {
break ;
}
if
(j == splitLen -
1 ) {
//
验证到 split 的最后一位,都没有 break ,则表明已经确认是 split 段
isMatchSplit =
true ;
}
}
}
}
else {
// split只有一位,则已经匹配了
isMatchSplit =
true ;
}
}
if
(isMatchSplit) {
byte [] part =
new byte [i - latestStartIndex];
System. arraycopy (encrypted, latestStartIndex,
part, 0 , part. length );
byte [] decryptPart =
decryptByPrivateKey (part, privateKey);
for
( byte
b : decryptPart) {
allBytes.add(b);
}
latestStartIndex = i + splitLen;
i = latestStartIndex -
1 ;
}
}
byte [] bytes =
new byte [allBytes.size()];
{
int
i =
0 ;
for
(Byte b : allBytes) {
bytes[i++] = b.byteValue();
}
}
return
bytes;
}
5. 私钥分段加密
/**
*
私钥分段加密
*
* @param
data 要加密的原始数据
* @param
privateKey
秘钥
*/
public static byte [] encryptByPrivateKeyForSpilt( byte []
data, byte [] privateKey)
throws
Exception {
int
dataLen = data. length ;
if
(dataLen <=
DEFAULT_BUFFERSIZE ) {
return
encryptByPrivateKey (data, privateKey);
}
List<Byte> allBytes =
new
ArrayList<Byte>( 2048 );
int
bufIndex =
0 ;
int
subDataLoop =
0 ;
byte [] buf =
new byte [ DEFAULT_BUFFERSIZE ];
for
( int
i =
0 ; i < dataLen; i++) {
buf[bufIndex] = data[i];
if
(++bufIndex ==
DEFAULT_BUFFERSIZE
|| i == dataLen -
1 ) {
subDataLoop++;
if
(subDataLoop !=
1 ) {
for
( byte
b :
DEFAULT_SPLIT ) {
allBytes.add(b);
}
}
byte [] encryptBytes =
encryptByPrivateKey (buf, privateKey);
for
( byte
b : encryptBytes) {
allBytes.add(b);
}
bufIndex =
0 ;
if
(i == dataLen -
1 ) {
buf =
null ;
}
else {
buf =
new byte [Math. min ( DEFAULT_BUFFERSIZE ,
dataLen - i - 1 )];
}
}
}
byte [] bytes =
new byte [allBytes.size()];
{
int
i =
0 ;
for
(Byte b : allBytes) {
bytes[i++] = b.byteValue();
}
}
return
bytes;
}
6. 公钥分段解密
/**
*
公钥分段解密
*
* @param
encrypted
待解密数据
* @param
publicKey
密钥
*/
public static byte [] decryptByPublicKeyForSpilt( byte []
encrypted, byte [] publicKey)
throws
Exception {
int
splitLen =
DEFAULT_SPLIT . length ;
if
(splitLen <=
0 ) {
return
decryptByPublicKey (encrypted, publicKey);
}
int
dataLen = encrypted. length ;
List<Byte> allBytes =
new
ArrayList<Byte>( 1024 );
int
latestStartIndex =
0 ;
for
( int
i =
0 ; i < dataLen; i++) {
byte
bt = encrypted[i];
boolean
isMatchSplit =
false ;
if
(i == dataLen -
1 ) {
//
到 data 的最后了
byte [] part =
new byte [dataLen - latestStartIndex];
System. arraycopy (encrypted, latestStartIndex,
part, 0 , part. length );
byte [] decryptPart =
decryptByPublicKey (part, publicKey);
for
( byte
b : decryptPart) {
allBytes.add(b);
}
latestStartIndex = i + splitLen;
i = latestStartIndex -
1 ;
}
else if (bt ==
DEFAULT_SPLIT [ 0 ])
{
//
这个是以 split[0] 开头
if
(splitLen >
1 ) {
if
(i + splitLen < dataLen) {
//
没有超出 data 的范围
for
( int
j =
1 ; j < splitLen; j++) {
if
( DEFAULT_SPLIT [j] != encrypted[i
+ j]) {
break ;
}
if
(j == splitLen -
1 ) {
//
验证到 split 的最后一位,都没有 break ,则表明已经确认是 split 段
isMatchSplit =
true ;
}
}
}
}
else {
// split只有一位,则已经匹配了
isMatchSplit =
true ;
}
}
if
(isMatchSplit) {
byte [] part =
new byte [i - latestStartIndex];
System. arraycopy (encrypted, latestStartIndex,
part, 0 , part. length );
byte [] decryptPart =
decryptByPublicKey (part, publicKey);
for
( byte
b : decryptPart) {
allBytes.add(b);
}
latestStartIndex = i + splitLen;
i = latestStartIndex -
1 ;
}
}
byte [] bytes =
new byte [allBytes.size()];
{
int
i =
0 ;
for
(Byte b : allBytes) {
bytes[i++] = b.byteValue();
}
}
return
bytes;
}
7.
KeyPair keyPair =
generateRSAKeyPair ( DEFAULT_KEY_SIZE );
//
公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
//
私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
try
{
//公钥分段加密
byte [] encryByte =
encryptByPublicKeyForSpilt ( "大于秘钥支持加密的最大字节数 ..." .getBytes(),
publicKey.getEncoded());
String encryBase64 = Base64. encodeToString (encryByte,Base64. DEFAULT );
Log. e ( "Lking" , "RSA公钥加密 ---->" +encryBase64);
//私钥分段解密
byte [] encryBytepri =
decryptByPrivateKeyForSpilt (Base64. decode (encryBase64,Base64. DEFAULT ),
privateKey.getEncoded());
String pri =
new String(encryBytepri);
Log. e ( "Lking" , "RSA私钥解密 ---->" +pri);
} catch
(Exception e) {
e.printStackTrace();
}