Добавление ключей RSA в связку ключей iPhone - PullRequest
2 голосов
/ 14 мая 2009

Я пытаюсь добавить открытые и закрытые ключи RSA в связку ключей iPhone, чтобы я мог использовать библиотеку CommonCrypto, но не совсем уверен, как это сделать. Библиотека MYCrypto, похоже, сейчас работает только для Mac, а не для iPhone. Может кто-нибудь помочь и объяснить, как добавить закрытый / открытый ключ в цепочку ключей и получить для них SecKeyRef?

Ответы [ 4 ]

5 голосов
/ 20 мая 2014

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

Теперь, когда это не так, вы, безусловно, можете импортировать данные. Поскольку они NSString объекты, вам сначала нужно преобразовать их в NSData объекты, чтобы импортировать их правильно. Скорее всего, они закодированы в Base64, так что вам придется изменить это:

NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:base64String options:0];

Теперь, когда это сделано, вы можете использовать этот метод, чтобы сохранить ключ в цепочке для ключей и получить SecKeyRef:

/**
 * key: the data you're importing
 * keySize: the length of the key (512, 1024, 2048)
 * isPrivate: is this a private key or public key?
 */
- (SecKeyRef)saveKeyToKeychain:(NSData *)key keySize:(NSUInteger)keySize private:(BOOL)isPrivate {
    OSStatus sanityCheck = noErr;
    NSData *tag;
    id keyClass;

    if (isPrivate) {
        tag = privateTag;
        keyClass = (__bridge id) kSecAttrKeyClassPrivate;
    }
    else {
        tag = publicTag;
        keyClass = (__bridge id) kSecAttrKeyClassPublic;
    }

    NSDictionary *saveDict = @{
            (__bridge id) kSecClass : (__bridge id) kSecClassKey,
            (__bridge id) kSecAttrKeyType : (__bridge id) kSecAttrKeyTypeRSA,
            (__bridge id) kSecAttrApplicationTag : tag,
            (__bridge id) kSecAttrKeyClass : keyClass,
            (__bridge id) kSecValueData : key,
            (__bridge id) kSecAttrKeySizeInBits : [NSNumber numberWithUnsignedInteger:keySize],
            (__bridge id) kSecAttrEffectiveKeySize : [NSNumber numberWithUnsignedInteger:keySize],
            (__bridge id) kSecAttrCanDerive : (__bridge id) kCFBooleanFalse,
            (__bridge id) kSecAttrCanEncrypt : (__bridge id) kCFBooleanTrue,
            (__bridge id) kSecAttrCanDecrypt : (__bridge id) kCFBooleanFalse,
            (__bridge id) kSecAttrCanVerify : (__bridge id) kCFBooleanTrue,
            (__bridge id) kSecAttrCanSign : (__bridge id) kCFBooleanFalse,
            (__bridge id) kSecAttrCanWrap : (__bridge id) kCFBooleanTrue,
            (__bridge id) kSecAttrCanUnwrap : (__bridge id) kCFBooleanFalse
    };

    SecKeyRef savedKeyRef = NULL;
    sanityCheck = SecItemAdd((__bridge CFDictionaryRef) saveDict, (CFTypeRef *)&savedKeyRef);
    if (sanityCheck != errSecSuccess) {
        LOGGING_FACILITY1(sanityCheck != noErr, @"Problem saving the key to keychain, OSStatus == %d.", sanityCheck);
    }

    return savedKeyRef;
}

Позже, если вы хотите получить SecKeyRef из цепочки для ключей, вы можете использовать это:

- (SecKeyRef)getKeyRef:(BOOL)isPrivate {
    OSStatus sanityCheck = noErr;
    NSData *tag;
    id keyClass;
    if (isPrivate) {
        if (privateKeyRef != NULL) {
            // already exists in memory, return
            return privateKeyRef;
        }
        tag = privateTag;
        keyClass = (__bridge id) kSecAttrKeyClassPrivate;
    }
    else {
        if (publicKeyRef != NULL) {
            // already exists in memory, return
            return publicKeyRef;
        }
        tag = publicTag;
        keyClass = (__bridge id) kSecAttrKeyClassPublic;
    }

    NSDictionary *queryDict = @{
            (__bridge id) kSecClass : (__bridge id) kSecClassKey,
            (__bridge id) kSecAttrKeyType : (__bridge id) kSecAttrKeyTypeRSA,
            (__bridge id) kSecAttrApplicationTag : tag,
            (__bridge id) kSecAttrKeyClass : keyClass,
            (__bridge id) kSecReturnRef : (__bridge id) kCFBooleanTrue
    };

    SecKeyRef keyReference = NULL;
    sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef) queryDict, (CFTypeRef *) &keyReference);
    if (sanityCheck != errSecSuccess) {
        NSLog(@"Error trying to retrieve key from server. isPrivate: %d. sanityCheck: %li", isPrivate, sanityCheck);
    }

    if (isPrivate) {
        privateKeyRef = keyReference;
    }
    else {
        publicKeyRef = keyReference;
    }
    return keyReference;
}

О privateTag и publicTag

privateTag и publicTag используются для обозначения kSecAttrApplicationTag, который определяет приложение, использующее этот ключ. Вы хотите иметь отдельные privateTag и publicTag, чтобы различать ваш закрытый ключ и открытый ключ.

Это немного запутанно, потому что я следовал примеру кода, но я определил свои privateTag и publicTag следующим образом:

SecKeyWrapper.h

#define kPublicKeyTag           "com.sample.app.publickey"
#define kPrivateKeyTag          "com.sample.app.privatekey"

SecKeyWrapper.m

// just under @implementation or @synthesize lines
static const uint8_t publicKeyIdentifier[] = kPublicKeyTag;
static const uint8_t privateKeyIdentifier[] = kPrivateKeyTag;

- (id)init {
    if (self = [super init]) {
        // Tag data to search for keys.
        privateTag = [[NSData alloc] initWithBytes:privateKeyIdentifier length:sizeof(privateKeyIdentifier)];
        publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];
    }

    return self;
}

Затем используйте privateTag и publicTag, как и в приведенных выше примерах кода.

1 голос
/ 24 июня 2009

Вы генерируете их на iPhone? Если это так, это сообщение плюс примерный код в Руководстве по программированию сертификатов, ключей и доверенных служб должны направить вас в правильном направлении. Если нет, я работаю над кодом, который должен это сделать - он еще не совсем там.

0 голосов
/ 25 сентября 2014

Код, который работает для меня, чтобы добавить открытый ключ в связку ключей iOS, приведен ниже:

- (NSData *)stripPublicKeyHeader:(NSData *)d_key
{
    // Skip ASN.1 public key header
    if (d_key == nil) return(nil);

    unsigned int len = [d_key length];
    if (!len) return(nil);

    unsigned char *c_key = (unsigned char *)[d_key bytes];
    unsigned int  idx    = 0;

    if (c_key[idx++] != 0x30) return(nil);

    if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
    else idx++;

    // PKCS #1 rsaEncryption szOID_RSA_RSA
    static unsigned char seqiod[] =
    { 0x30,   0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
        0x01, 0x05, 0x00 };
    if (memcmp(&c_key[idx], seqiod, 15)) return(nil);

    idx += 15;

    if (c_key[idx++] != 0x03) return(nil);

    if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
    else idx++;

    if (c_key[idx++] != '\0') return(nil);

    // Now make a new NSData from this buffer
    return([NSData dataWithBytes:&c_key[idx] length:len - idx]);
}

- (BOOL)addPublicKey:(NSString *)key withTag:(NSString *)tag
{    
    NSString *startPublicKey = @"-----BEGIN PUBLIC KEY-----";
    NSString *endPublicKey = @"-----END PUBLIC KEY-----";

    NSString *s_key = NULL;

    NSScanner *scanner = [NSScanner scannerWithString:key];
    [scanner scanUpToString:startPublicKey intoString:nil];
    [scanner scanString:startPublicKey intoString:nil];
    [scanner scanUpToString:endPublicKey intoString:&s_key];

    // This will be base64 encoded, decode it.
    NSData *d_key = [RSAKeyHandler base64DataFromString:s_key];
    d_key = [self stripPublicKeyHeader:d_key];
    if (d_key == nil) return(FALSE);

    NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]];

    // Delete any old lingering key with the same tag
    NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init];
    [publicKey setObject:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass];
    [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
    [publicKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag];
    SecItemDelete((__bridge CFDictionaryRef)publicKey);

    CFTypeRef persistKey = nil;

    // Add persistent version of the key to system keychain
    [publicKey setObject:d_key forKey:(__bridge id)kSecValueData];
    [publicKey setObject:(__bridge id) kSecAttrKeyClassPublic forKey:(__bridge id)
     kSecAttrKeyClass];
    [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)
     kSecReturnPersistentRef];

    OSStatus secStatus = SecItemAdd((__bridge CFDictionaryRef)publicKey, &persistKey);
    if (persistKey != nil) CFRelease(persistKey);

    if ((secStatus != noErr) && (secStatus != errSecDuplicateItem)) {
        NSLog(@"Release public key");
        return(FALSE);
    }

    // Now fetch the SecKeyRef version of the key
    SecKeyRef keyRef = nil;

    [publicKey removeObjectForKey:(__bridge id)kSecValueData];
    [publicKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef];
    [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef
     ];
    [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
    secStatus = SecItemCopyMatching((__bridge CFDictionaryRef)publicKey,
                                    (CFTypeRef *)&keyRef);

    //[publicKey release];

    if (keyRef == nil) return(FALSE);

    // Add to our pseudo keychain
    //[keyRefs addObject:[NSValue valueWithBytes:&keyRef objCType:@encode(
    //                                                                    SecKeyRef)]];

    return(TRUE);
}
0 голосов
/ 14 мая 2009

Похоже, что это дубликат этого SO вопроса .

MyCrypto говорит, что работает на iPhone . Какие проблемы вы видите?

...