1/* 2 * Copyright (c) 2011-2012,2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25#include "SecOTRMath.h" 26 27#include "SecOTRPacketData.h" 28 29#include <AssertMacros.h> 30 31#include <pthread.h> 32 33#include <Security/SecRandom.h> 34 35#include <corecrypto/ccsha2.h> 36#include <corecrypto/cczp.h> 37#include <corecrypto/ccdh_gp.h> 38 39#include <limits.h> 40 41void OTRExponentiate(cc_unit* res, const cc_unit* base, const cc_unit* exponent) 42{ 43 ccdh_const_gp_t gp = ccdh_gp_rfc3526group05(); 44 cczp_power(gp.zp, res, base, exponent); 45} 46 47void OTRGroupExponentiate(cc_unit* res, const cc_unit* exponent) 48{ 49 OTRExponentiate(res, ccdh_gp_g(ccdh_gp_rfc3526group05()) , exponent); 50} 51 52// 53// Random Number Generation 54// 55 56OSStatus GetRandomBytesInLSBs(size_t bytesOfRandomness, size_t n, cc_unit* place) 57{ 58 OSStatus result = errSecParam; 59 require(bytesOfRandomness * 8 <= ccn_bitsof_n(n), fail); 60 { 61 uint8_t randomBytes[bytesOfRandomness]; 62 63 result = SecRandomCopyBytes(kSecRandomDefault, sizeof(randomBytes), randomBytes); 64 65 require_noerr(result, fail); 66 67 ccn_read_uint(n, place, sizeof(randomBytes), randomBytes); 68 69 bzero(randomBytes, bytesOfRandomness); 70 } 71fail: 72 return result; 73} 74 75OSStatus FillWithRandomBytes(size_t n, cc_unit* place) 76{ 77 return GetRandomBytesInLSBs(ccn_sizeof(n), n, place); 78} 79 80 81static const uint8_t kIVZero[16] = { }; 82 83static void AES_CTR_Transform(size_t keySize, const uint8_t* key, 84 const uint8_t iv[16], 85 size_t howMuch, const uint8_t* from, uint8_t* to) 86{ 87 const struct ccmode_ctr* ctr_encrypt = ccaes_ctr_crypt_mode(); 88 ccctr_ctx_decl(ctr_encrypt->size, ctr_ctx); 89 ctr_encrypt->init(ctr_encrypt, ctr_ctx, keySize, key, iv); 90 91 ctr_encrypt->ctr(ctr_ctx, howMuch, from, to); 92} 93 94void AES_CTR_HighHalf_Transform(size_t keySize, const uint8_t* key, 95 uint64_t highHalf, 96 size_t howMuch, const uint8_t* from, uint8_t* to) 97{ 98 uint8_t iv[16] = { highHalf >> 56, highHalf >> 48, highHalf >> 40, highHalf >> 32, 99 highHalf >> 24, highHalf >> 16, highHalf >> 8 , highHalf >> 0, 100 0, 0, 0, 0, 101 0, 0, 0, 0 }; 102 AES_CTR_Transform(keySize, key, iv, howMuch, from, to); 103} 104 105void AES_CTR_IV0_Transform(size_t keySize, const uint8_t* key, 106 size_t howMuch, const uint8_t* from, uint8_t* to) 107{ 108 AES_CTR_Transform(keySize, key, kIVZero, howMuch, from, to); 109} 110 111 112// 113// Key Derivation 114// 115 116static void HashMPIWithPrefix(uint8_t byte, cc_size sN, const cc_unit* s, uint8_t* buffer) 117{ 118 CFMutableDataRef dataToHash = CFDataCreateMutable(kCFAllocatorDefault, 0); 119 CFDataAppendBytes(dataToHash, &byte, 1); 120 121 AppendMPI(dataToHash, sN, s); 122 123 uint8_t *bytesToHash = CFDataGetMutableBytePtr(dataToHash); 124 CFIndex amountToHash = CFDataGetLength(dataToHash); 125 126 /* 64 bits cast: amountToHash is the size of an identity +1 , which is currently hardcoded and never more than 2^32 bytes */ 127 assert((unsigned long)amountToHash<UINT32_MAX); /* Debug check, Correct as long as CFIndex is a signed long and CC_LONG is a uint32_t */ 128 129 (void) CC_SHA256(bytesToHash, (CC_LONG)amountToHash, buffer); 130 131 bzero(bytesToHash, (size_t)amountToHash); 132 CFReleaseNull(dataToHash); 133} 134 135void DeriveOTR256BitsFromS(KeyType whichKey, cc_size sN, const cc_unit* s, size_t keySize, uint8_t* key) 136{ 137 HashMPIWithPrefix(whichKey, sN, s, key); 138} 139 140void DeriveOTR128BitPairFromS(KeyType whichKey, size_t sSize, const cc_unit* s, 141 size_t firstKeySize, uint8_t* firstKey, 142 size_t secondKeySize, uint8_t* secondKey) 143{ 144 uint8_t hashBuffer[CCSHA256_OUTPUT_SIZE]; 145 146 HashMPIWithPrefix(whichKey, sSize, s, hashBuffer); 147 148 if (firstKey) { 149 firstKeySize = firstKeySize > CCSHA256_OUTPUT_SIZE/2 ? CCSHA256_OUTPUT_SIZE/2 : firstKeySize; 150 memcpy(firstKey, hashBuffer, firstKeySize); 151 } 152 if (secondKey) { 153 secondKeySize = secondKeySize > CCSHA256_OUTPUT_SIZE/2 ? CCSHA256_OUTPUT_SIZE/2 : secondKeySize; 154 memcpy(secondKey, hashBuffer, secondKeySize); 155 } 156 157 bzero(hashBuffer, CCSHA256_OUTPUT_SIZE); 158 159} 160 161void DeriveOTR64BitsFromS(KeyType whichKey, size_t sn, const cc_unit* s, 162 size_t topKeySize, uint8_t* topKey) 163{ 164 uint8_t hashBuffer[CCSHA256_OUTPUT_SIZE]; 165 166 HashMPIWithPrefix(whichKey, sn, s, hashBuffer); 167 168 topKeySize = topKeySize > CCSHA256_OUTPUT_SIZE/2 ? CCSHA256_OUTPUT_SIZE/2 : topKeySize; 169 memcpy(topKey, hashBuffer, topKeySize); 170 171 bzero(hashBuffer, CCSHA256_OUTPUT_SIZE); 172} 173 174