程序员人生 网站导航

【iOS】MD5(加密)/AES/Base64加密和解密

栏目:综合技术时间:2016-07-05 14:57:56

MD5

  • 甚么是MD5

Message Digest Algorithm MD5(中文名为消息摘要算法第5版)为计算机安全领域广泛使用的1种散列函数,用以提供消息的完全性保护。MD5的典型利用是对1段信息(Message)产生信息摘要(Message-Digest),以避免被篡改。

  • MD5的特点

1、紧缩性:任意长度的数据,算出的MD5值长度都是固定的。
2、容易计算:从原数据计算出MD5值很容易。
3、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区分。
4、强抗碰撞:已知原数据和其MD5值,想找到1个具有相同MD5值的数据(即捏造数据)是非常困难的。
MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被”紧缩”成1种保密的格式(就是把1个任意长度的字节串变换成1定长的106进制数字串)。
比如之前在下载windows系统的时候,很多网站都会公布1个MD值,这个是这个软件对应的MD5值,当系统被修改了,哪怕是1个字节,以后生成的MD5值都会有比较大的差异。
详细的介绍,可以1步百度百科–MD5
MD5的实现
首先需要包括头文件:

#import <CommonCrypto/CommonDigest.h>
/** * MD5加密 * * @param string 需要加密的字符串 * * @return 返回加密后的结果 */ + (NSString *)md5:(NSString *)string{ // OC 字符串转换位C字符串 const char *cStr = [string UTF8String]; // 16位加密 unsigned char digest[CC_MD5_DIGEST_LENGTH]; // 1: 需要加密的C字符串 // 2: 加密的字符串的长度 // 3: 加密长度 CC_MD5(cStr, (CC_LONG)strlen(cStr), digest); NSMutableString *result = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; // 32位 for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) { [result appendFormat:@"%02X", digest[i]]; } // 返回1个32位长度的加密后的字符串 return result; }

关于MD5的加密和解密也能够在这个网站上测试:http://www.cmd5.com/

AES

  • 甚么是AES
    高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法。AES是1个对称分组密码算法,旨在取代DES成为广泛使用的标准。根据使用的密码长度,AES最多见的有3种方案,用以适应不同的场景要求,分别是AES⑴28、AES⑴92和AES⑵56。— 《iOS安全之路--AES》
    AES加密数据块分组长度必须为128比特,密钥长度可以是128比特、192比特、256比特中的任意1个(如果数据块及密钥长度不足时,会补齐)。AES加密有很多轮的重复和变换。大致步骤以下:1、密钥扩大(KeyExpansion),2、初始轮(Initial Round),3、重复轮(Rounds),每轮又包括:SubBytes、ShiftRows、MixColumns、AddRoundKey,4、终究轮(Final Round),终究轮没有MixColumns。

  • AES加密的实现

AES 加密的实现我们需要新建1个NSData的Category类,
然后包括两个头文件:

#import <CommonCrypto/CommonDigest.h> #import <CommonCrypto/CommonCryptor.h>

AES 加密时,我们需要自己定义1个16位的字符串,作为key。

// 自定义1个KEY #define AES_KEY @"0123456789ABCDEF"
/** * 对data加密 * * @param data 需要加密的数据 * * @return 加密后的数据 */ +(NSData *)aes256EncryptWithData:(NSData *)data{ if (!AES_KEY || AES_KEY.length !=16) { NSLog(@"key length must be 16"); return nil; } char keyPtr[kCCKeySizeAES256+1]; bzero(keyPtr, sizeof(keyPtr)); [AES_KEY getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; NSUInteger dataLength = data.length; size_t bufferSize = dataLength + kCCBlockSizeAES128; void *buffer = malloc(bufferSize); size_t numBytesEncrypted = 0; CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding | kCCOptionECBMode, keyPtr, kCCBlockSizeAES128, NULL, data.bytes, dataLength, buffer, bufferSize, &numBytesEncrypted); if (cryptStatus == kCCSuccess) { return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; } free(buffer); return nil; } /** * 对data解密 * * @param data 需要解密的数据 * * @return 解密后的数据 */ +(NSData *)aes256DecryptWithData:(NSData *)data{ if (!AES_KEY || AES_KEY.length !=16) { NSLog(@"key length must be 16"); return nil; } char keyPtr[kCCKeySizeAES256+1]; bzero(keyPtr, sizeof(keyPtr)); [AES_KEY getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; NSUInteger dataLength = data.length; size_t bufferSize = dataLength + kCCBlockSizeAES128; void *buffer = malloc(bufferSize); size_t numBytesDecrypted = 0; CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding | kCCOptionECBMode, keyPtr, kCCBlockSizeAES128, NULL, data.bytes, dataLength, buffer, bufferSize, &numBytesDecrypted); if (cryptStatus == kCCSuccess) { return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted]; } free(buffer); return nil; } /** * 对字符串加密 * * @param string 需要加密的字符串 * * @return 加密后的数据 */ +(NSData*)aes256EncryptWithString:(NSString*)string{ NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; NSData *encryptedData = [self aes256EncryptWithData:data]; return encryptedData; } /** * 解密 * * @param data 需要解密的数据 * * @return 解密后的字符串 */ +(NSString*)aes256DecryptStringWithData:(NSData *)data{ NSData *decryData = [self aes256DecryptWithData:data]; NSString *string = [[NSString alloc] initWithData:decryData encoding:NSUTF8StringEncoding]; return string; }

两种加密和解密,1种是字符串的1种是数据流的。

Base64

  • 甚么是base64

Base64是网络上最多见的用于传输8Bit字节代码的编码方式之1,大家可以查看RFC2045~RFC2049,上面有MIME的详细规范。Base64编码可用于在HTTP环境下传递较长的标识信息。例如,在Java Persistence系统Hibernate中,就采取了Base64来将1个较长的唯1标识符(1般为128-bit的UUID)编码为1个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他利用程序中,也常常需要把2进制数据编码为合适放在URL(包括隐藏表单域)中的情势。此时,采取Base64编码具有不可读性,即所编码的数据不会被人用肉眼所直接看到。

  • base64原理

转码进程例子:
3*8=4*6
内存1个字符占8位
转前: s 1 3
先转成ascii:对应 115 49 51
2进制: 01110011 00110001 00110011
6个1组(4组) 011100110011000100110011
然后才有后面的 011100 110011 000100 110011
然后计算机是8位8位的存数 6不够,自动就补两个高位0了
所有有了 高位补0
科学计算器输入 00011100 00110011 00000100 00110011
得到 28 51 4 51

  • base64的实现

base64和AES1样,需要1个NSData的Category类,但是不需要包括那两个头文件。

base64需要自己定义1个64位长度的编码表。

static const char base64EncodingTable[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

base64还需要1个解码表。

static const short base64DecodingTable[256] = { -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -2, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, -2, -2, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, ⑵, ⑵, ⑵, ⑵, ⑵, ⑵, -2, 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, ⑵, ⑵, ⑵, ⑵, ⑵, -2, 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, ⑵, ⑵, ⑵, ⑵, ⑵, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2 };
/** * 数据流加密 * * @param data 需要加密的数据流 * * @return 加密后的字符串 */ +(NSString *)base64EncodedWithData:(NSData *)data{ NSUInteger length = data.length; if (length == 0) return @""; NSUInteger out_length = ((length + 2) / 3) * 4; uint8_t *output = malloc(((out_length + 2) / 3) * 4); if (output == NULL) return nil; const char *input = data.bytes; NSInteger i, value; for (i = 0; i < length; i += 3) { value = 0; for (NSInteger j = i; j < i + 3; j++) { value <<= 8; if (j < length) { value |= (0xFF & input[j]); } } NSInteger index = (i / 3) * 4; output[index + 0] = base64EncodingTable[(value >> 18) & 0x3F]; output[index + 1] = base64EncodingTable[(value >> 12) & 0x3F]; output[index + 2] = ((i + 1) < length) ? base64EncodingTable[(value >> 6) & 0x3F] : '='; output[index + 3] = ((i + 2) < length) ? base64EncodingTable[(value >> 0) & 0x3F] : '='; } NSString *base64 = [[NSString alloc] initWithBytes:output length:out_length encoding:NSASCIIStringEncoding]; free(output); return base64; } /** * 字符串解密 * * @param base64EncodedString 需要解密的字符串 * * @return 解密后的数据流 */ +(NSData *)base64DecryptWithString:(NSString *)base64EncodedString{ NSInteger length = base64EncodedString.length; const char *string = [base64EncodedString cStringUsingEncoding:NSASCIIStringEncoding]; if (string == NULL) return nil; while (length > 0 && string[length - 1] == '=') length--; NSInteger outputLength = length * 3 / 4; NSMutableData *data = [NSMutableData dataWithLength:outputLength]; if (data == nil) return nil; if (length == 0) return data; uint8_t *output = data.mutableBytes; NSInteger inputPoint = 0; NSInteger outputPoint = 0; while (inputPoint < length) { char i0 = string[inputPoint++]; char i1 = string[inputPoint++]; char i2 = inputPoint < length ? string[inputPoint++] : 'A'; char i3 = inputPoint < length ? string[inputPoint++] : 'A'; output[outputPoint++] = (base64DecodingTable[i0] << 2) | (base64DecodingTable[i1] >> 4); if (outputPoint < outputLength) { output[outputPoint++] = ((base64DecodingTable[i1] & 0xf) << 4) | (base64DecodingTable[i2] >> 2); } if (outputPoint < outputLength) { output[outputPoint++] = ((base64DecodingTable[i2] & 0x3) << 6) | base64DecodingTable[i3]; } } return data; } /** * 字符串做加密 * * @param str 需要加密的字符串 * * @return 加密后的字符串 */ +(NSString *)base64EncodedWithString:(NSString *)str{ NSData* data = [str dataUsingEncoding:NSUTF8StringEncoding]; return [self base64EncodedWithData:data]; } /** * 对字符串解密 * * @param base64EncodedString 需要解密的字符串 * * @return 解密后的字符串 */ + (NSString *)base64DecryptString:(NSString *)base64EncodedString{ NSData *data = [self base64DecryptWithString:base64EncodedString]; return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; }

加密和解密也是对应有字符串和NSData两种方法。

总结

从代码上看,这3种加密方式还是有点难度的,但是网上1堆代码,我们需要知道怎样使用。在实际项目中的使用,我使用的两点就是,和后台交互的时候,对接口中的参数加密就是接口地址“?”后面的数据,还有1点就是对服务器返回的json数据的加密。1般是前台对接口参数加密后台解密,后台对接口返回参数加密,前台对返回的数据解密。
代码下载地址:加密+解密。

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐