5 #import "SecRecoveryKey.h"
7 #import <corecrypto/cchkdf.h>
8 #import <corecrypto/ccsha2.h>
9 #import <corecrypto/ccec.h>
11 #import <utilities/SecCFWrappers.h>
12 #import <CommonCrypto/CommonRandomSPI.h>
13 #import <AssertMacros.h>
15 #import <Security/SecureObjectSync/SOSCloudCircle.h>
17 #import "SecCFAllocator.h"
18 #import "SecPasswordGenerate.h"
21 typedef struct _CFSecRecoveryKey *CFSecRecoveryKeyRef;
24 static uint8_t backupPublicKey[] = { 'B', 'a', 'c', 'k', 'u', ' ', 'P', 'u', 'b', 'l', 'i', 'c', 'k', 'e', 'y' };
25 static uint8_t passwordInfoKey[] = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd', ' ', 's', 'e', 'c', 'r', 'e', 't' };
27 #define RK_BACKUP_HKDF_SIZE 128
28 #define RK_PASSWORD_HKDF_SIZE 32
30 CFGiblisFor(CFSecRecoveryKey);
32 struct _CFSecRecoveryKey {
38 CFSecRecoveryKeyDestroy(CFTypeRef cf)
40 CFSecRecoveryKeyRef rk = (CFSecRecoveryKeyRef)cf;
41 CFReleaseNull(rk->basecode);
46 CFSecRecoveryKeyCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions)
48 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SecRecoveryKey: %p>"), cf);
53 ValidateRecoveryKey(CFStringRef recoveryKey)
56 return SecPasswordValidatePasswordFormat(kSecPasswordTypeiCloudRecoveryKey, recoveryKey, NULL);
61 SecRKCreateRecoveryKeyString(NSError **error)
63 CFErrorRef cferror = NULL;
65 CFStringRef recoveryKey = SecPasswordGenerate(kSecPasswordTypeiCloudRecoveryKey, &cferror, NULL);
66 if (recoveryKey == NULL) {
68 *error = CFBridgingRelease(cferror);
70 CFReleaseNull(cferror);
74 if (!ValidateRecoveryKey(recoveryKey)) {
75 CFRelease(recoveryKey);
79 return (__bridge NSString *)recoveryKey;
84 SecRKCreateRecoveryKey(NSString *masterKey)
86 if (!ValidateRecoveryKey((__bridge CFStringRef)masterKey))
89 CFSecRecoveryKeyRef rk = CFTypeAllocate(CFSecRecoveryKey, struct _CFSecRecoveryKey, NULL);
93 rk->basecode = CFStringCreateExternalRepresentation(SecCFAllocatorZeroize(),
94 (__bridge CFStringRef)masterKey,
95 kCFStringEncodingUTF8, 0);
96 if (rk->basecode == NULL) {
101 return (__bridge SecRecoveryKey *)rk;
105 SecRKCreateDerivedSecret(CFSecRecoveryKeyRef rk, CFIndex outputLength,
106 const uint8_t *variant, size_t variantLength)
108 CFMutableDataRef derived;
111 derived = CFDataCreateMutableWithScratch(SecCFAllocatorZeroize(), outputLength);
115 status = cchkdf(ccsha256_di(),
116 CFDataGetLength(rk->basecode), CFDataGetBytePtr(rk->basecode),
118 variantLength, variant,
119 CFDataGetLength(derived), CFDataGetMutableBytePtr(derived));
121 CFReleaseNull(derived);
128 SecRKCopyAccountRecoveryPassword(SecRecoveryKey *rk)
130 CFStringRef base64Data = NULL;
131 CFDataRef derived = NULL;
132 void *b64string = NULL;
133 size_t base64Len = 0;
135 derived = SecRKCreateDerivedSecret((__bridge CFSecRecoveryKeyRef)rk,
136 RK_PASSWORD_HKDF_SIZE,
137 passwordInfoKey, sizeof(passwordInfoKey));
138 require(derived, fail);
140 base64Len = SecBase64Encode(CFDataGetBytePtr(derived), CFDataGetLength(derived), NULL, 0);
141 assert(base64Len < 1024);
143 b64string = malloc(base64Len);
144 require(b64string, fail);
146 SecBase64Encode(CFDataGetBytePtr(derived), CFDataGetLength(derived), b64string, base64Len);
148 base64Data = CFStringCreateWithBytes(SecCFAllocatorZeroize(),
149 (const UInt8 *)b64string, base64Len,
150 kCFStringEncodingUTF8, false);
151 require(base64Data, fail);
155 cc_clear(base64Len, b64string);
158 CFReleaseNull(derived);
160 return (__bridge NSString *)base64Data;
165 SecRKCopyAccountRecoveryVerifier(SecRecoveryKey *rk,
168 NSNumber *iterations,
171 /* use verifier create function from AppleIDAuthSupport with dlopen/dlsym
174 AppleIDAuthSupportCreateVerifier(CFStringRef proto,
175 CFStringRef username,
178 CFStringRef password,
187 RKBackupCreateECKey(SecRecoveryKey *rk, bool fullkey)
189 CFMutableDataRef publicKeyData = NULL;
190 CFDataRef derivedSecret = NULL;
191 ccec_const_cp_t cp = ccec_cp_256();
192 CFDataRef result = NULL;
195 ccec_full_ctx_decl_cp(cp, fullKey);
197 derivedSecret = SecRKCreateDerivedSecret((__bridge CFSecRecoveryKeyRef)rk, RK_BACKUP_HKDF_SIZE,
198 backupPublicKey, sizeof(backupPublicKey));
199 require(derivedSecret, fail);
201 status = ccec_generate_key_deterministic(cp,
202 CFDataGetLength(derivedSecret), CFDataGetBytePtr(derivedSecret),
204 CCEC_GENKEY_DETERMINISTIC_COMPACT,
206 require_noerr(status, fail);
208 size_t space = ccec_compact_export_size(fullkey, fullKey);
209 publicKeyData = CFDataCreateMutableWithScratch(SecCFAllocatorZeroize(), space);
210 require_quiet(publicKeyData, fail);
212 ccec_compact_export(fullkey, CFDataGetMutableBytePtr(publicKeyData), fullKey);
214 CFTransferRetained(result, publicKeyData);
216 CFReleaseNull(derivedSecret);
217 CFReleaseNull(publicKeyData);
219 return (__bridge NSData *)result;
223 SecRKCopyBackupFullKey(SecRecoveryKey *rk)
225 return RKBackupCreateECKey(rk, true);
230 SecRKCopyBackupPublicKey(SecRecoveryKey *rk)
232 return RKBackupCreateECKey(rk, false);
236 SecRKRegisterBackupPublicKey(SecRecoveryKey *rk, CFErrorRef *error)
238 CFDataRef backupKey = (__bridge CFDataRef)SecRKCopyBackupPublicKey(rk);
241 require(backupKey, fail);
243 res = SOSCCRegisterRecoveryPublicKey(backupKey, error);
245 CFReleaseNull(backupKey);