Message Digest Algorithm MD5(中文名为消息摘要算法第5版)为计算机安全领域广泛使用的1种散列函数,用以提供消息的完全性保护。MD5的典型利用是对1段信息(Message)产生信息摘要(Message-Digest),以避免被篡改。
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
高级加密标准(英语: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是网络上最多见的用于传输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编码具有不可读性,即所编码的数据不会被人用肉眼所直接看到。
转码进程例子:
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和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般是前台对接口参数加密后台解密,后台对接口返回参数加密,前台对返回的数据解密。
代码下载地址:加密+解密。
上一篇 近似算法---首次适宜法