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