iOS-AES對稱加密
實驗要求
- 程式語言不限制
- 明文“學號+姓名+專業+學院”
- 實現對明文的加密,輸出密文
- 對密文實現解密,輸出明文
- 不能是DES加密演算法
- 報告中說明該語言提供的加密函式都有哪些,具體的使用方法並分析優缺點
程式碼
#import "ViewController.h" #import "AES.h" #import "NSString+AES.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //原文資訊 NSString *plainText = @"3180807001+黃振鋒+電腦科學與技術+網路空間安全學院"; //祕鑰 NSString *key = @"HuangZhenFeng"; NSLog(@"純加密:%@",[plainText AES256_Encrypt:key]); NSLog(@"純解密:%@",[[plainText AES256_Encrypt:key] AES256_Decrypt:key]); //原文轉碼資料NSData NSData *plainData = [plainText dataUsingEncoding:NSUTF8StringEncoding]; //用祕鑰加密 NSData *cipher = [plainData AES256EncryptWithKey:key]; //得到密文 NSLog(@"密文:%@",[cipher base64EncodedStringWithOptions:0]); //用祕鑰解密 NSData *cipher1 = [cipher AES256DecryptWithKey:key]; //得到明文 NSString *plainText1 = [[NSString alloc] initWithData:cipher1 encoding:NSUTF8StringEncoding]; NSLog(@"明文:%@",plainText1); } #import "AES.h" #import <Foundation/Foundation.h> #import <CommonCrypto/CommonCryptor.h> static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @implementation NSData (AES) - (NSData *)AES256EncryptWithKey:(NSString *)key { // 'key' should be 32 bytes for AES256, will be null-padded otherwise char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused) bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding) // fetch key data [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; NSUInteger dataLength = [self length]; //See the doc: For block ciphers, the output size will always be less than or //equal to the input size plus the size of one block. //That's why we need to add the size of one block here size_t bufferSize = dataLength + kCCBlockSizeAES128; void *buffer = malloc(bufferSize); size_t numBytesEncrypted = 0; CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, keyPtr, kCCKeySizeAES256, NULL /* initialization vector (optional) */, [self bytes], dataLength, /* input */ buffer, bufferSize, /* output */ &numBytesEncrypted); if (cryptStatus == kCCSuccess) { //the returned NSData takes ownership of the buffer and will free it on deallocation return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; } free(buffer); //free the buffer; return nil; } - (NSData *)AES256DecryptWithKey:(NSString *)key { // 'key' should be 32 bytes for AES256, will be null-padded otherwise char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused) bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding) // fetch key data [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; NSUInteger dataLength = [self length]; //See the doc: For block ciphers, the output size will always be less than or //equal to the input size plus the size of one block. //That's why we need to add the size of one block here size_t bufferSize = dataLength + kCCBlockSizeAES128; void *buffer = malloc(bufferSize); size_t numBytesDecrypted = 0; CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, keyPtr, kCCKeySizeAES256, NULL /* initialization vector (optional) */, [self bytes], dataLength, /* input */ buffer, bufferSize, /* output */ &numBytesDecrypted); if (cryptStatus == kCCSuccess) { //the returned NSData takes ownership of the buffer and will free it on deallocation return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted]; } free(buffer); //free the buffer; return nil; } - (NSString *)newStringInBase64FromData //追加64編碼 { NSMutableString *dest = [[NSMutableString alloc] initWithString:@""]; unsigned char * working = (unsigned char *)[self bytes]; int srcLen = [self length]; for (int i=0; i<srcLen; i += 3) { for (int nib=0; nib<4; nib++) { int byt = (nib == 0)?0:nib-1; int ix = (nib+1)*2; if (i+byt >= srcLen) break; unsigned char curr = ((working[i+byt] << (8-ix)) & 0x3F); if (i+nib < srcLen) curr |= ((working[i+nib] >> ix) & 0x3F); [dest appendFormat:@"%c", base64[curr]]; } } return dest; } + (NSString*)base64encode:(NSString*)str { if ([str length] == 0) return @""; const char *source = [str UTF8String]; int strlength = strlen(source); char *characters = malloc(((strlength + 2) / 3) * 4); if (characters == NULL) return nil; NSUInteger length = 0; NSUInteger i = 0; while (i < strlength) { char buffer[3] = {0,0,0}; short bufferLength = 0; while (bufferLength < 3 && i < strlength) buffer[bufferLength++] = source[i++]; characters[length++] = base64[(buffer[0] & 0xFC) >> 2]; characters[length++] = base64[((buffer[0] & 0x03) << 4) | ((buffer[1] & 0xF0) >> 4)]; if (bufferLength > 1) characters[length++] = base64[((buffer[1] & 0x0F) << 2) | ((buffer[2] & 0xC0) >> 6)]; else characters[length++] = '='; if (bufferLength > 2) characters[length++] = base64[buffer[2] & 0x3F]; else characters[length++] = '='; } NSString *g = [[NSString alloc] initWithBytesNoCopy:characters length:length encoding:NSASCIIStringEncoding freeWhenDone:YES]; return g; } #import "NSData+AES.h" @implementation NSData (AES) //加密 - (NSData *) AES256_Encrypt:(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 *) AES256_Decrypt:(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 "NSString+AES.h" @implementation NSString (AES) //加密 - (NSString *) AES256_Encrypt:(NSString *)key{ const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding]; NSData *data = [NSData dataWithBytes:cstr length:self.length]; //對資料進行加密 NSData *result = [data AES256_Encrypt:key]; //轉換為2進位制字串 if (result && result.length > 0) { Byte *datas = (Byte*)[result bytes]; NSMutableString *output = [NSMutableString stringWithCapacity:result.length * 2]; for(int i = 0; i < result.length; i++){ [output appendFormat:@"%02x", datas[i]]; } return output; } return nil; } //解密 - (NSString *) AES256_Decrypt:(NSString *)key{ //轉換為2進位制Data NSMutableData *data = [NSMutableData dataWithCapacity:self.length / 2]; unsigned char whole_byte; char byte_chars[3] = {'\0','\0','\0'}; int i; for (i=0; i < [self length] / 2; i++) { byte_chars[0] = [self characterAtIndex:i*2]; byte_chars[1] = [self characterAtIndex:i*2+1]; whole_byte = strtol(byte_chars, NULL, 16); [data appendBytes:&whole_byte length:1]; } //對資料進行解密 NSData* result = [data AES256_Decrypt:key]; if (result && result.length > 0) { return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding]; } return nil;}
總結
常見的對稱加密演算法有DES、3DES、AES。
本次實驗使用對稱加密演算法是AES,AES是高階加密,也是目前使用最多的對稱加密演算法,目前美國國家安全域性使用AES加密,蘋果的鑰匙串訪問就是使用AES加密。對稱加密的優點是演算法公開,計算量小,加密速度快,加密效率高。對稱加密的缺點是雙方使用相同的鑰匙,安全性得不到保證。使用對稱加密需要注意的是祕鑰的保密工作需要非常重視,並且祕鑰要求定期更換。
實驗中,我先使用純AES演算法加解密,然後我再使用AES+Base64演算法加解密。我使用的是Objective-C語言進行程式設計,我先使用AES演算法純加密的時候,我發現加密方法目前不支援中文加解密,所以解密出來的東西為空,但是是數字或者英文的時候,可以加解密。後來我使用AES+Base64演算法的時候,可以對中文進行正常的加解密。AES+Base64實際上是在純AES演算法上再對加密內容進行Base64加密,得到一串不含空格的英文、數字、符號的組合字串。其中,純AES演算法加解密函式分別是:- (NSData *) AES256_Encrypt:(NSString *)key;,- (NSData *) AES256_Decrypt:(NSString *)key;。AES+Base64演算法加解密函式為:- (NSData *)AES256EncryptWithKey:(NSString *)key; - (NSData *)AES256DecryptWithKey:(NSString *)key; - (NSString *)newStringInBase64FromData;。 其中key是自定義的祕鑰,我的祕鑰設定為“HuangZhenFeng”,明文不需要用引數傳遞進入,因為Objective-C支援在函式裡面使用“self”來提取誰呼叫這個函式,所以就能取到原文資訊。