iOS 8 (OS X Yosemite) introdujo una nueva API/constante utilizada para detectar si el dispositivo de un usuario tiene una contraseña.
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
se puede utilizar para detectar si una contraseña está configurada en el dispositivo.
El flujo es:
- intento de salvar un nuevo punto en el llavero con ese conjunto de atributos
- Si tiene éxito que indica que un código de acceso está habilitado
- Si la contraseña no lo hace obtener guardado, eso indica que no hay código de acceso
- Limpiar el elemento, porque si ya está en el llavero hará que un "agregar" falle, pareciendo que el código no está establecido
He probado esto en mi iPhone 5S, primero devolvió true
, luego deshabilité la contraseña en la configuración, y devolvió false
.Finalmente, volví a habilitar el código de acceso y devuelve true
. Las versiones anteriores de SO devolverán false
. El código funciona en el simulador, devolviendo true
en una máquina con la contraseña de OS X establecida (no he probado escenarios alternativos de OS X).
Véase también proyecto de ejemplo aquí: https://github.com/project-imas/passcode-check/pull/5
último, que yo sepa iOS 8 no tiene una opción para desactivar la protección de datos, así que supongo que esto es todo lo que necesita para garantizar la encriptación.
BOOL isAPIAvailable = (&kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly != NULL);
// Not available prior to iOS 8 - safe to return false rather than crashing
if(isAPIAvailable) {
// From http://pastebin.com/T9YwEjnL
NSData* secret = [@"Device has passcode set?" dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *attributes = @{
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: @"LocalDeviceServices",
(__bridge id)kSecAttrAccount: @"NoAccount",
(__bridge id)kSecValueData: secret,
(__bridge id)kSecAttrAccessible: (__bridge id)kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
};
// Original code claimed to check if the item was already on the keychain
// but in reality you can't add duplicates so this will fail with errSecDuplicateItem
// if the item is already on the keychain (which could throw off our check if
// kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly was not set)
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL);
if (status == errSecSuccess) { // item added okay, passcode has been set
NSDictionary *query = @{
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: @"LocalDeviceServices",
(__bridge id)kSecAttrAccount: @"NoAccount"
};
status = SecItemDelete((__bridge CFDictionaryRef)query);
return true;
}
// errSecDecode seems to be the error thrown on a device with no passcode set
if (status == errSecDecode) {
return false;
}
}
return false;
P.S. Como señala Apple en el video de la WWDC que presenta esto (Keychain 711 y autenticación con Touch ID), optaron por no hacer que el estado del código de acceso esté directamente disponible a través de la API a propósito, para evitar que las aplicaciones entren en situaciones que no deberían (es decir, "¿este dispositivo tiene un código de acceso? De acuerdo, genial, almacenaré esta información privada en texto sin formato." Sería mucho mejor crear una clave de cifrado, almacenarla en kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
y encriptar ese archivo, que será irrecuperable si un usuario decide desactivar su contraseña).
Supongo que el bloqueo de código de acceso es irrelevante para la aplicación en ejecución, así que supongo que no es parte del SDK. Si lo fuera, probablemente sea parte de esta API: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIDevice_Class/Reference/UIDevice.html –
Es extremadamente relevante para una aplicación en ejecución porque sin un código de acceso, sus datos no están protegidos en el dispositivo. Sería un gran descuido de Apple si no hay forma de saber si sus datos están protegidos o no. Hace que el nuevo cifrado iOS 4 sea bastante inútil para la mayoría de las aplicaciones empresariales vendidas a través de la tienda de aplicaciones. – Mike
La mayoría de las empresas deberían (deberían) tener un perfil de implementación enviado a todos los iPhones de la compañía para requerir el código de acceso. Esto no es un problema del programa, este es un problema de gestión. ¿Realmente desea mostrar una advertencia que le diga al usuario que active su contraseña? O mejor aún, ¿se niegan a correr a menos que esté encendido? Los usuarios generalmente no se toman bien que les digan qué hacer con sus dispositivos. –