]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_transform/lib/Digest.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_transform / lib / Digest.cpp
1 #include "Digest.h"
2 #include "SecDigestTransform.h"
3 #include "Utilities.h"
4
5 Digest::Digest(CFStringRef digestType, size_t digestLength) : mDigestType(digestType), mDigestLength(digestLength)
6 {
7 // we don't need to retain the type here because it's a constant
8 }
9
10
11
12 Digest::~Digest()
13 {
14 }
15
16 int Digest::LengthForType(CFStringRef type)
17 {
18 if (!CFStringCompare(kSecDigestSHA1, type, kCFCompareAnchored)) {
19 return CC_SHA1_DIGEST_LENGTH;
20 } else if (!CFStringCompare(kSecDigestSHA2, type, kCFCompareAnchored)) {
21 // XXX SHA2 comes in multiple length flavors, our buest guess is "the big one"
22 return CC_SHA256_DIGEST_LENGTH;
23 } else if (!CFStringCompare(kSecDigestMD2, type, kCFCompareAnchored)) {
24 return CC_MD2_DIGEST_LENGTH;
25 } else if (!CFStringCompare(kSecDigestMD4, type, kCFCompareAnchored)) {
26 return CC_MD4_DIGEST_LENGTH;
27 } else if (!CFStringCompare(kSecDigestMD5, type, kCFCompareAnchored)) {
28 return CC_MD5_DIGEST_LENGTH;
29 } else {
30 return transforms_assume(type == CFSTR("A supported digest type"));
31 }
32 }
33
34 CFDictionaryRef Digest::CopyState()
35 {
36 CFMutableDictionaryRef dr = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
37 CFDictionaryAddValue(dr, kSecDigestTypeAttribute, mDigestType);
38
39 CFIndex size = mDigestLength;
40 CFNumberRef nr = CFNumberCreate(NULL, kCFNumberCFIndexType, &size);
41 CFDictionaryAddValue(dr, kSecDigestLengthAttribute, nr);
42 CFReleaseNull(nr);
43
44 return dr;
45 }
46
47
48
49 MD2Digest::MD2Digest() : Digest(kSecDigestMD2, CC_MD2_DIGEST_LENGTH)
50 {
51 CC_MD2_Init(&mContext);
52 }
53
54
55
56 void MD2Digest::Update(const void* buffer, size_t length)
57 {
58 CC_MD2_Update(&mContext, buffer, (CC_LONG)length);
59 }
60
61
62
63 size_t MD2Digest::DigestLength()
64 {
65 return CC_MD2_DIGEST_LENGTH;
66 }
67
68
69
70 const void* MD2Digest::Finalize()
71 {
72 CC_MD2_Final(mDigestBuffer, &mContext);
73 return mDigestBuffer;
74 }
75
76
77
78 MD4Digest::MD4Digest() : Digest(kSecDigestMD4, CC_MD4_DIGEST_LENGTH)
79 {
80 CC_MD4_Init(&mContext);
81 }
82
83
84
85 void MD4Digest::Update(const void* buffer, size_t length)
86 {
87 CC_MD4_Update(&mContext, buffer, (CC_LONG)length);
88 }
89
90
91
92 size_t MD4Digest::DigestLength()
93 {
94 return CC_MD4_DIGEST_LENGTH;
95 }
96
97
98
99 const void* MD4Digest::Finalize()
100 {
101 CC_MD4_Final(mDigestBuffer, &mContext);
102 return mDigestBuffer;
103 }
104
105
106
107
108
109
110 MD5Digest::MD5Digest() : Digest(kSecDigestMD5, CC_MD5_DIGEST_LENGTH)
111 {
112 CC_MD5_Init(&mContext);
113 }
114
115
116
117 void MD5Digest::Update(const void* buffer, size_t length)
118 {
119 CC_MD5_Update(&mContext, buffer, (CC_LONG)length);
120 }
121
122
123
124 size_t MD5Digest::DigestLength()
125 {
126 return CC_MD5_DIGEST_LENGTH;
127 }
128
129
130
131 const void* MD5Digest::Finalize()
132 {
133 CC_MD5_Final(mDigestBuffer, &mContext);
134 return mDigestBuffer;
135 }
136
137
138
139 SHA1Digest::SHA1Digest() : Digest(kSecDigestSHA1, CC_SHA1_DIGEST_LENGTH)
140 {
141 CC_SHA1_Init(&mContext);
142 }
143
144
145
146 void SHA1Digest::Update(const void* buffer, size_t length)
147 {
148 CC_SHA1_Update(&mContext, buffer, (CC_LONG)length);
149 }
150
151
152
153 size_t SHA1Digest::DigestLength()
154 {
155 return CC_SHA1_DIGEST_LENGTH;
156 }
157
158
159
160 const void* SHA1Digest::Finalize()
161 {
162 CC_SHA1_Final(mDigestBuffer, &mContext);
163 return mDigestBuffer;
164 }
165
166
167
168 SHA256Digest::SHA256Digest() : Digest(kSecDigestSHA2, CC_SHA256_DIGEST_LENGTH)
169 {
170 CC_SHA256_Init(&mContext);
171 }
172
173
174
175 void SHA256Digest::Update(const void* buffer, size_t length)
176 {
177 CC_SHA256_Update(&mContext, buffer, (CC_LONG)length);
178 }
179
180
181
182 size_t SHA256Digest::DigestLength()
183 {
184 return CC_SHA256_DIGEST_LENGTH;
185 }
186
187
188
189 const void* SHA256Digest::Finalize()
190 {
191 CC_SHA256_Final(mDigestBuffer, &mContext);
192 return mDigestBuffer;
193 }
194
195
196
197 SHA224Digest::SHA224Digest() : Digest(kSecDigestSHA2, CC_SHA224_DIGEST_LENGTH)
198 {
199 CC_SHA224_Init(&mContext);
200 }
201
202
203
204 void SHA224Digest::Update(const void* buffer, size_t length)
205 {
206 CC_SHA224_Update(&mContext, buffer, (CC_LONG)length);
207 }
208
209
210
211 size_t SHA224Digest::DigestLength()
212 {
213 return CC_SHA224_DIGEST_LENGTH;
214 }
215
216
217
218 const void* SHA224Digest::Finalize()
219 {
220 CC_SHA224_Final(mDigestBuffer, &mContext);
221 return mDigestBuffer;
222 }
223
224
225
226 SHA512Digest::SHA512Digest() : Digest(kSecDigestSHA2, CC_SHA512_DIGEST_LENGTH)
227 {
228 CC_SHA512_Init(&mContext);
229 }
230
231
232
233 void SHA512Digest::Update(const void* buffer, size_t length)
234 {
235 CC_SHA512_Update(&mContext, buffer, (CC_LONG)length);
236 }
237
238
239
240 size_t SHA512Digest::DigestLength()
241 {
242 return CC_SHA512_DIGEST_LENGTH;
243 }
244
245
246
247 const void* SHA512Digest::Finalize()
248 {
249 CC_SHA512_Final(mDigestBuffer, &mContext);
250 return mDigestBuffer;
251 }
252
253
254
255 SHA384Digest::SHA384Digest() : Digest(kSecDigestSHA2, CC_SHA384_DIGEST_LENGTH)
256 {
257 CC_SHA384_Init(&mContext);
258 }
259
260
261
262 void SHA384Digest::Update(const void* buffer, size_t length)
263 {
264 CC_SHA384_Update(&mContext, buffer, (CC_LONG)length);
265 }
266
267
268
269 size_t SHA384Digest::DigestLength()
270 {
271 return CC_SHA384_DIGEST_LENGTH;
272 }
273
274
275
276 const void* SHA384Digest::Finalize()
277 {
278 CC_SHA384_Final(mDigestBuffer, &mContext);
279 return mDigestBuffer;
280 }
281
282
283
284 DigestTransform::DigestTransform() : Transform(CFSTR("Digest Transform"))
285 {
286 mDigest = NULL;
287 }
288
289
290 CFErrorRef DigestTransform::Setup(CFTypeRef dt, CFIndex length)
291 {
292 if (dt == NULL)
293 {
294 dt = kSecDigestSHA2;
295 length = 512;
296 }
297 transforms_assume_zero(mDigest);
298
299 CFStringRef digestType = (CFStringRef) dt;
300
301 // figure out what kind of digest is being requested
302 if (CFStringCompare(digestType, kSecDigestMD2, 0) == kCFCompareEqualTo)
303 {
304 mDigest = new MD2Digest();
305 }
306 else if (CFStringCompare(digestType, kSecDigestMD4, 0) == kCFCompareEqualTo)
307 {
308 mDigest = new MD4Digest();
309 }
310 else if (CFStringCompare(digestType, kSecDigestMD5, 0) == kCFCompareEqualTo)
311 {
312 mDigest = new MD5Digest();
313 }
314 else if (CFStringCompare(digestType, kSecDigestSHA1, 0) == kCFCompareEqualTo)
315 {
316 mDigest = new SHA1Digest();
317 }
318 else if (CFStringCompare(digestType, kSecDigestSHA2, 0) == kCFCompareEqualTo)
319 {
320 switch (length)
321 {
322 case 224:
323 mDigest = new SHA224Digest();
324 break;
325
326 case 256:
327 mDigest = new SHA256Digest();
328 break;
329
330 case 384:
331 mDigest = new SHA384Digest();
332 break;
333
334 case 0:
335 case 512:
336 mDigest = new SHA512Digest();
337 break;
338
339 default:
340 {
341 CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidLength, "%d is an invalid digest size (use 224, 256, 384, 512, or 0).", length);
342 CFAutorelease(result);
343 return result;
344 }
345 }
346 }
347 else
348 {
349 if (CFStringCompare(digestType, kSecDigestHMACMD5, 0) == kCFCompareEqualTo)
350 {
351 mDigest = new Hmac(this, digestType, kCCHmacAlgMD5, CC_MD5_DIGEST_LENGTH);
352 }
353 else if (CFStringCompare(digestType, kSecDigestHMACSHA1, 0) == kCFCompareEqualTo)
354 {
355 mDigest = new Hmac(this, digestType, kCCHmacAlgSHA1, CC_SHA1_DIGEST_LENGTH);
356 }
357 else if (CFStringCompare(digestType, kSecDigestHMACSHA2, 0) == kCFCompareEqualTo)
358 {
359 switch (length)
360 {
361 case 224:
362 {
363 mDigest = new Hmac(this, digestType, kCCHmacAlgSHA224, CC_SHA224_DIGEST_LENGTH);
364 }
365 break;
366
367 case 256:
368 {
369 mDigest = new Hmac(this, digestType, kCCHmacAlgSHA256, CC_SHA256_DIGEST_LENGTH);
370 }
371 break;
372
373 case 384:
374 {
375 mDigest = new Hmac(this, digestType, kCCHmacAlgSHA384, CC_SHA384_DIGEST_LENGTH);
376 }
377 break;
378
379 case 0:
380 case 512:
381 {
382 mDigest = new Hmac(this, digestType, kCCHmacAlgSHA512, CC_SHA512_DIGEST_LENGTH);
383 }
384 break;
385
386 default:
387 {
388 CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidLength, "%d is an invalid digest size (use 224, 256, 384, 512, or 0).", length);
389 CFAutorelease(result);
390 return result;
391 }
392 }
393 }
394 else
395 {
396 CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidAlgorithm, "%@ is not a supported digest algorithm (use kSecDigestSHA2, kSecDigestMD2, kSecDigestMD5, kSecDigestSHA or kSecDigestSHA2", digestType);
397 CFAutorelease(result);
398 return result;
399 }
400 }
401
402 long lengthInt = mDigest->DigestLength();
403 CFNumberRef lengthNumber = CFNumberCreate(NULL, kCFNumberLongType, &lengthInt);
404 SendAttribute(kSecDigestLengthAttribute, lengthNumber);
405 CFReleaseNull(lengthNumber);
406 return NULL;
407 }
408
409
410
411 static CFStringRef gDigestTransformName = CFSTR("SecDigestTransform");
412
413 CFTypeRef DigestTransform::Make() CF_RETURNS_RETAINED
414 {
415 DigestTransform* dt = new DigestTransform();
416 return CoreFoundationHolder::MakeHolder(gDigestTransformName, dt);
417 }
418
419
420
421 DigestTransform::~DigestTransform()
422 {
423 if (mDigest != NULL)
424 {
425 delete mDigest;
426 }
427 }
428
429
430
431 void DigestTransform::AttributeChanged(CFStringRef name, CFTypeRef value)
432 {
433 if (CFStringCompare(name, kSecTransformInputAttributeName, 0) == kCFCompareEqualTo)
434 {
435 if (value == NULL)
436 {
437 // we are done, finalize the digest and send the result forward
438 const void* result = mDigest->Finalize();
439
440 // send the result
441 CFDataRef resultRef = CFDataCreate(NULL, (UInt8*) result, mDigest->DigestLength());
442 SendAttribute(kSecTransformOutputAttributeName, resultRef);
443 CFReleaseNull(resultRef);
444
445 // send the EOS
446 SendAttribute(kSecTransformOutputAttributeName, NULL);
447 }
448 else
449 {
450 // if we got an error, just pass it on
451 CFTypeID valueType = CFGetTypeID(value);
452 if (valueType == CFErrorGetTypeID())
453 {
454 SendAttribute(kSecTransformOutputAttributeName, value);
455 }
456 else if (valueType != CFDataGetTypeID())
457 {
458 CFStringRef idType = CFCopyTypeIDDescription(valueType);
459 CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "value is not a CFDataRef -- it's a %@ instead", idType);
460 CFReleaseNull(idType);
461 SetAttributeNoCallback(kSecTransformOutputAttributeName, result);
462 }
463 else
464 {
465 CFDataRef valueRef = (CFDataRef) value;
466 mDigest->Update(CFDataGetBytePtr(valueRef), CFDataGetLength(valueRef));
467 }
468 }
469 }
470 }
471
472
473
474 class DigestTransformFactory : public TransformFactory
475 {
476 public:
477 DigestTransformFactory();
478 virtual CFTypeRef Make();
479 };
480
481
482 DigestTransformFactory::DigestTransformFactory() : TransformFactory(gDigestTransformName, true)
483 {
484 }
485
486
487
488 CFTypeRef DigestTransformFactory::Make()
489 {
490 return DigestTransform::Make();
491 }
492
493
494
495 TransformFactory* DigestTransform::MakeTransformFactory()
496 {
497 return new DigestTransformFactory();
498 }
499
500
501
502 CFDictionaryRef DigestTransform::CopyState()
503 {
504 return mDigest->CopyState();
505 }
506
507
508
509 void DigestTransform::RestoreState(CFDictionaryRef state)
510 {
511 if (mDigest != NULL)
512 {
513 delete mDigest;
514 }
515
516 // get the type and state from the dictionary
517 CFStringRef type = (CFStringRef) CFDictionaryGetValue(state, kSecDigestTypeAttribute);
518 CFNumberRef size = (CFNumberRef) CFDictionaryGetValue(state, kSecDigestLengthAttribute);
519 CFIndex realSize;
520 CFNumberGetValue(size, kCFNumberCFIndexType, &realSize);
521
522 Setup(type, realSize);
523 }
524
525
526
527 CFTypeID DigestTransform::GetCFTypeID()
528 {
529 return CoreFoundationObject::FindObjectType(gDigestTransformName);
530 }
531
532
533
534 Hmac::Hmac(Transform* parentTransform, CFStringRef digestType, CCHmacAlgorithm alg, size_t length) :
535 Digest(digestType, length), mInitialized(false), mParentTransform(parentTransform), mAlg(alg)
536 {
537 }
538
539
540
541 Hmac::~Hmac()
542 {
543 free(mDigestBuffer);
544 }
545
546
547
548 void Hmac::Initialize()
549 {
550 // initialize
551 const UInt8* data = NULL;
552 size_t dataLength = 0;
553
554 CFDataRef key = (CFDataRef) mParentTransform->GetAttribute(kSecDigestHMACKeyAttribute);
555 if (key)
556 {
557 data = CFDataGetBytePtr(key);
558 dataLength = CFDataGetLength(key);
559 }
560
561 CCHmacInit(&mHMACContext, mAlg, data, dataLength);
562
563 // make room to hold the result
564 mDigestBuffer = (UInt8*) malloc(mDigestLength);
565
566 mInitialized = true;
567 }
568
569
570
571 void Hmac::Update(const void* buffer, size_t length)
572 {
573 if (!mInitialized)
574 {
575 Initialize();
576 }
577
578 CCHmacUpdate(&mHMACContext, buffer, length);
579 }
580
581
582
583 size_t Hmac::DigestLength()
584 {
585 return mDigestLength;
586 }
587
588
589
590 const void* Hmac::Finalize()
591 {
592 CCHmacFinal(&mHMACContext, mDigestBuffer);
593 return mDigestBuffer;
594 }
595