1 2#include <Security/Security.h> 3#include <Security/SecBreadcrumb.h> 4#include <Security/SecRandom.h> 5 6#include <corecrypto/ccaes.h> 7#include <corecrypto/ccpbkdf2.h> 8#include <corecrypto/ccmode.h> 9#include <corecrypto/ccmode_factory.h> 10#include <corecrypto/ccsha2.h> 11 12#include <CommonCrypto/CommonRandomSPI.h> 13 14#define CFReleaseNull(CF) ({ __typeof__(CF) *const _pcf = &(CF), _cf = *_pcf; (_cf ? (*_pcf) = ((__typeof__(CF))0), (CFRelease(_cf), ((__typeof__(CF))0)) : _cf); }) 15 16static const int kKeySize = CCAES_KEY_SIZE_128; 17static const int kSaltSize = 20; 18static const int kIterations = 5000; 19static const CFIndex tagLen = 16; 20static const uint8_t BCversion = 1; 21static const size_t paddingSize = 256; 22static const size_t maxSize = 1024; 23 24Boolean 25SecBreadcrumbCreateFromPassword(CFStringRef inPassword, 26 CFDataRef *outBreadcrumb, 27 CFDataRef *outEncryptedKey, 28 CFErrorRef *outError) 29{ 30 const struct ccmode_ecb *ecb = ccaes_ecb_encrypt_mode(); 31 const struct ccmode_gcm gcm = CCMODE_FACTORY_GCM_ENCRYPT(ecb); 32 const struct ccdigest_info *di = ccsha256_di(); 33 CFMutableDataRef key, npw; 34 CFDataRef pw; 35 36 *outBreadcrumb = NULL; 37 *outEncryptedKey = NULL; 38 if (outError) 39 *outError = NULL; 40 41 key = CFDataCreateMutable(NULL, 0); 42 if (key == NULL) 43 return false; 44 45 CFDataSetLength(key, kKeySize + kSaltSize + 4); 46 CCRandomCopyBytes(kCCRandomDefault, CFDataGetMutableBytePtr(key), CFDataGetLength(key) - 4); 47 uint32_t size = htonl(kIterations); 48 memcpy(CFDataGetMutableBytePtr(key) + kKeySize + kSaltSize, &size, sizeof(size)); 49 50 /* 51 * Create data for password 52 */ 53 54 pw = CFStringCreateExternalRepresentation(NULL, inPassword, kCFStringEncodingUTF8, 0); 55 if (pw == NULL) { 56 CFReleaseNull(key); 57 return false; 58 } 59 60 const CFIndex passwordLength = CFDataGetLength(pw); 61 62 if (passwordLength > maxSize) { 63 CFReleaseNull(pw); 64 CFReleaseNull(key); 65 return false; 66 } 67 68 CFIndex paddedSize = passwordLength + paddingSize - (passwordLength % paddingSize); 69 const CFIndex outLength = 1 + 4 + paddedSize + tagLen; 70 71 npw = CFDataCreateMutable(NULL, outLength); 72 if (npw == NULL) { 73 CFReleaseNull(pw); 74 CFReleaseNull(key); 75 return false; 76 } 77 CFDataSetLength(npw, outLength); 78 79 memset(CFDataGetMutableBytePtr(npw), 0, outLength); 80 CFDataGetMutableBytePtr(npw)[0] = BCversion; 81 size = htonl(passwordLength); 82 memcpy(CFDataGetMutableBytePtr(npw) + 1, &size, sizeof(size)); 83 memcpy(CFDataGetMutableBytePtr(npw) + 5, CFDataGetBytePtr(pw), passwordLength); 84 85 /* 86 * Now create a GCM encrypted password using the random key 87 */ 88 89 ccgcm_ctx_decl(gcm.size, ctx); 90 gcm.init(&gcm, ctx, kKeySize, CFDataGetMutableBytePtr(key)); 91 gcm.gmac(ctx, 1, CFDataGetMutableBytePtr(npw)); 92 gcm.gcm(ctx, outLength - tagLen - 1, CFDataGetMutableBytePtr(npw) + 1, CFDataGetMutableBytePtr(npw) + 1); 93 gcm.finalize(ctx, tagLen, CFDataGetMutableBytePtr(npw) + outLength - tagLen); 94 ccgcm_ctx_clear(gcm.size, ctx); 95 96 /* 97 * Wrapping key is PBKDF2(sha256) over password 98 */ 99 100 if (di->output_size < kKeySize) abort(); 101 102 uint8_t rawkey[di->output_size]; 103 104 if (ccpbkdf2_hmac(di, CFDataGetLength(pw), CFDataGetBytePtr(pw), 105 kSaltSize, CFDataGetMutableBytePtr(key) + kKeySize, 106 kIterations, 107 sizeof(rawkey), rawkey) != 0) 108 abort(); 109 110 /* 111 * Wrap the random key with one round of ECB cryto 112 */ 113 114 ccecb_ctx_decl(ecb->size, ecbkey); 115 ecb->init(ecb, ecbkey, kKeySize, rawkey); 116 ecb->ecb(ecbkey, 1, CFDataGetMutableBytePtr(key), CFDataGetMutableBytePtr(key)); 117 118 /* 119 * 120 */ 121 122 memset(rawkey, 0, sizeof(rawkey)); 123 CFReleaseNull(pw); 124 125 *outBreadcrumb = npw; 126 *outEncryptedKey = key; 127 128 return true; 129} 130 131 132Boolean 133SecBreadcrumbCopyPassword(CFStringRef inPassword, 134 CFDataRef inBreadcrumb, 135 CFDataRef inEncryptedKey, 136 CFStringRef *outPassword, 137 CFErrorRef *outError) 138{ 139 const struct ccmode_ecb *ecb = ccaes_ecb_decrypt_mode(); 140 const struct ccmode_gcm gcm = CCMODE_FACTORY_GCM_DECRYPT(ccaes_ecb_encrypt_mode()); 141 const struct ccdigest_info *di = ccsha256_di(); 142 CFMutableDataRef gcmkey, oldpw; 143 CFDataRef pw; 144 uint32_t size; 145 146 *outPassword = NULL; 147 if (outError) 148 *outError = NULL; 149 150 if (CFDataGetLength(inEncryptedKey) < kKeySize + kSaltSize + 4) { 151 return false; 152 } 153 154 if (CFDataGetLength(inBreadcrumb) < 1 + 4 + paddingSize + tagLen) { 155 return false; 156 } 157 158 if (CFDataGetBytePtr(inBreadcrumb)[0] != BCversion) { 159 return false; 160 } 161 162 gcmkey = CFDataCreateMutableCopy(NULL, 0, inEncryptedKey); 163 if (gcmkey == NULL) { 164 return false; 165 } 166 167 const CFIndex outLength = CFDataGetLength(inBreadcrumb) - 1 - tagLen; 168 if ((outLength % 16) != 0 && outLength < 4) { 169 CFReleaseNull(gcmkey); 170 return false; 171 } 172 173 oldpw = CFDataCreateMutable(NULL, outLength); 174 if (oldpw == NULL) { 175 CFReleaseNull(gcmkey); 176 return false; 177 } 178 CFDataSetLength(oldpw, outLength); 179 180 181 /* 182 * Create data for password 183 */ 184 185 pw = CFStringCreateExternalRepresentation(NULL, inPassword, kCFStringEncodingUTF8, 0); 186 if (pw == NULL) { 187 CFReleaseNull(oldpw); 188 CFReleaseNull(gcmkey); 189 return false; 190 } 191 192 /* 193 * Wrapping key is HMAC(sha256) over password 194 */ 195 196 if (di->output_size < kKeySize) abort(); 197 198 uint8_t rawkey[di->output_size]; 199 200 memcpy(&size, CFDataGetMutableBytePtr(gcmkey) + kKeySize + kSaltSize, sizeof(size)); 201 size = ntohl(size); 202 203 if (ccpbkdf2_hmac(di, CFDataGetLength(pw), CFDataGetBytePtr(pw), 204 kSaltSize, CFDataGetMutableBytePtr(gcmkey) + kKeySize, 205 size, 206 sizeof(rawkey), rawkey) != 0) 207 abort(); 208 209 CFReleaseNull(pw); 210 211 /* 212 * Unwrap the random key with one round of ECB cryto 213 */ 214 215 ccecb_ctx_decl(ecb->size, ecbkey); 216 ecb->init(ecb, ecbkey, kKeySize, rawkey); 217 ecb->ecb(ecbkey, 1, CFDataGetMutableBytePtr(gcmkey), CFDataGetMutableBytePtr(gcmkey)); 218 219 /* 220 * GCM unwrap 221 */ 222 223 uint8_t tag[tagLen]; 224 ccgcm_ctx_decl(gcm.size, ctx); 225 226 gcm.init(&gcm, ctx, kKeySize, CFDataGetMutableBytePtr(gcmkey)); 227 gcm.gmac(ctx, 1, CFDataGetBytePtr(inBreadcrumb)); 228 gcm.gcm(ctx, outLength, CFDataGetBytePtr(inBreadcrumb) + 1, CFDataGetMutableBytePtr(oldpw)); 229 gcm.finalize(ctx, tagLen, tag); 230 ccgcm_ctx_clear(gcm.size, ctx); 231 232 CFReleaseNull(gcmkey); 233 234 if (memcmp(tag, CFDataGetBytePtr(inBreadcrumb) + 1 + outLength, tagLen) != 0) { 235 CFReleaseNull(oldpw); 236 return false; 237 } 238 239 memcpy(&size, CFDataGetMutableBytePtr(oldpw), sizeof(size)); 240 size = ntohl(size); 241 if (size > outLength - 4) { 242 CFReleaseNull(oldpw); 243 return false; 244 } 245 memmove(CFDataGetMutableBytePtr(oldpw), CFDataGetMutableBytePtr(oldpw) + 4, size); 246 CFDataSetLength(oldpw, size); 247 248 *outPassword = CFStringCreateFromExternalRepresentation(NULL, oldpw, kCFStringEncodingUTF8); 249 CFReleaseNull(oldpw); 250 251 return true; 252} 253 254CFDataRef 255SecBreadcrumbCreateNewEncryptedKey(CFStringRef oldPassword, 256 CFStringRef newPassword, 257 CFDataRef encryptedKey, 258 CFErrorRef *outError) 259{ 260 const struct ccmode_ecb *enc = ccaes_ecb_encrypt_mode(); 261 const struct ccmode_ecb *dec = ccaes_ecb_decrypt_mode(); 262 const struct ccdigest_info *di = ccsha256_di(); 263 CFMutableDataRef newEncryptedKey; 264 CFDataRef newpw = NULL, oldpw = NULL; 265 uint8_t rawkey[di->output_size]; 266 267 if (CFDataGetLength(encryptedKey) < kKeySize + kSaltSize + 4) { 268 return NULL; 269 } 270 271 newEncryptedKey = CFDataCreateMutableCopy(NULL, 0, encryptedKey); 272 if (newEncryptedKey == NULL) { 273 return NULL; 274 } 275 276 oldpw = CFStringCreateExternalRepresentation(NULL, oldPassword, kCFStringEncodingUTF8, 0); 277 if (oldpw == NULL) { 278 CFReleaseNull(newEncryptedKey); 279 return false; 280 } 281 282 newpw = CFStringCreateExternalRepresentation(NULL, newPassword, kCFStringEncodingUTF8, 0); 283 if (newpw == NULL) { 284 CFReleaseNull(newEncryptedKey); 285 CFReleaseNull(oldpw); 286 return false; 287 } 288 289 if (di->output_size < kKeySize) abort(); 290 291 /* 292 * Unwrap with new key 293 */ 294 295 uint32_t iter; 296 297 memcpy(&iter, CFDataGetMutableBytePtr(newEncryptedKey) + kKeySize + kSaltSize, sizeof(iter)); 298 iter = ntohl(iter); 299 300 if (ccpbkdf2_hmac(di, CFDataGetLength(oldpw), CFDataGetBytePtr(oldpw), 301 kSaltSize, CFDataGetMutableBytePtr(newEncryptedKey) + kKeySize, 302 iter, 303 sizeof(rawkey), rawkey) != 0) 304 abort(); 305 306 CFReleaseNull(oldpw); 307 308 309 ccecb_ctx_decl(dec->size, deckey); 310 dec->init(dec, deckey, kKeySize, rawkey); 311 dec->ecb(deckey, 1, CFDataGetMutableBytePtr(newEncryptedKey), CFDataGetMutableBytePtr(newEncryptedKey)); 312 313 memset(rawkey, 0, sizeof(rawkey)); 314 315 /* 316 * Re-wrap with new key 317 */ 318 319 if (ccpbkdf2_hmac(di, CFDataGetLength(newpw), CFDataGetBytePtr(newpw), 320 kSaltSize, CFDataGetMutableBytePtr(newEncryptedKey) + kKeySize, 321 iter, 322 sizeof(rawkey), rawkey) != 0) 323 abort(); 324 325 CFReleaseNull(newpw); 326 327 328 ccecb_ctx_decl(enc->size, enckey); 329 enc->init(enc, enckey, kKeySize, rawkey); 330 enc->ecb(enckey, 1, CFDataGetMutableBytePtr(newEncryptedKey), CFDataGetMutableBytePtr(newEncryptedKey)); 331 332 memset(rawkey, 0, sizeof(rawkey)); 333 334 return newEncryptedKey; 335} 336