static CFDataRef encryptString(SecKeyRef wrapKey, CFDataRef iv, CFStringRef str) { CFDataRef retval = NULL; CFErrorRef error = NULL; CFDataRef inputString = CFStringCreateExternalRepresentation(kCFAllocatorDefault, str, kCFStringEncodingMacRoman, 0xff); SecTransformRef encryptTrans = SecEncryptTransformCreate(wrapKey, &error); if(error == NULL) { SecTransformRef group = SecTransformCreateGroupTransform(); SecTransformSetAttribute(encryptTrans, kSecEncryptionMode, kSecModeCBCKey, &error); if(error == NULL) SecTransformSetAttribute(encryptTrans, kSecPaddingKey, kSecPaddingPKCS7Key, &error); if(error == NULL) SecTransformSetAttribute(encryptTrans, kSecTransformInputAttributeName, inputString, &error); if(error == NULL) SecTransformSetAttribute(encryptTrans, kSecIVKey, iv, &error); SecTransformRef encodeTrans = SecEncodeTransformCreate(kSecBase64Encoding, &error); SecTransformConnectTransforms(encryptTrans, kSecTransformOutputAttributeName, encodeTrans, kSecTransformInputAttributeName, group, &error); CFRelease(encodeTrans); CFRelease(encryptTrans); if(error == NULL) retval = SecTransformExecute(group, &error); if(error != NULL) secDebug(ASL_LEVEL_ERR, "Failed to encrypt recovery password\n", NULL); CFRelease(group); } return retval; }
TagLib::ByteVector TagLib::EncodeBase64(const TagLib::ByteVector& input) { ByteVector result; CFErrorRef error; SFB::SecTransform encoder = SecEncodeTransformCreate(kSecBase64Encoding, &error); if(nullptr == encoder) { LOGGER_WARNING("org.sbooth.AudioEngine", "SecEncodeTransformCreate failed: " << error); return TagLib::ByteVector::null; } SFB::CFData sourceData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)input.data(), (CFIndex)input.size(), kCFAllocatorNull); if(!sourceData) return TagLib::ByteVector::null; if(!SecTransformSetAttribute(encoder, kSecTransformInputAttributeName, sourceData, &error)) { LOGGER_WARNING("org.sbooth.AudioEngine", "SecTransformSetAttribute failed: " << error); return TagLib::ByteVector::null; } SFB::CFData encodedData = (CFDataRef)SecTransformExecute(encoder, &error); if(!encodedData) { LOGGER_WARNING("org.sbooth.AudioEngine", "SecTransformExecute failed: " << error); return TagLib::ByteVector::null; } result.setData((const char *)CFDataGetBytePtr((CFDataRef)encodedData), (TagLib::uint)CFDataGetLength((CFDataRef)encodedData)); return result; }
static CFDataRef b64encode(CFDataRef input) { CFDataRef retval = NULL; CFErrorRef error = NULL; SecTransformRef encodeTrans = SecEncodeTransformCreate(kSecBase64Encoding, &error); if(error == NULL) SecTransformSetAttribute(encodeTrans, kSecTransformInputAttributeName, input, &error); if(error == NULL) retval = SecTransformExecute(encodeTrans, &error); if(encodeTrans) CFRelease(encodeTrans); return retval; }
static inline String base64(const String& input) { #ifdef OS_Darwin String result; SecTransformRef transform = SecEncodeTransformCreate(kSecBase64Encoding, 0); CFDataRef sourceData = CFDataCreate(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(input.constData()), input.size()); SecTransformSetAttribute(transform, kSecTransformInputAttributeName, sourceData, 0); CFDataRef encodedData = static_cast<CFDataRef>(SecTransformExecute(transform, 0)); const long len = CFDataGetLength(encodedData); if (len > 0) { result.resize(len); CFDataGetBytes(encodedData, CFRangeMake(0, len), reinterpret_cast<UInt8*>(result.data())); } CFRelease(encodedData); CFRelease(transform); CFRelease(sourceData); #else BIO *base64_filter = BIO_new(BIO_f_base64()); BIO_set_flags(base64_filter, BIO_FLAGS_BASE64_NO_NL); BIO *bio = BIO_new(BIO_s_mem()); BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); bio = BIO_push(base64_filter, bio); BIO_write(bio, input.constData(), input.size()); BIO_flush(bio); char *new_data; const long bytes_written = BIO_get_mem_data(bio, &new_data); String result(new_data, bytes_written); BIO_free_all(bio); #endif return result; }
CFStringRef SecCreateRecoveryPassword(void) { CFStringRef result = NULL; CFErrorRef error = NULL; CFDataRef encodedData = NULL; CFDataRef randData = getRandomBytes(16); int i; // base32FDE is a "private" base32 encoding, it has no 0/O or L/l/1 in it (it uses 8 and 9). SecTransformRef encodeTrans = SecEncodeTransformCreate(CFSTR("base32FDE"), &error); if(error == NULL) { SecTransformSetAttribute(encodeTrans, kSecTransformInputAttributeName, randData, &error); if(error == NULL) encodedData = SecTransformExecute(encodeTrans, &error); CFRelease(encodeTrans); } CFRelease(randData); if(encodedData != NULL && error == NULL) { CFStringRef b32string = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, encodedData, kCFStringEncodingMacRoman); CFMutableStringRef encodedString = CFStringCreateMutableCopy(kCFAllocatorDefault, 64, b32string); // Add some hyphens to make the generated password easier to use for(i = 4; i < 34; i += 5) CFStringInsert(encodedString, i, CFSTR("-")); // Trim so the last section is 4 characters long CFStringDelete(encodedString, CFRangeMake(29,CFStringGetLength(encodedString)-29)); result = CFStringCreateCopy(kCFAllocatorDefault, encodedString); CFRelease(encodedString); CFRelease(b32string); CFRelease(encodedData); } else { secDebug(ASL_LEVEL_ERR, "Failed to base32 encode random data for recovery password\n", NULL); } return result; }
TagLib::ByteVector TagLib::EncodeBase64(const TagLib::ByteVector& input) { #if USE_SECURITY_FRAMEWORK ByteVector result; CFErrorRef error; SecTransformRef encoder = SecEncodeTransformCreate(kSecBase64Encoding, &error); if(nullptr == encoder) { CFShow(error); return TagLib::ByteVector::null; } CFDataRef sourceData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)input.data(), input.size(), kCFAllocatorNull); if(nullptr == sourceData) { CFRelease(encoder), encoder = nullptr; return TagLib::ByteVector::null; } if(!SecTransformSetAttribute(encoder, kSecTransformInputAttributeName, sourceData, &error)) { CFShow(error); CFRelease(sourceData), sourceData = nullptr; CFRelease(encoder), encoder = nullptr; return TagLib::ByteVector::null; } CFTypeRef encodedData = SecTransformExecute(encoder, &error); if(nullptr == encodedData) { CFShow(error); CFRelease(sourceData), sourceData = nullptr; CFRelease(encoder), encoder = nullptr; return TagLib::ByteVector::null; } result.setData((const char *)CFDataGetBytePtr((CFDataRef)encodedData), (TagLib::uint)CFDataGetLength((CFDataRef)encodedData)); CFRelease(encodedData), encodedData = nullptr; CFRelease(sourceData), sourceData = nullptr; CFRelease(encoder), encoder = nullptr; return result; #else ByteVector result; BIO *b64 = BIO_new(BIO_f_base64()); BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); BIO *bio = BIO_new(BIO_s_mem()); bio = BIO_push(b64, bio); BIO_write(bio, input.data(), input.size()); (void)BIO_flush(bio); void *mem = nullptr; long size = BIO_get_mem_data(bio, &mem); if(0 < size) result.setData(static_cast<const char *>(mem), static_cast<uint>(size)); BIO_free_all(bio); return result; #endif }
CFStringRef APPEMKeyCreateFromHexKey(CFStringRef hexKey) { // Convert a raw 1024 bit key to a PEM formatted string that includes the headers // -----BEGIN RSA PUBLIC KEY----- // (base64 ASN1 encoded data here) // -----END RSA PUBLIC KEY----- uint8_t raw1[] = { 0x30, 0x81, 0x9F, // SEQUENCE length 0x9F 0x30, 0x0D, // SEQUENCE length 0x0D 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, // rsaEncryption, PKCS #1 0x05, 0x00, // NULL 0x03, 0x81, 0x8D, 0x00, // BIT STRING, length 0x8D 0x30, 0x81, 0x89, // SEQUENCE length 0x89 0x02, 0x81, 0x81, // INTEGER length 0x81 0x00 // MSB = zero to make sure INTEGER is positively signed }; uint8_t raw2[] = { 0x02, 0x03, 0x00, 0x00, 0x03 // INTEGER length 3, value = 0x03 (RSA exponent) }; // Munch through the hex string, taking two characters at a time for each byte // to append as the key data CFDataRef rawKey = APCopyDataFromHexString(hexKey); if (rawKey == NULL) { // Failed to import the key (bad hex digit?) CFShow(CFSTR("Bad public key?")); return NULL; } CFMutableDataRef keyData = CFDataCreateMutable(kCFAllocatorDefault, 0); CFDataAppendBytes(keyData, raw1, sizeof(raw1)/sizeof(uint8_t)); const UInt8 *rawKeyBuffer = CFDataGetBytePtr(rawKey); CFDataAppendBytes(keyData, rawKeyBuffer, CFDataGetLength(rawKey)); CFRelease(rawKey); CFDataAppendBytes(keyData, raw2, sizeof(raw2)/sizeof(uint8_t)); // Just need to base64 encode this data now and wrap the string // in the BEGIN/END RSA PUBLIC KEY CFErrorRef error = NULL; SecTransformRef encoder = SecEncodeTransformCreate(kSecBase64Encoding, &error); if (error != NULL) { CFShow(error); if (encoder) { CFRelease(encoder); } if (keyData) { CFRelease(keyData); } return NULL; } SecTransformSetAttribute(encoder, kSecTransformInputAttributeName, keyData, &error); if (error != NULL) { CFRelease(encoder); if (keyData) { CFRelease(keyData); } CFShow(error); return NULL; } CFDataRef encodedKeyData = SecTransformExecute(encoder, &error); const UInt8 *keyDataBuffer = CFDataGetBytePtr(encodedKeyData); CFStringRef keyDataString = CFStringCreateWithBytes(kCFAllocatorDefault, keyDataBuffer, CFDataGetLength(encodedKeyData), kCFStringEncodingUTF8, false); CFRelease(encodedKeyData); CFRelease(encoder); CFRelease(keyData); CFStringRef beginRSAKey = CFSTR("-----BEGIN RSA PUBLIC KEY-----"); CFStringRef endRSAKey = CFSTR("-----END RSA PUBLIC KEY-----"); CFStringRef pemKey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@\n%@\n%@"), beginRSAKey, keyDataString, endRSAKey); CFRelease(keyDataString); return pemKey; }