2012-06-11 46 views
9

Tôi đang làm việc trên ứng dụng C Objective C Cocoa. Tôi đã thử nghiệm CC_MD5 in CommonCrypto và nó hoạt động tốt; Tuy nhiên, khi tôi đưa 5 tập tin gygabyte vào nó, toàn bộ máy tính của tôi bị đóng băng và bị rơi. Thuật toán MD5 xử lý đầu vào thành các khối 512 byte và không thực sự yêu cầu tất cả các đầu vào cùng một lúc. Có một thư viện trong mục tiêu C hoặc C yêu cầu đoạn 512 byte tiếp theo thay vì lấy tất cả các đầu vào cùng một lúc?Có thư viện MD5 nào không yêu cầu toàn bộ đầu vào cùng lúc không?

Trả lời

11

Có một chủ đề lớn về tính toán MD5 của tập tin lớn trong obj-C ở đây: http://www.iphonedevsdk.com/forum/iphone-sdk-development/17659-calculating-md5-hash-large-file.html

Dưới đây là giải pháp một người nào đó đã đưa ra có:

+(NSString*)fileMD5:(NSString*)path 
{ 
    NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path]; 
    if(handle== nil) return @"ERROR GETTING FILE MD5"; // file didnt exist 

    CC_MD5_CTX md5; 

    CC_MD5_Init(&md5); 

    BOOL done = NO; 
    while(!done) 
    { 
     NSAutoreleasePool * pool = [NSAutoreleasePool new]; 
     NSData* fileData = [handle readDataOfLength: CHUNK_SIZE ]; 
     CC_MD5_Update(&md5, [fileData bytes], [fileData length]); 
     if([fileData length] == 0) done = YES; 
       [pool drain]; 
    } 
    unsigned char digest[CC_MD5_DIGEST_LENGTH]; 
    CC_MD5_Final(digest, &md5); 
    NSString* s = [NSString stringWithFormat: @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", 
        digest[0], digest[1], 
        digest[2], digest[3], 
        digest[4], digest[5], 
        digest[6], digest[7], 
        digest[8], digest[9], 
        digest[10], digest[11], 
        digest[12], digest[13], 
        digest[14], digest[15]]; 
    return s; 
} 
+0

Cảm ơn bạn đã liên kết, đọc ngay bây giờ. –

+3

Câu trả lời này sẽ được hưởng lợi từ bản cập nhật cho ARC. Mã trong vòng lặp cần được đặt bên trong khối '@autoreleasepool {}'. –

2

CC_MD5() được thiết kế để xử lý tất cả đầu vào của nó cùng một lúc. 5GB có khả năng nhiều hơn nó thực sự có thể lưu trữ bất cứ nơi nào. Đối với dữ liệu lớn hơn, CommonCrypto có thể hoạt động trên các phần của nó tại một thời điểm, nếu bạn sử dụng CC_MD5_CTX, CC_MD5_Init(), CC_MD5_Update()CC_MD5_Final(). Kiểm tra tài liệu CommonCrypto hoặc Google để biết thêm thông tin và mã ví dụ.

2

Dưới đây là cách tốt hơn để thực hiện điều đó bằng cách sử dụng công cụ gửi, để có hiệu quả hơn. Tôi đang sử dụng nó trong sản xuất và nó hoạt động tốt!

#import "CalculateMD5.h" 

// Cryptography 
#include <CommonCrypto/CommonDigest.h> 

@implementation CalculateMD5 

- (id)init 
{ 
    self = [super init]; 
    if (self) 
    { 
     MD5ChecksumOperationQueue = dispatch_queue_create("com.test.calculateMD5Checksum", DISPATCH_QUEUE_SERIAL); 
    } 
    return self; 
} 

- (void)closeReadChannel 
{ 
    dispatch_async(MD5ChecksumOperationQueue, ^{ 
     dispatch_io_close(readChannel, DISPATCH_IO_STOP); 
    }); 
} 

- (void)MD5Checksum:(NSString *)pathToFile TCB:(void(^)(NSString *md5, NSError *error))tcb 
{ 
    // Initialize the hash object 
    __block CC_MD5_CTX hashObject; 
    CC_MD5_Init(&hashObject); 

    readChannel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, 
               pathToFile.UTF8String, 
               O_RDONLY, 0, 
               MD5ChecksumOperationQueue, 
               ^(int error) { 
                [self closeReadChannel]; 
               }); 

    if (readChannel == nil) 
    { 
     NSError* e = [NSError errorWithDomain:@"MD5Error" 
             code:-999 userInfo:@{ 
        NSLocalizedDescriptionKey : @"failed to open file for calculating MD5." 
         }]; 
     tcb(nil, e); 
     return; 
    } 

    dispatch_io_set_high_water(readChannel, 512*1024); 

    dispatch_io_read(readChannel, 0, SIZE_MAX, MD5ChecksumOperationQueue, ^(bool done, dispatch_data_t data, int error) { 
     if (error != 0) 
     { 
      NSError* e = [NSError errorWithDomain:@"ExamSoftMD5" 
              code:error userInfo:@{ 
         NSLocalizedDescriptionKey : @"failed to read from file for calculating MD5." 
          }]; 
      tcb(nil, e); 
      [self closeReadChannel]; 
      return; 
     } 

     if (dispatch_data_get_size(data) > 0) 
     { 
      const void *buffer = NULL; 
      size_t size = 0; 
      data = dispatch_data_create_map(data, &buffer, &size); 

      CC_MD5_Update(&hashObject, (const void *)buffer, (CC_LONG)size); 
     } 

     if (done == YES) 
     { 
      // Compute the hash digest 
      unsigned char digest[CC_MD5_DIGEST_LENGTH]; 
      CC_MD5_Final(digest, &hashObject); 

      // Compute the string result 
      char *hash = calloc((2 * sizeof(digest) + 1), sizeof(char)); 
      for (size_t i = 0; i < sizeof(digest); ++i) 
      { 
       snprintf(hash + (2 * i), 3, "%02x", (int)(digest[i])); 
      } 

      tcb(@(hash), nil); 

      [self closeReadChannel]; 
     } 
    }); 
} 


@end 
Các vấn đề liên quan