2 #include "SecDigestTransform.h"
5 Digest::Digest(CFStringRef digestType
, size_t digestLength
) : mDigestType(digestType
), mDigestLength(digestLength
)
7 // we don't need to retain the type here because it's a constant
16 int Digest::LengthForType(CFStringRef type
)
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
;
30 return transforms_assume(type
== CFSTR("A supported digest type"));
34 CFDictionaryRef
Digest::CopyState()
36 CFMutableDictionaryRef dr
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
37 CFDictionaryAddValue(dr
, kSecDigestTypeAttribute
, mDigestType
);
39 CFIndex size
= mDigestLength
;
40 CFNumberRef nr
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &size
);
41 CFDictionaryAddValue(dr
, kSecDigestLengthAttribute
, nr
);
49 MD2Digest::MD2Digest() : Digest(kSecDigestMD2
, CC_MD2_DIGEST_LENGTH
)
51 CC_MD2_Init(&mContext
);
56 void MD2Digest::Update(const void* buffer
, size_t length
)
58 CC_MD2_Update(&mContext
, buffer
, (CC_LONG
)length
);
63 size_t MD2Digest::DigestLength()
65 return CC_MD2_DIGEST_LENGTH
;
70 const void* MD2Digest::Finalize()
72 CC_MD2_Final(mDigestBuffer
, &mContext
);
78 MD4Digest::MD4Digest() : Digest(kSecDigestMD4
, CC_MD4_DIGEST_LENGTH
)
80 CC_MD4_Init(&mContext
);
85 void MD4Digest::Update(const void* buffer
, size_t length
)
87 CC_MD4_Update(&mContext
, buffer
, (CC_LONG
)length
);
92 size_t MD4Digest::DigestLength()
94 return CC_MD4_DIGEST_LENGTH
;
99 const void* MD4Digest::Finalize()
101 CC_MD4_Final(mDigestBuffer
, &mContext
);
102 return mDigestBuffer
;
110 MD5Digest::MD5Digest() : Digest(kSecDigestMD5
, CC_MD5_DIGEST_LENGTH
)
112 CC_MD5_Init(&mContext
);
117 void MD5Digest::Update(const void* buffer
, size_t length
)
119 CC_MD5_Update(&mContext
, buffer
, (CC_LONG
)length
);
124 size_t MD5Digest::DigestLength()
126 return CC_MD5_DIGEST_LENGTH
;
131 const void* MD5Digest::Finalize()
133 CC_MD5_Final(mDigestBuffer
, &mContext
);
134 return mDigestBuffer
;
139 SHA1Digest::SHA1Digest() : Digest(kSecDigestSHA1
, CC_SHA1_DIGEST_LENGTH
)
141 CC_SHA1_Init(&mContext
);
146 void SHA1Digest::Update(const void* buffer
, size_t length
)
148 CC_SHA1_Update(&mContext
, buffer
, (CC_LONG
)length
);
153 size_t SHA1Digest::DigestLength()
155 return CC_SHA1_DIGEST_LENGTH
;
160 const void* SHA1Digest::Finalize()
162 CC_SHA1_Final(mDigestBuffer
, &mContext
);
163 return mDigestBuffer
;
168 SHA256Digest::SHA256Digest() : Digest(kSecDigestSHA2
, CC_SHA256_DIGEST_LENGTH
)
170 CC_SHA256_Init(&mContext
);
175 void SHA256Digest::Update(const void* buffer
, size_t length
)
177 CC_SHA256_Update(&mContext
, buffer
, (CC_LONG
)length
);
182 size_t SHA256Digest::DigestLength()
184 return CC_SHA256_DIGEST_LENGTH
;
189 const void* SHA256Digest::Finalize()
191 CC_SHA256_Final(mDigestBuffer
, &mContext
);
192 return mDigestBuffer
;
197 SHA224Digest::SHA224Digest() : Digest(kSecDigestSHA2
, CC_SHA224_DIGEST_LENGTH
)
199 CC_SHA224_Init(&mContext
);
204 void SHA224Digest::Update(const void* buffer
, size_t length
)
206 CC_SHA224_Update(&mContext
, buffer
, (CC_LONG
)length
);
211 size_t SHA224Digest::DigestLength()
213 return CC_SHA224_DIGEST_LENGTH
;
218 const void* SHA224Digest::Finalize()
220 CC_SHA224_Final(mDigestBuffer
, &mContext
);
221 return mDigestBuffer
;
226 SHA512Digest::SHA512Digest() : Digest(kSecDigestSHA2
, CC_SHA512_DIGEST_LENGTH
)
228 CC_SHA512_Init(&mContext
);
233 void SHA512Digest::Update(const void* buffer
, size_t length
)
235 CC_SHA512_Update(&mContext
, buffer
, (CC_LONG
)length
);
240 size_t SHA512Digest::DigestLength()
242 return CC_SHA512_DIGEST_LENGTH
;
247 const void* SHA512Digest::Finalize()
249 CC_SHA512_Final(mDigestBuffer
, &mContext
);
250 return mDigestBuffer
;
255 SHA384Digest::SHA384Digest() : Digest(kSecDigestSHA2
, CC_SHA384_DIGEST_LENGTH
)
257 CC_SHA384_Init(&mContext
);
262 void SHA384Digest::Update(const void* buffer
, size_t length
)
264 CC_SHA384_Update(&mContext
, buffer
, (CC_LONG
)length
);
269 size_t SHA384Digest::DigestLength()
271 return CC_SHA384_DIGEST_LENGTH
;
276 const void* SHA384Digest::Finalize()
278 CC_SHA384_Final(mDigestBuffer
, &mContext
);
279 return mDigestBuffer
;
284 DigestTransform::DigestTransform() : Transform(CFSTR("Digest Transform"))
290 CFErrorRef
DigestTransform::Setup(CFTypeRef dt
, CFIndex length
)
297 transforms_assume_zero(mDigest
);
299 CFStringRef digestType
= (CFStringRef
) dt
;
301 // figure out what kind of digest is being requested
302 if (CFStringCompare(digestType
, kSecDigestMD2
, 0) == kCFCompareEqualTo
)
304 mDigest
= new MD2Digest();
306 else if (CFStringCompare(digestType
, kSecDigestMD4
, 0) == kCFCompareEqualTo
)
308 mDigest
= new MD4Digest();
310 else if (CFStringCompare(digestType
, kSecDigestMD5
, 0) == kCFCompareEqualTo
)
312 mDigest
= new MD5Digest();
314 else if (CFStringCompare(digestType
, kSecDigestSHA1
, 0) == kCFCompareEqualTo
)
316 mDigest
= new SHA1Digest();
318 else if (CFStringCompare(digestType
, kSecDigestSHA2
, 0) == kCFCompareEqualTo
)
323 mDigest
= new SHA224Digest();
327 mDigest
= new SHA256Digest();
331 mDigest
= new SHA384Digest();
336 mDigest
= new SHA512Digest();
341 CFErrorRef result
= CreateSecTransformErrorRef(kSecTransformErrorInvalidLength
, "%d is an invalid digest size (use 224, 256, 384, 512, or 0).", length
);
342 CFAutorelease(result
);
349 if (CFStringCompare(digestType
, kSecDigestHMACMD5
, 0) == kCFCompareEqualTo
)
351 mDigest
= new Hmac(this, digestType
, kCCHmacAlgMD5
, CC_MD5_DIGEST_LENGTH
);
353 else if (CFStringCompare(digestType
, kSecDigestHMACSHA1
, 0) == kCFCompareEqualTo
)
355 mDigest
= new Hmac(this, digestType
, kCCHmacAlgSHA1
, CC_SHA1_DIGEST_LENGTH
);
357 else if (CFStringCompare(digestType
, kSecDigestHMACSHA2
, 0) == kCFCompareEqualTo
)
363 mDigest
= new Hmac(this, digestType
, kCCHmacAlgSHA224
, CC_SHA224_DIGEST_LENGTH
);
369 mDigest
= new Hmac(this, digestType
, kCCHmacAlgSHA256
, CC_SHA256_DIGEST_LENGTH
);
375 mDigest
= new Hmac(this, digestType
, kCCHmacAlgSHA384
, CC_SHA384_DIGEST_LENGTH
);
382 mDigest
= new Hmac(this, digestType
, kCCHmacAlgSHA512
, CC_SHA512_DIGEST_LENGTH
);
388 CFErrorRef result
= CreateSecTransformErrorRef(kSecTransformErrorInvalidLength
, "%d is an invalid digest size (use 224, 256, 384, 512, or 0).", length
);
389 CFAutorelease(result
);
396 CFErrorRef result
= CreateSecTransformErrorRef(kSecTransformErrorInvalidAlgorithm
, "%@ is not a supported digest algorithm (use kSecDigestSHA2, kSecDigestMD2, kSecDigestMD5, kSecDigestSHA or kSecDigestSHA2", digestType
);
397 CFAutorelease(result
);
402 long lengthInt
= mDigest
->DigestLength();
403 CFNumberRef lengthNumber
= CFNumberCreate(NULL
, kCFNumberLongType
, &lengthInt
);
404 SendAttribute(kSecDigestLengthAttribute
, lengthNumber
);
405 CFReleaseNull(lengthNumber
);
411 static CFStringRef gDigestTransformName
= CFSTR("SecDigestTransform");
413 CFTypeRef
DigestTransform::Make() CF_RETURNS_RETAINED
415 DigestTransform
* dt
= new DigestTransform();
416 return CoreFoundationHolder::MakeHolder(gDigestTransformName
, dt
);
421 DigestTransform::~DigestTransform()
431 void DigestTransform::AttributeChanged(CFStringRef name
, CFTypeRef value
)
433 if (CFStringCompare(name
, kSecTransformInputAttributeName
, 0) == kCFCompareEqualTo
)
437 // we are done, finalize the digest and send the result forward
438 const void* result
= mDigest
->Finalize();
441 CFDataRef resultRef
= CFDataCreate(NULL
, (UInt8
*) result
, mDigest
->DigestLength());
442 SendAttribute(kSecTransformOutputAttributeName
, resultRef
);
443 CFReleaseNull(resultRef
);
446 SendAttribute(kSecTransformOutputAttributeName
, NULL
);
450 // if we got an error, just pass it on
451 CFTypeID valueType
= CFGetTypeID(value
);
452 if (valueType
== CFErrorGetTypeID())
454 SendAttribute(kSecTransformOutputAttributeName
, value
);
456 else if (valueType
!= CFDataGetTypeID())
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
);
465 CFDataRef valueRef
= (CFDataRef
) value
;
466 mDigest
->Update(CFDataGetBytePtr(valueRef
), CFDataGetLength(valueRef
));
474 class DigestTransformFactory
: public TransformFactory
477 DigestTransformFactory();
478 virtual CFTypeRef
Make();
482 DigestTransformFactory::DigestTransformFactory() : TransformFactory(gDigestTransformName
, true)
488 CFTypeRef
DigestTransformFactory::Make()
490 return DigestTransform::Make();
495 TransformFactory
* DigestTransform::MakeTransformFactory()
497 return new DigestTransformFactory();
502 CFDictionaryRef
DigestTransform::CopyState()
504 return mDigest
->CopyState();
509 void DigestTransform::RestoreState(CFDictionaryRef state
)
516 // get the type and state from the dictionary
517 CFStringRef type
= (CFStringRef
) CFDictionaryGetValue(state
, kSecDigestTypeAttribute
);
518 CFNumberRef size
= (CFNumberRef
) CFDictionaryGetValue(state
, kSecDigestLengthAttribute
);
520 CFNumberGetValue(size
, kCFNumberCFIndexType
, &realSize
);
522 Setup(type
, realSize
);
527 CFTypeID
DigestTransform::GetCFTypeID()
529 return CoreFoundationObject::FindObjectType(gDigestTransformName
);
534 Hmac::Hmac(Transform
* parentTransform
, CFStringRef digestType
, CCHmacAlgorithm alg
, size_t length
) :
535 Digest(digestType
, length
), mInitialized(false), mParentTransform(parentTransform
), mAlg(alg
)
548 void Hmac::Initialize()
551 const UInt8
* data
= NULL
;
552 size_t dataLength
= 0;
554 CFDataRef key
= (CFDataRef
) mParentTransform
->GetAttribute(kSecDigestHMACKeyAttribute
);
557 data
= CFDataGetBytePtr(key
);
558 dataLength
= CFDataGetLength(key
);
561 CCHmacInit(&mHMACContext
, mAlg
, data
, dataLength
);
563 // make room to hold the result
564 mDigestBuffer
= (UInt8
*) malloc(mDigestLength
);
571 void Hmac::Update(const void* buffer
, size_t length
)
578 CCHmacUpdate(&mHMACContext
, buffer
, length
);
583 size_t Hmac::DigestLength()
585 return mDigestLength
;
590 const void* Hmac::Finalize()
592 CCHmacFinal(&mHMACContext
, mDigestBuffer
);
593 return mDigestBuffer
;