iOS ApplePay paymentData 加解密 (待续)
概述
本篇主要讲述在 iOS 环境下如何做 ApplePay 加解密处理,通过这次研究和学习,加深对数据加解密的认识。
注意:正常流程中,加解密不会放在前端处理,需要由服务端处理。
苹果官方对相关数据的结构说明:
https://developer.apple.com/library/content/documentation/PassKit/Reference/PaymentTokenJSON/PaymentTokenJSON.html
国内加密采用的RSA加密,美国区采用的是ECC加密算法。本文只介绍中国区的方式。
1 paymentData获取
在ApplePay sheet 用户验证指纹或密码通过后,会进入系统的下面这个回调方法里:
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controllerdidAuthorizePayment:(PKPayment *)paymentcompletion:(void (^)(PKPaymentAuthorizationStatus status))completion
{if (payment){NSData * paymentData = payment.token.paymentData;NSError * error = nil ;NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:paymentDataoptions:NSJSONReadingMutableContainerserror:&error];NSLog(@"token: %@", dic);// 通常流程,将 paymentData 传给服务端,由服务端解密数据,在调用银联后端接口发起扣款// ...... UI展示流程处理...... 略}
}
上述代码中的 paymentData 二进制数据是 json数据格式,中包含了苹果加密后的支付信息数据。
例如:对打印出来的数据进行整理可以看到如下:
{"data" : "juTLgE+0gQPg3RSe5DdJj1/w4amEvJOWSIka+nHNGFmFVd028omhkwMNNqG0exHgT39DAXnKqVNBh4ExGvIEgO7yi97JhDOmwq0nTyvPF/U393wgizrmoe8zX1FpUzI7e2co8PIYCJLkC6uTIuuumsE//503nDhvnz9frzmiMYVhdquf56couB028QBhJiQAupLM+NawVJ41i7e7WJIfyVhYEEn1Qw0TKZKy+Y65PkhAgdwlUGkKUI6r2IpHCc/l4EWvpn1tcVQvVeoG6qJxUdszgL6qrJBLtaT+/8teg9/jfn0iQwipEgYfTjalgHwXx3nop0dK2ZxzcOzdclfTY3uguM6HBNK6rK3hL2B/LnidAuWE0EWMp5/kqNunDJsSXsUM4+g6zg7ceVjlndZ0YLrQozxRkhPkgHHGtjFxn01PpeGSMMdoAVc8iOgpGKrjx/AAIp2jNY1fZZ1G4cYzW+gsJo5PrmPV7gGxA+M+HG5xdwMVfa9/cxS0qVU2eMw92OB7hdgaIW6cwONETgrd0Y2vF/oHiw7AbRiX/3GxkOJfJ9/5S0P6cxJF4JsvVHkrgit6gZPMCMXFQxDQsK8DlmQ9YxzDRIJCb9jxKE0=","header" : {"publicKeyHash" : "YcmdtTV209LCGVZV99T0lNab3yo0KnudAyBKQPo+5e8=","transactionId":" 41a6eb8dd8602def5f41463ad314e484289258df71ab17b50204ea4795a3db52","wrappedKey" : "l6w4oBmvLF/f/6Gj7idhO5aIFlwZ5qZrqSLxR+mLqsjJqHLf2OUTObn+UOO/Iaupc+nc6Kuz1ZTQbBMG2w6/KC8F07lZTPnCOcHVxxBP03UQn6gNkNV8DLNNqJ9GoBDzbGy/dWgKBBPNEdgA59jKY+8H/XQzvNuZqiFDM4LTr+O3/FdqGy6PxfFHRwRNV15WoKtsfQ91xPf++MI4GoTZSdxpc63ewm/8l5Q81AqnZMH03PMRyu8POT92tl10tg8GRmQFCXMgBm7GM+6nz0tebOoLndspqHbe9xtAGmxzseuFCi4A2q8WaqzPgnQ917bvuUnxNHAkXoPTVIUCsXzxXA=="},"signature" : "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","version" : "RSA_v1"
}
json数据中的每一个字段说明,参见之前提到的苹果文档。文档中的验签流程暂不涉及。
加密的支付信息保存在data中
3 解密步骤
- 使用ApplePay证书的私钥,对 wrappedKey 进行 RSA 解密,得到 AES加密 key
- 使用步骤1得到的AES key,对 data 数据进行 AES 解密,得到相关的支付信息。
3.1 获取AES Key
wrappedKey 采用的加密方式为 RSA/ECB/OAEPWithSHA256AndMGF1Padding
系统的iOS10 以前的api,暂时没有找到解密工具方法。(使用第三方 openssl 库应该也可以解密)
最新找到的系统 API 是 iOS 10 提供的。
解密的参考代码如下:
// 获取私钥
// 传入.p12的私钥文件路径和密码
+ (SecKeyRef)getPrivateKeyRefWithContentsOfFile:(NSString *)filePath password:(NSString*)password{NSData *p12Data = [NSData dataWithContentsOfFile:filePath];if (!p12Data) {return nil;}SecKeyRef privateKeyRef = NULL;NSMutableDictionary * options = [[NSMutableDictionary alloc] init];[options setObject: password forKey:(__bridge id)kSecImportExportPassphrase];CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);OSStatus securityError = SecPKCS12Import((__bridge CFDataRef) p12Data, (__bridge CFDictionaryRef)options, &items);if (securityError == noErr && CFArrayGetCount(items) > 0) {CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);SecIdentityRef identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);securityError = SecIdentityCopyPrivateKey(identityApp, &privateKeyRef);if (securityError != noErr) {privateKeyRef = NULL;}}CFRelease(items);return privateKeyRef;
}// 解密数据,返回字符串类型
+ (NSString *)decryptWrappedKey:(NSString *)strprivateKeyWithContentsOfFile:(NSString *)pathpassword:(NSString *)password
{SecKeyRef keyRef = [self getPrivateKeyRefWithContentsOfFile:path password:password];NSData *origionData = [[NSData alloc] initWithBase64EncodedString:str options:0];CFErrorRef errorRef = nil;size_t blockBytes = SecKeyGetBlockSize(keyRef);size_t src_block_size = blockBytes;NSMutableData *resultData = [[NSMutableData alloc] init];for (int idx = 0; idx < origionData.length; idx += src_block_size){NSData *targetData = [[origionData subdataWithRange:NSMakeRange(idx, src_block_size)] copy];CFDataRef targetDataRef = (__bridge CFDataRef)(targetData);CFDataRef dataRef = SecKeyCreateDecryptedData(keyRef, kSecKeyAlgorithmRSAEncryptionOAEPSHA256, targetDataRef, &errorRef);if (dataRef != nil) {NSData *partData = (__bridge NSData *)(dataRef);[resultData appendData:partData];NSLog(@"add %i", idx);}if (errorRef != nil) {NSLog(@"error = %@", errorRef);}NSUInteger leftSize = origionData.length - idx - src_block_size;if ((leftSize < src_block_size) && leftSize > 0) {// 剩余部分也要解密NSData *targetData2 = [[origionData subdataWithRange:NSMakeRange(idx + src_block_size, leftSize)] copy];CFDataRef targetDataRef2 = (__bridge CFDataRef)(targetData2);CFDataRef dataRef2 = SecKeyCreateDecryptedData(keyRef, kSecKeyAlgorithmRSAEncryptionOAEPSHA256, targetDataRef2, &errorRef);if (dataRef2 != nil) {NSData *partData2 = (__bridge NSData *)(dataRef2);[resultData appendData:partData2];NSLog(@"add %i", idx);}break;}}if (resultData.length == 0) {return nil;}else {//2.把二进制数据转换为字符串返回return [resultData base64EncodedStringWithOptions:0];}
}
得到的解密后的key
3.2 解密Data(未完成)
data 字段加密方式为“ AES–128 (id-aes128-GCM 2.16.840.1.101.3.4.1.6), with an initialization vector of 16 null bytes and no associated authentication data.”
注意:是GCM模式,初始向量为16个空字节,并且没有associated authentication data(即所谓的AAD)
ECB 或 CBC 比较常见,暂时没有找到AES-GCM模式的解密API,故打算自己编译 openssl 库,研究openssl 的 API 来解密。
TODO:学习 openssl api 使用,解密 AES 128 GCM 数据。
进阶
目前的加解密只停留在 api 和工具的使用,以后需要进一步了解和学习背后的算法和原理,更进一步提升自己
转载于:https://my.oschina.net/u/859523/blog/786918
iOS ApplePay paymentData 加解密 (待续)相关推荐
- ios下使用rsa算法与php进行加解密通讯
首先了解一下几个相关概念,以方便后面遇到的问题的解决: RSA算法:1977年由Ron Rivest.Adi Shamirh和LenAdleman发明的,RSA就是取自他们三个人的名字.算法基于一个数 ...
- android byte转string_高性能AES256对称加解密,兼容Java、IOS、Android
最近在设计一个给IOS和Android提供接口的项目框架,在接口安全上准备使用常规的加密技术,确保在非法访问接口的情况下拿到的数据一时半会也没用. 查了相关的资料,用的最多的几种加密算法,DES.AE ...
- java ios rsa解密乱码_java与IOS之间的RSA加解密
很简单的一个需求,ipad端给密码RSA加密,传到java后台,解密.RSA加密算法是基于一个密钥对的,分为公钥和私钥,一般情况公钥加密,私钥解密,但也可私钥加密,公钥解密.还可以验签,就是先用私钥对 ...
- ios java aes_PHP7 AES加密解密函数_兼容ios/andriod/java对等加解密
**PHP7.0 7.1 7.2 7.3 AES对等加解密类 函数文件_兼容ios/andriod/java等** 由于新项目规划要求使用PHP7.2开发环境,但在部分新系统中仍需使用AES加解密方式 ...
- SM2加密解决java与iOS端加解密不配套问题
SM2加密解决java与iOS端加解密不配套问题 问题描述 问题判定 代码 声明 问题描述 使用java开发的SM2加解密,由java层生成SM2公私钥,iOS.Android(因和java层一致,暂 ...
- iOS 使用 SM2 SM4 加解密,SM2 签名验签及 SM3 签名
前言 对于开发人员,开发中加解密是经常用到的,常见的密码算法 MD5.SHA.AES.DES,RSA 等等,这些无一例外都是国外的加密算法.基于安全和宏观战略考虑,我国从 2010 年先后推出了 SM ...
- iOS - 加解密(对称,非对称)(AES DES base64这里都有),数字签名,cookie
这篇文章不是研究性的东西,主要是简单的一些知识, 开篇如此, 我尽量不让读者失望. 首先罗列一些知识点: 1.加密算法通常分为对称性加密算法和非对称性加密算法:对于对称性加密算法,信息接收双方都需事先 ...
- linux安装php7 nagnx,iOS下使用rsa算法與php進行加解密通訊
首先了解一下幾個相關概念,以方便后面遇到的問題的解決: RSA算法:1977年由Ron Rivest.Adi Shamirh和LenAdleman發明的,RSA就是取自他們三個人的名字.算法基於一個數 ...
- Java/IOS通用异或加解密字符串
1.Java的异或加解密算法 在使用异或加解密时,加密和解密的密钥必须保持相同,否则解密时无法恢复为原来的内容. public class XOREncryptAndDecrypt {//密钥 加解密 ...
- CCCrypt函数——iOS加解密必知
需要引入框架 #import <CommonCrypto/CommonCryptor.h> 函数定义: CCCryptorStatus CCCrypt(CCOperation op, / ...
最新文章
- c语言算法6,c语言6函数和算法.ppt
- 高并发编程-Runtime.getRuntime().addShutdownHook为自己的应用添加hook
- 漫步者蓝牙驱动_有什么平价好用的蓝牙耳机?双11不踩雷高性价比蓝牙耳机推荐...
- 1020 月饼 (25 分)(c语言)
- js 里面的键盘事件对应的键码
- java 统计图 mysql_java实现各种数据统计图(转)
- springmvc 后台向页面EasyUI的Datagrid传递数据(JSon格式)
- 小学接触web的我是如何拿下蚂蚁实习 Offer的
- 【转】使用CSS 禁止文本选择
- ubuntu复制文件到另一个文件夹_Excel VBA之FSO-2.2文件夹的复制
- c\c++中比较两个字符串或string对象是否相等
- PHP作用域和文件夹操作
- 单身10年!最孤单水蛙“罗密欧”有望“脱单”
- matlab 关闭mdl,双击m文件和mdl文件重新打开一个matlab主程序
- Linux中c语言strcmp,c语言常用函数strcmp函数和strcpy函数
- RecyclerView系列:GridLayoutManager的构造函数中的orientation理解
- java 生成二维码图片
- opencv 脸部识别开源软件
- 百度飞桨7日营——世界冠军带你从零实践强化学习总结
- 阿里国际站装修尺寸是多少1920像素模板阿里巴巴全屏代码装修教程优化美化店铺工具