MYDigest.m
author snej@snej.local
Sat Apr 04 22:56:13 2009 -0700 (2009-04-04)
changeset 1 60e4cbbb5128
child 2 8982b8fada63
permissions -rw-r--r--
Code cleanup, more header comments.
     1 //
     2 //  MYDigest.m
     3 //  MYCrypto
     4 //
     5 //  Created by Jens Alfke on 1/4/08.
     6 //  Copyright 2008 Jens Alfke. All rights reserved.
     7 //
     8 
     9 #import "MYDigest.h"
    10 #import <CommonCrypto/CommonDigest.h>
    11 #import "MYCrypto_Private.h"
    12 
    13 
    14 #if USE_IPHONE_API
    15 enum {
    16     CSSM_ALGID_SHA1 = 8,
    17     CSSM_ALGID_SHA256 = 0x80000000 + 14
    18 };
    19 #endif
    20 
    21 
    22 @implementation MYDigest
    23 
    24 + (uint32_t) algorithm {
    25     AssertAbstractMethod();
    26 }
    27 
    28 + (size_t) length {
    29     AssertAbstractMethod();
    30 }
    31 
    32 + (void) computeDigest: (void*)dstDigest ofBytes: (const void*)bytes length: (size_t)length {
    33     AssertAbstractMethod();
    34 }
    35 
    36 
    37 - (id) initWithRawDigest: (const void*)rawDigest length: (size_t)length {
    38     Assert([self class] != [MYDigest class], @"MYDigest is an abstract class");
    39     Assert(rawDigest!=NULL);
    40     AssertEq(length,[[self class] length]);
    41     self = [super init];
    42     if (self) {
    43         _rawDigest = malloc(length);
    44         Assert(_rawDigest);
    45         memcpy(_rawDigest,rawDigest,length);
    46     }
    47     return self;
    48 }
    49 
    50 - (void) dealloc
    51 {
    52     if(_rawDigest) free(_rawDigest);
    53     [super dealloc];
    54 }
    55 
    56 
    57 - (id) copyWithZone: (NSZone*)zone
    58 {
    59     return [self retain];
    60 }
    61 
    62 - (id)initWithCoder:(NSCoder *)decoder
    63 {
    64     NSUInteger length;
    65     const void *bytes = [decoder decodeBytesForKey: @"digest" returnedLength: &length];
    66     return [self initWithRawDigest: bytes length: length];
    67 }
    68 
    69 
    70 - (void)encodeWithCoder:(NSCoder *)coder
    71 {
    72     [coder encodeBytes: self.bytes length: self.length forKey: @"digest"];
    73 }
    74 
    75 
    76 + (MYDigest*) digestFromDigestData: (NSData*)digestData {
    77     return [[[self alloc] initWithRawDigest: digestData.bytes length: digestData.length] autorelease];
    78 }
    79 
    80 + (MYDigest*) digestFromHexString: (NSString*)hexString
    81 {
    82     const char *cStr = [hexString UTF8String];
    83     const size_t length = [self length];
    84     if( !cStr || strlen(cStr)!=2*length )
    85         return nil;
    86     uint8_t digest[length];
    87     for( int i=0; i<length; i++ ) {
    88         if( sscanf(cStr, "%2hhx", &digest[i]) != 1 )
    89             return nil;
    90         cStr += 2;
    91     }
    92     return [[[self alloc] initWithRawDigest: &digest length: length] autorelease];
    93 }
    94 
    95 + (MYDigest*) digestOfData: (NSData*)data {
    96     return [self digestOfBytes: data.bytes length: data.length];
    97 }
    98 + (MYDigest*) digestOfBytes: (const void*)bytes length: (size_t)length {
    99     const size_t digestLength = [self length];
   100     uint8_t digest[digestLength];
   101     [self computeDigest: digest ofBytes: bytes length: length];
   102     return [[[self alloc] initWithRawDigest: &digest length: digestLength] autorelease];
   103 }
   104 
   105 - (uint32_t) algorithm {
   106     return [[self class] algorithm];
   107 }
   108 
   109 - (size_t) length {
   110     return [[self class] length];
   111 }
   112 
   113 - (const void*) bytes {
   114     return _rawDigest;
   115 }
   116 
   117 
   118 - (BOOL) isEqual: (id)digest
   119 {
   120     return [digest isKindOfClass: [MYDigest class]]
   121         && [digest algorithm] == self.algorithm
   122         && memcmp(self.bytes, [digest bytes], self.length)==0;
   123 }
   124 
   125 - (NSUInteger) hash
   126 {
   127     return *(NSUInteger*)self.bytes;
   128     //? This makes the hashcode endian-dependent. Does that matter?
   129 }
   130 
   131 - (NSComparisonResult) compare: (MYDigest*)other
   132 {
   133     size_t size=self.length, otherSize=other.length;
   134     NSComparisonResult cmp = memcmp(self.bytes, other.bytes, MIN(size,otherSize));
   135     return cmp ? cmp : ((int)size - (int)otherSize);
   136 }
   137 
   138 
   139 - (NSData*) asData
   140 {
   141     return [NSData dataWithBytes: self.bytes length: self.length];
   142 }
   143 
   144 - (NSString*) description
   145 {
   146     return [NSString stringWithFormat: @"%@[%@]", [self class], [self abbreviatedHexString]];
   147 }
   148 
   149 - (NSString*) hexString
   150 {
   151     const uint8_t *bytes = self.bytes;
   152     size_t length = self.length;
   153     char out[2*length+1];
   154     char *dst = &out[0];
   155     for( int i=0; i<length; i+=1 )
   156         dst += sprintf(dst,"%02X", bytes[i]);
   157     return [[[NSString alloc] initWithBytes: out length: 2*length encoding: NSASCIIStringEncoding]
   158             autorelease];
   159 }
   160 
   161 - (NSString*) abbreviatedHexString
   162 {
   163     const uint8_t *bytes = self.bytes;
   164     return [NSString stringWithFormat: @"%02hhX%02hhX%02hhX%02hhX...",
   165             bytes[0],bytes[1],bytes[2],bytes[3]];
   166 }
   167 
   168 
   169 @end
   170 
   171 
   172 
   173 @implementation MYSHA1Digest
   174 
   175 + (void) computeDigest: (void*)dstDigest ofBytes: (const void*)bytes length: (size_t)length {
   176     NSParameterAssert(bytes!=NULL);
   177     NSParameterAssert(length>0);
   178     CC_SHA1(bytes,length, dstDigest);
   179 }
   180 
   181 + (uint32_t) algorithm            {return CSSM_ALGID_SHA1;}
   182 + (size_t) length               {return sizeof(RawSHA1Digest);}
   183 
   184 - (MYSHA1Digest*) initWithRawSHA1Digest: (const RawSHA1Digest*)rawDigest {
   185     return [super initWithRawDigest: rawDigest length: sizeof(*rawDigest)];
   186 }
   187 
   188 + (MYSHA1Digest*) digestFromRawSHA1Digest: (const RawSHA1Digest*)rawDigest {
   189     return [[[self alloc] initWithRawSHA1Digest: rawDigest] autorelease];
   190 }
   191 
   192 - (const RawSHA1Digest*) rawSHA1Digest {
   193     return self.bytes;
   194 }
   195 
   196 
   197 @end
   198 
   199 
   200 
   201 @implementation MYSHA256Digest
   202 
   203 + (void) computeDigest: (void*)dstDigest ofBytes: (const void*)bytes length: (size_t)length {
   204     NSParameterAssert(bytes!=NULL);
   205     NSParameterAssert(length>0);
   206     CC_SHA256(bytes,length, dstDigest);
   207 }
   208 
   209 + (uint32_t) algorithm            {return CSSM_ALGID_SHA256;}
   210 + (size_t) length               {return sizeof(RawSHA256Digest);}
   211 
   212 - (MYSHA256Digest*) initWithRawSHA256Digest: (const RawSHA256Digest*)rawDigest {
   213     return [super initWithRawDigest: rawDigest length: sizeof(*rawDigest)];
   214 }
   215 
   216 + (MYSHA256Digest*) digestFromRawSHA256Digest: (const RawSHA256Digest*)rawDigest {
   217     return [[[self alloc] initWithRawSHA256Digest: rawDigest] autorelease];
   218 }
   219 
   220 - (const RawSHA256Digest*) rawSHA256Digest {
   221     return self.bytes;
   222 }
   223 
   224 
   225 @end
   226 
   227 
   228 
   229 @implementation NSData (MYDigest)
   230 
   231 - (MYSHA1Digest*) my_SHA1Digest
   232 {
   233     return (MYSHA1Digest*) [MYSHA1Digest digestOfData: self];
   234 }
   235 
   236 - (MYSHA256Digest*) my_SHA256Digest
   237 {
   238     return (MYSHA256Digest*) [MYSHA256Digest digestOfData: self];
   239 }
   240 
   241 @end
   242 
   243 
   244 
   245 #import "Test.h"
   246 
   247 
   248 static void testDigestOf( NSData *src, NSString *expectedSHA1Hex, NSString *expectedSHA256Hex )
   249 {
   250     MYSHA1Digest *d1 = [src my_SHA1Digest];
   251     NSString *hex = d1.hexString;
   252     Log(@"Digesting %u bytes to %@",src.length,hex);
   253     if( expectedSHA1Hex )
   254         CAssertEqual(hex,expectedSHA1Hex);
   255     MYSHA1Digest *d2 = (MYSHA1Digest*) [MYSHA1Digest digestFromHexString: hex];
   256     CAssertEqual(d1,d2);
   257     CAssertEqual(d2.hexString,hex);
   258 
   259     MYSHA256Digest *d256 = [src my_SHA256Digest];
   260     hex = d256.hexString;
   261     Log(@"Digesting %u bytes to %@",src.length,hex);
   262     if( expectedSHA256Hex )
   263         CAssertEqual(hex,expectedSHA256Hex);
   264     MYSHA256Digest *d256_2 = (MYSHA256Digest*) [MYSHA256Digest digestFromHexString: hex];
   265     CAssertEqual(d256,d256_2);
   266     CAssertEqual(d256_2.hexString,hex);
   267 }
   268 
   269 
   270 TestCase(MYDigest) {
   271     testDigestOf([@"Pack my box with five dozen liquor jugs, you ugly potatoe pie!" 
   272                           dataUsingEncoding: NSUTF8StringEncoding],
   273                  @"4F254781ED6C0103BE056DD8418EFBAC0C2EBE3C",
   274                  @"08AA4BCDDF7654D7AB5CDD25395A4DD8F3BEB5C79FE567D10C1A21B9134F48FD");
   275     testDigestOf([NSData dataWithContentsOfFile: @"/Library/Desktop Pictures/Nature/Zen Garden.jpg"],
   276                  @"62A17839B3B86D3543EB2E34D2718A0FE044FA31",
   277                  @"FBD25FA6CEE794049973DE3BDF752345617FCA81018C8FC65350BCDD901142DB");
   278 }