MYDigest.m
author snej@snej-mbp.mtv.corp.google.com
Wed Apr 08 16:30:52 2009 -0700 (2009-04-08)
changeset 3 1dfe820d7ebe
parent 2 8982b8fada63
child 14 3af1d1c0ceb5
permissions -rw-r--r--
* Replaced MYKeyPair with MYPrivateKey.
* Changed config files.
     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 MYCRYPTO_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 - (void) finalize
    57 {
    58     if(_rawDigest) free(_rawDigest);
    59     [super finalize];
    60 }
    61 
    62 
    63 - (id) copyWithZone: (NSZone*)zone
    64 {
    65     return [self retain];
    66 }
    67 
    68 - (id)initWithCoder:(NSCoder *)decoder
    69 {
    70     NSUInteger length;
    71     const void *bytes = [decoder decodeBytesForKey: @"digest" returnedLength: &length];
    72     return [self initWithRawDigest: bytes length: length];
    73 }
    74 
    75 
    76 - (void)encodeWithCoder:(NSCoder *)coder
    77 {
    78     [coder encodeBytes: self.bytes length: self.length forKey: @"digest"];
    79 }
    80 
    81 
    82 + (MYDigest*) digestFromDigestData: (NSData*)digestData {
    83     return [[[self alloc] initWithRawDigest: digestData.bytes length: digestData.length] autorelease];
    84 }
    85 
    86 + (MYDigest*) digestFromHexString: (NSString*)hexString
    87 {
    88     const char *cStr = [hexString UTF8String];
    89     const size_t length = [self length];
    90     if( !cStr || strlen(cStr)!=2*length )
    91         return nil;
    92     uint8_t digest[length];
    93     for( size_t i=0; i<length; i++ ) {
    94         if( sscanf(cStr, "%2hhx", &digest[i]) != 1 )
    95             return nil;
    96         cStr += 2;
    97     }
    98     return [[[self alloc] initWithRawDigest: &digest length: length] autorelease];
    99 }
   100 
   101 + (MYDigest*) digestOfData: (NSData*)data {
   102     return [self digestOfBytes: data.bytes length: data.length];
   103 }
   104 + (MYDigest*) digestOfBytes: (const void*)bytes length: (size_t)length {
   105     const size_t digestLength = [self length];
   106     uint8_t digest[digestLength];
   107     [self computeDigest: digest ofBytes: bytes length: length];
   108     return [[[self alloc] initWithRawDigest: &digest length: digestLength] autorelease];
   109 }
   110 
   111 - (uint32_t) algorithm {
   112     return [[self class] algorithm];
   113 }
   114 
   115 - (size_t) length {
   116     return [[self class] length];
   117 }
   118 
   119 - (const void*) bytes {
   120     return _rawDigest;
   121 }
   122 
   123 
   124 - (BOOL) isEqual: (id)digest
   125 {
   126     return [digest isKindOfClass: [MYDigest class]]
   127         && [digest algorithm] == self.algorithm
   128         && memcmp(self.bytes, [digest bytes], self.length)==0;
   129 }
   130 
   131 - (NSUInteger) hash
   132 {
   133     return *(NSUInteger*)self.bytes;
   134     //? This makes the hashcode endian-dependent. Does that matter?
   135 }
   136 
   137 - (NSComparisonResult) compare: (MYDigest*)other
   138 {
   139     size_t size=self.length, otherSize=other.length;
   140     NSComparisonResult cmp = memcmp(self.bytes, other.bytes, MIN(size,otherSize));
   141     return cmp ? cmp : ((int)size - (int)otherSize);
   142 }
   143 
   144 
   145 - (NSData*) asData
   146 {
   147     return [NSData dataWithBytes: self.bytes length: self.length];
   148 }
   149 
   150 - (NSString*) description
   151 {
   152     return [NSString stringWithFormat: @"%@[%@]", [self class], [self abbreviatedHexString]];
   153 }
   154 
   155 - (NSString*) hexString
   156 {
   157     const uint8_t *bytes = self.bytes;
   158     size_t length = self.length;
   159     char out[2*length+1];
   160     char *dst = &out[0];
   161     for( size_t i=0; i<length; i+=1 )
   162         dst += sprintf(dst,"%02X", bytes[i]);
   163     return [[[NSString alloc] initWithBytes: out length: 2*length encoding: NSASCIIStringEncoding]
   164             autorelease];
   165 }
   166 
   167 - (NSString*) abbreviatedHexString
   168 {
   169     const uint8_t *bytes = self.bytes;
   170     return [NSString stringWithFormat: @"%02hhX%02hhX%02hhX%02hhX...",
   171             bytes[0],bytes[1],bytes[2],bytes[3]];
   172 }
   173 
   174 
   175 @end
   176 
   177 
   178 
   179 @implementation MYSHA1Digest
   180 
   181 + (void) computeDigest: (void*)dstDigest ofBytes: (const void*)bytes length: (size_t)length {
   182     NSParameterAssert(bytes!=NULL);
   183     NSParameterAssert(length>0);
   184     CC_SHA1(bytes,length, dstDigest);
   185 }
   186 
   187 + (uint32_t) algorithm            {return CSSM_ALGID_SHA1;}
   188 + (size_t) length               {return sizeof(RawSHA1Digest);}
   189 
   190 - (MYSHA1Digest*) initWithRawSHA1Digest: (const RawSHA1Digest*)rawDigest {
   191     return [super initWithRawDigest: rawDigest length: sizeof(*rawDigest)];
   192 }
   193 
   194 + (MYSHA1Digest*) digestFromRawSHA1Digest: (const RawSHA1Digest*)rawDigest {
   195     return [[[self alloc] initWithRawSHA1Digest: rawDigest] autorelease];
   196 }
   197 
   198 - (const RawSHA1Digest*) rawSHA1Digest {
   199     return self.bytes;
   200 }
   201 
   202 
   203 @end
   204 
   205 
   206 
   207 @implementation MYSHA256Digest
   208 
   209 + (void) computeDigest: (void*)dstDigest ofBytes: (const void*)bytes length: (size_t)length {
   210     NSParameterAssert(bytes!=NULL);
   211     NSParameterAssert(length>0);
   212     CC_SHA256(bytes,length, dstDigest);
   213 }
   214 
   215 + (uint32_t) algorithm            {return CSSM_ALGID_SHA256;}
   216 + (size_t) length               {return sizeof(RawSHA256Digest);}
   217 
   218 - (MYSHA256Digest*) initWithRawSHA256Digest: (const RawSHA256Digest*)rawDigest {
   219     return [super initWithRawDigest: rawDigest length: sizeof(*rawDigest)];
   220 }
   221 
   222 + (MYSHA256Digest*) digestFromRawSHA256Digest: (const RawSHA256Digest*)rawDigest {
   223     return [[[self alloc] initWithRawSHA256Digest: rawDigest] autorelease];
   224 }
   225 
   226 - (const RawSHA256Digest*) rawSHA256Digest {
   227     return self.bytes;
   228 }
   229 
   230 
   231 @end
   232 
   233 
   234 
   235 @implementation NSData (MYDigest)
   236 
   237 - (MYSHA1Digest*) my_SHA1Digest
   238 {
   239     return (MYSHA1Digest*) [MYSHA1Digest digestOfData: self];
   240 }
   241 
   242 - (MYSHA256Digest*) my_SHA256Digest
   243 {
   244     return (MYSHA256Digest*) [MYSHA256Digest digestOfData: self];
   245 }
   246 
   247 @end
   248 
   249 
   250 
   251 #import "Test.h"
   252 
   253 
   254 static void testDigestOf( NSData *src, NSString *expectedSHA1Hex, NSString *expectedSHA256Hex )
   255 {
   256     MYSHA1Digest *d1 = [src my_SHA1Digest];
   257     NSString *hex = d1.hexString;
   258     Log(@"Digesting %u bytes to %@",src.length,hex);
   259     if( expectedSHA1Hex )
   260         CAssertEqual(hex,expectedSHA1Hex);
   261     MYSHA1Digest *d2 = (MYSHA1Digest*) [MYSHA1Digest digestFromHexString: hex];
   262     CAssertEqual(d1,d2);
   263     CAssertEqual(d2.hexString,hex);
   264 
   265     MYSHA256Digest *d256 = [src my_SHA256Digest];
   266     hex = d256.hexString;
   267     Log(@"Digesting %u bytes to %@",src.length,hex);
   268     if( expectedSHA256Hex )
   269         CAssertEqual(hex,expectedSHA256Hex);
   270     MYSHA256Digest *d256_2 = (MYSHA256Digest*) [MYSHA256Digest digestFromHexString: hex];
   271     CAssertEqual(d256,d256_2);
   272     CAssertEqual(d256_2.hexString,hex);
   273 }
   274 
   275 
   276 TestCase(MYDigest) {
   277     testDigestOf([@"Pack my box with five dozen liquor jugs, you ugly potatoe pie!" 
   278                           dataUsingEncoding: NSUTF8StringEncoding],
   279                  @"4F254781ED6C0103BE056DD8418EFBAC0C2EBE3C",
   280                  @"08AA4BCDDF7654D7AB5CDD25395A4DD8F3BEB5C79FE567D10C1A21B9134F48FD");
   281     testDigestOf([NSData dataWithContentsOfFile: @"/Library/Desktop Pictures/Nature/Zen Garden.jpg"],
   282                  @"62A17839B3B86D3543EB2E34D2718A0FE044FA31",
   283                  @"FBD25FA6CEE794049973DE3BDF752345617FCA81018C8FC65350BCDD901142DB");
   284 }