因为项目中需要传输用户密码,为了安全需要用RSA加密,所以就学习了下RSA加密在iOS中的应用。
关于RSA的历史及原理,下面的两篇文章讲的很清楚了:
 
简单来说,RSA建立在一个数学难题之上,就是大数分解:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难。至于为什么难,难在哪里那就是数学家的事了。。。
明白了这个就可以大致知道RSA的原理:非对称加密
(1)乙方生成两把密钥(公钥和私钥)。公钥是公开的,任何人都可以获得,私钥则是保密的。
(2)甲方获取乙方的公钥,然后用它对信息加密。
(3)乙方得到加密后的信息,用私钥解密。
 
就好比有一套特殊的锁和钥匙,锁是公开的,谁都可以拿这个锁来锁住他的东西,只有有钥匙的人可以打开。
那么问题来了,既然锁是公开的,难道不能通过锁的结构来倒推出钥匙的形状吗?
答案是:不能!因为这个锁是特殊的,它就特殊在很难倒推。(这个倒不是绝对的,也许将来某一天大数分解的数学难题解决了,这种算法就不安全了,详见开头链接)
 
我遇到的应用场景是,客户端有服务器的公钥,客户端要把用户的密码用公钥加密上后上传到服务器,服务器可以用私钥解密。
所以客户端要做的是,将需要加密的内容用服务器给的公钥进行RSA加密。
iOS上并没有直接的RSA加密API,所以需要折腾一下。
gitHub上的代码大同小异,主要是三个方法(抄自https://github.com/ideawu/Objective-C-RSA
注意代码里有个kSecPaddingPKCS1是作者写死的,而我们的项目中需要传kSecPaddingNone才行!!!
 
+ (NSData *)stripPublicKeyHeader:(NSData *)d_key{
// Skip ASN.1 public key header
if (d_key == nil) return(nil); unsigned long len = [d_key length];
if (!len) return(nil); unsigned char *c_key = (unsigned char *)[d_key bytes];
unsigned int idx = ; if (c_key[idx++] != 0x30) return(nil); if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + ;
else idx++; // PKCS #1 rsaEncryption szOID_RSA_RSA
static unsigned char seqiod[] =
{ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
0x01, 0x05, 0x00 };
if (memcmp(&c_key[idx], seqiod, )) return(nil); idx += ; if (c_key[idx++] != 0x03) return(nil); if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + ;
else idx++; if (c_key[idx++] != '\0') return(nil); // Now make a new NSData from this buffer
return([NSData dataWithBytes:&c_key[idx] length:len - idx]);
}
 
 
+ (SecKeyRef)addPublicKey:(NSString *)key{
NSRange spos = [key rangeOfString:@"-----BEGIN PUBLIC KEY-----"];
NSRange epos = [key rangeOfString:@"-----END PUBLIC KEY-----"];
if(spos.location != NSNotFound && epos.location != NSNotFound){
NSUInteger s = spos.location + spos.length;
NSUInteger e = epos.location;
NSRange range = NSMakeRange(s, e-s);
key = [key substringWithRange:range];
}
key = [key stringByReplacingOccurrencesOfString:@"\r" withString:@""];
key = [key stringByReplacingOccurrencesOfString:@"\n" withString:@""];
key = [key stringByReplacingOccurrencesOfString:@"\t" withString:@""];
key = [key stringByReplacingOccurrencesOfString:@" " withString:@""]; // This will be base64 encoded, decode it.
NSData *data = base64_decode(key);
data = [RSA stripPublicKeyHeader:data];
if(!data){
return nil;
} NSString *tag = @"what_the_fuck_is_this";
NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]]; // Delete any old lingering key with the same tag
NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init];
[publicKey setObject:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass];
[publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[publicKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag];
SecItemDelete((__bridge CFDictionaryRef)publicKey); // Add persistent version of the key to system keychain
[publicKey setObject:data forKey:(__bridge id)kSecValueData];
[publicKey setObject:(__bridge id) kSecAttrKeyClassPublic forKey:(__bridge id)
kSecAttrKeyClass];
[publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)
kSecReturnPersistentRef]; CFTypeRef persistKey = nil;
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)publicKey, &persistKey);
if (persistKey != nil){
CFRelease(persistKey);
}
if ((status != noErr) && (status != errSecDuplicateItem)) {
return nil;
} [publicKey removeObjectForKey:(__bridge id)kSecValueData];
[publicKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef];
[publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
[publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; // Now fetch the SecKeyRef version of the key
SecKeyRef keyRef = nil;
status = SecItemCopyMatching((__bridge CFDictionaryRef)publicKey, (CFTypeRef *)&keyRef);
if(status != noErr){
return nil;
}
return keyRef;
}
 
 + (NSString *)encryptData:(NSData *)data publicKey:(NSString *)pubKey{
if(!data || !pubKey){
return nil;
}
SecKeyRef keyRef = [RSA addPublicKey:pubKey];
if(!keyRef){
return nil;
} const uint8_t *srcbuf = (const uint8_t *)[data bytes];
size_t srclen = (size_t)data.length; size_t outlen = SecKeyGetBlockSize(keyRef) * sizeof(uint8_t);
if(srclen > outlen - ){
CFRelease(keyRef);
return nil;
}
void *outbuf = malloc(outlen); OSStatus status = noErr;
status = SecKeyEncrypt(keyRef,
kSecPaddingNone, //原作者写的是kSecPaddingPKCS1,经春哥研究这里写成kSecPaddingNone才符合我们使用
srcbuf,
srclen,
outbuf,
&outlen
);
NSString *ret = nil;
if (status != ) {
//NSLog(@"SecKeyEncrypt fail. Error Code: %ld", status);
}else{
NSData *data = [NSData dataWithBytes:outbuf length:outlen];
ret = base64_encode_data(data);
}
free(outbuf);
CFRelease(keyRef);
return ret;
}
 
还有一篇文章可以参考:http://blog.iamzsx.me/show.html?id=155002
 
 
签名机制
仅仅加密某个参数是不够的,还需要保证请求没有被篡改,所以签名机制就很有必要。
比较简单和常用就是MD5签名:
拿到待签名的字符串A(比如某个url),将其与服务器约定好的密钥拼成新的字符串B,对B进行MD5算法得到签名C,
然后将C作为A的签名一起发送到服务器。
服务器收到请求后,对A用与客户端约定好的密钥进行相同的算法得到C’,如果C==C’,那就说明改请求没有被篡改过,
否则验证不通过
 
当然也可以做RSA签名
这个要比MD5签名要稍微麻烦一点,因为需要客户端生成公钥私钥对,基本流程也和MD5签名一样
拿到待签名的字符串A(比如某个url),将其用私钥加密得到的字符串B,然后将B和原数据A还有自己的公钥一起发送给服务器,
服务器收到请求,用公钥解密得到B',如果B==B',则说明原数据没有被篡改过,否则验证不通过。
 
也有说这里得到B以后,需要再用服务器的公钥加密一遍得到C,将C和原数据和自己的公钥一起发送给服务器,
服务器收到之后,现需要用自己的私钥解密一遍得到C',然后再用客户端公钥解密得到B',然后同上。。。
 
RSA签名及验证我还没用到,所以具体怎么实现的还需要研究下,待补充!!!
 
 
HTTPS
https算是对RSA加密的一个典型应用吧,不过这个服务器的公钥私钥不是自己生产的,而是CA颁发的。
具体原理网上很多,其中一个:http://jingyan.baidu.com/article/2fb0ba4048e15500f3ec5f7e.html
 
 

RSA算法及其在iOS中的使用的更多相关文章

  1. RSA算法在Python Django中的简单应用

    说明 RSA算法是当今使用最广泛,安全度最高的加密算法. • RSA算法的安全性理论基础 [引]根据百科介绍,对极大整数做因数分解的难度决定了RSA算法的可靠性.换言之,对一极大整数做因数分解愈困难, ...

  2. iOS中使用RSA对数据进行加密解密

    RSA算法是一种非对称加密算法,常被用于加密数据传输.如果配合上数字摘要算法, 也可以用于文件签名. 本文将讨论如何在iOS中使用RSA传输加密数据. 本文环境 mac os openssl-1.0. ...

  3. [BS-28] iOS中分页的几种算法

    iOS中分页的几种算法 总记录数:totalRecord 每页最大记录数:maxResult 算法一: totalPage = totalRecord % maxResult == 0 ? total ...

  4. 在IOS中使用DES算法对Sqlite数据库进行内容加密存储并读取解密

    在IOS中使用DES算法对Sqlite 数据库进行内容加密存储并读取解密 涉及知识点: 1.DES加密算法: 2.OC对Sqlite数据库的读写: 3.IOS APP文件存储的两种方式及读取方式. 以 ...

  5. Java中使用RSA算法加密

    Java中使用RSA算法加密 概述 RSA加密算法是一种非对称加密算法 RSA加密的方式 使用公钥加密的数据,利用私钥进行解密 使用私钥加密的数据,利用公钥进行解密 RSA是一对密钥.分别是公钥和私钥 ...

  6. iOS 中的加密方式

    iOS 中的加密方式 1 加密方式主要有: Base64,MD5,RSA,DES,AES,钥匙串存储,Cookie 2 各加密方式的比较 2.1 Base64 2.1.1 基本原理:采用64个基本的 ...

  7. 浅谈IM软件业务知识——非对称加密,RSA算法,数字签名,公钥,私钥

    概述 首先了解一下相关概念:RSA算法:1977年由Ron Rivest.Adi Shamirh和LenAdleman发明的.RSA就是取自他们三个人的名字. 算法基于一个数论:将两个大素数相乘很ea ...

  8. iOS中MD5加密字符串实现

    1.MD5加密 Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护.该算法的文件号为RFC 1321 ...

  9. iOS中支付宝集成

    iOS中支付宝集成 如今各种的App中都使用了三方支付的功能,现在将我在使用支付宝支付集成过程的心得分享一下,希望对大家都能有所帮助 要集成一个支付宝支付过程的环境,大致需要: 1>公司:先与支 ...

随机推荐

  1. Windows系统盘占用空间分析

    磁盘分析 本机的系统盘是C盘,操作系统是Windows 7 专业版,通过磁盘属性可以看到C盘的已用空间是69.4G. 而我们运行自己编写的脚本(脚本程序参考附录,统计原理:计算目录下各个文件的大小,然 ...

  2. js动态给当前点击元素添加css类

    1.页面:

  3. TextView+Fragment实现底部导航栏

    前言:项目第二版刚上线没多久,产品又对需求进行了大改动,以前用的是左滑菜单,现在又要换成底部导航栏,于是今天又苦逼加班了.花了几个小时实现了一个底部导航栏的demo,然后总结一下.写一篇博客.供自己以 ...

  4. [C#]浅析ref、out参数

    转载:http://www.cnblogs.com/vd630/p/4601919.html#top 按引用传递的参数算是C#与很多其他语言相比的一大特色,想要深入理解这一概念应该说不是一件容易的事, ...

  5. 浅谈 php 采用curl 函数库获取网页 cookie 和 带着cookie去访问 网页的方法!!!!

    由于近段时间帮朋友开发一个能够查询正方教务系统的微信公众平台号.有所收获.这里总结下个人经验. 开讲前,先吐槽一下新浪云服务器,一个程序里的   同一个函数  在PC测试可以正常运行,在它那里就会挂的 ...

  6. 把《c++ primer》读薄(4-2 c和c++的数组 和 指针初探)

    督促读书,总结精华,提炼笔记,抛砖引玉,有不合适的地方,欢迎留言指正. 问题1.我们知道,将一个数组赋给另一个数组,就是将一个数组的元素逐个赋值给另一数组的对应元素,相应的,将一个vector 赋给另 ...

  7. [linux]ssh(转载)

    ssh登陆问题 SSH分客户端openssh-client和openssh-server 如果你只是想登陆别的机器的SSH只需要安装openssh-client(ubuntu有默认安装,如果没有则su ...

  8. CSS实现的手风琴特效

    CSS样式: //图像个数 @imageN:5; //图像hover之前的总宽度 @w:800px; //图像hover之后的宽度 @imageL:640px; //图像hover之前的宽度 @ima ...

  9. centos-5.5安装vmvare tools

    centos-5.5安装vmvare tools 虚拟机管理,安装tools 找到VMwareTools压缩包 解压到Desktop,桌面 终端进入桌面 执行程序# ./vmware-install. ...

  10. 【十大经典数据挖掘算法】CART

    [十大经典数据挖掘算法]系列 C4.5 K-Means SVM Apriori EM PageRank AdaBoost kNN Naïve Bayes CART 1. 前言 分类与回归树(Class ...