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