iOS安全相关 - RSA public key的处理

RSA部分基础

通常我们所说的RSA公钥1024位,2048位是RSA算法的模长度,https的TSL ssl部分也是使用RSA来进行加密握手.

RSA基本原理(略过)

$ openssl req -x509 -out public_key.der -outform der -new -newkey rsa:1024 -keyout private_key.pem -days 3650
  • public_key.der is an output based on x509 certificate. Note that in iOS must be .der format but not .pem
  • private_key.pem is the private key that you can use it to decrypt
  • rsa:1024 有时候是2048.is the key length. The longer the length, the safer it is
  • days is the days for effective period for this cert. In this case, is 10-Years

然后,将public_key.der拖到iOS project然后使用RSA.h RSA.m .

参考: http://jslim.net/blog/2013/01/05/rsa-encryption-in-ios-and-decrypt-it-using-php/

RSA加密中的Padding

padding即是填充方式,先说下为什么会有padding,由于RSA的算法原理中,需要被加密的明文c是要比模数小的。padding就是通过一些填充方式保证明文c的位数,且不能使c大于n.因此模的长度也觉得可以加密明文的长度,因此RSA不适合加密大段文本,一般用来加密一个对称加密的密钥,然后再用此对称加密密钥对大段文本加密。一般选择模式是RSA_PKCS1_PADDING

IOS中的RSA

在ios中可以使用<sercurity.framework>可实现些RSA的加密解密,但是framework的api只支持从标准证书文件(cer, crt)中读取公钥.

//加密方法
OSStatus SecKeyEncrypt(
    SecKeyRef           key,
    SecPadding          padding,
    const uint8_t       *plainText,
    size_t              plainTextLen,
    uint8_t             *cipherText,
    size_t              *cipherTextLen)
    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0);

// 解密方法
OSStatus SecKeyDecrypt(
    SecKeyRef           key,    
    SecPadding          padding,
    const uint8_t       *cipherText,
    size_t              cipherTextLen,
    uint8_t             *plainText, 
    size_t              *plainTextLen)  

iOS拿到的公钥类型

第一种: pem格式文件 或者 base64的 public key

一个pem格式的公钥文件,其中保存的公钥信息是base64编码的字符串,这个用iOS 系统sercurity.framework的api就不能读取。

后台经常会给一个xxx.pem的文件. 里面的内容用sublime打开就如上所示.
下面是pem内容示例(ps: 每行64个字符)

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApfNDz78E4qnU23PeE3lQ
DYaW9AtniNMWNn51eMANFtiFj6yvpAo+ejstkC4u0PevoA9YrhPUC97f8xd5Jss2
INyynKH3okVS4at5lxBBdpoqR3LxLSQPRcmh5h19PZj0/B6QO1Lm66qoxjoQUjoQ
4eqryb0zD5vwu+6kCQHH/sHSky8ZYdUH9p5baJOmLUFpqROPWZpliq7qxFTuLLoZ
jHEgbdPad/IX9IouYzrlnhQzUP+WjugnLU6NoeoKUer9YtPZg1WVbg/n98orsb8H
hmJL/RtAqWpOPMvEoYLGyiguFEPgjvYPV2dnSJxkTgb3XqnnujTN1BFsYDWmMC9S
TQIDAQAB
-----END PUBLIC KEY-----

实际, 上述文件中每行结尾都有一个隐藏的换行符\n,如果把换行符加上,然后写成一个NSString:

NSSring *pemPublicKey = @"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApfNDz78E4qnU23PeE3lQ\nDYaW9AtniNMWNn51eMANFtiFj6yvpAo+ejstkC4u0PevoA9YrhPUC97f8xd5Jss2\nINyynKH3okVS4at5lxBBdpoqR3LxLSQPRcmh5h19PZj0/B6QO1Lm66qoxjoQUjoQ\n4eqryb0zD5vwu+6kCQHH/sHSky8ZYdUH9p5baJOmLUFpqROPWZpliq7qxFTuLLoZ\njHEgbdPad/IX9IouYzrlnhQzUP+WjugnLU6NoeoKUer9YtPZg1WVbg/n98orsb8H\nhmJL/RtAqWpOPMvEoYLGyiguFEPgjvYPV2dnSJxkTgb3XqnnujTN1BFsYDWmMC9S\nTQIDAQAB\n-----END PUBLIC KEY-----";

这种是上面pem格式中间部分, 同时也不包含回车换行, 需要每64个字符添加一个换行符.

// base64编码的字符串
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApfNDz78E4qnU23PeE3lQDYaW9AtniNMWNn51eMANFtiFj6yvpAo+ejstkC4u0PevoA9YrhPUC97f8xd5Jss2INyynKH3okVS4at5lxBBdpoqR3LxLSQPRcmh5h19PZj0/B6QO1Lm66qoxjoQUjoQ4eqryb0zD5vwu+6kCQHH/sHSky8ZYdUH9p5baJOmLUFpqROPWZpliq7qxFTuLLoZjHEgbdPad/IX9IouYzrlnhQzUP+WjugnLU6NoeoKUer9YtPZg1WVbg/n98orsb8HhmJL/RtAqWpOPMvEoYLGyiguFEPgjvYPV2dnSJxkTgb3XqnnujTN1BFsYDWmMC9STQIDAQAB

第二种: public key 的16进制字符串

第二种,后台可能直接给Public Key 的16进制的字符串(Hex String), 或者 2进制字符串, 这种公钥一般称为裸公钥, HJ就是提供的这种中key.

16进制字符串表示的Public key

一共512位16进制,2进制位2048位(ps: 也有256位16进制,2进制1024位的public key).这种裸公钥相当于上面pem格式中的中间部分(除了-BEGIN- -END-两行, 并且中间部分不包含\n回车换行符), 只不过二进制/十六进制数据通过进行了base64编码成字符串,用sublime可以直接打开.

下面是一个16进制字符串public key, 提供512位16进制的字符串:

E00B364554A35D6705468698DC366115C09F2BA109D1F3A45901EF8872429752A0DAED95F50B31977FCF1989BC105143444D4583A479478F89148F1A35DACBACAC9584BFC528BE1AFF94685177514468F96F707BCBCD4F76DF989E5D7223384593AE81A1F2254D7CDD1CCA7BA01B006C4BAD87C2D270C51BF48B6CCECFA7022CAE93E9B17D31F0DB7A59E68D103BC99A3DDCA411CDDF2BC5558C7A88A884EFD33E52253C6D9E050F54C813A5EF38688C7A547072685399E5759FCFD03FD22B21E58D583C4D46EC5582A78FE4E18C10AF081970EEB14FEEDAA04F315D216EF988CB16F84FBBEE767CD51EDFFB23E83B303AD715B6E7A9D6CC475496F9BA3951A5

这种模式比较好存储, 我们可以通过编写代码将这种格式的数据转化成第一种格式(PEM)格式,

将裸Public Key转化成为需要

  1. 为裸 public_key 添加完整的头部和尾部
  2. 头部:30820122300D06092A864886F70D01010105000382010F003082010A0282010100
  3. 尾部: 0203010001
  4. 然后执行base64编码,然后每一行64位换行处理,加标准头和尾部就是标准的PEM文件的中间部分。

在Terminal中直接运行下面命令可以得到base64编码的public key
16进制字符串显示 -> 二进制字符串显示 -> base64编码

echo 30820122300D06092A864886F70D01010105000382010F003082010A0282010100E00B364554A35D6705468698DC366115C09F2BA109D1F3A45901EF8872429752A0DAED95F50B31977FCF1989BC105143444D4583A479478F89148F1A35DACBACAC9584BFC528BE1AFF94685177514468F96F707BCBCD4F76DF989E5D7223384593AE81A1F2254D7CDD1CCA7BA01B006C4BAD87C2D270C51BF48B6CCECFA7022CAE93E9B17D31F0DB7A59E68D103BC99A3DDCA411CDDF2BC5558C7A88A884EFD33E52253C6D9E050F54C813A5EF38688C7A547072685399E5759FCFD03FD22B21E58D583C4D46EC5582A78FE4E18C10AF081970EEB14FEEDAA04F315D216EF988CB16F84FBBEE767CD51EDFFB23E83B303AD715B6E7A9D6CC475496F9BA3951A50203010001 | xxd -r -ps | openssl base64

输出的结果是:

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4As2RVSjXWcFRoaY3DZh
FcCfK6EJ0fOkWQHviHJCl1Kg2u2V9Qsxl3/PGYm8EFFDRE1Fg6R5R4+JFI8aNdrL
rKyVhL/FKL4a/5RoUXdRRGj5b3B7y81Pdt+Ynl1yIzhFk66BofIlTXzdHMp7oBsA
bEuth8LScMUb9Itszs+nAiyuk+mxfTHw23pZ5o0QO8maPdykEc3fK8VVjHqIqITv
0z5SJTxtngUPVMgTpe84aIx6VHByaFOZ5XWfz9A/0ish5Y1YPE1G7FWCp4/k4YwQ
rwgZcO6xT+7aoE8xXSFu+YjLFvhPu+52fNUe3/sj6DswOtcVtuep1sxHVJb5ujlR
pQIDAQAB

然后手动添加首部和尾部,最终结果就和上面PEM格式内容一样了:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApfNDz78E4qnU23PeE3lQ
DYaW9AtniNMWNn51eMANFtiFj6yvpAo+ejstkC4u0PevoA9YrhPUC97f8xd5Jss2
INyynKH3okVS4at5lxBBdpoqR3LxLSQPRcmh5h19PZj0/B6QO1Lm66qoxjoQUjoQ
4eqryb0zD5vwu+6kCQHH/sHSky8ZYdUH9p5baJOmLUFpqROPWZpliq7qxFTuLLoZ
jHEgbdPad/IX9IouYzrlnhQzUP+WjugnLU6NoeoKUer9YtPZg1WVbg/n98orsb8H
hmJL/RtAqWpOPMvEoYLGyiguFEPgjvYPV2dnSJxkTgb3XqnnujTN1BFsYDWmMC9S
TQIDAQAB
-----END PUBLIC KEY-----

第二种解决方法, 直接转化成证书der格式的数据

例如,随便找一张der证书, 将它转化成的16进制字符串展示:

30820308308201f00209008932a038393835a1300d06092a864886f70d01010505003045310b30090603550406130241553113301106035504080c0a536f6d652d53746174653121301f060355040a0c18496e7465726e6574205769646769747320507479204c74643020170d3135303631303037333931355a180f32313135303531373037333931355a3045310b30090603550406130241553113301106035504080c0a536f6d652d53746174653121301f060355040a0c18496e7465726e6574205769646769747320507479204c746430820122300d06092a864886f70d01010105000382010f003082010a0282010100

*E00B364554A35D6705468698DC366115C09F2BA109D1F3A45901EF8872429752A0DAED95F50B31977FCF1989BC105143444D4583A479478F89148F1A35DACBACAC9584BFC528BE1AFF94685177514468F96F707BCBCD4F76DF989E5D7223384593AE81A1F2254D7CDD1CCA7BA01B006C4BAD87C2D270C51BF48B6CCECFA7022CAE93E9B17D31F0DB7A59E68D103BC99A3DDCA411CDDF2BC5558C7A88A884EFD33E52253C6D9E050F54C813A5EF38688C7A547072685399E5759FCFD03FD22B21E58D583C4D46EC5582A78FE4E18C10AF081970EEB14FEEDAA04F315D216EF988CB16F84FBBEE767CD51EDFFB23E83B303AD715B6E7A9D6CC475496F9BA3951A5*

0203010001300d06092a864886f70d0101050500038201010045c2e98898344a645889e227c112bbbaf09a66105e5e964a90f298420e4187510b4c13c705177ebf605a09c7df74b2ed51fe117a2ad291ee554ecd38db3c92ec06e9b5c1df27ca519d5c0330986bf7b6447e5e8e87607febef6ace24111a308840543458a52b365ac6ac392bf009df15bbba44155d095ddb711dd9599bb10c5d8a55f8531d09fa5be8db2dcdbcce869ea04a4dbfcd693f1f67689c3b1c259a3ece586008a69cdae17892cdcb6a11d45680b6854721c185937b24295b0fa115b9751020f65d6bfda0f4fb47a8982e80c7c3682daa113ef24bae4a7e82aaa2aa634bab8faa68b28b3d999720dc9c2fc272dc488d2256f0cd1dd8a13a400ab9dd6c
  • 找到30820122300D06092A864886F70D01010105000382010F003082010A0282010100 (这段代表-----BEGIN PUBLIC KEY-----)
  • 找到尾部'0203010001' (-----END PUBLIC KEY-----)
  • 两者之间刚好512位16进制数据,就是证书的2048位 publi key所在的地方. 直接用自己的16进制字符串public key换掉这部分,就伪造了一个后缀是.der的证书

注意: .der证书内还包括很多信息,例如地址.公司,过期时间.等等,一般rsa加密只用中间256字节(2048位)的public key就行了

其他参考内容 - 后台给出的 java 参考

后台给出的使用public key的参考:

String publicKeyStr = "30820122300D06092A864886F70D01010105000382010F003082010A0282010100"
+ "E00B364554A35D6705468698DC366115C09F2BA109D1F3A45901EF8872429752A0DAED95F50B31977FCF1989BC105143444D4583A479478F89148F1A35DACBACAC9584BFC528BE1AFF94685177514468F96F707BCBCD4F76DF989E5D7223384593AE81A1F2254D7CDD1CCA7BA01B006C4BAD87C2D270C51BF48B6CCECFA7022CAE93E9B17D31F0DB7A59E68D103BC99A3DDCA411CDDF2BC5558C7A88A884EFD33E52253C6D9E050F54C813A5EF38688C7A547072685399E5759FCFD03FD22B21E58D583C4D46EC5582A78FE4E18C10AF081970EEB14FEEDAA04F315D216EF988CB16F84FBBEE767CD51EDFFB23E83B303AD715B6E7A9D6CC475496F9BA3951A5"
+ "0203010001";

一般js中给的是裸公钥,即512位16进制(实际为二进制的2048位)

因为NDK中实现加密和解密,需要完整的公钥和私钥,所以需要相应的头部和尾部。

头部:30820122300D06092A864886F70D01010105000382010F003082010A0282010100

尾部: 0203010001

然后执行base64编码,然后每一行64位换行处理,加标准头和尾部就是标准的公钥了。

base64编码的命令: termial中,直接运行下面命令可以得到标准的公钥:

echo 30820122300D06092A864886F70D01010105000382010F003082010A0282010100A5F343CFBF04E2A9D4DB73DE1379500D8696F40B6788D316367E7578C00D16D8858FACAFA40A3E7A3B2D902E2ED0F7AFA00F58AE13D40BDEDFF3177926CB3620DCB29CA1F7A24552E1AB79971041769A2A4772F12D240F45C9A1E61D7D3D98F4FC1E903B52E6EBAAA8C63A10523A10E1EAABC9BD330F9BF0BBEEA40901C7FEC1D2932F1961D507F69E5B6893A62D4169A9138F599A658AAEEAC454EE2CBA198C71206DD3DA77F217F48A2E633AE59E143350FF968EE8272D4E8DA1EA0A51EAFD62D3D98355956E0FE7F7CA2BB1BF0786624BFD1B40A96A4E3CCBC4A182C6CA282E1443E08EF60F576767489C644E06F75EA9E7BA34CDD4116C6035A6302F524D0203010001| xxd -r -ps | openssl base64

其他参考文档:

关于PEM格式的public key 进行加密, 解密可以参考以下开源库:

https://github.com/ideawu/Objective-C-RSA

https://github.com/kuapay/iOS-Certificate--Key--and-Trust-Sample-Project

后面两个项目需要引入openssl库

https://blog.cnbluebox.com/blog/2014/03/19/rsajia-mi/

https://github.com/NianJi/BBRSACryptor

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容

  • /**ios常见的几种加密方法: 普通的加密方法是讲密码进行加密后保存到用户偏好设置( [NSUserDefaul...
    彬至睢阳阅读 2,837评论 0 7
  • 嘟哝嘟哝:最近接到一个任务:在客户端动态生成RSA密钥对,然后向服务器发送这个密钥对中的公钥字符串,由服务器进行公...
    TimmyR阅读 7,864评论 19 21
  • 这本享誉世界,出现在各大书评榜上,摆渡人灵魂深处的心灵鸡汤《摆渡人》,我想都看过吧,就算没看过也可能听说过。 我是...
    安茶阅读 595评论 12 13
  • wine_ids:2,4,5,6,7,8,14,22,23,24 menu_ids:17,18,19 SELECT...
    wjing阅读 224评论 0 0
  • 农夫种了一朵美丽玫瑰,他爱这朵玫瑰。 有一天,一个帅气王子路过,看到了这朵玫瑰花 王子说,我从未见过这般美丽,我能...
    洛阳创新梦工厂纪阅读 362评论 0 0