您的位置:首页 > 编程语言 > PHP开发

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']));
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: