SSL加密
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SSL加密相关的知识,希望对你有一定的参考价值。
SSL利用数据加密、身份验证和消息完整性验证机制,为基于TCP等可靠连接的应用层协议提供安全性保证
SSL协议实现的安全机制包括:
l 数据传输的机密性:利用对称密钥算法对传输的数据进行加密。
l 身份验证机制:基于证书利用数字签名方法对服务器和客户端进行身份验证,其中客户端的身份验证是可选的。
l 消息完整性验证:消息传输过程中使用MAC算法来检验消息的完整性
加密通道,是指发送方在发送数据前,使用加密算法和加密密钥对数据进行加密,然后将数据发送给对方;接收方接收到数据后,利用解密算法和解密密钥从密文中获取明文。没有解密密钥的第三方,无法将密文恢复为明文,从而保证数据传输的机密性
加解密算法分为两类:
l 对称密钥算法:数据加密和解密时使用相同的密钥。
l 非对称密钥算法:数据加密和解密时使用不同的密钥,一个是公开的公钥,一个是由用户秘密保存的私钥。利用公钥(或私钥)加密的数据只能用相应的私钥(或公钥)才能解密。
与非对称密钥算法相比,对称密钥算法具有计算速度快的优点,通常用于对大量信息进行加密(如对所有报文加密);而非对称密钥算法,一般用于数字签名和对较少的信息进行加密。
SSL加密通道上的数据加解密使用对称密钥算法,目前主要支持的算法有DES、3DES、AES等,这些算法都可以有效地防止交互数据被窃听。
SSL客户端必须验证SSL服务器的身份,SSL服务器是否验证SSL客户端的身份,则由SSL服务器决定
为了避免网络中传输的数据被非法篡改,SSL利用基于MD5或SHA的MAC算法来保证消息的完整性。
MAC算法是在密钥参与下的数据摘要算法,能将密钥和任意长度的数据转换为固定长度的数据。利用MAC算法验证消息完整性的过程如图2所示。发送者在密钥的参与下,利用MAC算法计算出消息的MAC值,并将其加在消息之后发送给接收者。接收者利用同样的密钥和MAC算法计算出消息的MAC值,并与接收到的MAC值比较。如果二者相同,则报文没有改变;否则,报文在传输过程中被修改,接收者将丢弃该报文
l 消息的任何改变,都会引起输出的固定长度数据产生变化。通过比较MAC值,可以保证接收者能够发现消息的改变。
l MAC算法需要密钥的参与,因此没有密钥的非法用户在改变消息的内容后,无法添加正确的MAC值,从而保证非法用户无法随意修改消息内容。
MAC算法要求通信双方具有相同的密钥,否则MAC值验证将会失败。因此,利用MAC算法验证消息完整性之前,需要在通信两端部署相同的密钥
SSL利用非对称密钥算法加密密钥的方法实现密钥交换,保证第三方无法获取该密钥。如图3所示,SSL客户端(如Web浏览器)利用SSL服务器(如Web服务器)的公钥加密密钥,将加密后的密钥发送给SSL服务器,只有拥有对应私钥的SSL服务器才能从密文中获取原始的密钥。SSL通常采用RSA算法加密传输密钥
l 实际上,SSL客户端发送给SSL服务器的密钥不能直接用来加密数据或计算MAC值,该密钥是用来计算对称密钥和MAC密钥的信息,称为premaster secret。SSL客户端和SSL服务器利用premaster secret计算出相同的主密钥(master secret),再利用master secret生成用于对称密钥算法、MAC算法等的密钥。premaster secret是计算对称密钥、MAC算法密钥的关键。
l 用来实现密钥交换的算法称为密钥交换算法。非对称密钥算法RSA用于密钥交换时,也可以称之为密钥交换算法
PKI通过数字证书来发布用户的公钥,并提供了验证公钥真实性的机制。数字证书(简称证书)是一个包含用户的公钥及其身份信息的文件,证明了用户与公钥的关联。数字证书由权威机构——CA签发
SSL客户端把密钥加密传递给SSL服务器之前,SSL服务器需要将从CA获取的证书发送给SSL客户端,SSL客户端通过PKI判断该证书的真实性。如果该证书确实属于SSL服务器,则利用该证书中的公钥加密密钥,发送给SSL服务器。
验证SSL服务器/SSL客户端的身份之前,SSL服务器/SSL客户端需要将从CA获取的证书发送给对端,对端通过PKI判断该证书的真实性。如果该证书确实属于SSL服务器/SSL客户端,则对端利用该证书中的公钥验证SSL服务器/SSL客户端的身份
SSL的分层结构
图4 SSL协议分层
如图4所示,SSL位于应用层和传输层之间,它可以为任何基于TCP等可靠连接的应用层协议提供安全性保证。SSL协议本身分为两层:
l 上层为SSL握手协议(SSL handshake protocol)、SSL密码变化协议(SSL change cipher spec protocol)和SSL警告协议(SSL alert protocol);
l 底层为SSL记录协议(SSL record protocol)。
其中:
l SSL握手协议:是SSL协议非常重要的组成部分,用来协商通信过程中使用的加密套件(加密算法、密钥交换算法和MAC算法等)、在服务器和客户端之间安全地交换密钥、实现服务器和客户端的身份验证。
l SSL密码变化协议:客户端和服务器端通过密码变化协议通知对端,随后的报文都将使用新协商的加密套件和密钥进行保护和传输。
l SSL警告协议:用来向通信对端报告告警信息,消息中包含告警的严重级别和描述。
l SSL记录协议:主要负责对上层的数据(SSL握手协议、SSL密码变化协议、SSL警告协议和应用层协议报文)进行分
块、计算并添加MAC值、加密,并把处理后的记录块传输给对端。
SSL握手过程
SSL通过握手过程在客户端和服务器之间协商会话参数,并建立会话。会话包含的主要参数有会话ID、对方的证书、加密套件(密钥交换算法、数据加密算法和MAC算法等)以及主密钥(master secret)。通过SSL会话传输的数据,都将采用该会话的主密钥和加密套件进行加密、计算MAC等处理。
不同情况下,SSL握手过程存在差异。下面将分别描述以下三种情况下的握手过程:
l 只验证服务器的SSL握手过程
l 验证服务器和客户端的SSL握手过程
l 恢复原有会话的SSL握手过程
3.2.1 只验证服务器的SSL握手过程
图5 只验证服务器的SSL握手过程
如图5所示,只需要验证SSL服务器身份,不需要验证SSL客户端身份时,SSL的握手过程为:
(1) SSL客户端通过Client Hello消息将它支持的SSL版本、加密算法、密钥交换算法、MAC算法等信息发送给SSL服务器。
(2) SSL服务器确定本次通信采用的SSL版本和加密套件,并通过Server Hello消息通知给SSL客户端。如果SSL服务器允许SSL客户端在以后的通信中重用本次会话,则SSL服务器会为本次会话分配会话ID,并通过Server Hello消息发送给SSL客户端。
(3) SSL服务器将携带自己公钥信息的数字证书通过Certificate消息发送给SSL客户端。
(4) SSL服务器发送Server Hello Done消息,通知SSL客户端版本和加密套件协商结束,开始进行密钥交换。
(5) SSL客户端验证SSL服务器的证书合法后,利用证书中的公钥加密SSL客户端随机生成的premaster secret,并通过Client Key Exchange消息发送给SSL服务器。
(6) SSL客户端发送Change Cipher Spec消息,通知SSL服务器后续报文将采用协商好的密钥和加密套件进行加密和MAC计算。
(7) SSL客户端计算已交互的握手消息(除Change Cipher Spec消息外所有已交互的消息)的Hash值,利用协商好的密钥和加密套件处理Hash值(计算并添加MAC值、加密等),并通过Finished消息发送给SSL服务器。SSL服务器利用同样的方法计算已交互的握手消息的Hash值,并与Finished消息的解密结果比较,如果二者相同,且MAC值验证成功,则证明密钥和加密套件协商成功。
(8) 同样地,SSL服务器发送Change Cipher Spec消息,通知SSL客户端后续报文将采用协商好的密钥和加密套件进行加密和MAC计算。
(9) SSL服务器计算已交互的握手消息的Hash值,利用协商好的密钥和加密套件处理Hash值(计算并添加MAC值、加密等),并通过Finished消息发送给SSL客户端。SSL客户端利用同样的方法计算已交互的握手消息的Hash值,并与Finished消息的解密结果比较,如果二者相同,且MAC值验证成功,则证明密钥和加密套件协商成功。
SSL客户端接收到SSL服务器发送的Finished消息后,如果解密成功,则可以判断SSL服务器是数字证书的拥有者,即SSL服务器身份验证成功,因为只有拥有私钥的SSL服务器才能从Client Key Exchange消息中解密得到premaster secret,从而间接地实现了SSL客户端对SSL服务器的身份验证。
& 说明:
l Change Cipher Spec消息属于SSL密码变化协议,其他握手过程交互的消息均属于SSL握手协议,统称为SSL握手消息。
l 计算Hash值,指的是利用Hash算法(MD5或SHA)将任意长度的数据转换为固定长度的数据。
3.2.2 验证服务器和客户端的SSL握手过程
图6 验证服务器和客户端的SSL握手过程
SSL客户端的身份验证是可选的,由SSL服务器决定是否验证SSL客户端的身份。如图6中蓝色部分标识的内容所示,如果SSL服务器验证SSL客户端身份,则SSL服务器和SSL客户端除了交互“3.2.1 只验证服务器的SSL握手过程”中的消息协商密钥和加密套件外,还需要进行以下操作:
(1) SSL服务器发送Certificate Request消息,请求SSL客户端将其证书发送给SSL服务器。
(2) SSL客户端通过Certificate消息将携带自己公钥的证书发送给SSL服务器。SSL服务器验证该证书的合法性。
(3) SSL客户端计算已交互的握手消息、主密钥的Hash值,利用自己的私钥对其进行加密,并通过Certificate Verify消息发送给SSL服务器。
(4) SSL服务器计算已交互的握手消息、主密钥的Hash值,利用SSL客户端证书中的公钥解密Certificate Verify消息,并将解密结果与计算出的Hash值比较。如果二者相同,则SSL客户端身份验证成功。
3.2.3 恢复原有会话的SSL握手过程
图7 恢复原有会话的SSL握手过程
协商会话参数、建立会话的过程中,需要使用非对称密钥算法来加密密钥、验证通信对端的身份,计算量较大,占用了大量的系统资源。为了简化SSL握手过程,SSL允许重用已经协商过的会话,具体过程为:
(1) SSL客户端发送Client Hello消息,消息中的会话ID设置为计划重用的会话的ID。
(2) SSL服务器如果允许重用该会话,则通过在Server Hello消息中设置相同的会话ID来应答。这样,SSL客户端和SSL服务器就可以利用原有会话的密钥和加密套件,不必重新协商。
(3) SSL客户端发送Change Cipher Spec消息,通知SSL服务器后续报文将采用原有会话的密钥和加密套件进行加密和MAC计算。
(4) SSL客户端计算已交互的握手消息的Hash值,利用原有会话的密钥和加密套件处理Hash值,并通过Finished消息发送给SSL服务器,以便SSL服务器判断密钥和加密套件是否正确。
(5) 同样地,SSL服务器发送Change Cipher Spec消息,通知SSL客户端后续报文将采用原有会话的密钥和加密套件进行加密和MAC计算。
(6) SSL服务器计算已交互的握手消息的Hash值,利用原有会话的密钥和加密套件处理Hash值,并通过Finished消息发送给SSL客户端,以便SSL客户端判断密钥和加密套件是否正确。
双向认证 SSL 协议的具体过程
① 浏览器发送一个连接请求给安全服务器。
② 服务器将自己的证书,以及同证书相关的信息发送给客户浏览器。
③ 客户浏览器检查服务器送过来的证书是否是由自己信赖的 CA 中心所签发的。如果是,就继续执行协议;如果不是,客户浏览器就给客户一个警告消息:警告客户这个证书不是可以信赖的,询问客户是否需要继续。
④ 接着客户浏览器比较证书里的消息,例如域名和公钥,与服务器刚刚发送的相关消息是否一致,如果是一致的,客户浏览器认可这个服务器的合法身份。
⑤ 服务器要求客户发送客户自己的证书。收到后,服务器验证客户的证书,如果没有通过验证,拒绝连接;如果通过验证,服务器获得用户的公钥。
⑥ 客户浏览器告诉服务器自己所能够支持的通讯对称密码方案。
⑦ 服务器从客户发送过来的密码方案中,选择一种加密程度最高的密码方案,用客户的公钥加过密后通知浏览器。
⑧ 浏览器针对这个密码方案,选择一个通话密钥,接着用服务器的公钥加过密后发送给服务器。
⑨ 服务器接收到浏览器送过来的消息,用自己的私钥解密,获得通话密钥。
⑩ 服务器、浏览器接下来的通讯都是用对称密码方案,对称密钥是加过密的。
上面所述的是双向认证 SSL 协议的具体通讯过程,这种情况要求服务器和用户双方都有证书。单向认证 SSL 协议不需要客户拥有 CA 证书,具体的过程相对于上面的步骤,只需将服务器端验证客户证书的过程去掉,以及在协商对称密码方案,对称通话密钥时,服务器发送给客户的是没有加过密的 (这并不影响 SSL 过程的安全性)密码方案。 这样,双方具体的通讯内容,就是加过密的数据,如果有第三方攻击,获得的只是加密的数据,第三方要获得有用的信息,就需要对加密的数据进行解密,这时候的 安全就依赖于密码方案的安全。而幸运的是,目前所用的密码方案,只要通讯密钥长度足够的长,就足够的安全。这也是我们强调要求使用 128 位加密通讯的原因
步骤:
导入一个 identity.从导入的数据中获得证书.
获得用于证书评估的策略.校验证书,根据指定策略评估证书是否可信.
测试证书中的可恢复错误.判断证书是否过期.
改变评估条件,忽略过期证书.重新评估证书.
-
Security Transforms API —a Core-Foundation-level API that provides support for signing and verifying, symmetric cryptography, and Base64 encoding and decoding.是 CoreFoundation 级别的api, 提供了, 最全的功能和算法支持. 包括对称,非对称算法. 实现加密,签名功能. 但遗憾的是这个接口只在mac上有效. ios上没有. 但有些功能必须要用到, 所以要实现跨平台的代码,需要一些补丁.
-
Common Crypto—a C-level API that can perform most symmetric encryption and decryption tasks这是一个 C 风格的接口. 好消息是它在mac和ios上都有, 可以跨平台. 但坏消息是, 它只包含了, 对称加密算法, 却没有非对称算法. 因此只能加密解密,而不能签名和验证
/**SSL***/ 代码实现
AFHTTPRequestOperation *reqOperation = [[AFHTTPRequestOperationManager manager] HTTPRequestOperationWithRequest:mr success:^(AFHTTPRequestOperation *operation, id responseObject) {
reqOperation.credential = self.gerneraterCredential;//获取证书
reqOperation.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];//设置安全模式,公钥加密模式
[reqOperation.securityPolicy setPinnedCertificates:@[[[self class] setCertificateData]]];//加载证书,返回二进制数据
[reqOperation.securityPolicy setAllowInvalidCertificates:YES];//是否信任无效或过期证书
[reqOperation.securityPolicy setValidatesDomainName:YES];//是否去确认域名
+ (NSData *)setCertificateData {
static dispatch_once_t onceToken;//设置单例
static NSData *certificateData1 = nil;
dispatch_once(&onceToken, ^{
if (certificateData1 == nil){
certificateData1 = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"serverAPItest" ofType:@"cer"]];//加载证书
}
});
return certificateData1;
}
OSStatus securityError = errSecSuccess;// OSStatus-----32bit结果错误信息
CFStringRef password = CFSTR("159753”);//CoreFoudation里的字符串类型,CFStringRef和NSString是可以直接转换,CFSTR是直接赋常量的操作,相当于@,不会自动释放,且多线程不加锁,放到全局的字典内
const void *keys[] = { kSecImportExportPassphrase };//可信任对象?
const void *values[] = { password };
CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);//会把特殊字符转换成UTF格式编码
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);//CF框架下的数组
securityError = SecPKCS12Import(inP12Data, options, &items);//用SecPKCS12Import函数从.p12文件中提取identity和可信任对象,以及评估其可信度
if (securityError == 0)
{
CFDictionaryRef ident = CFArrayGetValueAtIndex(items,0);//数组中去字典
const void *tempIdentity = NULL;//定义了一个指针,可以指向任意类型,但它指向的值必须是常量
tempIdentity = CFDictionaryGetValue(ident, kSecImportItemIdentity);
*identity = (SecIdentityRef)tempIdentity;}
if (options) {//如果存在,需要手动进行释放
CFRelease(options); }
return securityError;}
收到认证要求时,NSURLConnection 的委托对象会收到相应的消息并得到一个 NSURLAuthenticationChallenge 实例。该实例的发送方遵守 NSURLAuthenticationChallengeSender 协议。为了继续收到真实的数据,需要向该发送方向发回一个 NSURLCredential 实例
+ (NSURLCredential *)gerneraterCredential {//响应时附带认证请求,需要提供正确的用户名和密码,然后才会真正的http响应
NSString *thePath = [[NSBundle mainBundle] pathForResource:@"clientPassPorttestwin" ofType:@"p12"];
NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data; //oc转c
SecIdentityRef identity = NULL;
// extract the ideneity from the certificate
[self extractIdentity :inPKCS12Data :&identity];//从钥匙串中寻找证书
SecCertificateRef certificate = NULL;
SecIdentityCopyCertificate (identity, &certificate);//是否提取成功
// CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL);
// create a credential from the certificate and ideneity, then reply to the challenge with the credential
return [NSURLCredential credentialWithIdentity:identity certificates:nil persistence:NSURLCredentialPersistencePermanent];
}
//以下是网络文章
客户端验证服务端证书:
需要http配置路径需要域名
1:先项目中倒入服务端证书 sever.cer,
2.然后设置 AFSecurityPolicy
self.manager = [AFHTTPRequestOperationManager manager];
self.manager.responseSerializer = [[AFHTTPResponseSerializer alloc] init];
[self.manager.requestSerializer setValue:@"iphone" forHTTPHeaderField:@"header-platform"];
self.manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];
self.manager.securityPolicy.allowInvalidCertificates = YES;
self.manager.securityPolicy.validatesDomainName = NO;
self.manager.securityPolicy.validatesCertificateChain = NO;
客户端会变了项目中的证书和服务端的证书匹配
服务端验证客户端证书,首先把服务端的证书client.p12 导入到服务端的密钥库里
然后在 AFURLConnectionOperation.m中加入以下方法
- (OSStatus)extractIdentity:(CFDataRef)inP12Data :(SecIdentityRef*)identity {
OSStatus securityError = errSecSuccess;
CFStringRef password = CFSTR("clic1234");
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { password };
CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
securityError = SecPKCS12Import(inP12Data, options, &items);
if (securityError == 0)
{
CFDictionaryRef ident = CFArrayGetValueAtIndex(items,0);
const void *tempIdentity = NULL;
tempIdentity = CFDictionaryGetValue(ident, kSecImportItemIdentity);
*identity = (SecIdentityRef)tempIdentity;
}
if (options) {
CFRelease(options);
}
return securityError;
}
把AFURLConnectionOperation.m中的
- (void)connection:(NSURLConnection *)connection
willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
替换成
- (void)connection:(NSURLConnection *)connection
willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSString *thePath = [[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"];
NSLog(@"thePath===========%@",thePath);
NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
SecIdentityRef identity = NULL;
// extract the ideneity from the certificate
[self extractIdentity :inPKCS12Data :&identity];
SecCertificateRef certificate = NULL;
SecIdentityCopyCertificate (identity, &certificate);
const void *certs[] = {certificate};
// CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL);
// create a credential from the certificate and ideneity, then reply to the challenge with the credential
//NSLog(@"identity=========%@",identity);
NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:nil persistence:NSURLCredentialPersistencePermanent];
// credential = [NSURLCredential credentialWithIdentity:identity certificates:(__bridge NSArray*)certArray persistence:NSURLCredentialPersistencePermanent];
[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
}
然后就可以进行双向认证了
以上是关于SSL加密的主要内容,如果未能解决你的问题,请参考以下文章