MD5是使用哈希算法計(jì)算文件或字符串的摘要蒸健,將不定長(zhǎng)的輸入數(shù)據(jù)轉(zhuǎn)化成128bit的數(shù)據(jù)衡创,一般在使用的時(shí)候需要將它轉(zhuǎn)換成十六進(jìn)制輸出,并且同時(shí)輸出為小寫(xiě)峡蟋,是不可還原出原始數(shù)據(jù)的(目前網(wǎng)站解密方式是采用撞庫(kù)的方式坟桅,不是真正的解密)。
項(xiàng)目有個(gè)校驗(yàn)圖片一致性的需要层亿,用戶(hù)上傳圖片到后臺(tái)桦卒,后臺(tái)根據(jù)一定的規(guī)則將圖片數(shù)據(jù)轉(zhuǎn)化成md5值返回給用戶(hù),當(dāng)用戶(hù)需要使用該圖片時(shí)需要傳入md5做一致性校驗(yàn)匿又,防止用戶(hù)修改圖片方灾。
字符串MD5的iOS代碼如下:
-(NSString *)md5:(NSString *)str {
const char *cStr = [str UTF8String];//轉(zhuǎn)換成utf-8
unsigned char result[16];//開(kāi)辟一個(gè)16字節(jié)(128位:md5加密出來(lái)就是128位/bit)的空間(一個(gè)字節(jié)=8字位=8個(gè)二進(jìn)制數(shù))
CC_MD5( cStr, strlen(cStr), result);
/*
extern unsigned char *CC_MD5(const void *data, CC_LONG len, unsigned char *md)官方封裝好的加密方法
把cStr字符串轉(zhuǎn)換成了32位的16進(jìn)制數(shù)列(這個(gè)過(guò)程不可逆轉(zhuǎn)) 存儲(chǔ)到了result這個(gè)空間中
*/
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]
];
/*
x表示十六進(jìn)制,%02X 意思是不足兩位將用0補(bǔ)齊碌更,如果多余兩位則不影響
NSLog("%02X", 0x888); //888
NSLog("%02X", 0x4); //04
*/
}
也可以采用循環(huán)輸出代碼更簡(jiǎn)潔裕偿,采用官方提供的md5方法,輸出固定長(zhǎng)度128位的字符痛单。
Androidd的md5校驗(yàn)代碼如下:
public static String stringToMD5(String string) {
byte[] hash;
try {
hash = MessageDigest.getInstance("MD5").digest(string.getBytes("UTF-8"));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
StringBuilder hex = new StringBuilder(hash.length * 2);
for (byte b : hash) {
if ((b & 0xFF) < 0x10)
hex.append("0");
hex.append(Integer.toHexString(b & 0xFF));
}
return hex.toString().toLowerCase();
}
輸入同樣的字符串可以得到相同的md5結(jié)果嘿棘,但是將圖片轉(zhuǎn)成相應(yīng)的字符串進(jìn)行md5算法不一致了,原因是圖片原始數(shù)據(jù)轉(zhuǎn)化成字符串必須經(jīng)過(guò)解碼處理(轉(zhuǎn)化成png或者jpg),Android和iOS不同的處理機(jī)制導(dǎo)致數(shù)據(jù)不一致旭绒,必須采用文件流的方式進(jìn)行md5轉(zhuǎn)化鸟妙。
iOS文件流md5轉(zhuǎn)化的相關(guān)代碼
#define FileHashDefaultChunkSizeForReadingData 1024*8
+(NSString*)getFileMD5WithPath:(NSString*)path
{
return (__bridge_transfer NSString *)FileMD5HashCreateWithPath((__bridge CFStringRef)path, FileHashDefaultChunkSizeForReadingData);
}
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 = FileHashDefaultChunkSizeForReadingData;
}
// 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;
}
Android文件流md5的相關(guān)代碼如下:
public static String getMD5(String imagePath) throws NoSuchAlgorithmException, IOException {
InputStream in = new FileInputStream(new File(imagePath));
StringBuffer md5 = new StringBuffer();
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] dataBytes = new byte[1024];
int nread = 0;
while ((nread = in.read(dataBytes)) != -1) {
md.update(dataBytes, 0, nread);
}
byte[] mdbytes = md.digest();
// convert the byte to hex format
for (int i = 0; i < mdbytes.length; i++) {
md5.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
}
return md5.toString().toLowerCase();
}
傳入相關(guān)圖片的路徑,圖片數(shù)據(jù)md5出來(lái)的數(shù)據(jù)一致挥吵,實(shí)現(xiàn)了md5校驗(yàn)的功能重父,使用md5校驗(yàn)時(shí)候要注意是字符串md5轉(zhuǎn)化還是文件md5轉(zhuǎn)化。