0
点赞
收藏
分享

微信扫一扫

iOS和Android的MD5校验一致性

MD5是使用哈希算法计算文件或字符串的摘要,将不定长的输入数据转化成128bit的数据,一般在使用的时候需要将它转换成十六进制输出,并且同时输出为小写,是不可还原出原始数据的(目前网站解密方式是采用撞库的方式,不是真正的解密)。
项目有个校验图片一致性的需要,用户上传图片到后台,后台根据一定的规则将图片数据转化成md5值返回给用户,当用户需要使用该图片时需要传入md5做一致性校验,防止用户修改图片。
字符串MD5的iOS代码如下:

-(NSString *)md5:(NSString *)str {
   const char *cStr = [str UTF8String];//转换成utf-8
   unsigned char result[16];//开辟一个16字节(128位:md5加密出来就是128位/bit)的空间(一个字节=8字位=8个二进制数)
   CC_MD5( cStr, strlen(cStr), result);
   /*
       extern unsigned char *CC_MD5(const void *data, CC_LONG len, unsigned char *md)官方封装好的加密方法
       把cStr字符串转换成了32位的16进制数列(这个过程不可逆转) 存储到了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]
           ];
   /*
       x表示十六进制,%02X  意思是不足两位将用0补齐,如果多余两位则不影响
       NSLog("%02X", 0x888);  //888
       NSLog("%02X", 0x4); //04
    */
}

也可以采用循环输出代码更简洁,采用官方提供的md5方法,输出固定长度128位的字符。
Androidd的md5校验代码如下:

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结果,但是将图片转成相应的字符串进行md5算法不一致了,原因是图片原始数据转化成字符串必须经过解码处理(转化成png或者jpg),Android和iOS不同的处理机制导致数据不一致,必须采用文件流的方式进行md5转化。
iOS文件流md5转化的相关代码

#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的相关代码如下:

 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();
    }

传入相关图片的路径,图片数据md5出来的数据一致,实现了md5校验的功能,使用md5校验时候要注意是字符串md5转化还是文件md5转化。

举报

相关推荐

0 条评论