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