MYDigest.m
author snej@snej.local
Sun Apr 19 21:19:35 2009 -0700 (2009-04-19)
changeset 14 3af1d1c0ceb5
parent 3 1dfe820d7ebe
child 23 39fec79de6e8
permissions -rw-r--r--
* Some cleanup. Got the test cases to pass again.
* Added some missing copyright notices.
     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 }
   285 
   286 
   287 
   288 /*
   289  Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   290  
   291  Redistribution and use in source and binary forms, with or without modification, are permitted
   292  provided that the following conditions are met:
   293  
   294  * Redistributions of source code must retain the above copyright notice, this list of conditions
   295  and the following disclaimer.
   296  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   297  and the following disclaimer in the documentation and/or other materials provided with the
   298  distribution.
   299  
   300  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   301  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   302  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   303  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   304  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   305   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   306  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   307  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   308  */