Last active
March 31, 2017 11:28
-
-
Save VictorZhang2014/ca1da59f50b728d8c6c2f5b950e01856 to your computer and use it in GitHub Desktop.
RSACryptography, a set of RSA encrypt/decrypt methods for a chunk of data in Objective-c/iOS
This file contains hidden or 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> | |
#import "RSACryptographic.h" | |
/**************** The following methods are decryption/encryption by using a certificate ****************/ | |
NSString * EncryptoString(NSString *inputStr) | |
{ | |
RSACryptographic *rsa = [[RSACryptographic alloc] init]; | |
//Load your public Key file | |
[rsa loadPublicKeyFromFile:@"/Users/VictorZhang/Desktop/RSA/public_key.der"]; | |
//encrypt | |
return [rsa rsaEncryptString:inputStr]; | |
} | |
NSString *DecryptoString(NSString *secureText) | |
{ | |
RSACryptographic *rsa = [[RSACryptographic alloc] init]; | |
//Load your private key file | |
[rsa loadPrivateKeyFromFile:@"/Users/VictorZhang/Desktop/RSA/private_key.p12" password:@"123456"]; | |
//decrypt | |
return [rsa rsaDecryptString:secureText]; | |
} | |
int main(int argc, const char * argv[]) { | |
//1.Encrypt String | |
NSString *hello = @"高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。"; | |
NSString *secureHello = EncryptoString(hello); | |
NSLog(@"Cipher Data : %@ \n", secureHello); | |
//2.Decrypt String | |
NSString *decryptStr = DecryptoString(secureHello); | |
NSLog(@"Decrypted Data: %@", decryptStr); | |
return 0; | |
} |
This file contains hidden or 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 RSACryptographic : NSObject | |
- (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; | |
@end |
This file contains hidden or 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 "RSACryptographic.h" | |
#import <Security/Security.h> | |
#import <CommonCrypto/CommonCrypto.h> | |
@implementation RSACryptographic | |
{ | |
SecKeyRef _publicKey; | |
SecKeyRef _privateKey; | |
} | |
- (void)dealloc { | |
if (_publicKey) { | |
CFRelease(_publicKey); | |
} | |
if (_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; | |
} | |
} | |
if (items) CFRelease(items); | |
return privateKeyRef; | |
} | |
#pragma mark - Encrypt | |
- (NSString*)rsaEncryptString:(NSString*)string { | |
NSData* data = [string dataUsingEncoding:NSUTF8StringEncoding]; | |
NSData* encryptedData = [self rsaEncryptData: data]; | |
NSString* base64EncryptedString = [encryptedData base64EncodedStringWithOptions:0]; | |
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++) { | |
unsigned long 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 keyRef = [self getPrivateKey]; | |
const uint8_t *srcbuf = (const uint8_t *)[data bytes]; | |
size_t srclen = (size_t)data.length; | |
size_t block_size = SecKeyGetBlockSize(keyRef) * sizeof(uint8_t); | |
UInt8 *outbuf = malloc(block_size); | |
size_t src_block_size = block_size; | |
NSMutableData *ret = [[NSMutableData alloc] init]; | |
for(int idx = 0; idx < srclen; idx += src_block_size){ | |
size_t data_len = srclen - idx; | |
if(data_len > src_block_size){ | |
data_len = src_block_size; | |
} | |
size_t outlen = block_size; | |
OSStatus status = noErr; | |
status = SecKeyDecrypt(keyRef, kSecPaddingNone, srcbuf + idx, data_len, outbuf, &outlen); | |
if (status != 0) { | |
NSLog(@"SecKeyEncrypt fail. Error Code: %d", status); | |
ret = nil; | |
break; | |
}else{ | |
//the actual decrypted data is in the middle, locate it! | |
int idxFirstZero = -1; | |
int idxNextZero = (int)outlen; | |
for ( int i = 0; i < outlen; i++ ) { | |
if ( outbuf[i] == 0 ) { | |
if ( idxFirstZero < 0 ) { | |
idxFirstZero = i; | |
} else { | |
idxNextZero = i; | |
break; | |
} | |
} | |
} | |
[ret appendBytes:&outbuf[idxFirstZero+1] length:idxNextZero-idxFirstZero-1]; | |
} | |
} | |
if (outbuf) | |
free(outbuf); | |
return ret; | |
} | |
#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; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment