項(xiàng)目也快兩年了,項(xiàng)目這么長(zhǎng)時(shí)間下來(lái)經(jīng)歷了各種加解密算法,坑也踩過(guò)不少.現(xiàn)在把項(xiàng)目中使用過(guò)一些常用的加解密算法總結(jié)一下,有些也只是功能實(shí)現(xiàn)沒(méi)有深究里面的原理。
一丹泉、項(xiàng)目中主要使用到的的有
1.MD5
2.sha1
3.MD5大文件校驗(yàn)
4.AES
5.RSA
6.大文件加解密和中間遇到的一些坑
</br>
這是所有算法的github庫(kù) Demo地址 下載地址情萤,
</br>
二达传、基礎(chǔ)篇主要內(nèi)容<strong>md5,sha1,AES,RSA</strong>忙厌,下面會(huì)一個(gè)一個(gè)介紹。隨后會(huì)有一篇提升篇會(huì)講一下大文件的加解密<寫著寫著突然發(fā)現(xiàn)還是一篇寫一種方式好了...要不然會(huì)很長(zhǎng)很長(zhǎng)看起來(lái)也很亂
</br>
三隘蝎、MD5加密算法
1.先從度娘那找一點(diǎn)名詞性解釋睬塌,MD5即Message-Digest Algorithm 5(信息-摘要算法5)泉蝌,用于確保信息傳輸完整一致。是計(jì)算機(jī)廣泛使用的雜湊算法之一(又譯摘要算法揩晴、哈希算法)勋陪,主流編程語(yǔ)言普遍已有MD5實(shí)現(xiàn)。將數(shù)據(jù)(如漢字)運(yùn)算為另一固定長(zhǎng)度值硫兰,是雜湊算法的基礎(chǔ)原理诅愚,MD5的前身有MD2、MD3和MD4劫映。
MD5算法具有以下特點(diǎn):
1违孝、壓縮性:任意長(zhǎng)度的數(shù)據(jù),算出的MD5值長(zhǎng)度都是固定的泳赋。
2雌桑、容易計(jì)算:從原數(shù)據(jù)計(jì)算出MD5值很容易。
3祖今、抗修改性:對(duì)原數(shù)據(jù)進(jìn)行任何改動(dòng)校坑,哪怕只修改1個(gè)字節(jié),所得到的MD5值都有很大區(qū)別千诬。
4耍目、強(qiáng)抗碰撞:已知原數(shù)據(jù)和其MD5值,想找到一個(gè)具有相同MD5值的數(shù)據(jù)(即偽造數(shù)據(jù))是非常困難的徐绑。
MD5的作用是讓大容量信息在用數(shù)字簽名軟件簽署私人密鑰前被"壓縮"成一種保密的格式(就是把一個(gè)任意長(zhǎng)度的字節(jié)串變換成一定長(zhǎng)的十六進(jìn)制數(shù)字串)邪驮。除了MD5以外,其中比較有名的還有sha-1傲茄、RIPEMD以及Haval等毅访。
2.因?yàn)閙d5加密算法只有加密算法沒(méi)有解密算法和易計(jì)算性,通常用作對(duì)用戶名和密碼加密之后再進(jìn)行用戶登陸驗(yàn)證的請(qǐng)求沮榜,避免用戶信息在傳輸途中被攔截解密。雖然看上去無(wú)懈可擊的樣子但是道高一尺魔高一丈,如果密碼設(shè)置過(guò)于簡(jiǎn)單對(duì)于一下解密網(wǎng)站通過(guò)群舉比對(duì)還是很容易直接破解出來(lái)的喻粹。那有什么好的方法可以預(yù)防這些潛在的風(fēng)險(xiǎn)呢敞映?
3.因?yàn)樗目剐薷男院蛷?qiáng)抗碰撞,MD5又通常用作文件傳輸?shù)耐暾则?yàn)證的用途。
4.上述兩種使用場(chǎng)景的具體實(shí)現(xiàn)方式磷斧,算法的實(shí)現(xiàn)其實(shí)沒(méi)有什么難度,可以寫一個(gè)NSString的分類
包含頭文件 <code></br>#import <CommonCrypto/CommonDigest.h></code>
<code>#import "NSString+MD5.h"</code>
<code>- (NSString *)md5String{
const char *cstring = self.UTF8String;
unsigned char bytes[CC_MD5_DIGEST_LENGTH];
CC_MD5(cstring, (CC_LONG)strlen(cstring), bytes);
// 拼接
NSMutableString *md5String = [NSMutableString string];
for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
[md5String appendFormat:@"%02x", bytes[i]];
}
return md5String;
}
</code>
5.2的遺留問(wèn)題,如何避免被別人暴力破解
- 不推薦的方法
1.多次md5加密,別人群舉保存在數(shù)據(jù)庫(kù)中的也是有多次md5后的值,而且每天都在群舉字符串更新到數(shù)據(jù)庫(kù)中 國(guó)內(nèi)的一個(gè)連接:http://pmd5.com,應(yīng)該也是調(diào)用國(guó)外服務(wù)器的接口吧破解的吧捷犹。
2.讓用戶設(shè)置復(fù)雜的密碼組合或者保證密碼長(zhǎng)度,一切和用戶過(guò)不去的設(shè)定都是反人類設(shè)計(jì)弛饭。用戶畢竟是上帝.但是簡(jiǎn)單長(zhǎng)度限制和字母數(shù)字的組合還是稍稍有點(diǎn)必要的。
</br> - 常用的方法
1.一般常用的方式是加Salt,就是在加密前自己生成一段長(zhǎng)度較長(zhǎng)的字符加載用戶填的密碼前后然后在Md5加密傳輸萍歉。這對(duì)于MD5群舉來(lái)說(shuō)沒(méi)增添一個(gè)字符群舉的難度都是成幾何倍數(shù)增長(zhǎng),更別說(shuō)你給他加個(gè)幾十個(gè)甚至上百個(gè)字符了侣颂。只要和服務(wù)端實(shí)現(xiàn)約定一個(gè)字符串兩邊同時(shí)做驗(yàn)證就可以了。
2.其實(shí)我就知道這一種...,歡迎補(bǔ)充!
四枪孩、MD5大文件加密
1.文件的MD5加密是最常用的文件完整性驗(yàn)證的算法.如果下載完成的文件的MD5值和原先的不一樣憔晒,要么下載的文件不完整 要么,中間被別人串改。15年xcode被別人下了木馬蔑舞,很多大的互聯(lián)網(wǎng)公司都接連中招拒担,就是在原先的xcode安裝文件植入了木馬之后再提供額外鏈接給別人下載。很多開發(fā)者也沒(méi)有去做MD5驗(yàn)證攻询。
2.因?yàn)槲覀冺?xiàng)目中進(jìn)場(chǎng)下載一些較大的文件从撼,少則30 50MB,多則3 400MB的钧栖,當(dāng)時(shí)服務(wù)端直接將文件加載到內(nèi)存然后整體MD5加密,然后把值給我讓我去做驗(yàn)證....我當(dāng)時(shí)的內(nèi)心是奔潰的...我們移動(dòng)端內(nèi)存小剛不住這么大的文件整體計(jì)算啊低零。最后和服務(wù)端討論了下然后分段加密,當(dāng)然這也是我網(wǎng)上Copy來(lái)小改了下的...-_-#
重要的是約定一個(gè)分段的長(zhǎng)度大小 我們定的是10MB一分段 就是參數(shù):readingDataLength后傳的值:10 * 1024 * 1024
<code>
+(NSString)fileMD5withFilePath:(NSString)path readingDataLength:(NSInteger)dataLength
{
return (__bridge_transfer NSString *)FileMD5HashCreateWithPath((__bridge CFStringRef)path, dataLength);
}
CFStringRef FileMD5HashCreateWithPath(CFStringRef filePath,size_t chunkSizeForReadingData) {
// Declare needed variables
CFStringRef result = NULL;
CFReadStreamRef readStream = NULL;
// Get the file URL
CFURLRef fileURL =
CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
(CFStringRef)filePath,
kCFURLPOSIXPathStyle,
(Boolean)false);
if (!fileURL) goto done;
// Create and open the read stream
readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault,
(CFURLRef)fileURL);
if (!readStream) goto done;
bool didSucceed = (bool)CFReadStreamOpen(readStream);
if (!didSucceed) goto done;
// Initialize the hash object
CC_MD5_CTX hashObject;
CC_MD5_Init(&hashObject);
// Make sure chunkSizeForReadingData is valid
if (!chunkSizeForReadingData) {
chunkSizeForReadingData = chunkSizeForReadingData;
}
// Feed the data to the hash object
bool hasMoreData = true;
while (hasMoreData) {
uint8_t buffer[chunkSizeForReadingData];
CFIndex readBytesCount = CFReadStreamRead(readStream,(UInt8 *)buffer,(CFIndex)sizeof(buffer));
if (readBytesCount == -1) break;
if (readBytesCount == 0) {
hasMoreData = false;
continue;
}
CC_MD5_Update(&hashObject,(const void *)buffer,(CC_LONG)readBytesCount);
}
// Check if the read operation succeeded
didSucceed = !hasMoreData;
// Compute the hash digest
unsigned char digest[CC_MD5_DIGEST_LENGTH];
CC_MD5_Final(digest, &hashObject);
// Abort if the read operation failed
if (!didSucceed) goto done;
// Compute the string result
char hash[2 * sizeof(digest) + 1];
for (size_t i = 0; i < sizeof(digest); ++i) {
snprintf(hash + (2 * i), 3, "%02x", (int)(digest[i]));
}
result = CFStringCreateWithCString(kCFAllocatorDefault,(const char *)hash,kCFStringEncodingUTF8);
done:
if (readStream) {
CFReadStreamClose(readStream);
CFRelease(readStream);
}
if (fileURL) {
CFRelease(fileURL);
}
return result;
}
</code>
五.Sha1算法
1.度娘說(shuō):安全哈希算法(Secure Hash Algorithm)主要適用于數(shù)字簽名標(biāo)準(zhǔn) (Digital Signature Standard DSS)里面定義的數(shù)字簽名算法(Digital Signature Algorithm DSA)。對(duì)于長(zhǎng)度小于2^64位的消息拯杠,SHA1會(huì)產(chǎn)生一個(gè)160位的消息摘要掏婶。當(dāng)接收到消息的時(shí)候,這個(gè)消息摘要可以用來(lái)驗(yàn)證數(shù)據(jù)的完整性潭陪。在傳輸?shù)倪^(guò)程中雄妥,數(shù)據(jù)很可能會(huì)發(fā)生變化,那么這時(shí)候就會(huì)產(chǎn)生不同的消息摘要畔咧。 SHA1有如下特性:不可以從消息摘要中復(fù)原信息茎芭;兩個(gè)不同的消息不會(huì)產(chǎn)生同樣的消息摘要,(但會(huì)有1x10 ^ 48分之一的機(jī)率出現(xiàn)相同的消息摘要,一般使用時(shí)忽略)。
2.用途和MD5有很多相似的地方這里就不在累述了
3.實(shí)現(xiàn)
<code>#import <CommonCrypto/CommonDigest.h>
<code>- (NSString*)sha1
{
const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];
NSData data = [NSData dataWithBytes:cstr length:self.length];
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(data.bytes, (int)data.length, digest);
NSMutableString output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
[output appendFormat:@"%02x", digest[i]];
return output;
}
</code>