+ (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 = 0; if (c_key[idx++] != 0x30) return(nil); if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; 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, 15)) return(nil); idx += 15; if (c_key[idx++] != 0x03) return(nil); if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; 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; }
1 + (NSString *)encryptData:(NSData *)data publicKey:(NSString *)pubKey{ 2 if(!data || !pubKey){ 3 return nil; 4 } 5 SecKeyRef keyRef = [RSA addPublicKey:pubKey]; 6 if(!keyRef){ 7 return nil; 8 } 9 10 const uint8_t *srcbuf = (const uint8_t *)[data bytes]; 11 size_t srclen = (size_t)data.length; 12 13 size_t outlen = SecKeyGetBlockSize(keyRef) * sizeof(uint8_t); 14 if(srclen > outlen - 11){ 15 CFRelease(keyRef); 16 return nil; 17 } 18 void *outbuf = malloc(outlen); 19 20 OSStatus status = noErr; 21 status = SecKeyEncrypt(keyRef, 22 kSecPaddingNone, //原作者写的是kSecPaddingPKCS1,经春哥研究这里写成kSecPaddingNone才符合我们使用 23 srcbuf, 24 srclen, 25 outbuf, 26 &outlen 27 ); 28 NSString *ret = nil; 29 if (status != 0) { 30 //NSLog(@"SecKeyEncrypt fail. Error Code: %ld", status); 31 }else{ 32 NSData *data = [NSData dataWithBytes:outbuf length:outlen]; 33 ret = base64_encode_data(data); 34 } 35 free(outbuf); 36 CFRelease(keyRef); 37 return ret; 38 }
还有一篇文章可以参考: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