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
);
348 if (CFStringCompare(digestType
, kSecDigestHMACMD5
, 0) == kCFCompareEqualTo
)
350 mDigest
= new Hmac(this, digestType
, kCCHmacAlgMD5
, CC_MD5_DIGEST_LENGTH
);
352 else if (CFStringCompare(digestType
, kSecDigestHMACSHA1
, 0) == kCFCompareEqualTo
)
354 mDigest
= new Hmac(this, digestType
, kCCHmacAlgSHA1
, CC_SHA1_DIGEST_LENGTH
);
356 else if (CFStringCompare(digestType
, kSecDigestHMACSHA2
, 0) == kCFCompareEqualTo
)
362 mDigest
= new Hmac(this, digestType
, kCCHmacAlgSHA224
, CC_SHA224_DIGEST_LENGTH
);
368 mDigest
= new Hmac(this, digestType
, kCCHmacAlgSHA256
, CC_SHA256_DIGEST_LENGTH
);
374 mDigest
= new Hmac(this, digestType
, kCCHmacAlgSHA384
, CC_SHA384_DIGEST_LENGTH
);
381 mDigest
= new Hmac(this, digestType
, kCCHmacAlgSHA512
, CC_SHA512_DIGEST_LENGTH
);
387 CFErrorRef result
= CreateSecTransformErrorRef(kSecTransformErrorInvalidLength
, "%d is an invalid digest size (use 224, 256, 384, 512, or 0).", length
);
394 CFErrorRef result
= CreateSecTransformErrorRef(kSecTransformErrorInvalidAlgorithm
, "%@ is not a supported digest algorithm (use kSecDigestSHA2, kSecDigestMD2, kSecDigestMD5, kSecDigestSHA or kSecDigestSHA2", digestType
);
399 long lengthInt
= mDigest
->DigestLength();
400 CFNumberRef lengthNumber
= CFNumberCreate(NULL
, kCFNumberLongType
, &lengthInt
);
401 SendAttribute(kSecDigestLengthAttribute
, lengthNumber
);
402 CFRelease(lengthNumber
);
408 static CFStringRef gDigestTransformName
= CFSTR("SecDigestTransform");
410 CFTypeRef
DigestTransform::Make()
412 DigestTransform
* dt
= new DigestTransform();
413 return CoreFoundationHolder::MakeHolder(gDigestTransformName
, dt
);
418 DigestTransform::~DigestTransform()
428 void DigestTransform::AttributeChanged(CFStringRef name
, CFTypeRef value
)
430 if (CFStringCompare(name
, kSecTransformInputAttributeName
, 0) == kCFCompareEqualTo
)
434 // we are done, finalize the digest and send the result forward
435 const void* result
= mDigest
->Finalize();
438 CFDataRef resultRef
= CFDataCreate(NULL
, (UInt8
*) result
, mDigest
->DigestLength());
439 SendAttribute(kSecTransformOutputAttributeName
, resultRef
);
440 CFRelease(resultRef
);
443 SendAttribute(kSecTransformOutputAttributeName
, NULL
);
447 // if we got an error, just pass it on
448 CFTypeID valueType
= CFGetTypeID(value
);
449 if (valueType
== CFErrorGetTypeID())
451 SendAttribute(kSecTransformOutputAttributeName
, value
);
453 else if (valueType
!= CFDataGetTypeID())
455 CFStringRef idType
= CFCopyTypeIDDescription(valueType
);
456 CFErrorRef result
= CreateSecTransformErrorRef(kSecTransformErrorInvalidType
, "value is not a CFDataRef -- it's a %@ instead", idType
);
458 SetAttributeNoCallback(kSecTransformOutputAttributeName
, result
);
462 CFDataRef valueRef
= (CFDataRef
) value
;
463 mDigest
->Update(CFDataGetBytePtr(valueRef
), CFDataGetLength(valueRef
));
471 class DigestTransformFactory
: public TransformFactory
474 DigestTransformFactory();
475 virtual CFTypeRef
Make();
479 DigestTransformFactory::DigestTransformFactory() : TransformFactory(gDigestTransformName
, true)
485 CFTypeRef
DigestTransformFactory::Make()
487 return DigestTransform::Make();
492 TransformFactory
* DigestTransform::MakeTransformFactory()
494 return new DigestTransformFactory();
499 CFDictionaryRef
DigestTransform::CopyState()
501 return mDigest
->CopyState();
506 void DigestTransform::RestoreState(CFDictionaryRef state
)
513 // get the type and state from the dictionary
514 CFStringRef type
= (CFStringRef
) CFDictionaryGetValue(state
, kSecDigestTypeAttribute
);
515 CFNumberRef size
= (CFNumberRef
) CFDictionaryGetValue(state
, kSecDigestLengthAttribute
);
517 CFNumberGetValue(size
, kCFNumberCFIndexType
, &realSize
);
519 Setup(type
, realSize
);
524 CFTypeID
DigestTransform::GetCFTypeID()
526 return CoreFoundationObject::FindObjectType(gDigestTransformName
);
531 Hmac::Hmac(Transform
* parentTransform
, CFStringRef digestType
, CCHmacAlgorithm alg
, size_t length
) :
532 Digest(digestType
, length
), mInitialized(false), mParentTransform(parentTransform
), mAlg(alg
)
545 void Hmac::Initialize()
548 const UInt8
* data
= NULL
;
549 size_t dataLength
= 0;
551 CFDataRef key
= (CFDataRef
) mParentTransform
->GetAttribute(kSecDigestHMACKeyAttribute
);
554 data
= CFDataGetBytePtr(key
);
555 dataLength
= CFDataGetLength(key
);
558 CCHmacInit(&mHMACContext
, mAlg
, data
, dataLength
);
560 // make room to hold the result
561 mDigestBuffer
= (UInt8
*) malloc(mDigestLength
);
568 void Hmac::Update(const void* buffer
, size_t length
)
575 CCHmacUpdate(&mHMACContext
, buffer
, length
);
580 size_t Hmac::DigestLength()
582 return mDigestLength
;
587 const void* Hmac::Finalize()
589 CCHmacFinal(&mHMACContext
, mDigestBuffer
);
590 return mDigestBuffer
;