RSA是什么玩意这里就不再说了,大家可以自己搜索,不说废话,直接上正文
需求
客户端(android/ios)向服务端发送一串已经协议好的公钥加密数据到服务端,服务端使用私钥对公钥进行解码
思路
我们知道spring中我们有Filter
HandlerInterceptorAdapter
这些关于AOP方面的操作,所以各位童鞋如果不想在业务层面进行解码,可以从这些方面入手解码,具体方式自行操作,本文不做详细介绍,至于客户端就简单多了,直接用公钥进行加密发送到服务端即可。
准备工作:生成RSA私钥,公钥
关于怎么生成RSA的私钥和公钥据笔者所知就两种
1.通过openSSL自行生成,网上已经有很多教程,但是比较麻烦,下面贴出支付宝的官方教程
http://app.alipay.com/market/document.htm?name=saomazhifu#page-23
2.使用支付宝提供工具一键生成,省时省力,具体生成文件这里就不贴出来了,有心的同学可以自行搜索。
密钥说明
**private**.**.pkcs8.pem
java后端使用的私钥文件
私钥是用于服务解码用的,不对外暴露,所以请妥善保管好,内容应该如下。
这里需要注意,如果服务器使用的是java,那么应当使用带pkcs8
字样的私钥文件,而你又是以文件形式进行加载私钥的话,需要把
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
这两行删掉,最终应该如下图一致
***private**.pem
其他后端语言使用的私钥文件
***public***.pem
暴露在外的客户端公钥文件
java相关RSA加解密代码,适用java服务端和android端
package com.rsa;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import javax.crypto.Cipher;
import com.pay.ali.tool.Base64;
/**
*
* @author joncch
*
*/
public class RSADecrpyt {
/**
* 加载私钥
* @param privateKeyStr
* @return
* @throws Exception
*/
private static RSAPrivateKey loadPrivateKey(String privateKeyStr) throws Exception {
Base64 decoder = new Base64();
byte[] buffer = decoder.decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
}
/**
* 解码密文
* @param rsaBase64Context
* @return
*/
public static String getDecryptString(String privateKey,String rsaBase64Context) {
try {
RSAPrivateKey key = loadPrivateKey(privateKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] encryptData = Base64.decode(rsaBase64Context);
ByteArrayOutputStream out = new ByteArrayOutputStream(encryptData.length);
int BLOCK_SIZE = 128;
for (int i = 0; i < encryptData.length; i += BLOCK_SIZE) {
int leftBytes = encryptData.length - i;
int length = (leftBytes <= BLOCK_SIZE) ? leftBytes : BLOCK_SIZE;
out.write(cipher.doFinal(encryptData, i, length));
}
String string = new String(out.toByteArray(), "UTF-8");
System.out.println("RAS.Decrpyt.Result = "+string);
System.out.println("RAS.Decrpyt.Length = "+string.length());
return string;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream(new File("e:/temp.txt"));
byte[] bs = new byte[fis.available()];
fis.read(bs);
System.out.println(RSADecrpyt.getDecryptString("",new String(bs,"utf-8")));
fis.close();
}
}
解码代码
package com.rsa;
import java.nio.ByteBuffer;
import java.security.KeyFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.List;
import javax.crypto.Cipher;
import com.pay.ali.tool.Base64;
/**
*
* @author joncch
*
*/
public class RSAEncrypt {
/**
* 载入公钥
* @param publicKeyStr
* @return
* @throws Exception
*/
private static RSAPublicKey loadPublicKey(String publicKeyStr) throws Exception {
Base64 decoder = new Base64();
byte[] buffer = decoder.decode(publicKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}
/**
* 加密明文
* @param context 明文
* @return
*/
public static byte[] doEncrypt(String key,String context) {
try {
RSAPublicKey publicKey = loadPublicKey(key);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] rawText = context.getBytes("utf-8");
List<byte[]> bslist = new ArrayList<>();
int totallength = 0;
int BLOCK_SIZE = 128 - 11;
for (int i = 0; i < rawText.length; i += BLOCK_SIZE) {
int leftBytes = rawText.length - i;
int length = (leftBytes <= BLOCK_SIZE) ? leftBytes : BLOCK_SIZE;
byte[] bs = cipher.doFinal(rawText, i, length);
totallength += bs.length;
bslist.add(bs);
}
ByteBuffer bf = ByteBuffer.allocate(totallength);
for (int i = 0; i < bslist.size(); i++) {
bf.put(bslist.get(i));
}
return bf.array();
}catch(Exception e){
e.printStackTrace();
}
return null;
}
/**
* 获得密文base64字串
* @param context 文明
* @return
*/
public static String getBase64Encrypt(String publicKey,String context){
String string = Base64.encode(doEncrypt(publicKey,context));
System.out.println("RSA.Encrypt.Result="+string);
System.out.println("RSA.Encrypt.Lenth="+string.length());
return string;
}
public static void main(String[] args) {
String s = RSAEncrypt.getBase64Encrypt("","123456");
System.out.println(s);
}
}
说明
很多网上教程中对Cipher
的初始化都是直接使用RSA
但是因为android和java服务端的标准不太一样会导致解码失败
所以这里需要把值改变为RSA/ECB/PKCS1Padding
这样两边的算法就一致了
到此为止,服务端的解码已经完成,其中本文中加载密钥的方式是直接放到一个字符串常量中
Cipher cipher = Cipher.getInstance("RSA");//正常情况
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");//android对服务端后台情况
IOS公钥加密代码
值得注意的是,在java中密钥使用的是pem
格式,然而苹果中使用的是der
格式,所以需要使用openssl
进行转换,又因为苹果自带openssl
工具,所以打开终端执行已下步骤即可
按提示操作
生成出来的rsa_public_key.der即为IOS端密钥,使用此密钥进行加密
IOS端加密代码调用
rsaEncrypt
获得密文
- (SecKeyRef) getPublicKey{
if (_public_key == nil){
NSString* filePath = [[NSBundle mainBundle] pathForResource:@"rsa_public_key" ofType:@"der"];
NSData* certificateData = [NSData dataWithContentsOfFile:filePath];
SecCertificateRef myCertificate = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certificateData);
if (myCertificate == nil) {
NSLog(@"无法读取公钥内容");
return nil;
}
SecPolicyRef myPolicy = SecPolicyCreateBasicX509();
SecTrustRef myTrust;
OSStatus status = SecTrustCreateWithCertificates(myCertificate,myPolicy,&myTrust);
SecTrustResultType trustResult;
if (status == noErr) {
status = SecTrustEvaluate(myTrust, &trustResult);
}else{
return nil;
}
_public_key = SecTrustCopyPublicKey(myTrust);
CFRelease(myCertificate);
CFRelease(myPolicy);
CFRelease(myTrust);
}
return _public_key;
}
- (NSData*) rsaEncrypt:(NSData*) data{
SecKeyRef key = [self getPublicKey];
if (key == nil) {
return nil;
}
size_t cipherBufferSize = SecKeyGetBlockSize(key);
uint8_t* cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));
size_t blockSize = cipherBufferSize - 11;
size_t blockCount = (size_t)ceil([data length] / (double)blockSize);
NSMutableData *encryptedData = [[NSMutableData alloc] init];
for (int i=0; i < [data length] ; i += blockSize){
int bufferSize = (int)MIN(blockSize,[data length] - i * blockSize);
NSData *buffer = [data subdataWithRange:NSMakeRange(i * blockSize, bufferSize)];
OSStatus status = SecKeyEncrypt(key, kSecPaddingPKCS1, (const uint8_t *)[buffer bytes],
[buffer length], cipherBuffer, &cipherBufferSize);
if (status == noErr){
NSData *encryptedBytes = [[NSData alloc] initWithBytes:(const void *)cipherBuffer length:cipherBufferSize];
[encryptedData appendData:encryptedBytes];
}else{
if (cipherBuffer) free(cipherBuffer);
return nil;
}
}
if (cipherBuffer) free(cipherBuffer);
return encryptedData;
}