]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
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 | CFRelease(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 | { | |
427c49bc | 58 | CC_MD2_Update(&mContext, buffer, (CC_LONG)length); |
b1ab9ed8 A |
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 | { | |
427c49bc | 87 | CC_MD4_Update(&mContext, buffer, (CC_LONG)length); |
b1ab9ed8 A |
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 | { | |
427c49bc | 119 | CC_MD5_Update(&mContext, buffer, (CC_LONG)length); |
b1ab9ed8 A |
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 | { | |
427c49bc | 148 | CC_SHA1_Update(&mContext, buffer, (CC_LONG)length); |
b1ab9ed8 A |
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 | { | |
427c49bc | 177 | CC_SHA256_Update(&mContext, buffer, (CC_LONG)length); |
b1ab9ed8 A |
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 | { | |
427c49bc | 206 | CC_SHA224_Update(&mContext, buffer, (CC_LONG)length); |
b1ab9ed8 A |
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 | { | |
427c49bc | 235 | CC_SHA512_Update(&mContext, buffer, (CC_LONG)length); |
b1ab9ed8 A |
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 | { | |
427c49bc | 264 | CC_SHA384_Update(&mContext, buffer, (CC_LONG)length); |
b1ab9ed8 A |
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 | 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 | ||
408 | static CFStringRef gDigestTransformName = CFSTR("SecDigestTransform"); | |
409 | ||
410 | CFTypeRef DigestTransform::Make() | |
411 | { | |
412 | DigestTransform* dt = new DigestTransform(); | |
413 | return CoreFoundationHolder::MakeHolder(gDigestTransformName, dt); | |
414 | } | |
415 | ||
416 | ||
417 | ||
418 | DigestTransform::~DigestTransform() | |
419 | { | |
420 | if (mDigest != NULL) | |
421 | { | |
422 | delete mDigest; | |
423 | } | |
424 | } | |
425 | ||
426 | ||
427 | ||
428 | void 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 | ||
471 | class DigestTransformFactory : public TransformFactory | |
472 | { | |
473 | public: | |
474 | DigestTransformFactory(); | |
475 | virtual CFTypeRef Make(); | |
476 | }; | |
477 | ||
478 | ||
479 | DigestTransformFactory::DigestTransformFactory() : TransformFactory(gDigestTransformName, true) | |
480 | { | |
481 | } | |
482 | ||
483 | ||
484 | ||
485 | CFTypeRef DigestTransformFactory::Make() | |
486 | { | |
487 | return DigestTransform::Make(); | |
488 | } | |
489 | ||
490 | ||
491 | ||
492 | TransformFactory* DigestTransform::MakeTransformFactory() | |
493 | { | |
494 | return new DigestTransformFactory(); | |
495 | } | |
496 | ||
497 | ||
498 | ||
499 | CFDictionaryRef DigestTransform::CopyState() | |
500 | { | |
501 | return mDigest->CopyState(); | |
502 | } | |
503 | ||
504 | ||
505 | ||
506 | void 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 | ||
524 | CFTypeID DigestTransform::GetCFTypeID() | |
525 | { | |
526 | return CoreFoundationObject::FindObjectType(gDigestTransformName); | |
527 | } | |
528 | ||
529 | ||
530 | ||
531 | Hmac::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 | ||
538 | Hmac::~Hmac() | |
539 | { | |
540 | free(mDigestBuffer); | |
541 | } | |
542 | ||
543 | ||
544 | ||
545 | void 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 | ||
568 | void 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 | ||
580 | size_t Hmac::DigestLength() | |
581 | { | |
582 | return mDigestLength; | |
583 | } | |
584 | ||
585 | ||
586 | ||
587 | const void* Hmac::Finalize() | |
588 | { | |
589 | CCHmacFinal(&mHMACContext, mDigestBuffer); | |
590 | return mDigestBuffer; | |
591 | } | |
592 |