RSA客户端(android/ios)与服务端的通信实现

来源:互联网 发布:入驻淘宝费用是多少 编辑:程序博客网 时间:2024/05/21 11:14

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;}
阅读全文
0 0
原创粉丝点击