2014-06-28 20 views
11

Dato un SecKeyRef caricato utilizzando SecItemImport da una chiave privata RSA esiste un modo per ottenere o creare uno SecKeyRef solo per i componenti della chiave pubblica? In OpenSSL questo potrebbe essere fatto copiando il modulo e l'esponente pubblico in una nuova struttura, ma SecKeyRef è opaco e non sono riuscito a trovare una funzione che esegue questa operazione.Ottenere la chiave pubblica da SecKeyRef privato

risposta

1

al MacOS 10.12, iOS/TVOS 10, e watchos 3 la funzione SecKeyCopyPublicKey ora esiste per farlo.

0

Vecchia domanda, ma poiché stavo litigando con esso oggi, ho trovato un modo. Diciamo che avete codificato Base64 chiave pubblica RSA (non è certificato, non è der, PEM, ...), creato in Java (X509 chiave pubblica del certificato), è possibile creare SecKeyRef in questo modo:

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

    unsigned int len = [keyBits length]; 
    if (!len) { 
    return nil; 
    } 

    unsigned char *c_key = (unsigned char *)[keyBits 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++; 
    } 

    if (idx >= len) { 
    return nil; 
    } 

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

    idx += 15; 

    if (idx >= len - 2) { 
    return nil; 
    } 

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

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

    if (idx >= len) { 
    return nil; 
    } 

    if (c_key[idx++] != 0x00) { 
    return nil; 
    } 

    if (idx >= len) { 
    return nil; 
    } 

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

- (SecKeyRef)publicKey:(NSData *)d_key withTag:(NSString *)tag 
{ 
    NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]]; 

    NSDictionary *saveDict = @{ 
          (__bridge id) kSecClass : (__bridge id) kSecClassKey, 
          (__bridge id) kSecAttrKeyType : (__bridge id) kSecAttrKeyTypeRSA, 
          (__bridge id) kSecAttrApplicationTag : d_tag, 
          (__bridge id) kSecAttrKeyClass : (__bridge id) kSecAttrKeyClassPublic, 
          (__bridge id) kSecValueData : d_key 
          }; 

    OSStatus secStatus = SecItemAdd((__bridge CFDictionaryRef)saveDict, NULL); 
    if (secStatus == errSecDuplicateItem) { 
    SecItemDelete((__bridge CFDictionaryRef)saveDict); 
    secStatus = SecItemAdd((__bridge CFDictionaryRef)saveDict, NULL); 
    } 

    if (secStatus != noErr) { 
    return NULL; 
    } 

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

    // Now fetch the SecKeyRef version of the key 
    SecKeyRef keyRef = nil; 
    secStatus = SecItemCopyMatching((__bridge CFDictionaryRef)queryDict, 
            (CFTypeRef *)&keyRef); 

    if (secStatus != noErr) { 
    return NULL; 
    } 

    return keyRef; 
} 

NSData *keyData = [[NSData alloc] initWithBase64EncodedString:@"base64encoded X509 private key" 
                   options:0]; 
certificateData = [self stripPublicKeyHeader2:keyData]; 
SecKeyRef key = [self publicKey:certificateData withTag:[[NSUUID UUID] UUIDString]]; 

Un po 'imbarazzante, non il mio codice, è stato googling per tutto il giorno, molti pezzi incollati insieme. Devo pulirlo, ... Prendilo come un trucco compilato da internet.

Testato contro il server in cui il codice è in Java e questo è l'unico modo per farlo. L'unico modo che ho trovato. Forse ci sono altri modi, ma solo questo funziona per me e posso crittografarlo con questa chiave pubblica RSA (e il nostro codice server (Java) può decrittografarlo. Funziona solo senza padding (non consigliato) o con padding kSecPaddingOAEP sul lato iOS e con RSA/NONE/OAEPWithSHA1AndMGF1Padding sul lato Java.

Problemi correlati