第一次写博客,不知道写点什么会比较好,不知道写点什么会显得自己比较牛逼,哈哈,开个玩笑了,不过确实是第一次写博客,只好是先从最近遇到的问题开始写起吧。
最近因为有涉及密码上传到服务器的需求,而服务器那边要求必须用RSA加密,这件事情让我头大了半天。至于服务器为什么一定要选择RSA,我也不懂,维基上说是安全,但却让我这边费了一番时间,
废话不多说,切入正题,我在网上看到的别人的写法大部分是自己在客户端这边生成证书,然后利用证书进行加密,这与之前服务器说用他给的NSString公钥大相径庭,所以这样的帖子直接被我忽略了。但同时也确实找到了很多不错的利用NSString的例子,只不过由于我理解不够深入,始终不能通过NSString获得SeckeyRef,我先在这贴出来。
http://stackoverflow.com/questions/1536894/converting-raw-rsa-key-value-to-seckeyref-object-for-encryption
The following code comes from Apple's CryptoExercise example, in SecKeyWrapper.m. It assumes the "publicKey" NSData object is the binary DER-encoded ASN.1 object, not base-64 encoded. So you'll have to get a base-64 decoder and apply it first. You might also want to read this post in the Apple Developer Forums.
- (SecKeyRef)addPeerPublicKey:(NSString *)peerName keyBits:(NSData *)publicKey {
OSStatus sanityCheck = noErr;
SecKeyRef peerKeyRef = NULL;
CFTypeRef persistPeer = NULL;
LOGGING_FACILITY( peerName != nil, @"Peer name parameter is nil." );
LOGGING_FACILITY( publicKey != nil, @"Public key parameter is nil." );
NSData * peerTag = [[NSData alloc] initWithBytes:(const void *)[peerName UTF8String] length:[peerName length]];
NSMutableDictionary * peerPublicKeyAttr = [[NSMutableDictionary alloc] init];
[peerPublicKeyAttr setObject:(id)kSecClassKey forKey:(id)kSecClass];
[peerPublicKeyAttr setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
[peerPublicKeyAttr setObject:peerTag forKey:(id)kSecAttrApplicationTag];
[peerPublicKeyAttr setObject:publicKey forKey:(id)kSecValueData];
[peerPublicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnPersistentRef];
sanityCheck = SecItemAdd((CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef *)&persistPeer);
// The nice thing about persistent references is that you can write their value out to disk and
// then use them later. I don't do that here but it certainly can make sense for other situations
// where you don't want to have to keep building up dictionaries of attributes to get a reference.
//
// Also take a look at SecKeyWrapper's methods (CFTypeRef)getPersistentKeyRefWithKeyRef:(SecKeyRef)key
// & (SecKeyRef)getKeyRefWithPersistentKeyRef:(CFTypeRef)persistentRef.
LOGGING_FACILITY1( sanityCheck == noErr || sanityCheck == errSecDuplicateItem, @"Problem adding the peer public key to the keychain, OSStatus == %d.", sanityCheck );
if (persistPeer) {
peerKeyRef = [self getKeyRefWithPersistentKeyRef:persistPeer];
} else {
[peerPublicKeyAttr removeObjectForKey:(id)kSecValueData];
[peerPublicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef];
// Let's retry a different way.
sanityCheck = SecItemCopyMatching((CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef *)&peerKeyRef);
}
LOGGING_FACILITY1( sanityCheck == noErr && peerKeyRef != NULL, @"Problem acquiring reference to the public key, OSStatus == %d.", sanityCheck );
[peerTag release];
[peerPublicKeyAttr release];
if (persistPeer) CFRelease(persistPeer);
return peerKeyRef;
}
这个方法刚开始我用时仍然无法得到seckeyRef,所以我否定了它,不过现在想想可能是我运用不当。服务器最开始给我返回的NSString不错,可惜只是一个modulus,也就是RSA加密中公钥的e,如果不懂的同学可以先google下RSA。
我将服务器返回给我的这个NSString转成了NSData然后套入到如上方法,结果失败了。屡试屡败,所以原谅我粗浅的认为它错了。后来经过与服务器的沟通得知,服务器这边产生RSA一对秘钥采用的是openssl生成证书的形式,而iOS恰好也支持这样的证书,只不过要采用x509加签,貌似是说iOS没有这样的API,所以就找到了问题的关键,关于openssl生成证书,凡是遇到RSA问题的同学肯定都在找寻的路途中遇到过,大家可以参考这http://www.cnblogs.com/guola/archive/2012/10/30/2746159.html里:http://www.cnblogs.com/guola/archive/2012/10/30/2746159.html
上次写到一半,就被CSDN给封掉了,原因是新用户不允许使用链接。。。。以至于我的思路都断片了,还好有草稿备份了一部分,要不然真不知道自己是怎么死得。。。
继续吧,服务器用openssl生成private.pem,同时生成public.pem文件,然后服务器取出public.pem文件的内容,掐头去尾传给我,何为掐头去尾?pem格式的文件貌似就是在der格式的文件内容中在头和尾加了个标签,去掉即为der格式文件的内容,但是貌似der格式无法用文本编辑器打开,所以我采取了这个较为笨拙的方法,我将其写入自己用openssl生成的证书der格式,这样就可以用网上那些诸多的方法读取到证书中的内容信息了。
贴出我这部分的代码:
- (SecKeyRef) getPublicKey{// 从公钥证书文件中获取到公钥的SecKeyRef指针
if(_public_key ==nil){
NSString *publicKeyPath = [[[NSBundlemainBundle]bundlePath]stringByAppendingString:@"/publick_key1.der"];
if(publicKeyPath == nil)
{
NSLog(@"Can not find public_key.der");
return nil;
}
NSData *publickData = [NSDatadataWithContentsOfFile:publicKeyPath];
publickData = [GTMBase64 decodeData:publickData];
if(publickData == nil)
{
NSLog(@"Can not read from pub.der");
return nil;
}
SecCertificateRef myCertificate = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridgeCFDataRef)publickData);
SecPolicyRef myPolicy =SecPolicyCreateBasicX509();
SecTrustRef myTrust;
OSStatus status = SecTrustCreateWithCertificates(myCertificate,myPolicy,&myTrust);
SecTrustResultType trustResult;
if (status == noErr) {
status = SecTrustEvaluate(myTrust, &trustResult);
}
_public_key = SecTrustCopyPublicKey(myTrust);
CFRelease(myCertificate);
CFRelease(myPolicy);
CFRelease(myTrust);
}
//NSLog(@"public_key:%@",_public_key);
return_public_key;
}
转载请注明出处,谢谢。