Encrypting and Decrypting Data
The encryption and decryption transforms provide various symmetric block cipher encryption algorithms, with optional padding (PKCS #1, #5, and #7) and support for multiple block modes (ECB, CBC, CFB, OFB, or single-block). These transforms also allow you to specify an initialization vector, if appropriate for the desired block mode.
The basic encryption and decryption process consists of two parts: obtaining or generating a key object in the appropriate format and performing the transform itself.
Obtaining a SecKeyRef Object for Symmetric Cryptography
Before you can encrypt or decrypt data, you must create or obtain a SecKeyRef
object for the encryption key. In addition to storing the bytes of the key itself, this object stores information about the type of key stored within.
Obtaining a Key From the Keychain
First, read Certificate, Key, and Trust Services to learn how to retrieve a public key from the keychain. Once you have obtained a SecKeychainItemRef
, you can cast it to a SecKeyRef
for use with this API.
Generating a Random Symmetric Key
If you do not already have an encryption key, you can ask macOS to generate one for you by calling SecKeyGenerateSymmetric
.
Create a parameters dictionary that tells the function what kind of key to generate.
For example, you can create a minimal parameters dictionary for an AES key like this:
CFMutableDictionaryRef parameters = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(parameters, kSecAttrKeyType, kSecAttrKeyTypeAES);
Set the key size to 256 bits.
int32_t rawnum = 256;
CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,
kCFNumberSInt32Type, &rawnum);
CFDictionarySetValue(parameters, kSecAttrKeySizeInBits, num);
Generate the key.
cryptokey = SecKeyGenerateSymmetric(parameters, &error);
Creating a Key Object from an Existing Key
Before you can import or generate a key, you must create a parameters dictionary to describe the expected contents of that key.
For example, you can create a minimal parameters dictionary for an AES key as follows:
CFMutableDictionaryRef parameters = CFDictionaryCreateMutable( |
kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, |
&kCFTypeDictionaryValueCallBacks); |
CFDictionarySetValue(parameters, kSecAttrKeyType, kSecAttrKeyTypeAES); |
If you have an existing key that you want to use for encryption, you must load that key into a CFData
object. Two techniques are described below.
If you have a key in a block of memory, you can create the object from a raw array of bytes like this:
CFDataRef cfdatacryptokey = NULL;
/*
128-bit AES key. This is for demonstration purposes
only. Do NOT hard-code a key into your code.
*/
const uint8_t rawcryptokeyarr[16] = {
63, 17, 27, 99, 185, 231, 1, 191,
217, 74, 141, 16, 12, 99, 253, 41
};
size_t keylen = sizeof(rawcryptokeyarr);
cfdatacryptokey = CFDataCreate(
kCFAllocatorDefault,
rawcryptokeyarr,
keylen);
If the key is in a file, you can use a read transform to get the contents of a file in a
CFDataRef
object, as described in Reading Files.Once you have the key in a
CFData
object, you must callSecKeyCreateFromData
to create the key object.SecKeyRef cryptokey;
CFErrorRef error = NULL;
cryptokey = SecKeyCreateFromData(parameters,
cfdatacryptokey,
&error);
if (error) { CFShow(error); exit(-1); }
Performing the Actual Encryption and Decryption
Once you have the encryption key object, you can create transform objects and use them to encrypt and decrypt the contents of CFData
objects.
Create the encryption objects.
SecTransformRef encrypt = NULL, decrypt = NULL;
/* Create the transform objects */
encrypt = SecEncryptTransformCreate(cryptokey, &error);
if (error) { CFShow(error); exit(-1); }
decrypt = SecDecryptTransformCreate(cryptokey, &error);
if (error) { CFShow(error); exit(-1); }
Set attributes on those objects to specify padding, initialization vectors, and so on, as desired.
For example, to use PKCS #7 padding, you would use the following code:
SecTransformSetAttribute(
encrypt,
kSecPaddingKey,
kSecPaddingPKCS7Key,
&error);
if (error) { CFShow(error); exit(-1); }
SecTransformSetAttribute(
decrypt,
kSecPaddingKey,
kSecPaddingPKCS7Key,
&error);
if (error) { CFShow(error); exit(-1); }
Set the input attributes and execute the transforms.
CFDataRef sourceData = ...
CFDataRef encryptedData = NULL;
CFDataRef decryptedData = NULL;
CFErrorRef error = NULL;
/* Use the sourceData object as input to the encryption object. */
SecTransformSetAttribute(encrypt, kSecTransformInputAttributeName,
sourceData, &error);
if (error) { CFShow(error); exit(-1); }
/* Encrypt the data. */
encryptedData = SecTransformExecute(encrypt, &error);
if (error) { CFShow(error); exit(-1); }
/* Use the encrypted data as input to the decryption object. */
SecTransformSetAttribute(decrypt, kSecTransformInputAttributeName,
encryptedData, &error);
if (error) { CFShow(error); exit(-1); }
/* Decrypt the data. */
decryptedData = SecTransformExecute(decrypt, &error);
if (error) { CFShow(error); exit(-1); }
Copyright © 2018 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2018-06-04