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)
snej@0
     1
//
snej@0
     2
//  MYDigest.m
snej@0
     3
//  MYCrypto
snej@0
     4
//
snej@0
     5
//  Created by Jens Alfke on 1/4/08.
snej@0
     6
//  Copyright 2008 Jens Alfke. All rights reserved.
snej@0
     7
//
snej@0
     8
snej@0
     9
#import "MYDigest.h"
snej@0
    10
#import <CommonCrypto/CommonDigest.h>
snej@0
    11
#import "MYCrypto_Private.h"
snej@0
    12
snej@0
    13
snej@2
    14
#if MYCRYPTO_USE_IPHONE_API
snej@0
    15
enum {
snej@0
    16
    CSSM_ALGID_SHA1 = 8,
snej@0
    17
    CSSM_ALGID_SHA256 = 0x80000000 + 14
snej@0
    18
};
snej@0
    19
#endif
snej@0
    20
snej@0
    21
snej@0
    22
@implementation MYDigest
snej@0
    23
snej@0
    24
+ (uint32_t) algorithm {
snej@0
    25
    AssertAbstractMethod();
snej@0
    26
}
snej@0
    27
snej@0
    28
+ (size_t) length {
snej@0
    29
    AssertAbstractMethod();
snej@0
    30
}
snej@0
    31
snej@0
    32
+ (void) computeDigest: (void*)dstDigest ofBytes: (const void*)bytes length: (size_t)length {
snej@0
    33
    AssertAbstractMethod();
snej@0
    34
}
snej@0
    35
snej@0
    36
snej@0
    37
- (id) initWithRawDigest: (const void*)rawDigest length: (size_t)length {
snej@0
    38
    Assert([self class] != [MYDigest class], @"MYDigest is an abstract class");
snej@0
    39
    Assert(rawDigest!=NULL);
snej@0
    40
    AssertEq(length,[[self class] length]);
snej@0
    41
    self = [super init];
snej@0
    42
    if (self) {
snej@0
    43
        _rawDigest = malloc(length);
snej@0
    44
        Assert(_rawDigest);
snej@0
    45
        memcpy(_rawDigest,rawDigest,length);
snej@0
    46
    }
snej@0
    47
    return self;
snej@0
    48
}
snej@0
    49
snej@0
    50
- (void) dealloc
snej@0
    51
{
snej@0
    52
    if(_rawDigest) free(_rawDigest);
snej@0
    53
    [super dealloc];
snej@0
    54
}
snej@0
    55
snej@2
    56
- (void) finalize
snej@2
    57
{
snej@2
    58
    if(_rawDigest) free(_rawDigest);
snej@2
    59
    [super finalize];
snej@2
    60
}
snej@2
    61
snej@0
    62
snej@0
    63
- (id) copyWithZone: (NSZone*)zone
snej@0
    64
{
snej@0
    65
    return [self retain];
snej@0
    66
}
snej@0
    67
snej@0
    68
- (id)initWithCoder:(NSCoder *)decoder
snej@0
    69
{
snej@0
    70
    NSUInteger length;
snej@0
    71
    const void *bytes = [decoder decodeBytesForKey: @"digest" returnedLength: &length];
snej@0
    72
    return [self initWithRawDigest: bytes length: length];
snej@0
    73
}
snej@0
    74
snej@0
    75
snej@0
    76
- (void)encodeWithCoder:(NSCoder *)coder
snej@0
    77
{
snej@0
    78
    [coder encodeBytes: self.bytes length: self.length forKey: @"digest"];
snej@0
    79
}
snej@0
    80
snej@0
    81
jens@23
    82
+ (id) digestFromDigestData: (NSData*)digestData {
snej@0
    83
    return [[[self alloc] initWithRawDigest: digestData.bytes length: digestData.length] autorelease];
snej@0
    84
}
snej@0
    85
jens@23
    86
+ (id) digestFromHexString: (NSString*)hexString
snej@0
    87
{
snej@0
    88
    const char *cStr = [hexString UTF8String];
snej@0
    89
    const size_t length = [self length];
snej@0
    90
    if( !cStr || strlen(cStr)!=2*length )
snej@0
    91
        return nil;
snej@0
    92
    uint8_t digest[length];
snej@3
    93
    for( size_t i=0; i<length; i++ ) {
snej@0
    94
        if( sscanf(cStr, "%2hhx", &digest[i]) != 1 )
snej@0
    95
            return nil;
snej@0
    96
        cStr += 2;
snej@0
    97
    }
snej@0
    98
    return [[[self alloc] initWithRawDigest: &digest length: length] autorelease];
snej@0
    99
}
snej@0
   100
jens@23
   101
+ (id) digestOfData: (NSData*)data {
snej@0
   102
    return [self digestOfBytes: data.bytes length: data.length];
snej@0
   103
}
jens@23
   104
jens@23
   105
+ (id) digestOfBytes: (const void*)bytes length: (size_t)length {
snej@0
   106
    const size_t digestLength = [self length];
snej@0
   107
    uint8_t digest[digestLength];
snej@0
   108
    [self computeDigest: digest ofBytes: bytes length: length];
snej@0
   109
    return [[[self alloc] initWithRawDigest: &digest length: digestLength] autorelease];
snej@0
   110
}
snej@0
   111
snej@0
   112
- (uint32_t) algorithm {
snej@0
   113
    return [[self class] algorithm];
snej@0
   114
}
snej@0
   115
snej@0
   116
- (size_t) length {
snej@0
   117
    return [[self class] length];
snej@0
   118
}
snej@0
   119
snej@0
   120
- (const void*) bytes {
snej@0
   121
    return _rawDigest;
snej@0
   122
}
snej@0
   123
snej@0
   124
snej@0
   125
- (BOOL) isEqual: (id)digest
snej@0
   126
{
snej@0
   127
    return [digest isKindOfClass: [MYDigest class]]
snej@0
   128
        && [digest algorithm] == self.algorithm
snej@0
   129
        && memcmp(self.bytes, [digest bytes], self.length)==0;
snej@0
   130
}
snej@0
   131
snej@0
   132
- (NSUInteger) hash
snej@0
   133
{
snej@0
   134
    return *(NSUInteger*)self.bytes;
snej@0
   135
    //? This makes the hashcode endian-dependent. Does that matter?
snej@0
   136
}
snej@0
   137
snej@0
   138
- (NSComparisonResult) compare: (MYDigest*)other
snej@0
   139
{
snej@0
   140
    size_t size=self.length, otherSize=other.length;
snej@0
   141
    NSComparisonResult cmp = memcmp(self.bytes, other.bytes, MIN(size,otherSize));
snej@0
   142
    return cmp ? cmp : ((int)size - (int)otherSize);
snej@0
   143
}
snej@0
   144
snej@0
   145
snej@0
   146
- (NSData*) asData
snej@0
   147
{
snej@0
   148
    return [NSData dataWithBytes: self.bytes length: self.length];
snej@0
   149
}
snej@0
   150
snej@0
   151
- (NSString*) description
snej@0
   152
{
snej@0
   153
    return [NSString stringWithFormat: @"%@[%@]", [self class], [self abbreviatedHexString]];
snej@0
   154
}
snej@0
   155
snej@0
   156
- (NSString*) hexString
snej@0
   157
{
snej@0
   158
    const uint8_t *bytes = self.bytes;
snej@0
   159
    size_t length = self.length;
snej@0
   160
    char out[2*length+1];
snej@0
   161
    char *dst = &out[0];
snej@3
   162
    for( size_t i=0; i<length; i+=1 )
snej@0
   163
        dst += sprintf(dst,"%02X", bytes[i]);
snej@0
   164
    return [[[NSString alloc] initWithBytes: out length: 2*length encoding: NSASCIIStringEncoding]
snej@0
   165
            autorelease];
snej@0
   166
}
snej@0
   167
snej@0
   168
- (NSString*) abbreviatedHexString
snej@0
   169
{
snej@0
   170
    const uint8_t *bytes = self.bytes;
snej@0
   171
    return [NSString stringWithFormat: @"%02hhX%02hhX%02hhX%02hhX...",
snej@0
   172
            bytes[0],bytes[1],bytes[2],bytes[3]];
snej@0
   173
}
snej@0
   174
snej@0
   175
snej@0
   176
@end
snej@0
   177
snej@0
   178
snej@0
   179
snej@0
   180
@implementation MYSHA1Digest
snej@0
   181
snej@0
   182
+ (void) computeDigest: (void*)dstDigest ofBytes: (const void*)bytes length: (size_t)length {
snej@0
   183
    NSParameterAssert(bytes!=NULL);
snej@0
   184
    NSParameterAssert(length>0);
snej@0
   185
    CC_SHA1(bytes,length, dstDigest);
snej@0
   186
}
snej@0
   187
snej@0
   188
+ (uint32_t) algorithm            {return CSSM_ALGID_SHA1;}
snej@0
   189
+ (size_t) length               {return sizeof(RawSHA1Digest);}
snej@0
   190
snej@0
   191
- (MYSHA1Digest*) initWithRawSHA1Digest: (const RawSHA1Digest*)rawDigest {
snej@0
   192
    return [super initWithRawDigest: rawDigest length: sizeof(*rawDigest)];
snej@0
   193
}
snej@0
   194
snej@0
   195
+ (MYSHA1Digest*) digestFromRawSHA1Digest: (const RawSHA1Digest*)rawDigest {
snej@0
   196
    return [[[self alloc] initWithRawSHA1Digest: rawDigest] autorelease];
snej@0
   197
}
snej@0
   198
snej@0
   199
- (const RawSHA1Digest*) rawSHA1Digest {
snej@0
   200
    return self.bytes;
snej@0
   201
}
snej@0
   202
snej@0
   203
snej@0
   204
@end
snej@0
   205
snej@0
   206
snej@0
   207
snej@0
   208
@implementation MYSHA256Digest
snej@0
   209
snej@0
   210
+ (void) computeDigest: (void*)dstDigest ofBytes: (const void*)bytes length: (size_t)length {
snej@0
   211
    NSParameterAssert(bytes!=NULL);
snej@0
   212
    NSParameterAssert(length>0);
snej@0
   213
    CC_SHA256(bytes,length, dstDigest);
snej@0
   214
}
snej@0
   215
snej@0
   216
+ (uint32_t) algorithm            {return CSSM_ALGID_SHA256;}
snej@0
   217
+ (size_t) length               {return sizeof(RawSHA256Digest);}
snej@0
   218
snej@0
   219
- (MYSHA256Digest*) initWithRawSHA256Digest: (const RawSHA256Digest*)rawDigest {
snej@0
   220
    return [super initWithRawDigest: rawDigest length: sizeof(*rawDigest)];
snej@0
   221
}
snej@0
   222
snej@0
   223
+ (MYSHA256Digest*) digestFromRawSHA256Digest: (const RawSHA256Digest*)rawDigest {
snej@0
   224
    return [[[self alloc] initWithRawSHA256Digest: rawDigest] autorelease];
snej@0
   225
}
snej@0
   226
snej@0
   227
- (const RawSHA256Digest*) rawSHA256Digest {
snej@0
   228
    return self.bytes;
snej@0
   229
}
snej@0
   230
snej@0
   231
snej@0
   232
@end
snej@0
   233
snej@0
   234
snej@0
   235
snej@0
   236
@implementation NSData (MYDigest)
snej@0
   237
snej@0
   238
- (MYSHA1Digest*) my_SHA1Digest
snej@0
   239
{
snej@0
   240
    return (MYSHA1Digest*) [MYSHA1Digest digestOfData: self];
snej@0
   241
}
snej@0
   242
snej@0
   243
- (MYSHA256Digest*) my_SHA256Digest
snej@0
   244
{
snej@0
   245
    return (MYSHA256Digest*) [MYSHA256Digest digestOfData: self];
snej@0
   246
}
snej@0
   247
snej@0
   248
@end
snej@0
   249
snej@0
   250
snej@0
   251
snej@0
   252
#import "Test.h"
snej@0
   253
snej@0
   254
snej@0
   255
static void testDigestOf( NSData *src, NSString *expectedSHA1Hex, NSString *expectedSHA256Hex )
snej@0
   256
{
snej@0
   257
    MYSHA1Digest *d1 = [src my_SHA1Digest];
snej@0
   258
    NSString *hex = d1.hexString;
snej@0
   259
    Log(@"Digesting %u bytes to %@",src.length,hex);
snej@0
   260
    if( expectedSHA1Hex )
snej@0
   261
        CAssertEqual(hex,expectedSHA1Hex);
snej@0
   262
    MYSHA1Digest *d2 = (MYSHA1Digest*) [MYSHA1Digest digestFromHexString: hex];
snej@0
   263
    CAssertEqual(d1,d2);
snej@0
   264
    CAssertEqual(d2.hexString,hex);
snej@0
   265
snej@0
   266
    MYSHA256Digest *d256 = [src my_SHA256Digest];
snej@0
   267
    hex = d256.hexString;
snej@0
   268
    Log(@"Digesting %u bytes to %@",src.length,hex);
snej@0
   269
    if( expectedSHA256Hex )
snej@0
   270
        CAssertEqual(hex,expectedSHA256Hex);
snej@0
   271
    MYSHA256Digest *d256_2 = (MYSHA256Digest*) [MYSHA256Digest digestFromHexString: hex];
snej@0
   272
    CAssertEqual(d256,d256_2);
snej@0
   273
    CAssertEqual(d256_2.hexString,hex);
snej@0
   274
}
snej@0
   275
snej@0
   276
snej@0
   277
TestCase(MYDigest) {
snej@0
   278
    testDigestOf([@"Pack my box with five dozen liquor jugs, you ugly potatoe pie!" 
snej@0
   279
                          dataUsingEncoding: NSUTF8StringEncoding],
snej@0
   280
                 @"4F254781ED6C0103BE056DD8418EFBAC0C2EBE3C",
snej@0
   281
                 @"08AA4BCDDF7654D7AB5CDD25395A4DD8F3BEB5C79FE567D10C1A21B9134F48FD");
snej@0
   282
    testDigestOf([NSData dataWithContentsOfFile: @"/Library/Desktop Pictures/Nature/Zen Garden.jpg"],
snej@0
   283
                 @"62A17839B3B86D3543EB2E34D2718A0FE044FA31",
snej@0
   284
                 @"FBD25FA6CEE794049973DE3BDF752345617FCA81018C8FC65350BCDD901142DB");
snej@0
   285
}
snej@14
   286
snej@14
   287
snej@14
   288
snej@14
   289
/*
snej@14
   290
 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
snej@14
   291
 
snej@14
   292
 Redistribution and use in source and binary forms, with or without modification, are permitted
snej@14
   293
 provided that the following conditions are met:
snej@14
   294
 
snej@14
   295
 * Redistributions of source code must retain the above copyright notice, this list of conditions
snej@14
   296
 and the following disclaimer.
snej@14
   297
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
snej@14
   298
 and the following disclaimer in the documentation and/or other materials provided with the
snej@14
   299
 distribution.
snej@14
   300
 
snej@14
   301
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
snej@14
   302
 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
snej@14
   303
 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
snej@14
   304
 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
snej@14
   305
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
snej@14
   306
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
snej@14
   307
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
snej@14
   308
 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
snej@14
   309
 */