Сертификат, Ключ и Задачи Trust Services для iOS

В этой главе описываются и иллюстрирует использование Сертификата, Ключа, и функций Trust Services, чтобы импортировать идентификационные данные, оценить доверие сертификата, определить причину доверительного отказа и восстановиться с доверительного отказа.

Последовательность операций, проиллюстрированных в этой главе:

  1. Импортируйте идентификационные данные.

  2. Получите сертификат из импортированных данных.

  3. Получите объект политики для политики, используемой в оценке сертификата.

  4. Проверьте сертификат и оцените, можно ли ему доверять, как указано политикой.

  5. Тест для восстанавливаемой доверительной ошибки.

  6. Определите, является ли доверительная ошибка вследствие сертификата с истекшим сроком.

  7. Измените критерии оценки для игнорирования истекших сертификатов.

  8. Переоцените сертификат.

Сертификат, Ключ и Понятия Trust Services обеспечивают введение в понятия и терминологию Сертификата, Ключа и Trust Services. Для получения дальнейшей информации обо всем Сертификате, Ключ и функции Trust Services, видят Сертификат, Ключ и Ссылку Trust Services.

Фрагменты кода в этой главе предполагают, что Вы уже включали упомянутые ниже заголовки и что Ваше программное обеспечение уже соединяется против Базовой Основы, Основы и Концепций безопасности.

#import <UIKit/UIKit.h>
#import <Security/Security.h>
#import <CoreFoundation/CoreFoundation.h>

Извлечение и оценка идентификационных данных от *.P12 файла

При необходимости в криптографических идентификационных данных (т.е. закрытый ключ и его связанный сертификат) на основанном на iOS устройстве — для аутентификации клиентской стороны, например — можно передать его устройству надежно как данные PKCS № 12 в защищенном паролем *.p12 файл. Этот раздел показывает, как извлечь идентификационные данные и доверительные объекты от данных № 12 PKCS и как оценить доверие.

Перечисление 2-1 показывает пример кода для использования SecPKCS12Import функционируйте для извлечения идентификационных данных и доверительных объектов от a *.p12 файл и как оценить доверие. Перечисление 2-2 показывает, как получить сертификат от идентификационных данных и информации о сертификате дисплея. Объяснения пронумерованных строк кода следуют за каждым перечислением.

Обязательно добавьте Концепцию безопасности к Вашему проекту XCode при компиляции кода с этим отрывком.

Перечисление 2-1  , Извлекающее идентификационные данные и доверие, возражает от Данных № 12 PKCS

OSStatus extractIdentityAndTrust(CFDataRef inPKCS12Data,
                                 SecIdentityRef *outIdentity,
                                 SecTrustRef *outTrust,
                                 CFStringRef keyPassword)
{
    OSStatus securityError = errSecSuccess;
 
 
    const void *keys[] =   { kSecImportExportPassphrase };
    const void *values[] = { keyPassword };
    CFDictionaryRef optionsDictionary = NULL;
 
    /* Create a dictionary containing the passphrase if one
       was specified.  Otherwise, create an empty dictionary. */
    optionsDictionary = CFDictionaryCreate(
                                                  NULL, keys,
                                                  values, (keyPassword ? 1 : 0),
                                                  NULL, NULL);  // 1
 
    CFArrayRef items = NULL;
    securityError = SecPKCS12Import(inPKCS12Data,
                                    optionsDictionary,
                                    &items);                    // 2
 
 
    //
    if (securityError == 0) {                                   // 3
        CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);
        const void *tempIdentity = NULL;
        tempIdentity = CFDictionaryGetValue (myIdentityAndTrust,
                                                       kSecImportItemIdentity);
        CFRetain(tempIdentity);
        *outIdentity = (SecIdentityRef)tempIdentity;
        const void *tempTrust = NULL;
        tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust);
 
        CFRetain(tempTrust);
        *outTrust = (SecTrustRef)tempTrust;
    }
 
    if (optionsDictionary)                                      // 4
        CFRelease(optionsDictionary);
 
    if (items)
        CFRelease(items);
 
    return securityError;
}

Этот код предполагает что:

Вот то, что делает код:

  1. Устанавливает словарь, содержащий пароль для передачи SecPKCS12Import. Заметьте что базовые словари основы — как используется здесь — и NSDictionary класс полностью эквивалентен. См. Перечисление 2-9 для использования в качестве примера NSDictionary методы.

  2. Извлекает сертификат, ключ и доверие от данных № 12 PKCS и помещает их в массив.

  3. Вытаскивает первый словарь из массива и вытаскивает идентификационные данные и доверие из словаря. SecPKCS12Import функционируйте возвращает один словарь для каждого элемента (идентификационные данные или сертификат) в данных № 12 PKCS. В этой выборке извлекаемые идентификационные данные являются первым в массиве (элемент № 0).

  4. Избавляется от словаря опций и массива элементов, которые больше не необходимы.

После выполнения этих шагов Вы обычно должны:

  1. Выпустите CFDataRef объект, содержащий необработанные данные.

  2. Оцените доверие путем вызова SecTrustEvaluate или SecTrustEvaluateAsync на возвращенном доверительном объекте.

  3. Обработайте доверительный результат.

    Если доверительный результат kSecTrustResultInvalid, kSecTrustResultDeny, kSecTrustResultFatalTrustFailure, Вы не можете продолжить и должны перестать работать корректно.

    Если доверительный результат kSecTrustResultRecoverableTrustFailure, Вы могли бы быть в состоянии восстановиться с отказа. Посмотрите Восстановление С Доверительного Отказа.

Следующее перечисление показывает, как получить сертификат от идентификационных данных и как вывести на экран информацию из сертификата. Обязательно добавьте Концепцию безопасности к Вашему проекту XCode при компиляции кода с этим отрывком.

Перечисление 2-2  , Выводящее на экран информацию из сертификата

NSString *copySummaryString(SecIdentityRef identity)
{
    // Get the certificate from the identity.
    SecCertificateRef myReturnedCertificate = NULL;
    OSStatus status = SecIdentityCopyCertificate (identity,
                                      &myReturnedCertificate);  // 1
 
    if (status) {
        NSLog(@"SecIdentityCopyCertificate failed.\n");
        return NULL;
    }
 
    CFStringRef certSummary = SecCertificateCopySubjectSummary
                                      (myReturnedCertificate);  // 2
 
    NSString* summaryString = [[NSString alloc]
                       initWithString:(__bridge NSString *)certSummary];  // 3
 
    CFRelease(certSummary);
 
    return summaryString;
}

Вот то, что делает код:

  1. Извлекает сертификат из идентификационных данных.

  2. Получает сводную информацию из сертификата.

  3. Преобразовывает строку в NSString возразите, таким образом, это может быть выведено на экран.

  4. Выпуски NSString объект.

Добираясь и Используя персистентные ссылки цепочки для ключей

Когда Вы добавляете элемент к цепочке для ключей или находите элемент в цепочке для ключей, можно запросить персистентную ссылку. Поскольку персистентная ссылка остается допустимой между вызовами Вашей программы и может быть сохранена на диске, можно использовать, чтобы упростить находить элемент цепочки для ключей, в котором Вы будете неоднократно нуждаться. Следующий пример кода показывает, как получить персистентную ссылку для объекта идентификационных данных, полученного в Перечислении 2-1.

Перечисление 2-3  , Получающее персистентную ссылку для идентификационных данных

CFDataRef persistentRefForIdentity(SecIdentityRef identity)
{
    OSStatus status = errSecSuccess;
 
    CFTypeRef  persistent_ref = NULL;
    const void *keys[] =   { kSecReturnPersistentRef, kSecValueRef };
    const void *values[] = { kCFBooleanTrue,          identity };
    CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values,
                                              2, NULL, NULL);
    status = SecItemAdd(dict, &persistent_ref);
 
    if (dict)
        CFRelease(dict);
 
    return (CFDataRef)persistent_ref;
}

Следующая выборка показывает, как получить объект идентификационных данных от цепочки для ключей с помощью персистентной ссылки.

Перечисление 2-4  , Добирающееся идентификационные данные с помощью персистентной ссылки

SecIdentityRef identityForPersistentRef(CFDataRef persistent_ref)
{
    CFTypeRef   identity_ref     = NULL;
    const void *keys[] =   { kSecClass, kSecReturnRef,  kSecValuePersistentRef };
    const void *values[] = { kSecClassIdentity, kCFBooleanTrue, persistent_ref };
    CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values,
                                              3, NULL, NULL);
    SecItemCopyMatching(dict, &identity_ref);
 
    if (dict)
        CFRelease(dict);
 
    return (SecIdentityRef)identity_ref;
}

Нахождение сертификата в цепочке для ключей

Следующий пример кода показывает, как найти сертификат в цепочке для ключей с помощью имени сертификата для идентификации его. Для нахождения элемента цепочки для ключей с помощью персистентной ссылки см. Перечисление 2-4. Для нахождения элемента цепочки для ключей с помощью строки идентификатора, сохраненной как атрибут элемента цепочки для ключей, посмотрите Шифрование и Дешифрование Данных. Объяснение каждой пронумерованной строки кода следует за перечислением.

Перечисление 2-5  , Находящее сертификат В Цепочке для ключей

    OSStatus status = errSecSuccess;
    CFTypeRef   certificateRef     = NULL;                      // 1
    const char *certLabelString = "Romeo Montague";
    CFStringRef certLabel = CFStringCreateWithCString(
                                NULL, certLabelString,
                                kCFStringEncodingUTF8);         // 2
 
    const void *keys[] =   { kSecClass, kSecAttrLabel, kSecReturnRef };
    const void *values[] = { kSecClassCertificate, certLabel, kCFBooleanTrue };
    CFDictionaryRef dict = CFDictionaryCreate(NULL, keys,
                                               values, 3,
                                             NULL, NULL);       // 3
    status = SecItemCopyMatching(dict, &certificateRef);        // 4
 
    if (status == errSecSuccess) {
        CFRelease(certificateRef);
        certificateRef = NULL;
    }
 
    /* Do something with certificateRef here */
 
    if (dict)
        CFRelease(dict);

Вот то, что делает код:

  1. Определяет переменную для содержания объекта сертификата.

  2. Создает строку, содержащую имя сертификата.

  3. Создает словарь атрибутов, которые будут использоваться в поиске сертификата. kSecReturnRef ключ указывает, что функция должна возвратить ссылку на элемент цепочки для ключей, когда это найдено.

  4. Поиски сертификата в цепочке для ключей.

Получение объекта политики и оценка доверия

Прежде чем можно будет оценить доверие сертификата, необходимо получить ссылочный объект для сертификата. Можно получить объект сертификата путем извлечения его из идентификационных данных (см. Перечисление 2-2), путем создания один от данных сертификата DER с помощью SecCertificateCreateWithData функция (см. следующую выборку: Перечисление 2-6), или путем нахождения сертификата на цепочке для ключей (Перечисление 2-5).

Критерии оценки доверия установлены доверительными политиками. Перечисление 2-6 показывает, как можно получить объект политики для использования в оценке. Существует две политики, доступные в iOS с этой целью: Основной X509 и SSL (см. Политики Доверия AppleX509TP). Вы используете SecPolicyCreateBasicX509 или SecPolicyCreateSSL функция для получения объекта политики.

Следующий пример кода показывает, как получить объект политики и использовать его для оценки доверия сертификата. Объяснение каждой пронумерованной строки кода следует за перечислением.

Перечисление 2-6  Получая ссылку политики возражает и оценивая доверие

    NSString *thePath = [[NSBundle mainBundle]
                          pathForResource:@"Romeo Montague" ofType:@"cer"];
    NSData *certData = [[NSData alloc]
                         initWithContentsOfFile:thePath];
    CFDataRef myCertData = (__bridge CFDataRef)certData;                 // 1
 
    SecCertificateRef myCert;
    myCert = SecCertificateCreateWithData(NULL, myCertData);    // 2
 
    SecPolicyRef myPolicy = SecPolicyCreateBasicX509();         // 3
 
    SecCertificateRef certArray[1] = { myCert };
    CFArrayRef myCerts = CFArrayCreate(
                                       NULL, (void *)certArray,
                                       1, NULL);
    SecTrustRef myTrust;
    OSStatus status = SecTrustCreateWithCertificates(
                                                    myCerts,
                                                    myPolicy,
                                                    &myTrust);  // 4
 
    SecTrustResultType trustResult;
    if (status == noErr) {
        status = SecTrustEvaluate(myTrust, &trustResult);       // 5
    }
//...                                                             // 6
    if (trustResult == kSecTrustResultRecoverableTrustFailure) {
        // ...;
    }
// ...
    if (myPolicy)
        CFRelease(myPolicy);                                    // 7

Вот то, что делает код:

  1. Находит файл сертификата и получает данные. В этом примере файл включен в комплект приложений. Если Вы предпочитаете, Однако можно передать сертификат приложению по сети. Если сертификат уже находится в цепочке для ключей, посмотрите Нахождение Сертификата В Цепочке для ключей.

  2. Создает ссылку сертификата из данных сертификата.

  3. Создает политику, которая будет использоваться в оценке доверия.

  4. Создает доверительный объект с помощью сертификата и политики. Если у Вас есть промежуточные сертификаты или сертификат привязки для цепочки сертификата, можно включать, те в массиве сертификата передали SecTrustCreateWithCertificates функция. Выполнение так ускоряет доверительную оценку.

  5. Оценивает доверие.

  6. Обрабатывает доверительный результат. Если доверительный результат kSecTrustResultInvalid, kSecTrustResultDeny, kSecTrustResultFatalTrustFailure, Вы не можете продолжить и должны перестать работать корректно. Если доверительный результат kSecTrustResultRecoverableTrustFailure, Вы могли бы быть в состоянии восстановиться с отказа. Посмотрите Восстановление С Доверительного Отказа.

  7. Избавляется от объекта политики в конце подпрограммы, после того, как это использовалось для оценки доверия.

Восстановление с доверительного отказа

Существует несколько возможных результатов доверительной оценки, в зависимости от таких факторов как, были ли все сертификаты в цепочке найдены, допустимы ли они все, и что пользовательские настройки доверия для сертификатов. Это до Вашего приложения для определения плана действий на основе результата оценки. Например, если результат kSecTrustResultConfirm, необходимо вывести на экран диалоговое окно, запрашивающее, чтобы пользователь дал разрешение продолжиться.

Результат оценки kSecTrustResultRecoverableTrustFailure указывает, что доверие было отклонено, но что возможно изменить настройки для получения различного результата. Например, если сертификат, используемый для подписания документа, истек, можно изменить дату, используемую для оценки, чтобы видеть, был ли сертификат допустим, когда был подписан документ. Код в Перечислении 2-7 иллюстрирует, как изменить дату оценки. Обратите внимание на то, что CFDateCreate функция занимает абсолютное время (число секунд с 1 января 2001); можно использовать CFGregorianDateGetAbsoluteTime функционируйте для преобразования календарной даты и время в абсолютное время. Объяснение каждой пронумерованной строки кода следует за перечислением.

Перечисление 2-7  , Назначающее дату оценки

void recoverFromTrustFailure(SecTrustRef myTrust)
{
    SecTrustResultType trustResult;
    OSStatus status = SecTrustEvaluate(myTrust, &trustResult);  // 1
 
    //Get time used to verify trust
    CFAbsoluteTime trustTime,currentTime,timeIncrement,newTime;
    CFDateRef newDate;
    if (trustResult == kSecTrustResultRecoverableTrustFailure) {// 2
        trustTime = SecTrustGetVerifyTime(myTrust);             // 3
        timeIncrement = 31536000;                               // 4
        currentTime = CFAbsoluteTimeGetCurrent();               // 5
        newTime = currentTime - timeIncrement;                  // 6
        if (trustTime - newTime){                               // 7
            newDate = CFDateCreate(NULL, newTime);              // 8
            SecTrustSetVerifyDate(myTrust, newDate);            // 9
            status = SecTrustEvaluate(myTrust, &trustResult);   // 10
        }
    }
    if (trustResult != kSecTrustResultProceed) {                // 11
//...
    }
}

Вот то, что делает код:

  1. Оценивает доверие сертификата. Посмотрите Получение Объекта политики и Оценку Доверия.

  2. Проверки, был ли результатом доверительной оценки восстанавливаемый доверительный отказ.

  3. Получает абсолютное время, использовавшееся для оценки доверия. Если сертификат истек перед этим временем, то это считают недопустимым.

  4. Устанавливает инкремент времени, равный числу секунд через год.

  5. Получает текущее (абсолютное) время.

  6. Вычитает год с текущего времени.

  7. Проверки, было ли время, используемое для оценки доверия, более свежим, чем один год перед текущим временем. Если это было, то доверие оценено снова с помощью нового времени; т.е. сертификат проверяется, чтобы видеть, привел ли он проверку к сбою, потому что он истек когда-то в прошлом году.

  8. Преобразовывает новое время в a CFDateRef. Можно также использовать NSDate управлять датами; CFDateRef и NSDate бесплатный соединенный мостом, означая в методе, где Вы видите NSDate * параметр, можно передать в a CFDateRef, и в функции, где Вы видите a CFDateRef параметр, можно передать в экземпляре NSDate или конкретного подкласса NSDate.

  9. Назначает дату, используемую для проверки, доверяют новому времени (годом ранее).

  10. Переоценивает доверие. Если причина, которой состояла в том доверительная отказавшая оценка, потому что должен теперь успешно выполниться сертификат, истекший в течение года после текущего времени, оценка.

  11. Проверки, успешно выполняется ли теперь оценка. В противном случае можно попробовать что-то еще, такое как то, чтобы просить, чтобы пользователь установил промежуточный сертификат, или можно сказать пользователю, что сертификат не допустим, и перестали работать корректно.

Шифрование и дешифрование данных

Сертификат, Ключ и Доверие API включают функции для генерации асимметричных пар ключей и использования их, чтобы зашифровать и дешифровать данные. Вы могли бы хотеть использовать эту функцию для шифрования данных, что Вы не хотите быть доступными в данных резервного копирования, например. Или, можно использовать пару частную с открытым ключом, совместно использованную приложением для iOS и настольным приложением для отправки зашифрованных данных по сети. Код в Перечислении 2-8 показывает, как генерировать пару общедоступную с закрытым ключом для использования на мобильном устройстве. Перечисление 2-9 показывает, как использовать открытый ключ для шифрования данных с помощью Сертификата, Ключа и Доверительных функций, и Перечисление 2-10 показывает, как использовать закрытый ключ для дешифрования данных. Заметьте, что эти выборки используют объекты Какао (такой как NSMutableDictionary) вместо базовых объектов основы (такой как CFMutableDictionaryRef) используемый в других выборках в этой главе. Объекты Какао и их Базовые дубликаты Основы абсолютно эквивалентны и бесплатные соединенный мостом; например, в методе, где Вы видите NSMutableDictionary * параметр, можно передать в a CFMutableDictionaryRef, и в функции, где Вы видите a CFMutableDictionaryRef параметр, можно передать в экземпляре NSMutableDictionary. Объяснения пронумерованных строк кода следуют за каждым перечислением.

Перечисление 2-8  , Генерирующее пару ключей

static const UInt8 publicKeyIdentifier[] = "com.apple.sample.publickey\0";
static const UInt8 privateKeyIdentifier[] = "com.apple.sample.privatekey\0";
 
- (void)generateKeyPairPlease
{
    OSStatus status = noErr;
    NSMutableDictionary *privateKeyAttr = [[NSMutableDictionary alloc] init];
    NSMutableDictionary *publicKeyAttr = [[NSMutableDictionary alloc] init];
    NSMutableDictionary *keyPairAttr = [[NSMutableDictionary alloc] init];
                                                                // 2
 
    NSData * publicTag = [NSData dataWithBytes:publicKeyIdentifier
                                length:strlen((const char *)publicKeyIdentifier)];
    NSData * privateTag = [NSData dataWithBytes:privateKeyIdentifier
                               length:strlen((const char *)privateKeyIdentifier)];
                                                                // 3
 
    SecKeyRef publicKey = NULL;
    SecKeyRef privateKey = NULL;                                // 4
 
    [keyPairAttr setObject:(__bridge id)kSecAttrKeyTypeRSA
                                   forKey:(__bridge id)kSecAttrKeyType]; // 5
    [keyPairAttr setObject:[NSNumber numberWithInt:1024]
                             forKey:(__bridge id)kSecAttrKeySizeInBits]; // 6
 
    [privateKeyAttr setObject:[NSNumber numberWithBool:YES]
                               forKey:(__bridge id)kSecAttrIsPermanent]; // 7
    [privateKeyAttr setObject:privateTag
                            forKey:(__bridge id)kSecAttrApplicationTag]; // 8
 
    [publicKeyAttr setObject:[NSNumber numberWithBool:YES]
                               forKey:(__bridge id)kSecAttrIsPermanent]; // 9
    [publicKeyAttr setObject:publicTag
                            forKey:(__bridge id)kSecAttrApplicationTag]; // 10
 
    [keyPairAttr setObject:privateKeyAttr
                               forKey:(__bridge id)kSecPrivateKeyAttrs]; // 11
    [keyPairAttr setObject:publicKeyAttr
                                forKey:(__bridge id)kSecPublicKeyAttrs]; // 12
 
    status = SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttr,
                                      &publicKey, &privateKey); // 13
//    error handling...
 
 
    if(publicKey) CFRelease(publicKey);
    if(privateKey) CFRelease(privateKey);                       // 14
}

Вот то, что делает код:

  1. Определяет уникальные строки, которые будут добавлены как атрибуты к элементам цепочки для ключей с открытым ключом и с закрытым ключом для создания их проще найти позже.

  2. Выделяет словари, которые будут использоваться для атрибутов в SecKeyGeneratePair функция.

  3. Создает NSData объекты, содержащие строки идентификатора, определенные на шаге 1.

  4. Выделяет SecKeyRef объекты для открытых и закрытых ключей.

  5. Устанавливает ключевой атрибут типа для пары ключей к RSA.

  6. Устанавливает атрибут размера ключа для пары ключей к 1 024 битам.

  7. Устанавливает атрибут, указывающий, что закрытый ключ должен быть сохранен постоянно (т.е. помещен в цепочку для ключей).

  8. Добавляет строка идентификатора, определенная на шагах 1 и 3 к словарю для закрытого ключа.

  9. Устанавливает атрибут, указывающий, что открытый ключ должен быть сохранен постоянно (т.е. помещен в цепочку для ключей).

  10. Добавляет строка идентификатора, определенная на шагах 1 и 3 к словарю для открытого ключа.

  11. Добавляет словарь атрибутов с закрытым ключом к словарю пары ключей.

  12. Добавляет словарь атрибутов с открытым ключом к словарю пары ключей.

  13. Генерирует пару ключей.

  14. Память выпусков, которая больше не необходима.

Можно отправить открытый ключ любому, кто может тогда использовать его для шифрования данных. Принятие Вас сохраняет Ваш закрытый ключ безопасным, тогда только Вы будете в состоянии дешифровать данные. Следующий пример кода показывает, как зашифровать данные с помощью открытого ключа. Это может быть открытым ключом, который Вы генерировали на устройстве (см. предыдущий пример кода), или открытый ключ, который Вы извлекли из сертификата, отправленного Вам или это находится в Вашей цепочке для ключей. Можно использовать SecTrustCopyPublicKey функционируйте для извлечения открытого ключа из сертификата. В следующем примере кода ключ, как предполагается, был сгенерирован на устройстве и помещен в цепочку для ключей. Объяснение каждой пронумерованной строки кода следует за перечислением.

Перечисление 2-9  , Шифрующее данные с открытым ключом

- (NSData *)encryptWithPublicKey
{
    OSStatus status = noErr;
 
    size_t cipherBufferSize;
    uint8_t *cipherBuffer;                     // 1
 
// [cipherBufferSize]
    const uint8_t dataToEncrypt[] = "the quick brown fox jumps "
                            "over the lazy dog\0"; // 2
    size_t dataLength = sizeof(dataToEncrypt)/sizeof(dataToEncrypt[0]);
 
    SecKeyRef publicKey = NULL;                                 // 3
 
    NSData * publicTag = [NSData dataWithBytes:publicKeyIdentifier
             length:strlen((const char *)publicKeyIdentifier)]; // 4
 
    NSMutableDictionary *queryPublicKey =
                            [[NSMutableDictionary alloc] init]; // 5
 
    [queryPublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
    [queryPublicKey setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
    [queryPublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
    [queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
                                                                // 6
 
    status = SecItemCopyMatching
    ((__bridge CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKey); // 7
 
//  Allocate a buffer
 
    cipherBufferSize = SecKeyGetBlockSize(publicKey);
    cipherBuffer = malloc(cipherBufferSize);
 
//  Error handling
 
    if (cipherBufferSize < sizeof(dataToEncrypt)) {
        // Ordinarily, you would split the data up into blocks
        // equal to cipherBufferSize, with the last block being
        // shorter. For simplicity, this example assumes that
        // the data is short enough to fit.
        printf("Could not decrypt.  Packet too large.\n");
        return NULL;
    }
 
    // Encrypt using the public.
    status = SecKeyEncrypt(    publicKey,
                                kSecPaddingPKCS1,
                                dataToEncrypt,
                                (size_t) dataLength,
                                cipherBuffer,
                                &cipherBufferSize
                                );                              // 8
 
//  Error handling
//  Store or transmit the encrypted text
 
    if (publicKey) CFRelease(publicKey);
 
    NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:dataLength];
 
    free(cipherBuffer);
 
    return encryptedData;
}

Вот то, что делает код:

  1. Выделяет буфер для содержания зашифрованного текста.

  2. Указывает текст, который будет зашифрован.

  3. Выделяет a SecKeyRef объект для открытого ключа.

  4. Создает NSData объект, содержащий уникальную строку раньше, идентифицировал открытый ключ в цепочке для ключей (см. шаги 1, 3, и 8 в Перечислении 2-8).

  5. Выделяет словарь, который будет использоваться для нахождения открытого ключа в цепочке для ключей.

  6. Указывает пар атрибута значения ключа для словаря, который будет использоваться для нахождения открытого ключа в цепочке для ключей. Атрибуты указывают, что элемент цепочки для ключей является ключом шифрования; то, что элемент цепочки для ключей имеет атрибут, содержащий уникальную строку, указанную на шаге 4; то, что элемент является ключом RSA; и что должна быть возвращена ссылка на элемент цепочки для ключей.

  7. Вызовы SecItemCopyMatching функционируйте для нахождения ключа в цепочке для ключей.

  8. Шифрует данные от шага 2 с помощью ключа, возвращенного SecItemCopyMatching функция на шаге 7 с помощью дополнения PKCS1.

  9. Память выпусков, которая больше не необходима.

Следующий пример кода показывает, как дешифровать данные. Эта выборка использует закрытый ключ, соответствующий открытому ключу, используемому для шифрования данных, и предполагает, что Вам уже создали шифрованный текст в предыдущем примере. Это получает закрытый ключ от цепочки для ключей с помощью того же метода, как используется в предыдущем примере получить открытый ключ.

  Дешифрование перечисления 2-10 с закрытым ключом

- (void)decryptWithPrivateKey: (NSData *)dataToDecrypt
{
    OSStatus status = noErr;
 
    size_t cipherBufferSize = [dataToDecrypt length];
    uint8_t *cipherBuffer = (uint8_t *)[dataToDecrypt bytes];
 
    size_t plainBufferSize;
    uint8_t *plainBuffer;
 
    SecKeyRef privateKey = NULL;
 
    NSData * privateTag = [NSData dataWithBytes:privateKeyIdentifier
                            length:strlen((const char *)privateKeyIdentifier)];
 
    NSMutableDictionary *queryPrivateKey = [[NSMutableDictionary alloc] init];
 
    // Set the private key query dictionary.
    [queryPrivateKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
    [queryPrivateKey setObject:privateTag forKey:(__bridge id)kSecAttrApplicationTag];
    [queryPrivateKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
    [queryPrivateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
                                                                // 1
 
    status = SecItemCopyMatching
  ((__bridge CFDictionaryRef)queryPrivateKey, (CFTypeRef *)&privateKey); // 2
 
    //  Allocate the buffer
    plainBufferSize = SecKeyGetBlockSize(privateKey);
    plainBuffer = malloc(plainBufferSize);
 
    if (plainBufferSize < cipherBufferSize) {
        // Ordinarily, you would split the data up into blocks
        // equal to plainBufferSize, with the last block being
        // shorter. For simplicity, this example assumes that
        // the data is short enough to fit.
        printf("Could not decrypt.  Packet too large.\n");
        return;
    }
 
//  Error handling
 
    status = SecKeyDecrypt(    privateKey,
                                kSecPaddingPKCS1,
                                cipherBuffer,
                                cipherBufferSize,
                                plainBuffer,
                                &plainBufferSize
                                );                              // 3
 
//  Error handling
//  Store or display the decrypted text
 
    if(privateKey) CFRelease(privateKey);
}

Вот то, что делает код:

  1. Устанавливает словарь, используемый для нахождения закрытого ключа в цепочке для ключей.

  2. Находит закрытый ключ в цепочке для ключей.

  3. Дешифрует данные.

  4. Память выпусков, которая больше не необходима.