概述

本篇主要讲述在 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 解密步骤

  1. 使用ApplePay证书的私钥,对 wrappedKey 进行 RSA 解密,得到 AES加密 key
  2. 使用步骤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 加解密 (待续)相关推荐

  1. ios下使用rsa算法与php进行加解密通讯

    首先了解一下几个相关概念,以方便后面遇到的问题的解决: RSA算法:1977年由Ron Rivest.Adi Shamirh和LenAdleman发明的,RSA就是取自他们三个人的名字.算法基于一个数 ...

  2. android byte转string_高性能AES256对称加解密,兼容Java、IOS、Android

    最近在设计一个给IOS和Android提供接口的项目框架,在接口安全上准备使用常规的加密技术,确保在非法访问接口的情况下拿到的数据一时半会也没用. 查了相关的资料,用的最多的几种加密算法,DES.AE ...

  3. java ios rsa解密乱码_java与IOS之间的RSA加解密

    很简单的一个需求,ipad端给密码RSA加密,传到java后台,解密.RSA加密算法是基于一个密钥对的,分为公钥和私钥,一般情况公钥加密,私钥解密,但也可私钥加密,公钥解密.还可以验签,就是先用私钥对 ...

  4. ios java aes_PHP7 AES加密解密函数_兼容ios/andriod/java对等加解密

    **PHP7.0 7.1 7.2 7.3 AES对等加解密类 函数文件_兼容ios/andriod/java等** 由于新项目规划要求使用PHP7.2开发环境,但在部分新系统中仍需使用AES加解密方式 ...

  5. SM2加密解决java与iOS端加解密不配套问题

    SM2加密解决java与iOS端加解密不配套问题 问题描述 问题判定 代码 声明 问题描述 使用java开发的SM2加解密,由java层生成SM2公私钥,iOS.Android(因和java层一致,暂 ...

  6. iOS 使用 SM2 SM4 加解密,SM2 签名验签及 SM3 签名

    前言 对于开发人员,开发中加解密是经常用到的,常见的密码算法 MD5.SHA.AES.DES,RSA 等等,这些无一例外都是国外的加密算法.基于安全和宏观战略考虑,我国从 2010 年先后推出了 SM ...

  7. iOS - 加解密(对称,非对称)(AES DES base64这里都有),数字签名,cookie

    这篇文章不是研究性的东西,主要是简单的一些知识, 开篇如此, 我尽量不让读者失望. 首先罗列一些知识点: 1.加密算法通常分为对称性加密算法和非对称性加密算法:对于对称性加密算法,信息接收双方都需事先 ...

  8. linux安装php7 nagnx,iOS下使用rsa算法與php進行加解密通訊

    首先了解一下幾個相關概念,以方便后面遇到的問題的解決: RSA算法:1977年由Ron Rivest.Adi Shamirh和LenAdleman發明的,RSA就是取自他們三個人的名字.算法基於一個數 ...

  9. Java/IOS通用异或加解密字符串

    1.Java的异或加解密算法 在使用异或加解密时,加密和解密的密钥必须保持相同,否则解密时无法恢复为原来的内容. public class XOREncryptAndDecrypt {//密钥 加解密 ...

  10. CCCrypt函数——iOS加解密必知

    需要引入框架 #import <CommonCrypto/CommonCryptor.h>  函数定义: CCCryptorStatus CCCrypt(CCOperation op, / ...

最新文章

  1. c语言算法6,c语言6函数和算法.ppt
  2. 高并发编程-Runtime.getRuntime().addShutdownHook为自己的应用添加hook
  3. 漫步者蓝牙驱动_有什么平价好用的蓝牙耳机?双11不踩雷高性价比蓝牙耳机推荐...
  4. 1020 月饼 (25 分)(c语言)
  5. js 里面的键盘事件对应的键码
  6. java 统计图 mysql_java实现各种数据统计图(转)
  7. springmvc 后台向页面EasyUI的Datagrid传递数据(JSon格式)
  8. 小学接触web的我是如何拿下蚂蚁实习 Offer的
  9. 【转】使用CSS 禁止文本选择
  10. ubuntu复制文件到另一个文件夹_Excel VBA之FSO-2.2文件夹的复制
  11. c\c++中比较两个字符串或string对象是否相等
  12. PHP作用域和文件夹操作
  13. 单身10年!最孤单水蛙“罗密欧”有望“脱单”
  14. matlab 关闭mdl,双击m文件和mdl文件重新打开一个matlab主程序
  15. Linux中c语言strcmp,c语言常用函数strcmp函数和strcpy函数
  16. RecyclerView系列:GridLayoutManager的构造函数中的orientation理解
  17. java 生成二维码图片
  18. opencv 脸部识别开源软件
  19. 百度飞桨7日营——世界冠军带你从零实践强化学习总结
  20. 阿里国际站装修尺寸是多少1920像素模板阿里巴巴全屏代码装修教程优化美化店铺工具

热门文章

  1. php中百度编辑器的使用
  2. 动手学深度学习 环境安装
  3. APP兼容性测试如何测试?
  4. 常用WEB前端框架大全
  5. 神经网络的优缺点是什么,深度神经网络的优缺点
  6. 饿了么app的架构演进之路,你的外卖可不简单
  7. Spring Boot配置文件yml格式详解
  8. ConfuserEx加密工具
  9. 如何用计算机制作pop海报,怎么用ps制作pop海报_ps制作pop字体
  10. c语言输出图形之小飞机