static CFStringRef decryptString(SecKeyRef wrapKey, CFDataRef iv, CFDataRef wrappedPassword) { CFStringRef retval = NULL; CFDataRef retData = NULL; CFErrorRef error = NULL; SecTransformRef decryptTrans = SecDecryptTransformCreate(wrapKey, &error); if(error == NULL) { SecTransformRef group = SecTransformCreateGroupTransform(); SecTransformRef decodeTrans = SecDecodeTransformCreate(kSecBase64Encoding, &error); if(error == NULL) SecTransformSetAttribute(decodeTrans, kSecTransformInputAttributeName, wrappedPassword, &error); if(error == NULL) SecTransformSetAttribute(decryptTrans, kSecEncryptionMode, kSecModeCBCKey, &error); if(error == NULL) SecTransformSetAttribute(decryptTrans, kSecPaddingKey, kSecPaddingPKCS7Key, &error); if(error == NULL) SecTransformSetAttribute(decryptTrans, kSecIVKey, iv, &error); SecTransformConnectTransforms(decodeTrans, kSecTransformOutputAttributeName, decryptTrans, kSecTransformInputAttributeName, group, &error); CFRelease(decodeTrans); CFRelease(decryptTrans); if(error == NULL) retData = SecTransformExecute(group, &error); if(error == NULL) retval = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, retData, kCFStringEncodingMacRoman); else secDebug(ASL_LEVEL_ERR, "Failed to decrypt recovery password\n", NULL); CFRelease(group); } return retval; }
void CryptoOperationImpl::initialize() { if (m_signingTransform) { // We have already initialized the signing transform return; } m_signingTransform = SecSignTransformCreate(getKeyRef(), NULL); SecTransformSetAttribute(m_signingTransform, kSecInputIsDigest, kCFBooleanTrue, NULL); SecTransformSetAttribute(m_signingTransform, kSecDigestTypeAttribute, kSecDigestSHA1, NULL); }
static dispatch_data_t execute_sectransform(SecTransformRef transformRef, dispatch_data_t data) { const void * bytes; size_t size; dispatch_data_t map = dispatch_data_create_map(data, &bytes, &size); assert(map); CFDataRef dataRef = CFDataCreate(kCFAllocatorDefault, bytes, size); assert(dataRef); dispatch_release(map); SecTransformSetAttribute(transformRef, kSecTransformInputAttributeName, dataRef, NULL); CFDataRef transformedDataRef = SecTransformExecute(transformRef, NULL); assert(transformedDataRef); CFRelease(dataRef); dispatch_data_t output = dispatch_data_create(CFDataGetBytePtr(transformedDataRef), CFDataGetLength(transformedDataRef), dispatch_get_main_queue(), DISPATCH_DATA_DESTRUCTOR_DEFAULT); CFRelease(transformedDataRef); return output; }
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 b64decode(CFDataRef input) { CFDataRef retval = NULL; CFErrorRef error = NULL; SecTransformRef decodeTrans = SecDecodeTransformCreate(kSecBase64Encoding, &error); if(error == NULL) SecTransformSetAttribute(decodeTrans, kSecTransformInputAttributeName, input, &error); if(error == NULL) retval = SecTransformExecute(decodeTrans, &error); if(decodeTrans) CFRelease(decodeTrans); return retval; }
void CryptoOperationImpl::processImpl(const char *buffer, unsigned long size) { initialize(); CFErrorRef error = NULL; CFDataRef dataRef = CFDataCreate(kCFAllocatorDefault, (UInt8*)buffer, size); //TODO doesn't seems to work, it looks like only the first kSecTransformInputAttributeName is used. SecTransformSetAttribute(m_signingTransform, kSecTransformInputAttributeName, dataRef, &error); if (NULL != error) { CFRelease(m_signingTransform); m_signingTransform = NULL; FireJSEvent("onabort", FB::VariantMap(), FB::variant_list_of()); } }
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; }
static int32_t ExecuteOaepTransform(SecTransformRef xform, uint8_t* pbData, int32_t cbData, PAL_HashAlgorithm algorithm, CFDataRef* pDataOut, CFErrorRef* pErrorOut) { if (!SecTransformSetAttribute(xform, kSecPaddingKey, kSecPaddingOAEPKey, pErrorOut)) { return kErrorSeeError; } // Documentation mentions kSecOAEPMGF1DigestAlgorithmAttributeName, but on the Apple platform // "SHA2" is an algorithm and the size is encoded separately. Since there doesn't seem to be // a second attribute to encode SHA2-256 vs SHA2-384, be limited to SHA-1. if (algorithm != PAL_SHA1) { return kErrorUnknownAlgorithm; } return ExecuteCFDataTransform(xform, pbData, cbData, pDataOut, pErrorOut); }
static CFDataRef digestString(CFStringRef str) { CFDataRef retval = NULL; CFErrorRef error = NULL; CFDataRef inputString = CFStringCreateExternalRepresentation(kCFAllocatorDefault, str, kCFStringEncodingUTF8, 0xff); SecTransformRef digestTrans = SecDigestTransformCreate(kSecDigestSHA2, 256, &error); if(error == NULL) { SecTransformSetAttribute(digestTrans, kSecTransformInputAttributeName, inputString, &error); if(error == NULL) { retval = SecTransformExecute(digestTrans, &error); if(retval == NULL) { secDebug(ASL_LEVEL_ERR, "Couldn't create digest %s\n", CFStringGetCStringPtr(CFErrorCopyFailureReason(error), kCFStringEncodingUTF8)); } } CFRelease(digestTrans); } CFRelease(inputString); return retval; }
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::DecodeBase64(const TagLib::ByteVector& input) { SFB::CFError error; SFB::SecTransform decoder(SecDecodeTransformCreate(kSecBase64Encoding, &error)); if(!decoder) { LOGGER_WARNING("org.sbooth.AudioEngine", "SecDecodeTransformCreate failed: " << error); return {}; } SFB::CFData sourceData(CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)input.data(), (CFIndex)input.size(), kCFAllocatorNull)); if(!sourceData) return {}; if(!SecTransformSetAttribute(decoder, kSecTransformInputAttributeName, sourceData, &error)) { LOGGER_WARNING("org.sbooth.AudioEngine", "SecTransformSetAttribute failed: " << error); return {}; } SFB::CFData decodedData((CFDataRef)SecTransformExecute(decoder, &error)); if(!decodedData) return {}; return {(const char *)CFDataGetBytePtr((CFDataRef)decodedData), (size_t)CFDataGetLength((CFDataRef)decodedData)}; }
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; }
CFDataRef APCreateHashFromDictionary(CFDictionaryRef dict) { __block CFErrorRef error = NULL; __block SecTransformRef hashFunction = NULL; void(^cleanup)(void) = ^(void) { if (error != NULL) { CFShow(error); CFRelease(error); error = NULL; } if (hashFunction != NULL) { CFRelease(hashFunction); hashFunction = NULL; } }; // Get the number of elements CFIndex count = CFDictionaryGetCount(dict); // Load the keys and build up the key array CFMutableArrayRef keyArray = CFArrayCreateMutable(kCFAllocatorDefault, count, NULL); CFStringRef keys[count]; CFDictionaryGetKeysAndValues(dict, (const void**)&keys, NULL); for (int idx = 0; idx < count; idx++) { // Skip the signature key if (CFStringCompare(keys[idx], CFSTR("Signature"), 0) == kCFCompareEqualTo) { continue; } CFArrayAppendValue(keyArray, keys[idx]); } // Sort the array int context = kCFCompareCaseInsensitive; CFArraySortValues(keyArray, CFRangeMake(0, count-1), (CFComparatorFunction)CFStringCompare, &context); // Build the data CFMutableDataRef dictData = CFDataCreateMutable(kCFAllocatorDefault, 0); int keyCount = CFArrayGetCount(keyArray); for (int keyIndex = 0; keyIndex < keyCount; keyIndex++) { CFStringRef key = CFArrayGetValueAtIndex(keyArray, keyIndex); CFStringRef value = CFDictionaryGetValue(dict, key); CFDataRef valueData = CFStringCreateExternalRepresentation(kCFAllocatorDefault, value, kCFStringEncodingUTF8, 0); const UInt8 *valueBuffer = CFDataGetBytePtr(valueData); CFDataAppendBytes(dictData, valueBuffer, CFDataGetLength(valueData)); CFRelease(valueData); } // Hash the data hashFunction = SecDigestTransformCreate(kSecDigestSHA1, 0, &error); if (error != NULL) { CFRelease(dictData); cleanup(); return NULL; } SecTransformSetAttribute(hashFunction, kSecTransformInputAttributeName, dictData, &error); CFDataRef hashData = SecTransformExecute(hashFunction, &error); CFRelease(dictData); if (error != NULL) { cleanup(); if (hashData) { CFRelease(hashData); } return NULL; } cleanup(); return hashData; }
CFDictionaryRef APCreateDictionaryForLicenseData(CFDataRef data) { __block CFPropertyListRef propertyList = NULL; __block CFDataRef hashData = NULL; __block CFErrorRef error = NULL; __block SecTransformRef verifyFunction = NULL; __block CFBooleanRef valid = NULL; void(^cleanup)(void) = ^(void) { if (propertyList != NULL) { CFRelease(propertyList); propertyList = NULL; } if (hashData != NULL) { CFRelease(hashData); hashData = NULL; } if (error != NULL) { CFShow(error); CFRelease(error); error = NULL; } if (verifyFunction != NULL) { CFRelease(verifyFunction); verifyFunction = NULL; } if (valid != NULL) { CFRelease(valid); valid = NULL; } }; if (!publicKeyRef) { CFShow(CFSTR("Public key is invalid")); return NULL; } // Make the property list from the data CFStringRef errorString = NULL; propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, data, kCFPropertyListMutableContainers, &errorString); if (errorString || CFDictionaryGetTypeID() != CFGetTypeID(propertyList) || !CFPropertyListIsValid(propertyList, kCFPropertyListXMLFormat_v1_0)) { if (propertyList) CFRelease(propertyList); return NULL; } CFMutableDictionaryRef licenseDictionary = (CFMutableDictionaryRef)propertyList; CFDataRef signature = CFDictionaryGetValue(licenseDictionary, CFSTR("Signature")); if (!signature) { CFShow(CFSTR("No signature")); cleanup(); return NULL; } hashData = APCreateHashFromDictionary(licenseDictionary); CFStringRef hashCheck = APCopyHexStringFromData(hashData); APSetHash(hashCheck); CFRelease(hashCheck); // Check the hash against license blacklist if (blacklist && CFArrayContainsValue(blacklist, CFRangeMake(0, CFArrayGetCount(blacklist)), hash)) { cleanup(); return NULL; } // Verify the signed hash using the public key, passing the raw hash data as the input verifyFunction = SecVerifyTransformCreate(publicKeyRef, signature, &error); if (error) { cleanup(); return NULL; } SecTransformSetAttribute(verifyFunction, kSecTransformInputAttributeName, hashData, &error); if (error) { cleanup(); return NULL; } SecTransformSetAttribute(verifyFunction, kSecInputIsAttributeName, kSecInputIsRaw, &error); if (error) { cleanup(); return NULL; } valid = SecTransformExecute(verifyFunction, &error); if (error) { cleanup(); return NULL; } if (valid != kCFBooleanTrue) { cleanup(); return NULL; } CFDictionaryRef resultDict = CFDictionaryCreateCopy(kCFAllocatorDefault, licenseDictionary); cleanup(); return resultDict; }
static int32_t ExecuteCFDataTransform( SecTransformRef xform, uint8_t* pbData, int32_t cbData, CFDataRef* pDataOut, CFErrorRef* pErrorOut) { if (xform == nullptr || pbData == nullptr || cbData < 0 || pDataOut == nullptr || pErrorOut == nullptr) { return kErrorBadInput; } *pDataOut = nullptr; *pErrorOut = nullptr; CFTypeRef xformOutput = nullptr; CFDataRef cfData = nullptr; int32_t ret = INT_MIN; cfData = CFDataCreateWithBytesNoCopy(nullptr, pbData, cbData, kCFAllocatorNull); if (cfData == nullptr) { // This probably means that there wasn't enough memory available, but no // particular failure cases are described. return kErrorUnknownState; } if (!SecTransformSetAttribute(xform, kSecTransformInputAttributeName, cfData, pErrorOut)) { ret = kErrorSeeError; goto cleanup; } xformOutput = SecTransformExecute(xform, pErrorOut); if (xformOutput == nullptr || *pErrorOut != nullptr) { ret = kErrorSeeError; goto cleanup; } if (CFGetTypeID(xformOutput) == CFDataGetTypeID()) { CFDataRef cfDataOut = reinterpret_cast<CFDataRef>(const_cast<void*>(xformOutput)); CFRetain(cfDataOut); *pDataOut = cfDataOut; ret = 1; } else { ret = kErrorUnknownState; } cleanup: if (xformOutput != nullptr) { CFRelease(xformOutput); } if (cfData != nullptr) { CFRelease(cfData); } return ret; }
TagLib::ByteVector TagLib::DecodeBase64(const TagLib::ByteVector& input) { #if USE_SECURITY_FRAMEWORK ByteVector result; CFErrorRef error; SecTransformRef decoder = SecDecodeTransformCreate(kSecBase64Encoding, &error); if(nullptr == decoder) { CFShow(error); return TagLib::ByteVector::null; } CFDataRef sourceData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)input.data(), input.size(), kCFAllocatorNull); if(nullptr == sourceData) { CFRelease(decoder), decoder = nullptr; return TagLib::ByteVector::null; } if(!SecTransformSetAttribute(decoder, kSecTransformInputAttributeName, sourceData, &error)) { CFShow(error); CFRelease(sourceData), sourceData = nullptr; CFRelease(decoder), decoder = nullptr; return TagLib::ByteVector::null; } CFTypeRef decodedData = SecTransformExecute(decoder, &error); if(nullptr == decodedData) { CFShow(error); CFRelease(sourceData), sourceData = nullptr; CFRelease(decoder), decoder = nullptr; return TagLib::ByteVector::null; } result.setData((const char *)CFDataGetBytePtr((CFDataRef)decodedData), (TagLib::uint)CFDataGetLength((CFDataRef)decodedData)); CFRelease(decodedData), decodedData = nullptr; CFRelease(sourceData), sourceData = nullptr; CFRelease(decoder), decoder = 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_mem_buf(reinterpret_cast<void *>(const_cast<char *>(input.data())), input.size()); bio = BIO_push(b64, bio); char inbuf [512]; int inlen; while(0 < (inlen = BIO_read(bio, inbuf, 512))) result.append(ByteVector(inbuf, inlen)); BIO_free_all(bio); return result; #endif }