2010-09-27 10 views
36

Estoy escribiendo una aplicación para iPhone que requiere que sus datos sean encriptados. Aprendí a activar el cifrado de archivos estableciendo el atributo NSFileProtectionComplete. También sé cómo verificar la versión de iPhone para asegurarme de que ejecuten iOS 4.0 o superior.¿Cómo puedo saber si el usuario de iPhone actualmente tiene un conjunto de códigos de acceso y cifrado habilitado?

Lo que me he dado cuenta es que si el usuario no ha elegido una contraseña y no ha habilitado específicamente la protección de datos en Configuración> General> Pantalla de bloqueo de Passcade, entonces los datos en realidad no están protegidos en absoluto.

Me gustaría mostrar una advertencia y decirle al usuario que debe habilitar una contraseña y activar la protección de datos (que requiere una copia de seguridad y restauración en iPhones anteriores a 4), y luego salir de la aplicación si lo hacen no tener una contraseña y protección de datos habilitada. Sin embargo, no puedo averiguar de todos modos para averiguar el estado de estas configuraciones. Todas las API que he encontrado, como "protectedDataAvailable" en UIApplication, todas pasan con éxito si la protección de datos está deshabilitada.

+0

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 –

+2

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

+3

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. –

Respuesta

18

exención de responsabilidad: Esta respuesta fue válida hasta ios 4.3.3

Si la protección de datos está activada, un archivo de nueva creación tendrán un nilNSFileProtectionKey por defecto.

Si la protección de datos está desactivada, un archivo recién creado tendrá un NSFileProtectionNone de forma predeterminada.

Por lo tanto, se puede detectar la presencia de la protección de archivos con el siguiente código:

NSString *tmpDirectoryPath = 
    [NSHomeDirectory() stringByAppendingPathComponent:@"tmp"]; 
NSString *testFilePath = 
    [tmpDirectoryPath stringByAppendingPathComponent:@"testFile"]; 
[@"" writeToFile:testFilePath 
     atomically:YES 
     encoding:NSUTF8StringEncoding 
      error:NULL]; // obviously, do better error handling 
NSDictionary *testFileAttributes = 
    [[NSFileManager defaultManager] attributesOfItemAtPath:testFile1Path 
                error:NULL]; 
BOOL fileProtectionEnabled = 
    [NSFileProtectionNone isEqualToString:[testFile1Attributes objectForKey:NSFileProtectionKey]]; 
+0

esto ayudó .. muchas gracias por hacer el esfuerzo de publicar el código .. – learner2010

+0

gracias por tomarse el tiempo para leer realmente la pregunta. excelente respuesta –

+1

¿Estás seguro de que esto está funcionando? Estoy probando en este momento con un iPad (4.3.5) y el atributo es siempre NSFIleProtectionNone ... "La protección de datos está activada" se muestra en la configuración del código clave .... –

1

Independientemente NSDataWritingAtomic o NSDataWritingFileProtectionComplete, resultado siempre es el mismo para mí. Comportamiento extraño, aquí está el código:

BOOL expandTilde = YES; 
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, expandTilde); 
NSString *filePath; 
filePath = [[paths lastObject] stringByAppendingPathComponent:@"passcode-check"]; 

NSMutableData *testData; 
testData = [NSMutableData dataWithLength:1024]; 

NSLog(@"Attempt to write data of length %u file: %@", [testData length], filePath); 

NSError *error = nil; 

if (![testData writeToFile:filePath options:NSDataWritingAtomic error:&error]) { 
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    return NO; 
} else { 
    NSLog(@"File write successful."); 

    error = nil; 
    NSDictionary *testFileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error]; 

    NSLog(@"Getting attributes: %@", testFileAttributes); 

    if ([NSFileProtectionComplete isEqualToString:[testFileAttributes objectForKey:NSFileProtectionKey]]) { 
     error = nil; 
     [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; 
     // passcode disabled 
     return YES; 
    } else { 
     error = nil; 
     [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; 
     return NO; 
    } 

} 
+2

Por cierto, la aplicación Find Friends tiene esta funcionalidad. Solicita que se vuelva a ingresar la contraseña solo si el dispositivo no está protegido con contraseña. – igraczech

+0

Hola, he comprobado el enlace pero cada vez devuelve el mismo valor NSFileProtectionKey = NSFileProtectionNone; – Suchi

3

Apple no proporciona un método para determinar si el usuario tiene un conjunto de códigos de acceso.

Si su aplicación necesita cifrado, debe considerar encriptar y desencriptar los archivos con una implementación de encriptación confiable y solicitando al usuario una clave de acceso o almacenando la clave en el llavero.

13

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:

  1. intento de salvar un nuevo punto en el llavero con ese conjunto de atributos
  2. Si tiene éxito que indica que un código de acceso está habilitado
  3. Si la contraseña no lo hace obtener guardado, eso indica que no hay código de acceso
  4. 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).

+0

¿está aprobado por Apple? – Nil

+0

No he enviado ninguna aplicación que la use, pero todas las funciones están documentadas (no hay API privadas), así que supongo que así será. – owenfi

0

Desde iOS 9, hay una bandera LAPolicyDeviceOwnerAuthentication en LocalAuthentication marco.

+ (BOOL)isPasscodeEnabled 
{ 
    NSError *error = nil; 
    LAContext *context = [[LAContext alloc] init]; 

    BOOL passcodeEnabled = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error]; 

    if(passcodeEnabled) { 
     return YES; 
    } 

    return NO; 
} 
0

Swift 3

func isPasscodeEnabled() -> Bool { 
    return LAContext().canEvaluatePolicy(LAPolicy.deviceOwnerAuthentica‌​tion, error:nil) 
} 

iOS 9 o mayor necesaria.

Cuestiones relacionadas