使用openssl创建证书
通常创建证书的命令如下:
$ openssl req -x509 -out public_key.der -outform der -new -newkey rsa:1024 -keyout private_key.pem -days 3650
其中会让填写很多证书相关的信息,比如:密码,CN,网站等等.有以下几点需要注意:
-
public_key.pem
: 就是公钥输出,是一个x509
格式的证书.还有一个需要注意的,iOS只支持证书是der
格式,而不是pem
-
private_key.pem
:是私钥,可以用来解密 -
rsa:1024
:表示证书中的密钥长度,一般用1024或者2048长度 -
-days
:表示证书的有效期
为了使用刚刚创建public_key.der
证书,我们需要将创建如下文件RSA.h
,RSA.m
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");
}
对应的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']));
上述RSA加密方法中使用的Padding模式是
RSA_PKCS1_PADDING
,这是最常用的填充方式.
这个模式要求输入的字符串必须比RSA的密钥模长少11字节即:RSA_size(rsa) - 11
,如果明文过长,必须切割,然后填充分段加密.根据这个要求,对于1024bit的密钥,block length = 1024/8 – 11 = 117 字节
ps: 这是翻译的一篇国外的博客.具体地址找不到了``