1/* Generic CommonDigest wrappers to match the semantics of libmd. */ 2 3#include <dispatch/dispatch.h> 4#include <assumes.h> 5#include <errno.h> 6#include <fcntl.h> 7 8#include "commoncrypto.h" 9 10char * 11Digest_End(CCDigestRef ctx, char *buf) 12{ 13 static const char hex[] = "0123456789abcdef"; 14 uint8_t digest[32]; // SHA256 is the biggest 15 size_t i, length; 16 17 (void)osx_assumes_zero(CCDigestFinal(ctx, digest)); 18 length = CCDigestOutputSize(ctx); 19 osx_assert(length <= sizeof(digest)); 20 for (i = 0; i < length; i++) { 21 buf[i+i] = hex[digest[i] >> 4]; 22 buf[i+i+1] = hex[digest[i] & 0x0f]; 23 } 24 buf[i+i] = '\0'; 25 return buf; 26} 27 28char * 29Digest_Data(CCDigestAlg algorithm, const void *data, size_t len, char *buf) 30{ 31 CCDigestCtx ctx; 32 33 (void)osx_assumes_zero(CCDigestInit(algorithm, &ctx)); 34 (void)osx_assumes_zero(CCDigestUpdate(&ctx, data, len)); 35 return Digest_End(&ctx, buf); 36} 37 38char * 39Digest_File(CCDigestAlg algorithm, const char *filename, char *buf) 40{ 41 int fd; 42 __block CCDigestCtx ctx; 43 dispatch_queue_t queue; 44 dispatch_semaphore_t sema; 45 dispatch_io_t io; 46 __block int s_error = 0; 47 48 /* dispatch_io_create_with_path requires an absolute path */ 49 fd = open(filename, O_RDONLY); 50 if (fd < 0) { 51 return NULL; 52 } 53 54 (void)fcntl(fd, F_NOCACHE, 1); 55 56 (void)osx_assumes_zero(CCDigestInit(algorithm, &ctx)); 57 58 queue = dispatch_queue_create("com.apple.mtree.io", NULL); 59 osx_assert(queue); 60 sema = dispatch_semaphore_create(0); 61 osx_assert(sema); 62 63 io = dispatch_io_create(DISPATCH_IO_STREAM, fd, queue, ^(int error) { 64 if (error != 0) { 65 s_error = error; 66 } 67 (void)close(fd); 68 (void)dispatch_semaphore_signal(sema); 69 }); 70 osx_assert(io); 71 dispatch_io_read(io, 0, SIZE_MAX, queue, ^(__unused bool done, dispatch_data_t data, int error) { 72 if (data != NULL) { 73 (void)dispatch_data_apply(data, ^(__unused dispatch_data_t region, __unused size_t offset, const void *buffer, size_t size) { 74 (void)osx_assumes_zero(CCDigestUpdate(&ctx, buffer, size)); 75 return (bool)true; 76 }); 77 } 78 79 if (error != 0) { 80 s_error = error; 81 } 82 }); 83 dispatch_release(io); // it will close on its own 84 85 (void)dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); 86 87 dispatch_release(queue); 88 dispatch_release(sema); 89 90 if (s_error != 0) { 91 errno = s_error; 92 return NULL; 93 } 94 95 return Digest_End(&ctx, buf); 96} 97