2013-10-09 19 views
9

Prima di tutto, ho visto la sessione del WWDC 2013 sulla protezione dei segreti con il portachiavi. Voglio fare un archivio di passcode di base. Ho guardato l'intero video, ma ho trovato ciò di cui avevo bisogno nei primi 10 minuti del video. Sembra semplice, ma non capisco completamente come funzionano la codifica e il recupero dei dati.secItemCopyMatching restituisce dati nil

PROBLEMA: dopo secItemCopyMatching, controllo l'oggetto NSData per verificare che non sia nullo prima di convertirlo in NSString. Il problema è che è sempre nullo. Di seguito è riportato come sto salvando la voce o l'aggiornamento del portachiavi, seguito da come lo sto recuperando. Qualsiasi aiuto e spiegazione sarebbe molto apprezzato.

AGGIORNAMENTO (MODIFICATO): Fruttato Geek, grazie per la risposta. Ho aggiornato il mio codice qui sotto utilizzando __bridge. Il mio problema ora si riduce a, sto memorizzando e recuperando la password correttamente? Ho sbagliato entrambi o solo uno o l'altro? La mia istanza NSData è sempre nullo. Sto controllando i codici di restituzione e il mio SecItemAdd e SecItemUpdate (quando esiste la voce keychaing) funzionano correttamente. Non riesco a recuperare il valore di stringa dei dati (passcode) memorizzati per confrontarlo con il passcode inserito dall'utente. Apprezzo l'aiuto ragazzi e ragazze. Ecco quello che sto facendo ora:

UPDATE # 2: (a cura con le risposte di Fruity Geek e la versione finale di lavoro le mie modifiche includono solo le modifiche al codice qui sotto..)

Set entrata portachiavi:

NSData *secret = [_backupPassword dataUsingEncoding:NSUTF8StringEncoding]; 
NSDictionary *query = @{ 
    (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, 
    (__bridge id)kSecAttrService: twServiceName, 
    (__bridge id)kSecAttrAccount: twAccountName, 
    (__bridge id)kSecValueData: secret, 
}; 
OSStatus status = 
    SecItemAdd((__bridge CFDictionaryRef)query, NULL); 

if (status == errSecDuplicateItem) { 
    // this item exists in the keychain already, update it 
    query = @{ 
     (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, 
     (__bridge id)kSecAttrService: twServiceName, 
     (__bridge id)kSecAttrAccount: twAccountName, 
    }; 
    NSDictionary *changes = @{ 
     (__bridge id)kSecValueData: secret, 
    }; 
    status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)changes); 
} 

recuperare la password dal portachiavi:

NSDictionary *query = @{ 
    (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, 
    (__bridge id)kSecAttrService: twServiceName, 
    (__bridge id)kSecAttrAccount: twAccountName, 
    (__bridge id)kSecReturnData: @YES, 
}; 
NSData *data = NULL; 
CFTypeRef dataTypeRef = (__bridge CFTypeRef)data; 
OSStatus status = 
    SecItemCopyMatching((__bridge CFDictionaryRef)query, &dataTypeRef); 

NSData *data = (__bridge NSData *)dataTypeRef; 

NSString *passcode = @"none"; 
if (status == errSecSuccess) { 
    // we found a keychain entry, set the passcode 
    if (data) 
     passcode = [NSString stringWithUTF8String:[data bytes]]; 
} 

twServiceName e twAccountName sono NSStrings statici.

Come ho già detto, non faccio esattamente quello che sto facendo con __bridge o CFTypeRef. Ho esaminato i documenti delle mele, numerosi post qui e altri siti, ma il portachiavi e questi termini sono nuovi di zecca per me e sto ancora cercando di capirlo. Sperando che qualcuno qui possa segnalare il mio errore e aiutarmi a capire. Grazie in anticipo per l'aiuto.

iOS 7/Xcode 5

risposta

8

Non è proprio uno qualsiasi degli oggetti core della Fondazione (non è stato creato o copiare loro) e non si desidera mantenere o liberare, così CFBridgingRelease e CFBridgingRetain non è corretto. Utilizzare invece (__bridge id) ogni volta che si desidera eseguire il cast su un oggetto Objective-C.

(__bridge id)kSecAttrService 

when should you use __bridge vs. CFBridgingRelease/CFBridgingRetain?

La variabile dei dati e dataTypeRef sono due puntatori distinti. Solo dataTypeRef è stato riempito con dati in SecItemCopyMatching. Getta il tuo CFTypeRef a NSData dopo che è stato popolato da SecItemCopyMatching modo i dati non è sempre pari a zero

CFTypeRef dataTypeRef = NULL; 
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &dataTypeRef); 
NSData *data = (__bridge NSData *)dataTypeRef; 

Si dovrebbe guardare più da vicino l'OSStatus restituito da tutte le funzioni SecItem chiamate. Ci sono molti possibili codici di ritorno che non hanno successo. Nel tuo caso, stai rilevando un oggetto duplicato in SecItemAdd, quindi lo aggiorni esattamente allo stesso oggetto (non facendo nulla). Invece, dovresti provare a recuperarlo prima usando SecItemCopyMatching. Se non viene trovata alcuna corrispondenza, utilizzare SecItemAdd. Se è stata trovata una corrispondenza, utilizzare SecItemUpdate.

Il codice di esempio da Apple è terribile, non scritto per ARC e confuso, ma esiste. In particolare, il metodo writeToKeychain è quello che ti serve. https://developer.apple.com/library/ios/documentation/Security/Conceptual/keychainServConcepts/iPhoneTasks/iPhoneTasks.html#//apple_ref/doc/uid/TP30000897-CH208-SW1

+0

Grazie. Questo aiuta a chiarire __bridge per me. Sto controllando il codice di ritorno. Ho pensato che provare ad aggiungere avrebbe raggiunto il risultato come secItemCopyMatching. O la voce non esiste e l'aggiunta funziona, o torno errSecDuplicateItem nel qual caso aggiorno la voce con la password. – knarf74

+0

È stato troppo lento a modificare il mio post precedente dopo aver premuto invio non rendendosi conto che avrebbe inviato il mio post ... Il mio problema rimane, sto codificando e memorizzando correttamente la password e come dovrei recuperarla? Dopo averlo memorizzato, cerco CopyMatching e rimuovo lo pssword, ma la mia istanza NSData è sempre nullo. Permettimi di aggiornare il mio codice nel post ... – knarf74

+0

ha trascurato il tuo ultimo commento su writeToKeychain .... leggendo attraverso questo ora. – knarf74

Problemi correlati