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;}
- RSA客户端(android/ios)与服务端的通信实现
- 客户端与服务端的TCP通信实现(Qt)
- Windows客户端与Android服务端的Socket通信(USB)
- IOS-18-网络通信之Socket通信中服务端与客户端的实现
- socket实现客户端与服务端通信(一)服务端
- socket实现客户端与服务端通信(三)服务端升级
- socket实现客户端与服务端通信(二)客户端
- 客户端(android/ios)与java服务端tomcat的gzip实现
- 警察与小偷的实现之一客户端与服务端通信
- iOS 客户端和服务端实现通信
- 实现Android手机(服务端)与PC(客户端)实现通信
- 使用简单的ServiceSockt实现服务端与客户端的通信
- WinSocket实现的服务端与客户端的通信
- 使用Mina框架开发 QQ Android 客户端(2) 客户端与服务端的通信
- HESSIAN 的VC++ 客户端与JAVA服务端通信 实现
- Windows客户端与Android服务端的Socket通信
- Windows客户端与Android服务端的Socket通信(USB
- PC客户端与Android服务端的Socket同步通信
- atitit 体系搭建的方法 解决方案 attilax总结.docx
- javaseday06(构造函数,this,static,main)
- C语言模式实现C++继承和多态
- atitit 总裁 执行长 分部负责人 ceo 总经理 执行委员会主席 日常工作职责.docx
- vue和php协作,开发环境不一致的问题?
- RSA客户端(android/ios)与服务端的通信实现
- Atitit 人员招募之道 attilax著
- The Tag Game(CodeForces
- 类 Unix 操作系统FreeBSD 11.1 发布
- 音视频直播--技术架构
- Atitit 2017年的技术趋势与未来的大技术趋势
- 乐观锁异常解决方法
- 先占坑 Pig的使用
- 【LeetCode大法】Merge Two Binary Trees