--- /dev/null
+//
+// SecOTRPackets.c
+// libsecurity_libSecOTR
+//
+// Created by Mitch Adler on 2/23/11.
+// Copyright 2011 Apple Inc. All rights reserved.
+//
+
+#include "SecOTRSessionPriv.h"
+#include "SecOTRPackets.h"
+
+#include "SecOTR.h"
+#include "SecOTRIdentityPriv.h"
+
+//*****************************************#include "SecCFWrappers.h"
+#include "SecOTRPacketData.h"
+#include "SecOTRDHKey.h"
+
+#ifdef USECOMMONCRYPTO
+#include <CommonCrypto/CommonHMAC.h>
+#endif
+
+#include <corecrypto/ccn.h>
+#include <corecrypto/ccdigest.h>
+
+#include <corecrypto/ccaes.h>
+#include <corecrypto/ccmode.h>
+#include <corecrypto/ccmode_factory.h>
+#include <corecrypto/cchmac.h>
+#include <corecrypto/ccsha2.h>
+
+//
+// Crypto functions
+//
+
+static inline void AppendSHA256HMAC(CFMutableDataRef appendTo,
+ size_t keybytes,
+ const uint8_t* key,
+ size_t howMuch,
+ const uint8_t* from)
+{
+ uint8_t *to = CFDataIncreaseLengthAndGetMutableBytes(appendTo, CCSHA256_OUTPUT_SIZE);
+
+#ifdef USECOMMONCRYPTO
+ CCHmac(kCCHmacAlgSHA256, key, keybytes, from, howMuch, to);
+#else
+ cchmac(ccsha256_di(), keybytes, key, howMuch, from, to);
+#endif
+}
+
+// First 160 bits of the HMAC
+static inline void AppendSHA256HMAC_160(CFMutableDataRef appendTo,
+ size_t keySize,
+ const uint8_t* key,
+ size_t howMuch,
+ const uint8_t* from)
+{
+ AppendSHA256HMAC(appendTo, keySize, key, howMuch, from);
+ const CFIndex bytesToRemove = CCSHA256_OUTPUT_SIZE - kSHA256HMAC160Bytes;
+ const CFRange rangeToDelete = CFRangeMake(CFDataGetLength(appendTo) - bytesToRemove, bytesToRemove);
+
+ CFDataDeleteBytes(appendTo, rangeToDelete);
+}
+
+static inline void DeriveAndAppendSHA256HMAC(CFMutableDataRef appendTo,
+ cc_size sN,
+ const cc_unit* s,
+ KeyType whichKey,
+ size_t howMuch,
+ const uint8_t* from)
+{
+ size_t localKeySize = CCSHA256_OUTPUT_SIZE;
+ uint8_t localKey[localKeySize];
+
+ DeriveOTR256BitsFromS(whichKey, sN, s, localKeySize, localKey);
+
+ AppendSHA256HMAC(appendTo, localKeySize, localKey, howMuch, from);
+
+ bzero(localKey, localKeySize);
+}
+
+static inline void DeriveAndAppendSHA256HMAC_160(CFMutableDataRef appendTo,
+ cc_size sN,
+ const cc_unit* s,
+ KeyType whichKey,
+ size_t howMuch,
+ const uint8_t* from)
+{
+ size_t localKeySize = CCSHA256_OUTPUT_SIZE;
+ uint8_t localKey[localKeySize];
+
+ DeriveOTR256BitsFromS(whichKey, sN, s, localKeySize, localKey);
+
+ AppendSHA256HMAC_160(appendTo, localKeySize, localKey, howMuch, from);
+
+ bzero(localKey, sizeof(localKey));
+}
+
+//
+// Message creators
+//
+
+void SecOTRAppendDHMessage(SecOTRSessionRef session,
+ CFMutableDataRef appendTo)
+{
+ //
+ // Message Type: kDHMessage (0x02)
+ // AES_CTR(r, 0) of G^X MPI
+ // SHA256(gxmpi)
+ //
+
+ if(!session) return;
+ CFMutableDataRef gxmpi = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ if(!gxmpi) return;
+
+ AppendHeader(appendTo, kDHMessage);
+
+ SecFDHKAppendPublicSerialization(session->_myKey, gxmpi);
+
+ size_t gxmpiSize = (size_t)CFDataGetLength(gxmpi);
+ if(gxmpiSize == 0) {
+ CFReleaseNull(gxmpi);
+ return;
+ }
+ const uint8_t* gxmpiLocation = CFDataGetBytePtr(gxmpi);
+
+ /* 64 bits cast: gxmpiSize is the size of the EC public key, which is hardcoded and never more than 2^32 bytes. */
+ assert(gxmpiSize<UINT32_MAX); /* debug check only */
+ AppendLong(appendTo, (uint32_t)gxmpiSize);
+ assert(gxmpiSize<INT32_MAX);
+ uint8_t* encGxmpiLocation = CFDataIncreaseLengthAndGetMutableBytes(appendTo, (CFIndex)gxmpiSize);
+ AES_CTR_IV0_Transform(sizeof(session->_r), session->_r, gxmpiSize, gxmpiLocation, encGxmpiLocation);
+
+ AppendLong(appendTo, CCSHA256_OUTPUT_SIZE);
+ uint8_t* hashLocation = CFDataIncreaseLengthAndGetMutableBytes(appendTo, CCSHA256_OUTPUT_SIZE);
+
+#ifdef USECOMMONCRYPTO
+ (void) CC_SHA256(gxmpiLocation, (uint32_t)gxmpiSize, hashLocation);
+#else
+ ccdigest(ccsha256_di(), gxmpiSize, gxmpiLocation, hashLocation);
+#endif
+ CFReleaseNull(gxmpi);
+}
+
+void SecOTRAppendDHKeyMessage(SecOTRSessionRef session,
+ CFMutableDataRef appendTo)
+{
+ //
+ // Message Type: kDHKeyMessage (0x0A)
+ // G^X Data MPI
+ //
+
+ AppendHeader(appendTo, kDHKeyMessage);
+ SecFDHKAppendPublicSerialization(session->_myKey, appendTo);
+}
+
+static uint8_t* AppendEncryptedSignature(SecOTRSessionRef session,
+ const cc_unit* s,
+ bool usePrime,
+ CFMutableDataRef appendTo)
+{
+ CFMutableDataRef signature = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ CFMutableDataRef mbData = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ CFMutableDataRef mb = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ SecFDHKAppendPublicSerialization(session->_myKey, mbData);
+ SecPDHKAppendSerialization(session->_theirKey, mbData);
+
+ CFIndex publicKeyOffset = CFDataGetLength(mbData);
+
+ SecOTRPublicIdentityRef myPublic = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, session->_me, NULL);
+ AppendPublicKey(mbData, myPublic);
+ CFReleaseNull(myPublic);
+
+ AppendLong(mbData, session->_keyID);
+
+ DeriveAndAppendSHA256HMAC(mb,
+ kExponentiationUnits, s,
+ usePrime ? kM1Prime : kM1,
+ (size_t)CFDataGetLength(mbData), CFDataGetBytePtr(mbData));
+
+ CFDataDeleteBytes(mbData, CFRangeMake(0, publicKeyOffset));
+
+ CFMutableDataRef xb = mbData; mbData = NULL;
+ SecOTRFIAppendSignature(session->_me, mb, signature, NULL);
+ CFReleaseNull(mb);
+
+ AppendCFDataAsDATA(xb, signature);
+ CFReleaseNull(signature);
+
+ CFIndex dataLength = CFDataGetLength(xb);
+
+ CFIndex signatureStartIndex = CFDataGetLength(appendTo);
+ /* 64 bits cast: We are appending the signature we just generated, which is never bigger than 2^32 bytes. */
+ assert(((unsigned long)dataLength)<=UINT32_MAX); /* debug check, correct as long as CFIndex is a signed long */
+ AppendLong(appendTo, (uint32_t)dataLength);
+ uint8_t *destination = CFDataIncreaseLengthAndGetMutableBytes(appendTo, dataLength);
+
+ uint8_t c[kOTRAuthKeyBytes];
+ DeriveOTR128BitPairFromS(kCs, kExponentiationUnits, s,
+ sizeof(c), usePrime ? NULL : c,
+ sizeof(c), usePrime ? c : NULL);
+
+ AES_CTR_IV0_Transform(sizeof(c), c,
+ (size_t)dataLength, CFDataGetBytePtr(xb),
+ destination);
+ bzero(c, sizeof(c));
+ CFReleaseNull(xb);
+
+ return CFDataGetMutableBytePtr(appendTo) + signatureStartIndex;
+}
+
+
+static void AppendMACedEncryptedSignature(SecOTRSessionRef session,
+ bool usePrime,
+ CFMutableDataRef appendTo)
+{
+
+ cc_unit s[kExponentiationUnits];
+
+ SecPDHKeyGenerateS(session->_myKey, session->_theirKey, s);
+
+ CFIndex signatureStartOffset = CFDataGetLength(appendTo);
+ const uint8_t *signatureStart = AppendEncryptedSignature(session, s, usePrime, appendTo);
+ size_t signatureSize = (size_t)CFDataGetLength(appendTo) - (size_t)signatureStartOffset;
+
+
+ DeriveAndAppendSHA256HMAC_160(appendTo,
+ kExponentiationUnits, s,
+ usePrime ? kM2Prime : kM2,
+ signatureSize, signatureStart);
+ bzero(s, sizeof(s));
+}
+
+
+void SecOTRAppendRevealSignatureMessage(SecOTRSessionRef session,
+ CFMutableDataRef appendTo)
+{
+ //
+ // Message Type: kRevealSignatureMessage (0x11)
+ // G^X Data MPI
+ //
+
+ AppendHeader(appendTo, kRevealSignatureMessage);
+
+ AppendLong(appendTo, kOTRAuthKeyBytes);
+ uint8_t* keyPosition = CFDataIncreaseLengthAndGetMutableBytes(appendTo, kOTRAuthKeyBytes);
+ memcpy(keyPosition, session->_r, kOTRAuthKeyBytes);
+
+ AppendMACedEncryptedSignature(session, false, appendTo);
+}
+
+void SecOTRAppendSignatureMessage(SecOTRSessionRef session,
+ CFMutableDataRef appendTo)
+{
+ //
+ // Message Type: kSignatureMessage (0x12)
+ // G^X Data MPI
+ //
+
+ AppendHeader(appendTo, kSignatureMessage);
+ AppendMACedEncryptedSignature(session, true, appendTo);
+}
+