openssl モデルを使用して暗号文を復号化しましたが、php サーバーが復号化された暗号文を返したり、null を返したりすることがあります
目標 c の CRSA.h
#import <Foundation/Foundation.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
typedef enum {
KeyTypePublic,
KeyTypePrivate
}KeyType;
typedef enum {
RSA_PADDING_TYPE_NONE = RSA_NO_PADDING,
RSA_PADDING_TYPE_PKCS1 = RSA_PKCS1_PADDING,
RSA_PADDING_TYPE_SSLV23 = RSA_SSLV23_PADDING
}RSA_PADDING_TYPE;
@interface CRSA : NSObject{
RSA *_rsa;
}
+ (id)shareInstance;
- (BOOL)importRSAKeyWithType:(KeyType)type;
- (int)getBlockSizeWithRSA_PADDING_TYPE:(RSA_PADDING_TYPE)padding_type;
- (NSString *) encryptByRsa:(NSString*)content withKeyType:(KeyType)keyType;
- (NSString *) decryptByRsa:(NSString*)content withKeyType:(KeyType)keyType;
@end
CRSA.m
#import "CRSA.h"
#define BUFFSIZE 1024
#import "Base64.h"
#define PADDING RSA_PADDING_TYPE_PKCS1
@implementation CRSA
+ (id)shareInstance
{
static CRSA *_crsa = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_crsa = [[self alloc] init];
});
return _crsa;
}
- (BOOL)importRSAKeyWithType:(KeyType)type
{
FILE *file;
NSString *keyName = type == KeyTypePublic ? @"public_key" : @"private_key";
NSString *keyPath = [[NSBundle mainBundle] pathForResource:keyName ofType:@"pem"];
file = fopen([keyPath UTF8String], "rb");
if (NULL != file)
{
if (type == KeyTypePublic)
{
_rsa = PEM_read_RSA_PUBKEY(file, NULL, NULL, NULL);
assert(_rsa != NULL);
}
else
{
_rsa = PEM_read_RSAPrivateKey(file, NULL, NULL, NULL);
assert(_rsa != NULL);
}
fclose(file);
return (_rsa != NULL) ? YES : NO;
}
return NO;
}
- (NSString *) encryptByRsa:(NSString*)content withKeyType:(KeyType)keyType
{
if (![self importRSAKeyWithType:keyType])
return nil;
int status;
int length = [content length];
unsigned char input[length + 1];
bzero(input, length + 1);
int i = 0;
for (; i < length; i++)
{
input[i] = [content characterAtIndex:i];
}
NSInteger flen = [self getBlockSizeWithRSA_PADDING_TYPE:PADDING];
char *encData = (char*)malloc(flen);
bzero(encData, flen);
switch (keyType) {
case KeyTypePublic:
status = RSA_public_encrypt(length, (unsigned char*)input, (unsigned char*)encData, _rsa, PADDING);
break;
default:
status = RSA_private_encrypt(length, (unsigned char*)input, (unsigned char*)encData, _rsa, PADDING);
break;
}
if (status)
{
NSData *returnData = [NSData dataWithBytes:encData length:status];
free(encData);
encData = NULL;
NSString *ret = [returnData base64EncodedString];
return ret;
}
free(encData);
encData = NULL;
return nil;
}
- (NSString *) decryptByRsa:(NSString*)content withKeyType:(KeyType)keyType
{
if (![self importRSAKeyWithType:keyType])
return nil;
int status;
NSData *data = [content base64DecodedData];
int length = [data length];
NSInteger flen = [self getBlockSizeWithRSA_PADDING_TYPE:PADDING];
char *decData = (char*)malloc(flen);
bzero(decData, flen);
switch (keyType) {
case KeyTypePublic:
status = RSA_public_decrypt(length, (unsigned char*)[data bytes], (unsigned char*)decData, _rsa, PADDING);
break;
default:
status = RSA_private_decrypt(length, (unsigned char*)[data bytes], (unsigned char*)decData, _rsa, PADDING);
break;
}
if (status)
{
NSMutableString *decryptString = [[NSMutableString alloc] initWithBytes:decData length:strlen(decData) encoding:NSASCIIStringEncoding];
free(decData);
decData = NULL;
return decryptString;
}
free(decData);
decData = NULL;
return nil;
}
- (int)getBlockSizeWithRSA_PADDING_TYPE:(RSA_PADDING_TYPE)padding_type
{
int len = RSA_size(_rsa);
if (padding_type == RSA_PADDING_TYPE_PKCS1 || padding_type == RSA_PADDING_TYPE_SSLV23) {
len -= 11;
}
return len;
}
@end
Base64.h
#import <Foundation/Foundation.h>
@interface NSData (Base64)
+ (NSData *)dataWithBase64EncodedString:(NSString *)string;
- (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth;
- (NSString *)base64EncodedString;
@end
@interface NSString (Base64)
+ (NSString *)stringWithBase64EncodedString:(NSString *)string;
- (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth;
- (NSString *)base64EncodedString;
- (NSString *)base64DecodedString;
- (NSData *)base64DecodedData;
@end
Base64.m
#import "Base64.h"
#import <Availability.h>
#if !__has_feature(objc_arc)
#error This library requires automatic reference counting
#endif
@implementation NSData (Base64)
+ (NSData *)dataWithBase64EncodedString:(NSString *)string
{
const char lookup[] =
{
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 62, 99, 99, 99, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 99, 99, 99, 99, 99, 99,
99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 99, 99, 99, 99, 99,
99, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 99, 99, 99, 99, 99
};
NSData *inputData = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
long long inputLength = [inputData length];
const unsigned char *inputBytes = [inputData bytes];
long long maxOutputLength = (inputLength / 4 + 1) * 3;
NSMutableData *outputData = [NSMutableData dataWithLength:maxOutputLength];
unsigned char *outputBytes = (unsigned char *)[outputData mutableBytes];
int accumulator = 0;
long long outputLength = 0;
unsigned char accumulated[] = {0, 0, 0, 0};
for (long long i = 0; i < inputLength; i++)
{
unsigned char decoded = lookup[inputBytes[i] & 0x7F];
if (decoded != 99)
{
accumulated[accumulator] = decoded;
if (accumulator == 3)
{
outputBytes[outputLength++] = (accumulated[0] << 2) | (accumulated[1] >> 4);
outputBytes[outputLength++] = (accumulated[1] << 4) | (accumulated[2] >> 2);
outputBytes[outputLength++] = (accumulated[2] << 6) | accumulated[3];
}
accumulator = (accumulator + 1) % 4;
}
}
//handle left-over data
if (accumulator > 0) outputBytes[outputLength] = (accumulated[0] << 2) | (accumulated[1] >> 4);
if (accumulator > 1) outputBytes[++outputLength] = (accumulated[1] << 4) | (accumulated[2] >> 2);
if (accumulator > 2) outputLength++;
//truncate data to match actual output length
outputData.length = outputLength;
return outputLength? outputData: nil;
}
- (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth
{
//ensure wrapWidth is a multiple of 4
wrapWidth = (wrapWidth / 4) * 4;
const char lookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
long long inputLength = [self length];
const unsigned char *inputBytes = [self bytes];
long long maxOutputLength = (inputLength / 3 + 1) * 4;
maxOutputLength += wrapWidth? (maxOutputLength / wrapWidth) * 2: 0;
unsigned char *outputBytes = (unsigned char *)malloc(maxOutputLength);
long long i;
long long outputLength = 0;
for (i = 0; i < inputLength - 2; i += 3)
{
outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2];
outputBytes[outputLength++] = lookup[((inputBytes[i] & 0x03) << 4) | ((inputBytes[i + 1] & 0xF0) >> 4)];
outputBytes[outputLength++] = lookup[((inputBytes[i + 1] & 0x0F) << 2) | ((inputBytes[i + 2] & 0xC0) >> 6)];
outputBytes[outputLength++] = lookup[inputBytes[i + 2] & 0x3F];
//add line break
if (wrapWidth && (outputLength + 2) % (wrapWidth + 2) == 0)
{
outputBytes[outputLength++] = '\r';
outputBytes[outputLength++] = '\n';
}
}
//handle left-over data
if (i == inputLength - 2)
{
// = terminator
outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2];
outputBytes[outputLength++] = lookup[((inputBytes[i] & 0x03) << 4) | ((inputBytes[i + 1] & 0xF0) >> 4)];
outputBytes[outputLength++] = lookup[(inputBytes[i + 1] & 0x0F) << 2];
outputBytes[outputLength++] = '=';
}
else if (i == inputLength - 1)
{
// == terminator
outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2];
outputBytes[outputLength++] = lookup[(inputBytes[i] & 0x03) << 4];
outputBytes[outputLength++] = '=';
outputBytes[outputLength++] = '=';
}
if (outputLength >= 4)
{
//truncate data to match actual output length
outputBytes = realloc(outputBytes, outputLength);
return [[NSString alloc] initWithBytesNoCopy:outputBytes
length:outputLength
encoding:NSASCIIStringEncoding
freeWhenDone:YES];
}
else if (outputBytes)
{
free(outputBytes);
}
return nil;
}
- (NSString *)base64EncodedString
{
return [self base64EncodedStringWithWrapWidth:0];
}
@end
@implementation NSString (Base64)
+ (NSString *)stringWithBase64EncodedString:(NSString *)string
{
NSData *data = [NSData dataWithBase64EncodedString:string];
if (data)
{
return [[self alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
return nil;
}
- (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth
{
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
return [data base64EncodedStringWithWrapWidth:wrapWidth];
}
- (NSString *)base64EncodedString
{
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
return [data base64EncodedString];
}
- (NSString *)base64DecodedString
{
return [NSString stringWithBase64EncodedString:self];
}
- (NSData *)base64DecodedData
{
return [NSData dataWithBase64EncodedString:self];
}
@end
PHP api.php で
<?php
define('IN_ECS', true);
include_once 'Rsa.php';
include_once 'cls_json.php';
parse_str(file_get_contents("php://input"), $post);
$json = new JSON;
$rsa = new Rsa;
$result['reply'] = $rsa->privDecrypt($post['text']);
show_json($json, $result, true);
function parse_json(&$json, $str)
{
if (defined('CHARSET') && CHARSET == 'gbk')
{
$str = addslashes(stripslashes(ecs_iconv('utf-8', 'gbk', $str)));
}
$json_obj = $json->decode($str, 1);
$_POST = $json_obj;
}
function show_json(&$json, $array, $convert = false)
{
$json_str = $json->encode($array, false);
if (!$convert && defined('CHARSET') && CHARSET == 'gbk')
{
$json_str = ecs_iconv('UTF-8', 'GBK', $json_str);
}
@header('Content-type:text/html; charset='.CHARSET);
exit($json_str);
}
?>
Rsa.php
<?php
class Rsa
{
private static $PRIVATE_KEY = <<<EOF
-----BEGIN RSA PRIVATE KEY-----
(MyPrivateKey)
-----END RSA PRIVATE KEY-----
EOF;
private static function getPrivateKey(){
$privKey = self::$PRIVATE_KEY;
return openssl_pkey_get_private($privKey);
}
public static function privEncrypt($data)
{
if(!is_string($data)){
return null;
}
return openssl_private_encrypt($data,$encrypted,self::getPrivateKey())? base64_encode($encrypted) : null;
}
public static function privDecrypt($encrypted)
{
if(!is_string($encrypted)){
return null;
}
openssl_private_decrypt(base64_decode($encrypted), $decrypted, self::getPrivateKey(),OPENSSL_PKCS1_PADDING);
return $decrypted;
// return (openssl_private_decrypt(base64_decode($encrypted), $decrypted, self::getPrivateKey()))? $decrypted : null;
}
}
?>
「テスト テスト」のような暗号文を送信し、Xcode で復号化された暗号文をログに記録します
NSLog
2013-10-20 13:54:47.518 test[1197:a0b] {"reply":null}
2013-10-20 13:54:47.700 test[1197:a0b] {"reply":"test test"}
2013-10-20 13:54:47.856 test[1197:a0b] {"reply":null}
2013-10-20 13:54:48.023 test[1197:a0b] {"reply":null}
2013-10-20 13:54:48.185 test[1197:a0b] {"reply":"test test"}
2013-10-20 13:54:48.346 test[1197:a0b] {"reply":null}
2013-10-20 13:54:48.486 test[1197:a0b] {"reply":null}
理由がわかりません、助けてください、thx