由于公司對(duì)于信息安全比較注重,需要對(duì)json數(shù)據(jù)并用AES加密,然后生成url_safe base64編碼。然后繼續(xù)拼接時(shí)間戳 session還有其他字段進(jìn)行MD5加密。然后使用RAC簽名后傳輸。本來沒覺得什么,以為加密算法之前也接觸過,或者去網(wǎng)上直接套用就好柬祠,結(jié)果廓块,發(fā)現(xiàn)沒那么簡單 = =
一: Base64
- 是網(wǎng)絡(luò)上使用最廣泛的編碼系統(tǒng),能夠?qū)⑷魏味M(jìn)制數(shù)據(jù),轉(zhuǎn)換成只有 65 個(gè)字符 * 組成的文本文件.
- 編碼后的數(shù)據(jù)由 a-z A-Z 0-9 + / = 表示.
- base64 編碼后的結(jié)果能夠反算,不夠安全.
- base64 是所有現(xiàn)代加密算法的基礎(chǔ)算法.
base64可以用來將binary的字節(jié)序列數(shù)據(jù)編碼成ASCII字符序列構(gòu)成的文本,使用時(shí)亏钩,在傳輸編碼方式中指定base64。使用的字符包括大小寫字母各26個(gè)欺旧,加上10個(gè)數(shù)字姑丑,和加號(hào)“+”,斜杠“/”辞友,一共64個(gè)字符栅哀,等號(hào)“=”用來作為后綴用途。
完整的base64定義可見RFC 1421和RFC 2045称龙。編碼后的數(shù)據(jù)比原始數(shù)據(jù)略長留拾,為原來的4/3.。在電子郵件中鲫尊,根據(jù)RFC 822規(guī)定痴柔,每76個(gè)字符,還需要加上一個(gè)回車換行疫向】任担可以估算編碼后數(shù)據(jù)長度大約為原長的135.1%。( 如果源碼為760個(gè)字符, 則編碼后的長度為760 * (4 / 3) + 10(換行符) )
URL_Safe Base64
這個(gè)參數(shù)意思是加密時(shí)不使用對(duì)URL和文件名有特殊意義的字符來作為加密字符,因?yàn)闃?biāo)準(zhǔn)base64包含"+"和"/",因此不適合直接放在URL中傳輸.因?yàn)閁RL編譯器會(huì)將"+","/"轉(zhuǎn)換成XX%的樣式.而這些"%"在錄入數(shù)據(jù)庫的時(shí)候還會(huì)進(jìn)行轉(zhuǎn)碼,為了解決此問題可采用一種適用于URL的改進(jìn)base64,它不在末位添加"=",將"+"轉(zhuǎn)換成"-",將"/"轉(zhuǎn)換成"_".
iOS原生API的有它自己的局限性, 所以我使用了base64的神器(GTMBase, 這個(gè)框架滿足了每一種的base64模式的編解碼.)
因此為了兩個(gè)平臺(tái)的兼容,使用總結(jié)如下
GTMBase64 Padded YES != Java DEFAULT
GTMBase64 Padded NO == Java NO_PADDING | NO_WRAP
GTMBase64 Padded YES == Java NO_WRAP
GTMBase64 websafe Padded NO == java NO_PADDING | NO_WRAP | URL_SAFE
GTMBase64 websafe Padded YES == java NO_WRAP | URL_SAFE
二:AES加解密
- 相較于DES和3DES算法而言搔驼,AES算法有著更高的速度和資源使用效率谈火,安全級(jí)別也較之更高了,被稱為下一代加密標(biāo)準(zhǔn)舌涨。
- AES使用的是對(duì)稱加密.所謂對(duì)稱加密就是加解密雙方使用的密鑰相同.因此通過一種保密的方法讓客戶端與服務(wù)器擁有該密鑰,即可成功使用加解密.
常見的IOS中AES加密
//加密
+(NSData *) AES128EncryptWithKey:(NSData*)key data:(NSData*)data
{
return [self doCipher:data iv:nil key:key context:kCCEncrypt error:nil];
}
//解密
+(NSData *) AES128DecryptWithKey:(NSData*)key data:(NSData*)data
{
return [self doCipher:data iv:nil key:key context:kCCDecrypt error:nil];
}
+ (NSData *)doCipher:(NSData *)dataIn
iv:(NSData *)iv
key:(NSData *)symmetricKey
context:(CCOperation)encryptOrDecrypt
error:(NSError **)error
{
CCCryptorStatus ccStatus = kCCSuccess;
size_t cryptBytes = 0;
NSMutableData *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];
ccStatus = CCCrypt( encryptOrDecrypt,
kCCAlgorithmAES,
kCCOptionECBMode | kCCOptionPKCS7Padding,
symmetricKey.bytes,
symmetricKey.length,
iv.bytes,
dataIn.bytes,
dataIn.length,
dataOut.mutableBytes,
dataOut.length,
&cryptBytes);
if (ccStatus == kCCSuccess) {
dataOut.length = cryptBytes;
}
else {
if (error) {
*error = [NSError errorWithDomain:@"kEncryptionError"
code:ccStatus
userInfo:nil];
}
dataOut = nil;
}
return dataOut;
}
坑爹的地方地方來了,傳給后臺(tái)永遠(yuǎn)是亂碼.用了網(wǎng)上大多數(shù)方法都不行...一開始懷疑是不是URL_Safe Base64錯(cuò)了,或者是哪個(gè)地方?jīng)]有UTF-8糯耍。與后臺(tái)的溝通,反復(fù)驗(yàn)證數(shù)據(jù)加密后的字符串,就是對(duì)不上~~~
- 網(wǎng)上拼命查資料發(fā)現(xiàn)好像是iv不對(duì),iv是什么??......
- 大概意思說,此屬性可選囊嘉,但只能用于CBC模式温技。如果出現(xiàn)那么他的長度必須和算法的block size保持一致。 如果是因?yàn)槟J(rèn)選擇的CBC模式而且向量沒有定義扭粱,那么向量會(huì)被定義為NULL荒揣。如果選擇了ECB模式或是其他的流密碼算法,之前所說的邏輯都不成立焊刹。
CBC??ECB一臉懵逼,繼續(xù)查資料
- 初始化向量與密鑰相比有不同的安全性需求系任,因此IV通常無須保密,然而在大多數(shù)情況中虐块,不應(yīng)當(dāng)在使用同一密鑰的情況下兩次使用同一個(gè)IV俩滥。對(duì)于CBC和CFB,重用IV會(huì)導(dǎo)致泄露明文首個(gè)塊的某些信息贺奠,亦包括兩個(gè)不同消息中相同的前綴霜旧。對(duì)于OFB和CTR而言,重用IV會(huì)導(dǎo)致完全失去安全性儡率。另外挂据,在CBC模式中以清,IV在加密時(shí)必須是無法預(yù)測(cè)的;特別的崎逃,在許多實(shí)現(xiàn)中使用的產(chǎn)生IV的方法掷倔,例如SSL2.0使用的,即采用上一個(gè)消息的最后一塊密文作為下一個(gè)消息的IV个绍,是不安全的勒葱。
ECB模式不需要初始化向量,CBC需要巴柿。
完善之后AES的代碼
//AES加密
+ (NSData *)AES128EncryptWithKey:(NSString *)key iv:(NSString *)iv withNSData:(NSData *)data
{
char keyPtr[kCCKeySizeAES128+1];
bzero(keyPtr, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
char ivPtr[kCCKeySizeAES128+1];
bzero(ivPtr, sizeof(ivPtr));
[iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [data length];
int diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128);
int newSize = 0;
if(diff > 0)
{
newSize = (int)(dataLength + diff);
}
char dataPtr[newSize];
memcpy(dataPtr, [data bytes], [data length]);
for(int i = 0; i < diff; i++)
{
dataPtr[i + dataLength] = 0x00;
}
size_t bufferSize = newSize + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
0x00, //No padding
keyPtr,
kCCKeySizeAES128,
ivPtr,
dataPtr,
sizeof(dataPtr),
buffer,
bufferSize,
&numBytesEncrypted);
if(cryptStatus == kCCSuccess)
{
// NSData *data =[NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
// NSString *str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
return nil;
}
//AES解密
+ (NSData *)AES128DecryptWithKey:(NSString *)key iv:(NSString *)iv withNSData:(NSData *)data
{
char keyPtr[kCCKeySizeAES128+1];
bzero(keyPtr, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
char ivPtr[kCCKeySizeAES128+1];
bzero(ivPtr, sizeof(ivPtr));
[iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [data length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmAES128,
0x00, //No padding
keyPtr,
kCCKeySizeAES128,
ivPtr,
[data bytes],
dataLength,
buffer,
bufferSize,
&numBytesEncrypted);
if(cryptStatus == kCCSuccess)
{
// NSData *data =[NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
// NSString *str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
return nil;
}
寫個(gè)工具類復(fù)制過去就可以了
三:MD5
- 對(duì)任意的數(shù)據(jù)進(jìn)行計(jì)算,生成固定長度的字符串.32個(gè)字符.
- 一般用來加密密碼.
- 有時(shí)候也用來驗(yàn)證文件下載時(shí),是否被篡改過.
文件下載完成之后計(jì)算文件的md5值,與服務(wù)器計(jì)算的MD5值比較,如果不一樣那么這個(gè)文件在下載的過程中被篡改了.
MD5終端命令
# 得到文件的MD5值
$ md5 文件名
# 得到字符串的MD5值
md5 -s "string"
+(NSString *) md5: (NSString *) inPutText
{
const char *cStr = [inPutText UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(cStr, strlen(cStr), result);
return [[NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15]
] lowercaseString];
}
- 如果原始密碼過于簡單,直接進(jìn)行MD5加密是很容易被暴力破解的.
- 為了增強(qiáng)密碼的安全性,防止加密的密碼被暴力破解,可以向原始密碼中加鹽.
- 鹽 : 服務(wù)器端和客戶端約定的一個(gè)字符串.
- MD5+鹽 : 原始密碼+鹽拼接出新的密碼字符串,再進(jìn)行MD加密.
- 以上為加一勺鹽,比單純的直接MD5加密安全性要高.
- 鹽要足夠的咸,越咸越安全.
RSA部分會(huì)在第二部分,如果有時(shí)間的話 笑~
參考文章:加密解密介紹