亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 1527 | 回復: 0
打印 上一主題 下一主題

[iOS] RSA算法及其在iOS中的使用 [復制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2015-06-18 09:56 |只看該作者 |倒序瀏覽
因為項目中需要傳輸用戶密碼,為了安全需要用RSA加密,所以就學習了下RSA加密在iOS中的應用。
關(guān)于RSA的歷史及原理,下面的兩篇文章講的很清楚了:
http://www.ruanyifeng.com/blog/2 ... rithm_part_one.html  
http://www.ruanyifeng.com/blog/2 ... rithm_part_two.html

簡單來說,RSA建立在一個數(shù)學難題之上,就是大數(shù)分解:將兩個大素數(shù)相乘十分容易,但是想要對其乘積進行因式分解卻極其困難。至于為什么難,難在哪里那就是數(shù)學家的事了。。。
明白了這個就可以大致知道RSA的原理:非對稱加密
(1)乙方生成兩把密鑰(公鑰和私鑰)。公鑰是公開的,任何人都可以獲得,私鑰則是保密的。
(2)甲方獲取乙方的公鑰,然后用它對信息加密。
(3)乙方得到加密后的信息,用私鑰解密。

就好比有一套特殊的鎖和鑰匙,鎖是公開的,誰都可以拿這個鎖來鎖住他的東西,只有有鑰匙的人可以打開。
那么問題來了,既然鎖是公開的,難道不能通過鎖的結(jié)構(gòu)來倒推出鑰匙的形狀嗎?
答案是:不能!因為這個鎖是特殊的,它就特殊在很難倒推。(這個倒不是絕對的,也許將來某一天大數(shù)分解的數(shù)學難題解決了,這種算法就不安全了,詳見開頭鏈接)

我遇到的應用場景是,客戶端有服務器的公鑰,客戶端要把用戶的密碼用公鑰加密上后上傳到服務器,服務器可以用私鑰解密。
所以客戶端要做的是,將需要加密的內(nèi)容用服務器給的公鑰進行RSA加密。
iOS上并沒有直接的RSA加密API,所以需要折騰一下。
gitHub上的代碼大同小異,主要是三個方法(抄自https://github.com/ideawu/Objective-C-RSA
注意代碼里有個kSecPaddingPKCS1是作者寫死的,而我們的項目中需要傳kSecPaddingNone才行。!
  1. + (NSData *)stripPublicKeyHeader:(NSData *)d_key{
  2. // Skip ASN.1 public key header
  3. if (d_key == nil) return(nil);

  4. unsigned long len = [d_key length];
  5. if (!len) return(nil);

  6. unsigned char *c_key = (unsigned char *)[d_key bytes];
  7. unsigned int  idx    = 0;

  8. if (c_key[idx++] != 0x30) return(nil);

  9. if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
  10. else idx++;

  11. // PKCS #1 rsaEncryption szOID_RSA_RSA
  12. static unsigned char seqiod[] =
  13. { 0x30,   0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
  14. 0x01, 0x05, 0x00 };
  15. if (memcmp(&c_key[idx], seqiod, 15)) return(nil);

  16. idx += 15;

  17. if (c_key[idx++] != 0x03) return(nil);

  18. if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
  19. else idx++;

  20. if (c_key[idx++] != '\0') return(nil);

  21. // Now make a new NSData from this buffer
  22. return([NSData dataWithBytes:&c_key[idx] length:len - idx]);
  23. }
復制代碼
  1. + (SecKeyRef)addPublicKey:(NSString *)key{
  2. NSRange spos = [key rangeOfString:@"-----BEGIN PUBLIC KEY-----"];
  3. NSRange epos = [key rangeOfString:@"-----END PUBLIC KEY-----"];
  4. if(spos.location != NSNotFound && epos.location != NSNotFound){
  5. NSUInteger s = spos.location + spos.length;
  6. NSUInteger e = epos.location;
  7. NSRange range = NSMakeRange(s, e-s);
  8. key = [key substringWithRange:range];
  9. }
  10. key = [key stringByReplacingOccurrencesOfString:@"\r" withString:@""];
  11. key = [key stringByReplacingOccurrencesOfString:@"\n" withString:@""];
  12. key = [key stringByReplacingOccurrencesOfString:@"\t" withString:@""];
  13. key = [key stringByReplacingOccurrencesOfString:@" "  withString:@""];

  14. // This will be base64 encoded, decode it.
  15. NSData *data = base64_decode(key);
  16. data = [RSA stripPublicKeyHeader:data];
  17. if(!data){
  18. return nil;
  19. }

  20. NSString *tag = @"what_the_fuck_is_this";
  21. NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]];

  22. // Delete any old lingering key with the same tag
  23. NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init];
  24. [publicKey setObject:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass];
  25. [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
  26. [publicKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag];
  27. SecItemDelete((__bridge CFDictionaryRef)publicKey);

  28. // Add persistent version of the key to system keychain
  29. [publicKey setObject:data forKey:(__bridge id)kSecValueData];
  30. [publicKey setObject:(__bridge id) kSecAttrKeyClassPublic forKey:(__bridge id)
  31. kSecAttrKeyClass];
  32. [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)
  33. kSecReturnPersistentRef];

  34. CFTypeRef persistKey = nil;
  35. OSStatus status = SecItemAdd((__bridge CFDictionaryRef)publicKey, &persistKey);
  36. if (persistKey != nil){
  37. CFRelease(persistKey);
  38. }
  39. if ((status != noErr) && (status != errSecDuplicateItem)) {
  40. return nil;
  41. }

  42. [publicKey removeObjectForKey:(__bridge id)kSecValueData];
  43. [publicKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef];
  44. [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
  45. [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];

  46. // Now fetch the SecKeyRef version of the key
  47. SecKeyRef keyRef = nil;
  48. status = SecItemCopyMatching((__bridge CFDictionaryRef)publicKey, (CFTypeRef *)&keyRef);
  49. if(status != noErr){
  50. return nil;
  51. }
  52. return keyRef;
  53. }
復制代碼
  1. + (NSString *)encryptData:(NSData *)data publicKey:(NSString *)pubKey{
  2. 2 if(!data || !pubKey){
  3. 3 return nil;
  4. 4 }
  5. 5 SecKeyRef keyRef = [RSA addPublicKey:pubKey];
  6. 6 if(!keyRef){
  7. 7 return nil;
  8. 8 }
  9. 9
  10. 10 const uint8_t *srcbuf = (const uint8_t *)[data bytes];
  11. 11 size_t srclen = (size_t)data.length;
  12. 12
  13. 13 size_t outlen = SecKeyGetBlockSize(keyRef) * sizeof(uint8_t);
  14. 14 if(srclen > outlen - 11){
  15. 15 CFRelease(keyRef);
  16. 16 return nil;
  17. 17 }
  18. 18 void *outbuf = malloc(outlen);
  19. 19
  20. 20 OSStatus status = noErr;
  21. 21 status = SecKeyEncrypt(keyRef,
  22. 22   kSecPaddingNone, //原作者寫的是kSecPaddingPKCS1,經(jīng)春哥研究這里寫成kSecPaddingNone才符合我們使用
  23. 23   srcbuf,
  24. 24   srclen,
  25. 25   outbuf,
  26. 26   &outlen
  27. 27   );
  28. 28 NSString *ret = nil;
  29. 29 if (status != 0) {
  30. 30 //NSLog(@"SecKeyEncrypt fail. Error Code: %ld", status);
  31. 31 }else{
  32. 32 NSData *data = [NSData dataWithBytes:outbuf length:outlen];
  33. 33 ret = base64_encode_data(data);
  34. 34 }
  35. 35 free(outbuf);
  36. 36 CFRelease(keyRef);
  37. 37 return ret;
  38. 38 }
復制代碼
還有一篇文章可以參考:http://blog.iamzsx.me/show.html?id=155002


簽名機制
僅僅加密某個參數(shù)是不夠的,還需要保證請求沒有被篡改,所以簽名機制就很有必要。
比較簡單和常用就是MD5簽名:
拿到待簽名的字符串A(比如某個url),將其與服務器約定好的密鑰拼成新的字符串B,對B進行MD5算法得到簽名C,
然后將C作為A的簽名一起發(fā)送到服務器。
服務器收到請求后,對A用與客戶端約定好的密鑰進行相同的算法得到C’,如果C==C’,那就說明改請求沒有被篡改過,
否則驗證不通過

當然也可以做RSA簽名
這個要比MD5簽名要稍微麻煩一點,因為需要客戶端生成公鑰私鑰對,基本流程也和MD5簽名一樣
拿到待簽名的字符串A(比如某個url),將其用私鑰加密得到的字符串B,然后將B和原數(shù)據(jù)A還有自己的公鑰一起發(fā)送給服務器,
服務器收到請求,用公鑰解密得到B',如果B==B',則說明原數(shù)據(jù)沒有被篡改過,否則驗證不通過。

也有說這里得到B以后,需要再用服務器的公鑰加密一遍得到C,將C和原數(shù)據(jù)和自己的公鑰一起發(fā)送給服務器,
服務器收到之后,現(xiàn)需要用自己的私鑰解密一遍得到C',然后再用客戶端公鑰解密得到B',然后同上。。。

RSA簽名及驗證我還沒用到,所以具體怎么實現(xiàn)的還需要研究下,待補充!。


HTTPS
https算是對RSA加密的一個典型應用吧,不過這個服務器的公鑰私鑰不是自己生產(chǎn)的,而是CA頒發(fā)的。
具體原理網(wǎng)上很多,其中一個:http://jingyan.baidu.com/article/2fb0ba4048e15500f3ec5f7e.html
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP