3 // libsecurity_libSecOTR
5 // Created by Mitch Adler on 3/2/11.
6 // Copyright 2011 Apple Inc. All rights reserved.
8 #include "SecOTRDHKey.h"
9 #include <utilities/SecCFWrappers.h>
11 #include "SecOTRMath.h"
12 #include "SecOTRPacketData.h"
14 #include <corecrypto/ccn.h>
15 #include <corecrypto/ccsha1.h>
16 #include <corecrypto/ccec_priv.h>
17 #include <corecrypto/ccec.h>
19 #include <CommonCrypto/CommonRandomSPI.h>
21 #ifdef USECOMMONCRYPTO
22 #include <CommonCrypto/CommonDigest.h>
25 #define kECKeySize 256
27 struct _SecOTRFullDHKey
{
30 ccec_full_ctx_decl(ccn_sizeof(kECKeySize
), _key
);
31 uint8_t keyHash
[CCSHA1_OUTPUT_SIZE
];
35 CFGiblisFor(SecOTRFullDHKey
);
37 static size_t AppendECPublicKeyAsDATA(CFMutableDataRef data
, ccec_pub_ctx_t public_key
)
39 size_t size
= ccec_export_pub_size(public_key
);
41 AppendLong(data
, (uint32_t)size
); /* cast: no overflow, pub size always fit in 32 bits */
42 ccec_export_pub(public_key
, CFDataIncreaseLengthAndGetMutableBytes(data
, (CFIndex
)size
));
48 static CF_RETURNS_RETAINED CFStringRef
SecOTRFullDHKeyCopyDescription(CFTypeRef cf
)
50 SecOTRFullDHKeyRef session
= (SecOTRFullDHKeyRef
)cf
;
51 return CFStringCreateWithFormat(kCFAllocatorDefault
,NULL
,CFSTR("<SecOTRFullDHKeyRef: %p>"), session
);
54 static void SecOTRFullDHKeyDestroy(CFTypeRef cf
)
56 SecOTRFullDHKeyRef fullKey
= (SecOTRFullDHKeyRef
)cf
;
58 bzero(fullKey
->_key
, sizeof(fullKey
->_key
));
61 SecOTRFullDHKeyRef
SecOTRFullDHKCreate(CFAllocatorRef allocator
)
63 SecOTRFullDHKeyRef newFDHK
= CFTypeAllocate(SecOTRFullDHKey
, struct _SecOTRFullDHKey
, allocator
);
65 SecFDHKNewKey(newFDHK
);
70 SecOTRFullDHKeyRef
SecOTRFullDHKCreateFromBytes(CFAllocatorRef allocator
, const uint8_t**bytes
, size_t*size
)
72 SecOTRFullDHKeyRef newFDHK
= CFTypeAllocate(SecOTRFullDHKey
, struct _SecOTRFullDHKey
, allocator
);
74 ccec_ctx_init(ccec_cp_256(), newFDHK
->_key
);
76 uint32_t publicKeySize
;
77 require_noerr(ReadLong(bytes
, size
, &publicKeySize
), fail
);
79 require(publicKeySize
<= *size
, fail
);
80 require_noerr(ccec_import_pub(ccec_cp_256(), publicKeySize
, *bytes
, newFDHK
->_key
), fail
);
81 ccdigest(ccsha1_di(), publicKeySize
, *bytes
, newFDHK
->keyHash
);
83 *size
-= publicKeySize
;
84 *bytes
+= publicKeySize
;
86 require_noerr(ReadMPI(bytes
, size
, ccec_ctx_n(newFDHK
->_key
), ccec_ctx_k(newFDHK
->_key
)), fail
);
91 CFReleaseNull(newFDHK
);
95 void SecFDHKNewKey(SecOTRFullDHKeyRef fullKey
)
97 struct ccrng_state
*rng
=ccDRBGGetRngState();
99 #if defined(CCECDH_AVAILABLE)
100 ccecdh_generate_key(ccec_cp_256(), rng
, fullKey
->_key
);
102 ccec_generate_key(ccec_cp_256(), rng
, fullKey
->_key
);
105 size_t size
= ccec_export_pub_size(fullKey
->_key
);
106 uint8_t publicKey
[size
];
108 ccec_export_pub(fullKey
->_key
, publicKey
);
109 ccdigest(ccsha1_di(), size
, publicKey
, fullKey
->keyHash
);
112 void SecFDHKAppendSerialization(SecOTRFullDHKeyRef fullKey
, CFMutableDataRef appendTo
)
114 AppendECPublicKeyAsDATA(appendTo
, fullKey
->_key
);
115 AppendMPI(appendTo
, ccec_ctx_n(fullKey
->_key
), ccec_ctx_k(fullKey
->_key
));
119 void SecFDHKAppendPublicSerialization(SecOTRFullDHKeyRef fullKey
, CFMutableDataRef appendTo
)
121 if(ccec_ctx_bitlen(fullKey
->_key
) != kECKeySize
) return;
122 AppendECPublicKeyAsDATA(appendTo
, fullKey
->_key
);
126 uint8_t* SecFDHKGetHash(SecOTRFullDHKeyRef fullKey
)
128 return fullKey
->keyHash
;
137 struct _SecOTRPublicDHKey
{
140 ccec_pub_ctx_decl(ccn_sizeof(kECKeySize
), _key
);
141 uint8_t keyHash
[CCSHA1_OUTPUT_SIZE
];
145 CFGiblisFor(SecOTRPublicDHKey
);
147 static CF_RETURNS_RETAINED CFStringRef
SecOTRPublicDHKeyCopyDescription(CFTypeRef cf
) {
148 SecOTRPublicDHKeyRef session
= (SecOTRPublicDHKeyRef
)cf
;
149 return CFStringCreateWithFormat(kCFAllocatorDefault
,NULL
,CFSTR("<SecOTRPublicDHKeyRef: %p>"), session
);
152 static void SecOTRPublicDHKeyDestroy(CFTypeRef cf
) {
153 SecOTRPublicDHKeyRef pubKey
= (SecOTRPublicDHKeyRef
)cf
;
157 static void ccec_copy_public(ccec_pub_ctx_t source
, ccec_pub_ctx_t dest
)
159 ccec_ctx_cp(dest
) = ccec_ctx_cp(source
);
161 ccn_set(3*ccec_ctx_n(source
), (cc_unit
*) ccec_ctx_point(dest
)._p
, (cc_unit
*) ccec_ctx_point(source
)._p
);
164 SecOTRPublicDHKeyRef
SecOTRPublicDHKCreateFromFullKey(CFAllocatorRef allocator
, SecOTRFullDHKeyRef full
)
166 SecOTRPublicDHKeyRef newPDHK
= CFTypeAllocate(SecOTRPublicDHKey
, struct _SecOTRPublicDHKey
, allocator
);
168 ccec_copy_public(full
->_key
, newPDHK
->_key
);
169 memcpy(newPDHK
->keyHash
, full
->keyHash
, CCSHA1_OUTPUT_SIZE
);
174 SecOTRPublicDHKeyRef
SecOTRPublicDHKCreateFromSerialization(CFAllocatorRef allocator
, const uint8_t** bytes
, size_t *size
)
176 SecOTRPublicDHKeyRef newPDHK
= CFTypeAllocate(SecOTRPublicDHKey
, struct _SecOTRPublicDHKey
, allocator
);
178 uint32_t publicKeySize
;
179 require_noerr(ReadLong(bytes
, size
, &publicKeySize
), fail
);
181 require(publicKeySize
<= *size
, fail
);
183 require_noerr(ccec_import_pub(ccec_cp_256(), publicKeySize
, *bytes
, newPDHK
->_key
), fail
);
184 ccdigest(ccsha1_di(), publicKeySize
, *bytes
, newPDHK
->keyHash
);
186 *size
-= publicKeySize
;
187 *bytes
+= publicKeySize
;
191 CFReleaseNull(newPDHK
);
195 SecOTRPublicDHKeyRef
SecOTRPublicDHKCreateFromBytes(CFAllocatorRef allocator
, const uint8_t** bytes
, size_t *size
)
197 SecOTRPublicDHKeyRef newPDHK
= CFTypeAllocate(SecOTRPublicDHKey
, struct _SecOTRPublicDHKey
, allocator
);
199 require_noerr(ccec_import_pub(ccec_cp_256(), *size
, *bytes
, newPDHK
->_key
), fail
);
200 ccdigest(ccsha1_di(), *size
, *bytes
, newPDHK
->keyHash
);
204 CFReleaseNull(newPDHK
);
208 void SecPDHKAppendSerialization(SecOTRPublicDHKeyRef pubKey
, CFMutableDataRef appendTo
)
210 AppendECPublicKeyAsDATA(appendTo
, pubKey
->_key
);
214 uint8_t* SecPDHKGetHash(SecOTRPublicDHKeyRef pubKey
)
216 return pubKey
->keyHash
;
220 void SecPDHKeyGenerateS(SecOTRFullDHKeyRef myKey
, SecOTRPublicDHKeyRef theirKey
, cc_unit
* s
)
222 ccn_zero(kExponentiationUnits
, s
);
224 size_t keyLen
= ccn_sizeof_n(kExponentiationUnits
);
225 ccec_compute_key(myKey
->_key
, theirKey
->_key
, &keyLen
, (uint8_t*)s
);
228 static int ccec_cmp(ccec_pub_ctx_t l
, ccec_pub_ctx_t r
)
230 size_t lsize
= ccec_export_pub_size(l
);
231 size_t rsize
= ccec_export_pub_size(r
);
235 if (lsize
== rsize
) {
239 ccec_export_pub(l
, lpub
);
240 ccec_export_pub(r
, rpub
);
242 result
= memcmp(lpub
, rpub
, lsize
);
244 result
= rsize
< lsize
? -1 : 1;
250 bool SecDHKIsGreater(SecOTRFullDHKeyRef myKey
, SecOTRPublicDHKeyRef theirKey
)
252 return ccec_cmp(myKey
->_key
, theirKey
->_key
) > 0;
255 static void DeriveKeys(CFDataRef dataToHash
,
259 if (messageKey
== NULL
&& macKey
== NULL
)
262 uint8_t hashedSharedKey
[CCSHA1_OUTPUT_SIZE
];
264 #ifdef USECOMMONCRYPTO
265 (void) CCDigest(kCCDigestSHA1
, CFDataGetBytePtr(dataToHash
), (uint32_t)CFDataGetLength(dataToHash
), hashedSharedKey
);
267 ccdigest(ccsha1_di(), CFDataGetLength(dataToHash
), CFDataGetBytePtr(dataToHash
), hashedSharedKey
);
271 memcpy(messageKey
, hashedSharedKey
, kOTRMessageKeyBytes
);
274 #ifdef USECOMMONCRYPTO
275 (void) CCDigest(kCCDigestSHA1
, messageKey
, kOTRMessageKeyBytes
, macKey
);
277 ccdigest(ccsha1_di(), kOTRMessageKeyBytes
, messageKey
, macKey
);
281 bzero(hashedSharedKey
, sizeof(hashedSharedKey
));
284 void SecOTRDHKGenerateOTRKeys(SecOTRFullDHKeyRef myKey
, SecOTRPublicDHKeyRef theirKey
,
285 uint8_t* sendMessageKey
, uint8_t* sendMacKey
,
286 uint8_t* receiveMessageKey
, uint8_t* receiveMacKey
)
288 CFMutableDataRef dataToHash
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
291 cc_unit s
[kExponentiationUnits
];
293 SecPDHKeyGenerateS(myKey
, theirKey
, s
);
294 AppendByte(dataToHash
, SecDHKIsGreater(myKey
, theirKey
) ? 0x01 : 0x02);
295 AppendMPI(dataToHash
, kExponentiationUnits
, s
);
297 ccn_zero(kExponentiationUnits
, s
);
300 DeriveKeys(dataToHash
, receiveMessageKey
, receiveMacKey
);
302 uint8_t *messageTypeByte
= CFDataGetMutableBytePtr(dataToHash
);
304 *messageTypeByte
^= 0x03; // Invert the bits since it's either 1 or 2.
306 DeriveKeys(dataToHash
, sendMessageKey
, sendMacKey
);
308 CFReleaseNull(dataToHash
);