problema llavero hubo funciona está eliminar dónde cuál contraseña como aprobar acceder ios swift keychain touch-id

ios - hubo - llavero icloud android



Solo se puede acceder a los datos en el llavero con Touch ID en Swift 3 (1)

La ventana emergente Touch ID aparece solo si llama a SecItemCopyMatching() en una cola de fondo. Esto se indica en la página 118 de la presentación en PDF de Llavero y autenticación con Touch ID :

Leyendo un secreto
...

dispatch_async(dispatch_get_global_queue(...), ^(void){ CFTypeRef dataTypeRef = NULL; OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, &dataTypeRef); });

De lo contrario, está bloqueando el hilo principal y la ventana emergente no aparece. SecItemCopyMatching() luego falla (después de un tiempo de espera) con el código de error -25293 = errSecAuthFailed .

El error no es evidente de inmediato en su proyecto de ejemplo porque imprime la variable incorrecta en el caso de error, por ejemplo

if(status != noErr) { print("SELECT Error: /(resultCode)."); // <-- Should be `status` }

y de forma similar para la actualización y borrado.

Aquí hay una versión completa de su código de muestra con el envío necesario a una cola de fondo para recuperar el elemento de llavero. (Por supuesto, las actualizaciones de la interfaz de usuario deben enviarse nuevamente a la cola principal).

Funcionó como se esperaba en mi prueba en un iPhone con Touch ID: aparece la ventana emergente de Touch ID y el elemento del llavero solo se recupera después de una autenticación exitosa.

La autenticación de Touch ID no funciona en el simulador de iOS.

override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // This two values identify the entry, together they become the // primary key in the database let myAttrService = "app_name" let myAttrAccount = "first_name" // DELETE keychain item (if present from previous run) let delete_query: NSDictionary = [ kSecClass: kSecClassGenericPassword, kSecAttrService: myAttrService, kSecAttrAccount: myAttrAccount, kSecReturnData: false ] let delete_status = SecItemDelete(delete_query) if delete_status == errSecSuccess { print("Deleted successfully.") } else if delete_status == errSecItemNotFound { print("Nothing to delete.") } else { print("DELETE Error: /(delete_status).") } // INSERT keychain item let valueData = "The Top Secret Message V1".data(using: .utf8)! let sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, .userPresence, nil)! let insert_query: NSDictionary = [ kSecClass: kSecClassGenericPassword, kSecAttrAccessControl: sacObject, kSecValueData: valueData, kSecUseAuthenticationUI: kSecUseAuthenticationUIAllow, kSecAttrService: myAttrService, kSecAttrAccount: myAttrAccount ] let insert_status = SecItemAdd(insert_query as CFDictionary, nil) if insert_status == errSecSuccess { print("Inserted successfully.") } else { print("INSERT Error: /(insert_status).") } DispatchQueue.global().async { // RETRIEVE keychain item let select_query: NSDictionary = [ kSecClass: kSecClassGenericPassword, kSecAttrService: myAttrService, kSecAttrAccount: myAttrAccount, kSecReturnData: true, kSecUseOperationPrompt: "Authenticate to access secret message" ] var extractedData: CFTypeRef? let select_status = SecItemCopyMatching(select_query, &extractedData) if select_status == errSecSuccess { if let retrievedData = extractedData as? Data, let secretMessage = String(data: retrievedData, encoding: .utf8) { print("Secret message: /(secretMessage)") // UI updates must be dispatched back to the main thread. DispatchQueue.main.async { self.messageLabel.text = secretMessage } } else { print("Invalid data") } } else if select_status == errSecUserCanceled { print("User canceled the operation.") } else { print("SELECT Error: /(select_status).") } } }

Estoy trabajando en un código de paz que debería hacer lo siguiente:

  • Almacenar algunos datos en llavero.
  • Obtenga los datos solo si un usuario se autentica con Touch ID o Pass Code.

Vi el llavero y la autenticación con la presentación de Touch ID y entendí lo siguiente:

Si configura el parámetro correcto mientras agrega un nuevo valor a Keychain, la próxima vez que intente sacarlo, el sistema mostrará automáticamente la ventana emergente Touch ID.

Escribí un código, y mi suposición no funciona. Esto es lo que he escrito:

// // Secret value to store // let valueData = "The Top Secret Message V1".data(using: .utf8)!; // // Create the Access Controll object telling how the new value // should be stored. Force Touch ID by the system on Read. // let sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, .userPresence, nil); // // Create the Key Value array, that holds the query to store // our data // let insert_query: NSDictionary = [ kSecClass: kSecClassGenericPassword, kSecAttrAccessControl: sacObject!, kSecValueData: valueData, kSecUseAuthenticationUI: kSecUseAuthenticationUIAllow, // This two valuse ideifieis the entry, together they become the // primary key in the Database kSecAttrService: "app_name", kSecAttrAccount: "first_name" ]; // // Execute the query to add our data to Keychain // let resultCode = SecItemAdd(insert_query as CFDictionary, nil);

Al principio pensé que el emulador tenía algún problema, pero no, pude comprobar si Touch ID está presente o no con el siguiente código:

// // Check if the device the code is running on is capapble of // finger printing. // let dose_it_can = LAContext() .canEvaluatePolicy( .deviceOwnerAuthenticationWithBiometrics, error: nil); if(dose_it_can) { print("Yes it can"); } else { print("No it can''t"); }

Y también pude mostrar programáticamente la ventana emergente Touch ID con el siguiente código:

// // Show the Touch ID dialog to check if we can get a print from // the user // LAContext().evaluatePolicy( LAPolicy.deviceOwnerAuthenticationWithBiometrics, localizedReason: "Such important reason ;)", reply: { (status: Bool, evaluationError: Error?) -> Void in if(status) { print("OK"); } else { print("Not OK"); } });

Para resumir todo esto

Touch ID funciona, pero guardar un valor en Llavero con la bandera para forzar Touch ID en el propio sistema no funciona. ¿Qué me falta?

Ejemplo de manzanas

El ejemplo que Apple proporciona llamado KeychainTouchID: el uso de Touch ID con Keychain y LocalAuthentication también muestra un resultado inconsistente y el sistema no impone el uso de Touch ID .

Especificaciones tecnológicas

  • Xcode 8.1
  • Swift 3