Message Digest Algorithm MD5(中文名為消息摘要算法第5版)為計(jì)算機(jī)安全領(lǐng)域廣泛使用的1種散列函數(shù),用以提供消息的完全性保護(hù)。MD5的典型利用是對1段信息(Message)產(chǎn)生信息摘要(Message-Digest),以避免被篡改。
1、緊縮性:任意長度的數(shù)據(jù),算出的MD5值長度都是固定的。
2、容易計(jì)算:從原數(shù)據(jù)計(jì)算出MD5值很容易。
3、抗修改性:對原數(shù)據(jù)進(jìn)行任何改動(dòng),哪怕只修改1個(gè)字節(jié),所得到的MD5值都有很大區(qū)分。
4、強(qiáng)抗碰撞:已知原數(shù)據(jù)和其MD5值,想找到1個(gè)具有相同MD5值的數(shù)據(jù)(即捏造數(shù)據(jù))是非常困難的。
MD5的作用是讓大容量信息在用數(shù)字簽名軟件簽署私人密鑰前被”緊縮”成1種保密的格式(就是把1個(gè)任意長度的字節(jié)串變換成1定長的106進(jìn)制數(shù)字串)。
比如之前在下載windows系統(tǒng)的時(shí)候,很多網(wǎng)站都會(huì)公布1個(gè)MD值,這個(gè)是這個(gè)軟件對應(yīng)的MD5值,當(dāng)系統(tǒng)被修改了,哪怕是1個(gè)字節(jié),以后生成的MD5值都會(huì)有比較大的差異。
詳細(xì)的介紹,可以1步百度百科–MD5
MD5的實(shí)現(xiàn)
首先需要包括頭文件:
#import <CommonCrypto/CommonDigest.h>
/**
* MD5加密
*
* @param string 需要加密的字符串
*
* @return 返回加密后的結(jié)果
*/
+ (NSString *)md5:(NSString *)string{
// OC 字符串轉(zhuǎn)換位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個(gè)32位長度的加密后的字符串
return result;
}
關(guān)于MD5的加密和解密也能夠在這個(gè)網(wǎng)站上測試:http://www.cmd5.com/
甚么是AES
高級(jí)加密標(biāo)準(zhǔn)(英語:Advanced Encryption Standard,縮寫:AES),在密碼學(xué)中又稱Rijndael加密法。AES是1個(gè)對稱分組密碼算法,旨在取代DES成為廣泛使用的標(biāo)準(zhǔn)。根據(jù)使用的密碼長度,AES最多見的有3種方案,用以適應(yīng)不同的場景要求,分別是AES⑴28、AES⑴92和AES⑵56。— 《iOS安全之路--AES》
AES加密數(shù)據(jù)塊分組長度必須為128比特,密鑰長度可以是128比特、192比特、256比特中的任意1個(gè)(如果數(shù)據(jù)塊及密鑰長度不足時(shí),會(huì)補(bǔ)齊)。AES加密有很多輪的重復(fù)和變換。大致步驟以下:1、密鑰擴(kuò)大(KeyExpansion),2、初始輪(Initial Round),3、重復(fù)輪(Rounds),每輪又包括:SubBytes、ShiftRows、MixColumns、AddRoundKey,4、終究輪(Final Round),終究輪沒有MixColumns。
AES加密的實(shí)現(xiàn)
AES 加密的實(shí)現(xiàn)我們需要新建1個(gè)NSData的Category類,
然后包括兩個(gè)頭文件:
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>
AES 加密時(shí),我們需要自己定義1個(gè)16位的字符串,作為key。
// 自定義1個(gè)KEY
#define AES_KEY @"0123456789ABCDEF"
/**
* 對data加密
*
* @param data 需要加密的數(shù)據(jù)
*
* @return 加密后的數(shù)據(jù)
*/
+(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 需要解密的數(shù)據(jù)
*
* @return 解密后的數(shù)據(jù)
*/
+(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 加密后的數(shù)據(jù)
*/
+(NSData*)aes256EncryptWithString:(NSString*)string{
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
NSData *encryptedData = [self aes256EncryptWithData:data];
return encryptedData;
}
/**
* 解密
*
* @param data 需要解密的數(shù)據(jù)
*
* @return 解密后的字符串
*/
+(NSString*)aes256DecryptStringWithData:(NSData *)data{
NSData *decryData = [self aes256DecryptWithData:data];
NSString *string = [[NSString alloc] initWithData:decryData encoding:NSUTF8StringEncoding];
return string;
}
兩種加密和解密,1種是字符串的1種是數(shù)據(jù)流的。
Base64是網(wǎng)絡(luò)上最多見的用于傳輸8Bit字節(jié)代碼的編碼方式之1,大家可以查看RFC2045~RFC2049,上面有MIME的詳細(xì)規(guī)范。Base64編碼可用于在HTTP環(huán)境下傳遞較長的標(biāo)識(shí)信息。例如,在Java Persistence系統(tǒng)Hibernate中,就采取了Base64來將1個(gè)較長的唯1標(biāo)識(shí)符(1般為128-bit的UUID)編碼為1個(gè)字符串,用作HTTP表單和HTTP GET URL中的參數(shù)。在其他利用程序中,也常常需要把2進(jìn)制數(shù)據(jù)編碼為合適放在URL(包括隱藏表單域)中的情勢。此時(shí),采取Base64編碼具有不可讀性,即所編碼的數(shù)據(jù)不會(huì)被人用肉眼所直接看到。
轉(zhuǎn)碼進(jìn)程例子:
3*8=4*6
內(nèi)存1個(gè)字符占8位
轉(zhuǎn)前: s 1 3
先轉(zhuǎn)成ascii:對應(yīng) 115 49 51
2進(jìn)制: 01110011 00110001 00110011
6個(gè)1組(4組) 011100110011000100110011
然后才有后面的 011100 110011 000100 110011
然后計(jì)算機(jī)是8位8位的存數(shù) 6不夠,自動(dòng)就補(bǔ)兩個(gè)高位0了
所有有了 高位補(bǔ)0
科學(xué)計(jì)算器輸入 00011100 00110011 00000100 00110011
得到 28 51 4 51
base64和AES1樣,需要1個(gè)NSData的Category類,但是不需要包括那兩個(gè)頭文件。
base64需要自己定義1個(gè)64位長度的編碼表。
static const char base64EncodingTable[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
base64還需要1個(gè)解碼表。
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
};
/**
* 數(shù)據(jù)流加密
*
* @param data 需要加密的數(shù)據(jù)流
*
* @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 解密后的數(shù)據(jù)流
*/
+(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];
}
加密和解密也是對應(yīng)有字符串和NSData兩種方法。
從代碼上看,這3種加密方式還是有點(diǎn)難度的,但是網(wǎng)上1堆代碼,我們需要知道怎樣使用。在實(shí)際項(xiàng)目中的使用,我使用的兩點(diǎn)就是,和后臺(tái)交互的時(shí)候,對接口中的參數(shù)加密就是接口地址“?”后面的數(shù)據(jù),還有1點(diǎn)就是對服務(wù)器返回的json數(shù)據(jù)的加密。1般是前臺(tái)對接口參數(shù)加密后臺(tái)解密,后臺(tái)對接口返回參數(shù)加密,前臺(tái)對返回的數(shù)據(jù)解密。
代碼下載地址:加密+解密。
上一篇 近似算法---首次適宜法