MYDigest.m
author Jens Alfke <jens@mooseyard.com>
Fri Aug 07 11:24:53 2009 -0700 (2009-08-07)
changeset 28 54b373aa65ab
parent 14 3af1d1c0ceb5
permissions -rw-r--r--
Fixed iPhone OS build. (issue 3)
     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 + (id) digestFromDigestData: (NSData*)digestData {
    83     return [[[self alloc] initWithRawDigest: digestData.bytes length: digestData.length] autorelease];
    84 }
    85 
    86 + (id) 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 + (id) digestOfData: (NSData*)data {
   102     return [self digestOfBytes: data.bytes length: data.length];
   103 }
   104 
   105 + (id) digestOfBytes: (const void*)bytes length: (size_t)length {
   106     const size_t digestLength = [self length];
   107     uint8_t digest[digestLength];
   108     [self computeDigest: digest ofBytes: bytes length: length];
   109     return [[[self alloc] initWithRawDigest: &digest length: digestLength] autorelease];
   110 }
   111 
   112 - (uint32_t) algorithm {
   113     return [[self class] algorithm];
   114 }
   115 
   116 - (size_t) length {
   117     return [[self class] length];
   118 }
   119 
   120 - (const void*) bytes {
   121     return _rawDigest;
   122 }
   123 
   124 
   125 - (BOOL) isEqual: (id)digest
   126 {
   127     return [digest isKindOfClass: [MYDigest class]]
   128         && [digest algorithm] == self.algorithm
   129         && memcmp(self.bytes, [digest bytes], self.length)==0;
   130 }
   131 
   132 - (NSUInteger) hash
   133 {
   134     return *(NSUInteger*)self.bytes;
   135     //? This makes the hashcode endian-dependent. Does that matter?
   136 }
   137 
   138 - (NSComparisonResult) compare: (MYDigest*)other
   139 {
   140     size_t size=self.length, otherSize=other.length;
   141     NSComparisonResult cmp = memcmp(self.bytes, other.bytes, MIN(size,otherSize));
   142     return cmp ? cmp : ((int)size - (int)otherSize);
   143 }
   144 
   145 
   146 - (NSData*) asData
   147 {
   148     return [NSData dataWithBytes: self.bytes length: self.length];
   149 }
   150 
   151 - (NSString*) description
   152 {
   153     return [NSString stringWithFormat: @"%@[%@]", [self class], [self abbreviatedHexString]];
   154 }
   155 
   156 - (NSString*) hexString
   157 {
   158     const uint8_t *bytes = self.bytes;
   159     size_t length = self.length;
   160     char out[2*length+1];
   161     char *dst = &out[0];
   162     for( size_t i=0; i<length; i+=1 )
   163         dst += sprintf(dst,"%02X", bytes[i]);
   164     return [[[NSString alloc] initWithBytes: out length: 2*length encoding: NSASCIIStringEncoding]
   165             autorelease];
   166 }
   167 
   168 - (NSString*) abbreviatedHexString
   169 {
   170     const uint8_t *bytes = self.bytes;
   171     return [NSString stringWithFormat: @"%02hhX%02hhX%02hhX%02hhX...",
   172             bytes[0],bytes[1],bytes[2],bytes[3]];
   173 }
   174 
   175 
   176 @end
   177 
   178 
   179 
   180 @implementation MYSHA1Digest
   181 
   182 + (void) computeDigest: (void*)dstDigest ofBytes: (const void*)bytes length: (size_t)length {
   183     NSParameterAssert(bytes!=NULL);
   184     NSParameterAssert(length>0);
   185     CC_SHA1(bytes,length, dstDigest);
   186 }
   187 
   188 + (uint32_t) algorithm            {return CSSM_ALGID_SHA1;}
   189 + (size_t) length               {return sizeof(RawSHA1Digest);}
   190 
   191 - (MYSHA1Digest*) initWithRawSHA1Digest: (const RawSHA1Digest*)rawDigest {
   192     return [super initWithRawDigest: rawDigest length: sizeof(*rawDigest)];
   193 }
   194 
   195 + (MYSHA1Digest*) digestFromRawSHA1Digest: (const RawSHA1Digest*)rawDigest {
   196     return [[[self alloc] initWithRawSHA1Digest: rawDigest] autorelease];
   197 }
   198 
   199 - (const RawSHA1Digest*) rawSHA1Digest {
   200     return self.bytes;
   201 }
   202 
   203 
   204 @end
   205 
   206 
   207 
   208 @implementation MYSHA256Digest
   209 
   210 + (void) computeDigest: (void*)dstDigest ofBytes: (const void*)bytes length: (size_t)length {
   211     NSParameterAssert(bytes!=NULL);
   212     NSParameterAssert(length>0);
   213     CC_SHA256(bytes,length, dstDigest);
   214 }
   215 
   216 + (uint32_t) algorithm            {return CSSM_ALGID_SHA256;}
   217 + (size_t) length               {return sizeof(RawSHA256Digest);}
   218 
   219 - (MYSHA256Digest*) initWithRawSHA256Digest: (const RawSHA256Digest*)rawDigest {
   220     return [super initWithRawDigest: rawDigest length: sizeof(*rawDigest)];
   221 }
   222 
   223 + (MYSHA256Digest*) digestFromRawSHA256Digest: (const RawSHA256Digest*)rawDigest {
   224     return [[[self alloc] initWithRawSHA256Digest: rawDigest] autorelease];
   225 }
   226 
   227 - (const RawSHA256Digest*) rawSHA256Digest {
   228     return self.bytes;
   229 }
   230 
   231 
   232 @end
   233 
   234 
   235 
   236 @implementation NSData (MYDigest)
   237 
   238 - (MYSHA1Digest*) my_SHA1Digest
   239 {
   240     return (MYSHA1Digest*) [MYSHA1Digest digestOfData: self];
   241 }
   242 
   243 - (MYSHA256Digest*) my_SHA256Digest
   244 {
   245     return (MYSHA256Digest*) [MYSHA256Digest digestOfData: self];
   246 }
   247 
   248 @end
   249 
   250 
   251 
   252 #import "Test.h"
   253 
   254 
   255 static void testDigestOf( NSData *src, NSString *expectedSHA1Hex, NSString *expectedSHA256Hex )
   256 {
   257     MYSHA1Digest *d1 = [src my_SHA1Digest];
   258     NSString *hex = d1.hexString;
   259     Log(@"Digesting %u bytes to %@",src.length,hex);
   260     if( expectedSHA1Hex )
   261         CAssertEqual(hex,expectedSHA1Hex);
   262     MYSHA1Digest *d2 = (MYSHA1Digest*) [MYSHA1Digest digestFromHexString: hex];
   263     CAssertEqual(d1,d2);
   264     CAssertEqual(d2.hexString,hex);
   265 
   266     MYSHA256Digest *d256 = [src my_SHA256Digest];
   267     hex = d256.hexString;
   268     Log(@"Digesting %u bytes to %@",src.length,hex);
   269     if( expectedSHA256Hex )
   270         CAssertEqual(hex,expectedSHA256Hex);
   271     MYSHA256Digest *d256_2 = (MYSHA256Digest*) [MYSHA256Digest digestFromHexString: hex];
   272     CAssertEqual(d256,d256_2);
   273     CAssertEqual(d256_2.hexString,hex);
   274 }
   275 
   276 
   277 TestCase(MYDigest) {
   278     testDigestOf([@"Pack my box with five dozen liquor jugs, you ugly potatoe pie!" 
   279                           dataUsingEncoding: NSUTF8StringEncoding],
   280                  @"4F254781ED6C0103BE056DD8418EFBAC0C2EBE3C",
   281                  @"08AA4BCDDF7654D7AB5CDD25395A4DD8F3BEB5C79FE567D10C1A21B9134F48FD");
   282     testDigestOf([NSData dataWithContentsOfFile: @"/Library/Desktop Pictures/Nature/Zen Garden.jpg"],
   283                  @"62A17839B3B86D3543EB2E34D2718A0FE044FA31",
   284                  @"FBD25FA6CEE794049973DE3BDF752345617FCA81018C8FC65350BCDD901142DB");
   285 }
   286 
   287 
   288 
   289 /*
   290  Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   291  
   292  Redistribution and use in source and binary forms, with or without modification, are permitted
   293  provided that the following conditions are met:
   294  
   295  * Redistributions of source code must retain the above copyright notice, this list of conditions
   296  and the following disclaimer.
   297  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   298  and the following disclaimer in the documentation and/or other materials provided with the
   299  distribution.
   300  
   301  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   302  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   303  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   304  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   305  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   306   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   307  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   308  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   309  */