1// 2// OTRMath.c 3// libsecurity_libSecOTR 4// 5// Created by Mitch Adler on 1/28/11. 6// Copyright 2011 Apple Inc. All rights reserved. 7// 8 9#include "SecOTRMath.h" 10#include "SecOTRMathPrivate.h" 11 12#include "SecOTRPacketData.h" 13 14#include <AssertMacros.h> 15 16#include <pthread.h> 17 18#include <Security/SecRandom.h> 19 20#include <corecrypto/ccsha2.h> 21#include <corecrypto/cczp.h> 22 23#include <limits.h> 24 25static inline 26void cczp_init_from_bytes(cc_size n, cczp_t zp, size_t pSize, const void *p, size_t rSize, const void* r) 27{ 28 CCZP_N(zp) = n; 29 zp.zp->mod_prime = cczp_mod; 30 ccn_read_uint(n, CCZP_PRIME(zp), pSize, p); 31 ccn_read_uint(n+1, CCZP_RECIP(zp), rSize, r); 32 33} 34 35static pthread_once_t kOTRImportGroupData = PTHREAD_ONCE_INIT; 36 37static cc_unit sOTRGenerator[kOTRDHGroupUnits]; 38static cczp_decl_n(kOTRDHGroupUnits, sOTRGroup_zp); 39 40static void setupGroupValues() 41{ 42 __Check( kExponentiationUnits == kOTRDHGroupUnits ); 43 44 cczp_init_from_bytes(kOTRDHGroupUnits, sOTRGroup_zp, 45 sizeof(kOTRDHGroup), kOTRDHGroup, 46 sizeof(kOTRDHGroup_Recip), kOTRDHGroup_Recip); 47 48 ccn_seti(kOTRDHGroupUnits, sOTRGenerator, kOTRGeneratorValue); 49} 50 51void OTRExponentiate(cc_unit* res, const cc_unit* base, const cc_unit* exponent) 52{ 53 pthread_once(&kOTRImportGroupData, setupGroupValues); 54 55 cczp_power(sOTRGroup_zp, res, base, exponent); 56} 57 58void OTRGroupExponentiate(cc_unit* res, const cc_unit* exponent) 59{ 60 pthread_once(&kOTRImportGroupData, setupGroupValues); 61 62 OTRExponentiate(res, sOTRGenerator, exponent); 63} 64 65// 66// Random Number Generation 67// 68 69OSStatus GetRandomBytesInLSBs(size_t bytesOfRandomness, size_t n, cc_unit* place) 70{ 71 OSStatus result = errSecParam; 72 require(bytesOfRandomness * 8 <= ccn_bitsof_n(n), fail); 73 { 74 uint8_t randomBytes[bytesOfRandomness]; 75 76 result = SecRandomCopyBytes(kSecRandomDefault, sizeof(randomBytes), randomBytes); 77 78 require_noerr(result, fail); 79 80 ccn_read_uint(n, place, sizeof(randomBytes), randomBytes); 81 82 bzero(randomBytes, bytesOfRandomness); 83 } 84fail: 85 return result; 86} 87 88OSStatus FillWithRandomBytes(size_t n, cc_unit* place) 89{ 90 return GetRandomBytesInLSBs(ccn_sizeof(n), n, place); 91} 92 93 94static const uint8_t kIVZero[16] = { }; 95 96static void AES_CTR_Transform(size_t keySize, const uint8_t* key, 97 const uint8_t iv[16], 98 size_t howMuch, const uint8_t* from, uint8_t* to) 99{ 100 const struct ccmode_ctr* ctr_encrypt = ccaes_ctr_crypt_mode(); 101 ccctr_ctx_decl(ctr_encrypt->size, ctr_ctx); 102 ctr_encrypt->init(ctr_encrypt, ctr_ctx, keySize, key, iv); 103 104 ctr_encrypt->ctr(ctr_ctx, howMuch, from, to); 105} 106 107void AES_CTR_HighHalf_Transform(size_t keySize, const uint8_t* key, 108 uint64_t highHalf, 109 size_t howMuch, const uint8_t* from, uint8_t* to) 110{ 111 uint8_t iv[16] = { highHalf >> 56, highHalf >> 48, highHalf >> 40, highHalf >> 32, 112 highHalf >> 24, highHalf >> 16, highHalf >> 8 , highHalf >> 0, 113 0, 0, 0, 0, 114 0, 0, 0, 0 }; 115 AES_CTR_Transform(keySize, key, iv, howMuch, from, to); 116} 117 118void AES_CTR_IV0_Transform(size_t keySize, const uint8_t* key, 119 size_t howMuch, const uint8_t* from, uint8_t* to) 120{ 121 AES_CTR_Transform(keySize, key, kIVZero, howMuch, from, to); 122} 123 124 125// 126// Key Derivation 127// 128 129static void HashMPIWithPrefix(uint8_t byte, cc_size sN, const cc_unit* s, uint8_t* buffer) 130{ 131 CFMutableDataRef dataToHash = CFDataCreateMutable(kCFAllocatorDefault, 0); 132 CFDataAppendBytes(dataToHash, &byte, 1); 133 134 AppendMPI(dataToHash, sN, s); 135 136 uint8_t *bytesToHash = CFDataGetMutableBytePtr(dataToHash); 137 CFIndex amountToHash = CFDataGetLength(dataToHash); 138 139 /* 64 bits cast: amountToHash is the size of an identity +1 , which is currently hardcoded and never more than 2^32 bytes */ 140 assert((unsigned long)amountToHash<UINT32_MAX); /* Debug check, Correct as long as CFIndex is a signed long and CC_LONG is a uint32_t */ 141 142 (void) CC_SHA256(bytesToHash, (CC_LONG)amountToHash, buffer); 143 144 bzero(bytesToHash, (size_t)amountToHash); 145 CFReleaseNull(dataToHash); 146} 147 148void DeriveOTR256BitsFromS(KeyType whichKey, cc_size sN, const cc_unit* s, size_t keySize, uint8_t* key) 149{ 150 HashMPIWithPrefix(whichKey, sN, s, key); 151} 152 153void DeriveOTR128BitPairFromS(KeyType whichKey, size_t sSize, const cc_unit* s, 154 size_t firstKeySize, uint8_t* firstKey, 155 size_t secondKeySize, uint8_t* secondKey) 156{ 157 uint8_t hashBuffer[CCSHA256_OUTPUT_SIZE]; 158 159 HashMPIWithPrefix(whichKey, sSize, s, hashBuffer); 160 161 if (firstKey) { 162 firstKeySize = firstKeySize > CCSHA256_OUTPUT_SIZE/2 ? CCSHA256_OUTPUT_SIZE/2 : firstKeySize; 163 memcpy(firstKey, hashBuffer, firstKeySize); 164 } 165 if (secondKey) { 166 secondKeySize = secondKeySize > CCSHA256_OUTPUT_SIZE/2 ? CCSHA256_OUTPUT_SIZE/2 : secondKeySize; 167 memcpy(secondKey, hashBuffer, secondKeySize); 168 } 169 170 bzero(hashBuffer, CCSHA256_OUTPUT_SIZE); 171 172} 173 174void DeriveOTR64BitsFromS(KeyType whichKey, size_t sn, const cc_unit* s, 175 size_t topKeySize, uint8_t* topKey) 176{ 177 uint8_t hashBuffer[CCSHA256_OUTPUT_SIZE]; 178 179 HashMPIWithPrefix(whichKey, sn, s, hashBuffer); 180 181 topKeySize = topKeySize > CCSHA256_OUTPUT_SIZE/2 ? CCSHA256_OUTPUT_SIZE/2 : topKeySize; 182 memcpy(topKey, hashBuffer, topKeySize); 183 184 bzero(hashBuffer, CCSHA256_OUTPUT_SIZE); 185} 186 187