-
-
Save lvjian700/204c23226fdffd6a505d to your computer and use it in GitHub Desktop.
RSAEncryptor for iOS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
@interface RSAEncryptor : NSObject | |
#pragma mark - Instance Methods | |
-(void) loadPublicKeyFromFile: (NSString*) derFilePath; | |
-(void) loadPublicKeyFromData: (NSData*) derData; | |
-(void) loadPrivateKeyFromFile: (NSString*) p12FilePath password:(NSString*)p12Password; | |
-(void) loadPrivateKeyFromData: (NSData*) p12Data password:(NSString*)p12Password; | |
-(NSString*) rsaEncryptString:(NSString*)string; | |
-(NSData*) rsaEncryptData:(NSData*)data ; | |
-(NSString*) rsaDecryptString:(NSString*)string; | |
-(NSData*) rsaDecryptData:(NSData*)data; | |
-(BOOL) rsaSHA1VerifyData:(NSData *) plainData | |
withSignature:(NSData *) signature; | |
#pragma mark - Class Methods | |
+(void) setSharedInstance: (RSAEncryptor*)instance; | |
+(RSAEncryptor*) sharedInstance; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Security/Security.h> | |
#import "RSAEncryptor.h" | |
#import "Base64.h" | |
#import <CommonCrypto/CommonCrypto.h> | |
@implementation RSAEncryptor | |
{ | |
SecKeyRef publicKey; | |
SecKeyRef privateKey; | |
} | |
-(void)dealloc | |
{ | |
if (nil != publicKey) { | |
CFRelease(publicKey); | |
} | |
if (nil != privateKey) { | |
CFRelease(privateKey); | |
} | |
} | |
-(SecKeyRef) getPublicKey { | |
return publicKey; | |
} | |
-(SecKeyRef) getPrivateKey { | |
return privateKey; | |
} | |
-(void) loadPublicKeyFromFile: (NSString*) derFilePath | |
{ | |
NSData *derData = [[NSData alloc] initWithContentsOfFile:derFilePath]; | |
[self loadPublicKeyFromData: derData]; | |
} | |
-(void) loadPublicKeyFromData: (NSData*) derData | |
{ | |
publicKey = [self getPublicKeyRefrenceFromeData: derData]; | |
} | |
-(void) loadPrivateKeyFromFile: (NSString*) p12FilePath password:(NSString*)p12Password | |
{ | |
NSData *p12Data = [NSData dataWithContentsOfFile:p12FilePath]; | |
[self loadPrivateKeyFromData: p12Data password:p12Password]; | |
} | |
-(void) loadPrivateKeyFromData: (NSData*) p12Data password:(NSString*)p12Password | |
{ | |
privateKey = [self getPrivateKeyRefrenceFromData: p12Data password: p12Password]; | |
} | |
#pragma mark - Private Methods | |
-(SecKeyRef) getPublicKeyRefrenceFromeData: (NSData*)derData | |
{ | |
SecCertificateRef myCertificate = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)derData); | |
SecPolicyRef myPolicy = SecPolicyCreateBasicX509(); | |
SecTrustRef myTrust; | |
OSStatus status = SecTrustCreateWithCertificates(myCertificate,myPolicy,&myTrust); | |
SecTrustResultType trustResult; | |
if (status == noErr) { | |
status = SecTrustEvaluate(myTrust, &trustResult); | |
} | |
SecKeyRef securityKey = SecTrustCopyPublicKey(myTrust); | |
CFRelease(myCertificate); | |
CFRelease(myPolicy); | |
CFRelease(myTrust); | |
return securityKey; | |
} | |
-(SecKeyRef) getPrivateKeyRefrenceFromData: (NSData*)p12Data password:(NSString*)password | |
{ | |
SecKeyRef privateKeyRef = NULL; | |
NSMutableDictionary * options = [[NSMutableDictionary alloc] init]; | |
[options setObject: password forKey:(__bridge id)kSecImportExportPassphrase]; | |
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); | |
OSStatus securityError = SecPKCS12Import((__bridge CFDataRef) p12Data, (__bridge CFDictionaryRef)options, &items); | |
if (securityError == noErr && CFArrayGetCount(items) > 0) { | |
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0); | |
SecIdentityRef identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity); | |
securityError = SecIdentityCopyPrivateKey(identityApp, &privateKeyRef); | |
if (securityError != noErr) { | |
privateKeyRef = NULL; | |
} | |
} | |
CFRelease(items); | |
return privateKeyRef; | |
} | |
#pragma mark - Encrypt | |
-(NSString*) rsaEncryptString:(NSString*)string { | |
NSData* data = [string dataUsingEncoding:NSUTF8StringEncoding]; | |
NSData* encryptedData = [self rsaEncryptData: data]; | |
NSString* base64EncryptedString = [encryptedData base64EncodedString]; | |
return base64EncryptedString; | |
} | |
// 加密的大小受限于SecKeyEncrypt函数,SecKeyEncrypt要求明文和密钥的长度一致,如果要加密更长的内容,需要把内容按密钥长度分成多份,然后多次调用SecKeyEncrypt来实现 | |
-(NSData*) rsaEncryptData:(NSData*)data { | |
SecKeyRef key = [self getPublicKey]; | |
size_t cipherBufferSize = SecKeyGetBlockSize(key); | |
uint8_t *cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t)); | |
size_t blockSize = cipherBufferSize - 11; // 分段加密 | |
size_t blockCount = (size_t)ceil([data length] / (double)blockSize); | |
NSMutableData *encryptedData = [[NSMutableData alloc] init] ; | |
for (int i=0; i<blockCount; i++) { | |
int bufferSize = MIN(blockSize,[data length] - i * blockSize); | |
NSData *buffer = [data subdataWithRange:NSMakeRange(i * blockSize, bufferSize)]; | |
OSStatus status = SecKeyEncrypt(key, kSecPaddingPKCS1, (const uint8_t *)[buffer bytes], [buffer length], cipherBuffer, &cipherBufferSize); | |
if (status == noErr){ | |
NSData *encryptedBytes = [[NSData alloc] initWithBytes:(const void *)cipherBuffer length:cipherBufferSize]; | |
[encryptedData appendData:encryptedBytes]; | |
}else{ | |
if (cipherBuffer) { | |
free(cipherBuffer); | |
} | |
return nil; | |
} | |
} | |
if (cipherBuffer){ | |
free(cipherBuffer); | |
} | |
return encryptedData; | |
} | |
#pragma mark - Decrypt | |
-(NSString*) rsaDecryptString:(NSString*)string { | |
NSData* data = [[NSData alloc] initWithBase64EncodedString:string options:NSDataBase64DecodingIgnoreUnknownCharacters]; | |
NSData* decryptData = [self rsaDecryptData: data]; | |
NSString* result = [[NSString alloc] initWithData: decryptData encoding:NSUTF8StringEncoding]; | |
return result; | |
} | |
-(NSData*) rsaDecryptData:(NSData*)data { | |
SecKeyRef key = [self getPrivateKey]; | |
size_t cipherLen = [data length]; | |
void *cipher = malloc(cipherLen); | |
[data getBytes:cipher length:cipherLen]; | |
size_t plainLen = SecKeyGetBlockSize(key) - 12; | |
void *plain = malloc(plainLen); | |
OSStatus status = SecKeyDecrypt(key, kSecPaddingPKCS1, cipher, cipherLen, plain, &plainLen); | |
if (status != noErr) { | |
return nil; | |
} | |
NSData *decryptedData = [[NSData alloc] initWithBytes:(const void *)plain length:plainLen]; | |
return decryptedData; | |
} | |
#pragma marke - verify file SHA1 | |
-(BOOL) rsaSHA1VerifyData:(NSData *) plainData | |
withSignature:(NSData *) signature { | |
size_t signedHashBytesSize = SecKeyGetBlockSize([self getPublicKey]); | |
const void* signedHashBytes = [signature bytes]; | |
size_t hashBytesSize = CC_SHA1_DIGEST_LENGTH; | |
uint8_t* hashBytes = malloc(hashBytesSize); | |
if (!CC_SHA1([plainData bytes], (CC_LONG)[plainData length], hashBytes)) { | |
return NO; | |
} | |
OSStatus status = SecKeyRawVerify(publicKey, | |
kSecPaddingPKCS1SHA1, | |
hashBytes, | |
hashBytesSize, | |
signedHashBytes, | |
signedHashBytesSize); | |
return status == errSecSuccess; | |
} | |
#pragma mark - Class Methods | |
static RSAEncryptor* sharedInstance = nil; | |
+(void) setSharedInstance: (RSAEncryptor*)instance | |
{ | |
sharedInstance = instance; | |
} | |
+(RSAEncryptor*) sharedInstance | |
{ | |
return sharedInstance; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Very useful! Thank you for sharing!