2 * Copyright (c) 2017 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 #import <CommonCrypto/CommonDigest.h>
28 @interface TPHashBuilder ()
30 @property (nonatomic, assign) TPHashAlgo algo;
31 @property (nonatomic, assign) CC_SHA256_CTX ctxSHA256; // used by SHA224 and SHA256
32 @property (nonatomic, assign) CC_SHA512_CTX ctxSHA512; // used by SHA384 and SHA512
36 @implementation TPHashBuilder
38 + (TPHashAlgo)algoOfHash:(NSString *)hash
40 if ([hash hasPrefix:@"SHA224:"]) {
41 return kTPHashAlgoSHA224;
43 if ([hash hasPrefix:@"SHA256:"]) {
44 return kTPHashAlgoSHA256;
46 if ([hash hasPrefix:@"SHA384:"]) {
47 return kTPHashAlgoSHA384;
49 if ([hash hasPrefix:@"SHA512:"]) {
50 return kTPHashAlgoSHA512;
52 return kTPHashAlgoUnknown;
59 _algo = kTPHashAlgoUnknown;
64 - (instancetype)initWithAlgo:(TPHashAlgo)algo
67 [self resetWithAlgo:algo];
71 - (void)resetWithAlgo:(TPHashAlgo)algo
75 case kTPHashAlgoSHA224:
76 CC_SHA224_Init(&_ctxSHA256);
78 case kTPHashAlgoSHA256:
79 CC_SHA256_Init(&_ctxSHA256);
81 case kTPHashAlgoSHA384:
82 CC_SHA384_Init(&_ctxSHA512);
84 case kTPHashAlgoSHA512:
85 CC_SHA512_Init(&_ctxSHA512);
88 [self throwInvalidAlgo];
92 - (void)updateWithData:(NSData *)data
94 [self updateWithBytes:data.bytes len:data.length];
97 - (void)updateWithBytes:(const void *)data len:(size_t)len
100 case kTPHashAlgoSHA224:
101 CC_SHA224_Update(&_ctxSHA256, data, (CC_LONG)len);
103 case kTPHashAlgoSHA256:
104 CC_SHA256_Update(&_ctxSHA256, data, (CC_LONG)len);
106 case kTPHashAlgoSHA384:
107 CC_SHA384_Update(&_ctxSHA512, data, (CC_LONG)len);
109 case kTPHashAlgoSHA512:
110 CC_SHA512_Update(&_ctxSHA512, data, (CC_LONG)len);
113 [self throwInvalidAlgo];
117 - (NSString *)finalHash
119 NSMutableData* data = [NSMutableData alloc];
120 NSString* name = nil;
122 case kTPHashAlgoSHA224:
123 data = [data initWithLength:224/8];
124 CC_SHA224_Final(data.mutableBytes, &_ctxSHA256);
127 case kTPHashAlgoSHA256:
128 data = [data initWithLength:256/8];
129 CC_SHA256_Final(data.mutableBytes, &_ctxSHA256);
132 case kTPHashAlgoSHA384:
133 data = [data initWithLength:384/8];
134 CC_SHA384_Final(data.mutableBytes, &_ctxSHA512);
137 case kTPHashAlgoSHA512:
138 data = [data initWithLength:512/8];
139 CC_SHA512_Final(data.mutableBytes, &_ctxSHA512);
143 [self throwInvalidAlgo];
145 NSString* hash = [NSString stringWithFormat:@"%@:%@",
146 name, [data base64EncodedStringWithOptions:0]];
148 // _ctxSHA* was "emptied" by the call to CC_SHA*_Final,
149 // so require the client to call resetWithAlgo: before reuse.
150 self.algo = kTPHashAlgoUnknown;
155 - (void)throwInvalidAlgo
157 NSException* ex = [NSException exceptionWithName:@"InvalidTPHashAlgo"
158 reason:@"Invalid TPHash algorithm"
163 + (NSString *)hashWithAlgo:(TPHashAlgo)algo ofData:(NSData *)data
165 return [TPHashBuilder hashWithAlgo:algo ofBytes:data.bytes len:data.length];
168 + (NSString *)hashWithAlgo:(TPHashAlgo)algo ofBytes:(const void *)data len:(size_t)len
170 TPHashBuilder *builder = [[TPHashBuilder alloc] initWithAlgo:algo];
171 [builder updateWithBytes:data len:len];
172 return [builder finalHash];