RSA部分基礎(chǔ)
通常我們所說(shuō)的RSA公鑰1024位,2048位是RSA算法的模長(zhǎng)度,https的TSL ssl部分也是使用RSA來(lái)進(jìn)行加密握手.
RSA基本原理(略過(guò))
$ 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 有時(shí)候是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即是填充方式,先說(shuō)下為什么會(huì)有padding髓绽,由于RSA的算法原理中,需要被加密的明文c是要比模數(shù)小的。padding就是通過(guò)一些填充方式保證明文c的位數(shù),且不能使c大于n.因此模的長(zhǎng)度也覺(jué)得可以加密明文的長(zhǎng)度,因此RSA不適合加密大段文本,一般用來(lái)加密一個(gè)對(duì)稱加密的密鑰沪伙,然后再用此對(duì)稱加密密鑰對(duì)大段文本加密喷好。一般選擇模式是RSA_PKCS1_PADDING
IOS中的RSA
在ios中可以使用<sercurity.framework>可實(shí)現(xiàn)些RSA的加密解密,但是framework的api只支持從標(biāo)準(zhǔn)證書(shū)文件(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
一個(gè)pem格式的公鑰文件泌类,其中保存的公鑰信息是base64編碼的字符串卧抗,這個(gè)用iOS 系統(tǒng)sercurity.framework的api就不能讀取藤滥。
后臺(tái)經(jīng)常會(huì)給一個(gè)xxx.pem
的文件. 里面的內(nèi)容用sublime打開(kāi)就如上所示.
下面是pem內(nèi)容示例(ps: 每行64個(gè)字符)
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApfNDz78E4qnU23PeE3lQ
DYaW9AtniNMWNn51eMANFtiFj6yvpAo+ejstkC4u0PevoA9YrhPUC97f8xd5Jss2
INyynKH3okVS4at5lxBBdpoqR3LxLSQPRcmh5h19PZj0/B6QO1Lm66qoxjoQUjoQ
4eqryb0zD5vwu+6kCQHH/sHSky8ZYdUH9p5baJOmLUFpqROPWZpliq7qxFTuLLoZ
jHEgbdPad/IX9IouYzrlnhQzUP+WjugnLU6NoeoKUer9YtPZg1WVbg/n98orsb8H
hmJL/RtAqWpOPMvEoYLGyiguFEPgjvYPV2dnSJxkTgb3XqnnujTN1BFsYDWmMC9S
TQIDAQAB
-----END PUBLIC KEY-----
實(shí)際, 上述文件中每行結(jié)尾都有一個(gè)隱藏的換行符\n
,如果把換行符加上,然后寫(xiě)成一個(gè)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格式中間部分, 同時(shí)也不包含回車(chē)換行, 需要每64個(gè)字符添加一個(gè)換行符.
// base64編碼的字符串
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApfNDz78E4qnU23PeE3lQDYaW9AtniNMWNn51eMANFtiFj6yvpAo+ejstkC4u0PevoA9YrhPUC97f8xd5Jss2INyynKH3okVS4at5lxBBdpoqR3LxLSQPRcmh5h19PZj0/B6QO1Lm66qoxjoQUjoQ4eqryb0zD5vwu+6kCQHH/sHSky8ZYdUH9p5baJOmLUFpqROPWZpliq7qxFTuLLoZjHEgbdPad/IX9IouYzrlnhQzUP+WjugnLU6NoeoKUer9YtPZg1WVbg/n98orsb8HhmJL/RtAqWpOPMvEoYLGyiguFEPgjvYPV2dnSJxkTgb3XqnnujTN1BFsYDWmMC9STQIDAQAB
第二種: public key 的16進(jìn)制字符串
第二種,后臺(tái)可能直接給Public Key 的16進(jìn)制的字符串(Hex String), 或者 2進(jìn)制字符串, 這種公鑰一般稱為裸公鑰, HJ就是提供的這種中key.
16進(jìn)制字符串表示的Public key
一共512位16進(jìn)制,2進(jìn)制位2048位(ps: 也有256位16進(jìn)制,2進(jìn)制1024位的public key).這種裸公鑰相當(dāng)于上面pem格式中的中間部分(除了-BEGIN- -END-兩行, 并且中間部分不包含\n
回車(chē)換行符), 只不過(guò)二進(jìn)制/十六進(jìn)制數(shù)據(jù)通過(guò)進(jìn)行了base64編碼成字符串,用sublime可以直接打開(kāi).
下面是一個(gè)16進(jìn)制字符串public key, 提供512位16進(jìn)制的字符串:
E00B364554A35D6705468698DC366115C09F2BA109D1F3A45901EF8872429752A0DAED95F50B31977FCF1989BC105143444D4583A479478F89148F1A35DACBACAC9584BFC528BE1AFF94685177514468F96F707BCBCD4F76DF989E5D7223384593AE81A1F2254D7CDD1CCA7BA01B006C4BAD87C2D270C51BF48B6CCECFA7022CAE93E9B17D31F0DB7A59E68D103BC99A3DDCA411CDDF2BC5558C7A88A884EFD33E52253C6D9E050F54C813A5EF38688C7A547072685399E5759FCFD03FD22B21E58D583C4D46EC5582A78FE4E18C10AF081970EEB14FEEDAA04F315D216EF988CB16F84FBBEE767CD51EDFFB23E83B303AD715B6E7A9D6CC475496F9BA3951A5
這種模式比較好存儲(chǔ), 我們可以通過(guò)編寫(xiě)代碼將這種格式的數(shù)據(jù)轉(zhuǎn)化成第一種格式(PEM)格式,
將裸Public Key轉(zhuǎn)化成為需要
- 為裸 public_key 添加完整的頭部和尾部
- 頭部:30820122300D06092A864886F70D01010105000382010F003082010A0282010100
- 尾部: 0203010001
- 然后執(zhí)行base64編碼,然后每一行64位換行處理社裆,加標(biāo)準(zhǔn)頭和尾部就是標(biāo)準(zhǔn)的PEM文件的中間部分拙绊。
在Terminal中直接運(yùn)行下面命令可以得到base64編碼的public key
16進(jìn)制字符串顯示 -> 二進(jìn)制字符串顯示 -> base64編碼
echo 30820122300D06092A864886F70D01010105000382010F003082010A0282010100E00B364554A35D6705468698DC366115C09F2BA109D1F3A45901EF8872429752A0DAED95F50B31977FCF1989BC105143444D4583A479478F89148F1A35DACBACAC9584BFC528BE1AFF94685177514468F96F707BCBCD4F76DF989E5D7223384593AE81A1F2254D7CDD1CCA7BA01B006C4BAD87C2D270C51BF48B6CCECFA7022CAE93E9B17D31F0DB7A59E68D103BC99A3DDCA411CDDF2BC5558C7A88A884EFD33E52253C6D9E050F54C813A5EF38688C7A547072685399E5759FCFD03FD22B21E58D583C4D46EC5582A78FE4E18C10AF081970EEB14FEEDAA04F315D216EF988CB16F84FBBEE767CD51EDFFB23E83B303AD715B6E7A9D6CC475496F9BA3951A50203010001 | xxd -r -ps | openssl base64
輸出的結(jié)果是:
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4As2RVSjXWcFRoaY3DZh
FcCfK6EJ0fOkWQHviHJCl1Kg2u2V9Qsxl3/PGYm8EFFDRE1Fg6R5R4+JFI8aNdrL
rKyVhL/FKL4a/5RoUXdRRGj5b3B7y81Pdt+Ynl1yIzhFk66BofIlTXzdHMp7oBsA
bEuth8LScMUb9Itszs+nAiyuk+mxfTHw23pZ5o0QO8maPdykEc3fK8VVjHqIqITv
0z5SJTxtngUPVMgTpe84aIx6VHByaFOZ5XWfz9A/0ish5Y1YPE1G7FWCp4/k4YwQ
rwgZcO6xT+7aoE8xXSFu+YjLFvhPu+52fNUe3/sj6DswOtcVtuep1sxHVJb5ujlR
pQIDAQAB
然后手動(dòng)添加首部和尾部,最終結(jié)果就和上面PEM格式內(nèi)容一樣了:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApfNDz78E4qnU23PeE3lQ
DYaW9AtniNMWNn51eMANFtiFj6yvpAo+ejstkC4u0PevoA9YrhPUC97f8xd5Jss2
INyynKH3okVS4at5lxBBdpoqR3LxLSQPRcmh5h19PZj0/B6QO1Lm66qoxjoQUjoQ
4eqryb0zD5vwu+6kCQHH/sHSky8ZYdUH9p5baJOmLUFpqROPWZpliq7qxFTuLLoZ
jHEgbdPad/IX9IouYzrlnhQzUP+WjugnLU6NoeoKUer9YtPZg1WVbg/n98orsb8H
hmJL/RtAqWpOPMvEoYLGyiguFEPgjvYPV2dnSJxkTgb3XqnnujTN1BFsYDWmMC9S
TQIDAQAB
-----END PUBLIC KEY-----
第二種解決方法, 直接轉(zhuǎn)化成證書(shū)der格式的數(shù)據(jù)
例如,隨便找一張der證書(shū), 將它轉(zhuǎn)化成的16進(jìn)制字符串展示:
30820308308201f00209008932a038393835a1300d06092a864886f70d01010505003045310b30090603550406130241553113301106035504080c0a536f6d652d53746174653121301f060355040a0c18496e7465726e6574205769646769747320507479204c74643020170d3135303631303037333931355a180f32313135303531373037333931355a3045310b30090603550406130241553113301106035504080c0a536f6d652d53746174653121301f060355040a0c18496e7465726e6574205769646769747320507479204c746430820122300d06092a864886f70d01010105000382010f003082010a0282010100
*E00B364554A35D6705468698DC366115C09F2BA109D1F3A45901EF8872429752A0DAED95F50B31977FCF1989BC105143444D4583A479478F89148F1A35DACBACAC9584BFC528BE1AFF94685177514468F96F707BCBCD4F76DF989E5D7223384593AE81A1F2254D7CDD1CCA7BA01B006C4BAD87C2D270C51BF48B6CCECFA7022CAE93E9B17D31F0DB7A59E68D103BC99A3DDCA411CDDF2BC5558C7A88A884EFD33E52253C6D9E050F54C813A5EF38688C7A547072685399E5759FCFD03FD22B21E58D583C4D46EC5582A78FE4E18C10AF081970EEB14FEEDAA04F315D216EF988CB16F84FBBEE767CD51EDFFB23E83B303AD715B6E7A9D6CC475496F9BA3951A5*
0203010001300d06092a864886f70d0101050500038201010045c2e98898344a645889e227c112bbbaf09a66105e5e964a90f298420e4187510b4c13c705177ebf605a09c7df74b2ed51fe117a2ad291ee554ecd38db3c92ec06e9b5c1df27ca519d5c0330986bf7b6447e5e8e87607febef6ace24111a308840543458a52b365ac6ac392bf009df15bbba44155d095ddb711dd9599bb10c5d8a55f8531d09fa5be8db2dcdbcce869ea04a4dbfcd693f1f67689c3b1c259a3ece586008a69cdae17892cdcb6a11d45680b6854721c185937b24295b0fa115b9751020f65d6bfda0f4fb47a8982e80c7c3682daa113ef24bae4a7e82aaa2aa634bab8faa68b28b3d999720dc9c2fc272dc488d2256f0cd1dd8a13a400ab9dd6c
- 找到
30820122300D06092A864886F70D01010105000382010F003082010A0282010100
(這段代表-----BEGIN PUBLIC KEY-----) - 找到尾部'0203010001' (-----END PUBLIC KEY-----)
- 兩者之間剛好512位16進(jìn)制數(shù)據(jù),就是證書(shū)的2048位 publi key所在的地方. 直接用自己的16進(jìn)制字符串public key換掉這部分,就偽造了一個(gè)后綴是.der的證書(shū)
注意: .der證書(shū)內(nèi)還包括很多信息,例如地址.公司,過(guò)期時(shí)間.等等,一般rsa加密只用中間256字節(jié)(2048位)的public key就行了
其他參考內(nèi)容 - 后臺(tái)給出的 java 參考
后臺(tái)給出的使用public key的參考:
String publicKeyStr = "30820122300D06092A864886F70D01010105000382010F003082010A0282010100"
+ "E00B364554A35D6705468698DC366115C09F2BA109D1F3A45901EF8872429752A0DAED95F50B31977FCF1989BC105143444D4583A479478F89148F1A35DACBACAC9584BFC528BE1AFF94685177514468F96F707BCBCD4F76DF989E5D7223384593AE81A1F2254D7CDD1CCA7BA01B006C4BAD87C2D270C51BF48B6CCECFA7022CAE93E9B17D31F0DB7A59E68D103BC99A3DDCA411CDDF2BC5558C7A88A884EFD33E52253C6D9E050F54C813A5EF38688C7A547072685399E5759FCFD03FD22B21E58D583C4D46EC5582A78FE4E18C10AF081970EEB14FEEDAA04F315D216EF988CB16F84FBBEE767CD51EDFFB23E83B303AD715B6E7A9D6CC475496F9BA3951A5"
+ "0203010001";
一般js中給的是裸公鑰,即512位16進(jìn)制(實(shí)際為二進(jìn)制的2048位)
因?yàn)镹DK中實(shí)現(xiàn)加密和解密泳秀,需要完整的公鑰和私鑰标沪,所以需要相應(yīng)的頭部和尾部。
頭部:30820122300D06092A864886F70D01010105000382010F003082010A0282010100
尾部: 0203010001
然后執(zhí)行base64編碼嗜傅,然后每一行64位換行處理金句,加標(biāo)準(zhǔn)頭和尾部就是標(biāo)準(zhǔn)的公鑰了。
base64編碼的命令: termial中,直接運(yùn)行下面命令可以得到標(biāo)準(zhǔn)的公鑰:
echo 30820122300D06092A864886F70D01010105000382010F003082010A0282010100A5F343CFBF04E2A9D4DB73DE1379500D8696F40B6788D316367E7578C00D16D8858FACAFA40A3E7A3B2D902E2ED0F7AFA00F58AE13D40BDEDFF3177926CB3620DCB29CA1F7A24552E1AB79971041769A2A4772F12D240F45C9A1E61D7D3D98F4FC1E903B52E6EBAAA8C63A10523A10E1EAABC9BD330F9BF0BBEEA40901C7FEC1D2932F1961D507F69E5B6893A62D4169A9138F599A658AAEEAC454EE2CBA198C71206DD3DA77F217F48A2E633AE59E143350FF968EE8272D4E8DA1EA0A51EAFD62D3D98355956E0FE7F7CA2BB1BF0786624BFD1B40A96A4E3CCBC4A182C6CA282E1443E08EF60F576767489C644E06F75EA9E7BA34CDD4116C6035A6302F524D0203010001| xxd -r -ps | openssl base64
其他參考文檔:
關(guān)于PEM格式的public key 進(jìn)行加密, 解密可以參考以下開(kāi)源庫(kù):
https://github.com/ideawu/Objective-C-RSA
https://github.com/kuapay/iOS-Certificate--Key--and-Trust-Sample-Project
后面兩個(gè)項(xiàng)目需要引入openssl庫(kù)