iOS 客户端进行 RSA 加密并在 PHP 服务端进行解密
2015-07-28 23:12
771 查看
前言
本文是对 Js Lim 的一篇博客的翻译,原文链接如下:http://jslim.net/blog/2013/06/24/rsa-decryption-on-ios/
若本文有翻译不妥的地方,欢迎大家批评指正,我也期望能够与各位大神探讨交流。
译文
在 iOS 上对 RSA 加密相关的问题折腾了几周,现在我希望跟大家一起分享我调研的结果。首先,利用 openssl 产生密钥对。(在终端中输入一下命令即可)
openssl req -x509 -out public_key.der -outform der -new -newkey rsa:1024 -keyout private_key.pem -days 3650
对于上面的命令,有几点需要说明:
public_key.der 是 X509 证书,在 iOS 中后缀名应该为 .der 而不是 .pem
private_key.pem 即为可以用来解密的密钥
rsa:1024 是密钥的长度,密钥的长度越长,越安全(基本上 1024 bits 就可以认为是安全的,2048 bits 则是极其安全的)
-days 证书的有效期,在这里,我们设置的有效期为十年
然后,拖拽 public_key.der 文件加入到你的 iOS 项目中,并且创建 RSA 类如下
RSA.h
#import <Foundation/Foundation.h> @interface RSA : NSObject { SecKeyRef publicKey; SecCertificateRef certificate; SecPolicyRef policy; SecTrustRef trust; size_t maxPlainLen; } - (NSData *) encryptWithData:(NSData *)content; - (NSData *) encryptWithString:(NSString *)content; - (NSString *) encryptToString:(NSString *)content; @end
‘
RSA.m
#import "RSA.h" @implementation RSA - (id)init { self = [super init]; NSString *publicKeyPath = [[NSBundle mainBundle] pathForResource:@"public_key" ofType:@"der"]; if (publicKeyPath == nil) { NSLog(@"Can not find pub.der"); return nil; } NSDate *publicKeyFileContent = [NSData dataWithContentsOfFile:publicKeyPath]; if (publicKeyFileContent == nil) { NSLog(@"Can not read from pub.der"); return nil; } certificate = SecCertificateCreateWithData(kCFAllocatorDefault, ( __bridge CFDataRef)publicKeyFileContent); if (certificate == nil) { NSLog(@"Can not read certificate from pub.der"); return nil; } policy = SecPolicyCreateBasicX509(); OSStatus returnCode = SecTrustCreateWithCertificates(certificate, policy, &trust); if (returnCode != 0) { NSLog(@"SecTrustCreateWithCertificates fail. Error Code: %ld", returnCode); return nil; } SecTrustResultType trustResultType; returnCode = SecTrustEvaluate(trust, &trustResultType); if (returnCode != 0) { return nil; } publicKey = SecTrustCopyPublicKey(trust); if (publicKey == nil) { NSLog(@"SecTrustCopyPublicKey fail"); return nil; } maxPlainLen = SecKeyGetBlockSize(publicKey) - 12; return self; } - (NSData *) encryptWithData:(NSData *)content { size_t plainLen = [content length]; if (plainLen > maxPlainLen) { NSLog(@"content(%ld) is too long, must < %ld", plainLen, maxPlainLen); return nil; } void *plain = malloc(plainLen); [content getBytes:plain length:plainLen]; size_t cipherLen = 128; // currently RSA key length is set to 128 bytes void *cipher = malloc(cipherLen); OSStatus returnCode = SecKeyEncrypt(publicKey, kSecPaddingPKCS1, plain, plainLen, cipher, &cipherLen); NSData *result = nil; if (returnCode != 0) { NSLog(@"SecKeyEncrypt fail. Error Code: %ld", returnCode); } else { result = [NSData dataWithBytes:cipher length:cipherLen]; } free(plain); free(cipher); return result; } - (NSData *) encryptWithString:(NSString *)content { return [self encryptWithData:[content dataUsingEncoding:NSUTF8StringEncoding]]; } - (NSString *) encryptToString:(NSString *)content { NSData *data = [self encryptWithString:content]; return [self base64forData:data]; } // convert NSData to NSString - (NSString*)base64forData:(NSData*)theData { const uint8_t* input = (const uint8_t*)[theData bytes]; NSInteger length = [theData length]; static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4]; uint8_t* output = (uint8_t*)data.mutableBytes; NSInteger i; for (i=0; i < length; i += 3) { NSInteger value = 0; NSInteger j; for (j = i; j < (i + 3); j++) { value <<= 8; if (j < length) { value |= (0xFF & input[j]); } } NSInteger theIndex = (i / 3) * 4; output[theIndex + 0] = table[(value >> 18) & 0x3F]; output[theIndex + 1] = table[(value >> 12) & 0x3F]; output[theIndex + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '='; output[theIndex + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '='; } return [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease]; } - (void)dealloc{ CFRelease(certificate); CFRelease(trust); CFRelease(policy); CFRelease(publicKey); } @end
对该类的使用方法:
#import "RSA.h" RSA *rsa = [[RSA alloc] init]; if (rsa != nil) { // just post the string to server NSLog(@"%@", [rsa encryptToString:@"This is plaintext"]); } else { NSLog(@"Error"); }
对于 iOS 客户端的解密到此简单介绍完毕,现在看看 PHP 服务端的解密,在这之前,我们需要下载 phpseclib 库来进行解密。(请自行下载)
<?php set_include_path(get_include_path() . PATH_SEPARATOR . 'phpseclib'); include('Crypt/RSA.php'); $rsa = new Crypt_RSA(); $rsa->setPassword('yourPassword'); $rsa->loadKey(file_get_contents('/path/to/private_key.pem')); $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1); echo $rsa->decrypt(base64_decode($_POST['ciphertext']));
相关文章推荐
- PHP 中 new static 和 new self 的区别
- URL路由设置-CI(codeigniter)PHP框架再探
- php-fpm 启动参数及重要配置详解
- php的curl抓包
- thinkphp 验证码显示问题
- 12. PHP 函数
- win7系统下ftp服务器的搭建
- 4步win7下简单FTP服务器搭建(试验成功)
- Yii提供的Htmler助手checkboxList可自定义Checkbox输出格式
- php.ini配置文件
- php读取目录下的文件
- TP中的快捷查询
- 一致性Hash算法php实现实例
- PHP学习笔记1
- FragmentPager +ViewPager +FragmentStatePagerAdapter详解
- PHP开发安全问题总结
- TP框架中,对数据的过滤函数
- php对象转化为数组
- 解决PHPCMS添加栏目时报错
- php 截取指定长度中文字符