分享源碼,讓苦逼的開發生活見鬼去。
最近一直苦於開發,今天稍微有些時間,趁機先分享一下數據的加解密。後續補充用戶數據的加密存儲以及數據存儲管理。
特點:
優點:簡單、可並行計算、誤差不傳遞
缺點:不能隱藏明文模式(比如圖像加密輪廓仍在)、主動攻擊(改明文,後續內容不影響,只要誤差不傳遞該缺點就存在)
用途:需要並行加密的應用
AES加密算法是密碼學中的高級加密標准,該加密算法采用對稱分組密碼體制,密鑰長度的最少支持為128、192、256,分組長度128位,算法應易於各種硬件和軟件實現。這種加密算法是美國聯邦政府采用的區塊加密標准,這個標准用來替代原先的DES,已經被多方分析且廣為全世界所使用。設計為支持128/192/256位(/32=nb)數據塊大小(即分組長度);支持128/192/256位(/32=nk)密碼長度,,在10進制裡,對應34×1038、62×1057、1.1×1077個密鑰
AES加密的原理可以百度,這裡就不詳細說明了,下面進入開發正題
NSData+AES.m 文件
// // NSData+AES.m // Encryption // // Created by llyouss on 16/10/16. // Copyright © 2016年 llyouss. All rights reserved. // #import "NSData+AES.h" #import@implementation NSData (AES) - (NSData *)AES256EncryptWithKey:(NSString *)key {//加密 char keyPtr[kCCKeySizeAES256+1]; bzero(keyPtr, sizeof(keyPtr)); [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; NSUInteger dataLength = [self length]; size_t bufferSize = dataLength + kCCBlockSizeAES128; void *buffer = malloc(bufferSize); size_t numBytesEncrypted = 0; CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding | kCCOptionECBMode, keyPtr, kCCBlockSizeAES128, NULL, [self bytes], dataLength, buffer, bufferSize, &numBytesEncrypted); if (cryptStatus == kCCSuccess) { return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; } free(buffer); return nil; } - (NSData *)AES256DecryptWithKey:(NSString *)key {//解密 char keyPtr[kCCKeySizeAES256+1]; bzero(keyPtr, sizeof(keyPtr)); [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; NSUInteger dataLength = [self length]; size_t bufferSize = dataLength + kCCBlockSizeAES128; void *buffer = malloc(bufferSize); size_t numBytesDecrypted = 0; CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding | kCCOptionECBMode, keyPtr, kCCBlockSizeAES128, NULL, [self bytes], dataLength, buffer, bufferSize, &numBytesDecrypted); if (cryptStatus == kCCSuccess) { return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted]; } free(buffer); return nil; } #import @end
調用事例
導入#import "SecurityUtil.h"
-(void)AESEncryption{ NSString *testString = @"AESllyouss"; NSLog(@"BASE64:%@", [SecurityUtil encodeBase64String:testString]); NSLog(@"MD5:%@", [SecurityUtil encryptMD5String:testString]); NSData *aesData = [SecurityUtil encryptAESData:testString]; NSLog(@"AES加密:%@", aesData); NSLog(@"AES解密:%@", [SecurityUtil decryptAESData:aesData]); }
其實base64編解碼方式使用系統的api已經很方便,但是還是喜歡現成的。
下載GTMBase64文件,在工程中加入三個文件
GTMDefines.h
GTMBase64.h
GTMBase64.m
下載地址:點擊打開鏈接
封裝一下
// // SecurityUtil.m // Encryption // // Created by llyouss on 16/10/16. // Copyright © 2016年 llyouss. All rights reserved. // #import "SecurityUtil.h" #import "GTMBase64.h" #import "NSData+AES.h" #import "NSString+MD5.h" #define APP_PUBLIC_PASSWORD @"boundary" @implementation SecurityUtil #pragma mark - base64 + (NSString*)encodeBase64String:(NSString * )input { NSData *data = [input dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]; data = [GTMBase64 encodeData:data]; NSString *base64String = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] ; return base64String; } + (NSString*)decodeBase64String:(NSString * )input { NSData *data = [input dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]; data = [GTMBase64 decodeData:data]; NSString *base64String = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; return base64String; } + (NSString*)encodeBase64Data:(NSData *)data { data = [GTMBase64 encodeData:data]; NSString *base64String = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; return base64String; } + (NSString*)decodeBase64Data:(NSData *)data { data = [GTMBase64 decodeData:data]; NSString *base64String = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; return base64String; }
MD5是哈希算法,作用大家都應該知道,加密非常簡單直接上方法
- (NSString *)md5Encrypt { const char *cStr = [self UTF8String]; unsigned char result[16]; CC_MD5( cStr, (int)strlen(cStr), result ); NSMutableString *hash = [NSMutableString string]; for (int i = 0; i < 16; i++) [hash appendFormat:@"%02X", result[i]]; return [hash lowercaseString]; }
MD5目前發現了重復,目前最新的是sha256,具體作用大家都應該知道。
//sha256加密方式 - (NSString *)Sha256String:(NSString *)srcString { const char *cstr = [srcString cStringUsingEncoding:NSUTF8StringEncoding]; NSData *data = [NSData dataWithBytes:cstr length:srcString.length]; uint8_t digest[CC_SHA256_DIGEST_LENGTH]; CC_SHA256(data.bytes, data.length, digest); NSMutableString* result = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2]; for(int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) { [result appendFormat:@"%02x", digest[i]]; } return result; }
- (NSString *)sha1Encrypt{ const char *cstr = [self UTF8String]; NSData *data = [NSData dataWithBytes:cstr length:self.length]; uint8_t digest[CC_SHA1_DIGEST_LENGTH]; CC_SHA1(data.bytes, (int)data.length, digest); NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2]; for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) [output appendFormat:@"%02x", digest[i]]; return output; }
特點
RSA加密算法是目前最有影響力的公鑰加密算法,並且被普遍認為是目前最優秀的公鑰方案之一。RSA是第一個能同時用於加密和數宇簽名的算法,它能夠抵抗到目前為止已知的所有密碼攻擊,已被ISO推薦為公鑰數據加密標准。RSA加密算法基於一個十分簡單的數論事實:將兩個大素數相乘十分容易,但想要對其乘積進行因式分解卻極其困難,因此可以將乘積公開作為加密密鑰。
使用openssl實現,可以在這下載:點擊打開鏈接
1.生成RSA密鑰
* 生成RSA私鑰
openssl genrsa -out rsa_private_key.pem 1024
* 生成RSA公鑰
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
pem文件可以直接文本編輯器打開
將RSA私鑰轉換成PKCS8格式
openssl pkcs8 -topk8 -inform PEM -in private_rsa.pem -outform PEM -nocrypt -out private_key.pem (後邊一定要加-out private_key.pem將轉換後的私鑰保存在private_key.pem,不然得到的結果要設置密碼且顯示在終端中,這個和得到pem中的私鑰有差異。)
2.導入OpenSSL,導入HBRSAHandler褲文件
小技巧:記得在headSearchpath設置路徑,不然編譯報錯。
HBRSAHandler.m 文件
// // HBRSAHandler.m // iOSRSAHandlerDemo // // Created by wangfeng on 15/10/19. // Copyright (c) 2015年 HustBroventure. All rights reserved. // #import "HBRSAHandler.h" #include#include #include #include 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; #define PADDING RSA_PADDING_TYPE_PKCS1 @implementation HBRSAHandler { RSA* _rsa_pub; RSA* _rsa_pri; } #pragma mark - public methord -(BOOL)importKeyWithType:(KeyType)type andPath:(NSString *)path { BOOL status = NO; const char* cPath = [path cStringUsingEncoding:NSUTF8StringEncoding]; FILE* file = fopen(cPath, "rb"); if (!file) { return status; } if (type == KeyTypePublic) { _rsa_pub = NULL; if((_rsa_pub = PEM_read_RSA_PUBKEY(file, NULL, NULL, NULL))){ status = YES; } }else if(type == KeyTypePrivate){ _rsa_pri = NULL; if ((_rsa_pri = PEM_read_RSAPrivateKey(file, NULL, NULL, NULL))) { status = YES; } } fclose(file); return status; } - (BOOL)importKeyWithType:(KeyType)type andkeyString:(NSString *)keyString { if (!keyString) { return NO; } BOOL status = NO; BIO *bio = NULL; RSA *rsa = NULL; bio = BIO_new(BIO_s_file()); NSString* temPath = NSTemporaryDirectory(); NSString* rsaFilePath = [temPath stringByAppendingPathComponent:@"RSAKEY"]; NSString* formatRSAKeyString = [self formatRSAKeyWithKeyString:keyString andKeytype:type]; BOOL writeSuccess = [formatRSAKeyString writeToFile:rsaFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; if (!writeSuccess) { return NO; } const char* cPath = [rsaFilePath cStringUsingEncoding:NSUTF8StringEncoding]; BIO_read_filename(bio, cPath); if (type == KeyTypePrivate) { rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, ""); _rsa_pri = rsa; if (rsa != NULL && 1 == RSA_check_key(rsa)) { status = YES; } else { status = NO; } } else{ rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL); _rsa_pub = rsa; if (rsa != NULL) { status = YES; } else { status = NO; } } BIO_free_all(bio); [[NSFileManager defaultManager] removeItemAtPath:rsaFilePath error:nil]; return status; } #pragma mark RSA sha1驗證簽名 //signString為base64字符串 - (BOOL)verifyString:(NSString *)string withSign:(NSString *)signString { if (!_rsa_pub) { NSLog(@"please import public key first"); return NO; } const char *message = [string cStringUsingEncoding:NSUTF8StringEncoding]; int messageLength = (int)[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; NSData *signatureData = [[NSData alloc]initWithBase64EncodedString:signString options:0]; unsigned char *sig = (unsigned char *)[signatureData bytes]; unsigned int sig_len = (int)[signatureData length]; unsigned char sha1[20]; SHA1((unsigned char *)message, messageLength, sha1); int verify_ok = RSA_verify(NID_sha1 , sha1, 20 , sig, sig_len , _rsa_pub); if (1 == verify_ok){ return YES; } return NO; } #pragma mark RSA MD5 驗證簽名 - (BOOL)verifyMD5String:(NSString *)string withSign:(NSString *)signString { if (!_rsa_pub) { NSLog(@"please import public key first"); return NO; } const char *message = [string cStringUsingEncoding:NSUTF8StringEncoding]; // int messageLength = (int)[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; NSData *signatureData = [[NSData alloc]initWithBase64EncodedString:signString options:0]; unsigned char *sig = (unsigned char *)[signatureData bytes]; unsigned int sig_len = (int)[signatureData length]; unsigned char digest[MD5_DIGEST_LENGTH]; MD5_CTX ctx; MD5_Init(&ctx); MD5_Update(&ctx, message, strlen(message)); MD5_Final(digest, &ctx); int verify_ok = RSA_verify(NID_md5 , digest, MD5_DIGEST_LENGTH , sig, sig_len , _rsa_pub); if (1 == verify_ok){ return YES; } return NO; } - (NSString *)signString:(NSString *)string { if (!_rsa_pri) { NSLog(@"please import private key first"); return nil; } const char *message = [string cStringUsingEncoding:NSUTF8StringEncoding]; int messageLength = (int)strlen(message); unsigned char *sig = (unsigned char *)malloc(256); unsigned int sig_len; unsigned char sha1[20]; SHA1((unsigned char *)message, messageLength, sha1); int rsa_sign_valid = RSA_sign(NID_sha1 , sha1, 20 , sig, &sig_len , _rsa_pri); if (rsa_sign_valid == 1) { NSData* data = [NSData dataWithBytes:sig length:sig_len]; NSString * base64String = [data base64EncodedStringWithOptions:0]; free(sig); return base64String; } free(sig); return nil; } - (NSString *)signMD5String:(NSString *)string { if (!_rsa_pri) { NSLog(@"please import private key first"); return nil; } const char *message = [string cStringUsingEncoding:NSUTF8StringEncoding]; //int messageLength = (int)strlen(message); unsigned char *sig = (unsigned char *)malloc(256); unsigned int sig_len; unsigned char digest[MD5_DIGEST_LENGTH]; MD5_CTX ctx; MD5_Init(&ctx); MD5_Update(&ctx, message, strlen(message)); MD5_Final(digest, &ctx); int rsa_sign_valid = RSA_sign(NID_md5 , digest, MD5_DIGEST_LENGTH , sig, &sig_len , _rsa_pri); if (rsa_sign_valid == 1) { NSData* data = [NSData dataWithBytes:sig length:sig_len]; NSString * base64String = [data base64EncodedStringWithOptions:0]; free(sig); return base64String; } free(sig); return nil; } - (NSString *) encryptWithPublicKey:(NSString*)content { if (!_rsa_pub) { NSLog(@"please import public key first"); return nil; } int status; int length = (int)[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 andRSA:_rsa_pub]; char *encData = (char*)malloc(flen); bzero(encData, flen); status = RSA_public_encrypt(length, (unsigned char*)input, (unsigned char*)encData, _rsa_pub, PADDING); if (status){ NSData *returnData = [NSData dataWithBytes:encData length:status]; free(encData); encData = NULL; //NSString *ret = [returnData base64EncodedString]; NSString *ret = [returnData base64EncodedStringWithOptions: NSDataBase64Encoding64CharacterLineLength]; return ret; } free(encData); encData = NULL; return nil; } - (NSString *) decryptWithPrivatecKey:(NSString*)content { if (!_rsa_pri) { NSLog(@"please import private key first"); return nil; } int status; //NSData *data = [content base64DecodedData]; NSData *data = [[NSData alloc]initWithBase64EncodedString:content options:NSDataBase64DecodingIgnoreUnknownCharacters]; int length = (int)[data length]; NSInteger flen = [self getBlockSizeWithRSA_PADDING_TYPE:PADDING andRSA:_rsa_pri]; char *decData = (char*)malloc(flen); bzero(decData, flen); status = RSA_private_decrypt(length, (unsigned char*)[data bytes], (unsigned char*)decData, _rsa_pri, PADDING); 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 andRSA:(RSA*)rsa { int len = RSA_size(rsa); if (padding_type == RSA_PADDING_TYPE_PKCS1 || padding_type == RSA_PADDING_TYPE_SSLV23) { len -= 11; } return len; } -(NSString*)formatRSAKeyWithKeyString:(NSString*)keyString andKeytype:(KeyType)type { NSInteger lineNum = -1; NSMutableString *result = [NSMutableString string]; if (type == KeyTypePrivate) { [result appendString:@"-----BEGIN PRIVATE KEY-----\n"]; lineNum = 79; }else if(type == KeyTypePublic){ [result appendString:@"-----BEGIN PUBLIC KEY-----\n"]; lineNum = 76; } int count = 0; for (int i = 0; i < [keyString length]; ++i) { unichar c = [keyString characterAtIndex:i]; if (c == '\n' || c == '\r') { continue; } [result appendFormat:@"%c", c]; if (++count == lineNum) { [result appendString:@"\n"]; count = 0; } } if (type == KeyTypePrivate) { [result appendString:@"\n-----END PRIVATE KEY-----"]; }else if(type == KeyTypePublic){ [result appendString:@"\n-----END PUBLIC KEY-----"]; } return result; } @end
導入#import "HBRSAHandler.h"
@implementation ViewController { HBRSAHandler* _handler; } NSString* private_key_string = @"MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOn0Mx9WBXbQYr55JsLKHdai1kO/iyA89YqUY3K0PK/YcCqsDNJ8y1VZQ4MBA4er6yr1LR3kSe6z6uux4oP2N4FHuV/BKM/MEkb0oyEKnuOXspOumOZ3Hn/CzpYSZSIAr5BgfADEUU9yfr+nTNIxW5sXh4bZmy3lRsSAKqeinmA9AgMBAAECgYEAxB/va2mVkxEGdl7h25HMic5giNLeMtxnixDyfYoTBecPwPYSmbH8U0RNkFkdOHMq5gw7Ej/6qp0xZvzsw2t5AtFmuAXjt1LS64ofsnbjxgKVYdMsLIn0jFSRt/riyvZLNEpNEwpbGb2Y1M9gCPHmBPU2CMgbKWvkiYquNCIVmoECQQD1wqXLRHY475AL/2AwAIUxGYeVdccL4qsDbsoUZNfaVC5iCvfgzArIg+xX4+XtKnuyuFFrRQWCVbgrsKGSn+6ZAkEA87OfAaKuRmPwMtyd4EY5GBhiOWQinWKIV9PkwozL+wyylHAdfKnMnCzglHFm5hdB+MkHs2R70R+U9DW82Vs5RQJAf+obH0x3+DSAli4Ko5FxwdeW4W0W+BG3jybYGXtPejz8k11AHYo2Rp2bozdkUmgdUC1te1bGgksZe+wIfOevaQJAU838KyrPdYNekY8Od5aOgbu443WM9cRxkIpci46xgsauDp+zdDBMHZTNMh8BPLTYyf4PuOAgOBz9MzHbnH9jZQJBAJKvVlrN3tehLIjBjzK1gfgqzIXDMZM/XkBVz8SIbz5SbeouGKCvGcSjLqD+CCFSdr8fP1EjQ0SiEwfpCpUHBcs="; NSString* public_key_string = @"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDp9DMfVgV20GK+eSbCyh3WotZDv4sgPPWKlGNytDyv2HAqrAzSfMtVWUODAQOHq+sq9S0d5Enus+rrseKD9jeBR7lfwSjPzBJG9KMhCp7jl7KTrpjmdx5/ws6WEmUiAK+QYHwAxFFPcn6/p0zSMVubF4eG2Zst5UbEgCqnop5gPQIDAQAB";
//RSA加密/簽名 -(void)RSAEncryptionAndDigest{ HBRSAHandler* handler = [HBRSAHandler new]; [handler importKeyWithType:KeyTypePrivate andkeyString:private_key_string]; [handler importKeyWithType:KeyTypePublic andkeyString:public_key_string]; _handler = handler; // 加密 NSString*str=@"RSAllyouss"; NSData *nsdata = [str dataUsingEncoding:NSUTF8StringEncoding]; // Get NSString from NSData object in Base64 NSString *base64Encoded = [nsdata base64EncodedStringWithOptions:0]; NSString* enString = [handler encryptWithPublicKey:base64Encoded]; NSLog(@"RSA加密:%@", enString); // 解密 NSString* deString = [handler decryptWithPrivatecKey:enString]; NSData *nsdataFromBase64String = [[NSData alloc] initWithBase64EncodedString:deString options:0]; NSLog(@"RSA解密:%@", deString); // Decoded NSString from the NSData NSString *base64Decoded = [[NSString alloc] initWithData:nsdataFromBase64String encoding:NSUTF8StringEncoding]; NSLog(@"%@",base64Decoded); // MD5簽名 NSString* sigMd5 = [handler signMD5String:enString]; NSLog(@"%@ ",sigMd5); // MD5驗簽 BOOL isMatchMd5 = [handler verifyMD5String:enString withSign:sigMd5]; NSLog(@"%d ",isMatchMd5); }