2010-09-27 1 views
36

Я пишу приложение iPhone, которое требует, чтобы его данные были зашифрованы. Я узнал, как включить шифрование файлов, установив атрибут NSFileProtectionComplete. Я также знаю, как проверить версию iPhone, чтобы убедиться, что они работают под управлением iOS 4.0 или выше.Как узнать, имеет ли пользователь iPhone в настоящее время набор паролей и шифрование?

Что я понял, что если пользователь не выбрал код доступа и специально не включил защиту данных на экране «Настройки»> «Основные»> «Паспортная блокировка», то данные фактически не защищены.

Я хотел бы открыть предупреждение и сообщить пользователю, что они должны включить код доступа и включить защиту данных (для чего требуется резервное копирование и восстановление на до 4-х iPhone), а затем выйти из приложения, если они это сделают не имеют защиты паролем и данными. Я все равно не могу понять состояние этих настроек. Все API-интерфейсы, которые я нашел, например «protectedDataAvailable» в UIApplication, проходят успешно, если защита данных отключена.

+0

Я бы предположил, что блокировка паролей не имеет отношения к запущенному приложению, поэтому я думаю, что это не часть SDK. Если бы это было так, вероятно, это было бы частью этого API: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIDevice_Class/Reference/UIDevice.html –

+2

Это очень актуально для запущенного приложения, потому что без кода доступа ваши данные не защищены на устройстве. Это был бы огромный надзор со стороны Apple, если нет способа узнать, защищены ли ваши данные или нет. Это делает новое шифрование iOS 4 практически бесполезным для большинства корпоративных приложений, продаваемых через магазин приложений. – Mike

+3

Большинство предприятий должны (должны) иметь профиль развертывания, который был бы перенаправлен на все iPhone компании, чтобы потребовать пароль. Это не проблема программы, это проблема управления. Вы действительно хотите выставить предупреждение, в котором пользователь должен включить свой пароль? Или еще лучше, откажитесь бежать, если он не включен? Пользователям обычно не нравится, когда им говорят, что делать с их устройствами. –

ответ

18

Отказ от ответственности: Этот ответ был действителен до ИОС 4.3.3

Если защита данных включена, вновь созданный файл будет иметь nilNSFileProtectionKey по умолчанию.

Если защита данных отключена, то по умолчанию новый файл будет иметь NSFileProtectionNoneNSFileProtectionKey.

Таким образом, можно обнаружить наличие защиты файла с помощью следующего кода:

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

это помогло .. Большое спасибо за то, что вы предприняли попытку опубликовать код. – learner2010

+0

спасибо, что нашли время, чтобы действительно прочитать вопрос. отличный ответ –

+1

Вы уверены, что это работает? Я тестирую на данный момент iPad (4.3.5), и атрибут всегда NSFIleProtectionNone ... «Защита данных включена» отображается в настройках кода клавиатуры .... –

1

Независимо NSDataWritingAtomic или NSDataWritingFileProtectionComplete, результат всегда одинаков для меня. Странное поведение, вот код:

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

Кстати, приложение Find Friends имеет эту функцию. Он запрашивает повторный ввод пароля только в том случае, если устройство не защищено паролем. – igraczech

+0

Привет, я проверил ссылку, но каждый раз, когда возвращал то же значение NSFileProtectionKey = NSFileProtectionNone; – Suchi

3

Apple не предоставляет способ определения, установлен ли пользователь в наборе паролей.

Если вашему приложению требуется шифрование, вы должны подумать о шифровании и расшифровке файлов с помощью надежной реализации шифрования и запросить у пользователя пароль или сохранить ключ в цепочке ключей.

13

iOS 8 (OS X Yosemite) представил новый API/константу, используемый для определения того, имеет ли пользовательское устройство код доступа.

kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly может использоваться для определения того, установлен ли пароль на устройстве.

Течение:

  1. Попытка сохранить новый элемент на брелка с этим набор атрибутов
  2. Если это удается, что указывает на то, что код доступа в данный момент включен
  3. Если пароль не получить сохраненный, что указывает на отсутствие кода доступа
  4. Очистка элемента, потому что, если он уже находится на брелках, он сделает ошибку «добавить», похоже, что код доступа не установлен

Я тестировал это на своем iPhone 5S, сначала он вернул true, затем я отключил пароль в настройках, и он вернул false.Наконец, я снова включил код доступа, и он возвращает true. Предыдущие версии ОС вернут false. Код работает в симуляторе, возвращая true на компьютере с набором пароля OS X (я не тестировал альтернативные сценарии OS X).

Также см пример проекта здесь: https://github.com/project-imas/passcode-check/pull/5

Наконец, к моему знанию IOS 8 не имеет настройки, чтобы отключить защиту данных, поэтому я предполагаю, что это все, что вам нужно, чтобы гарантировать шифрование.

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. Поскольку Apple указывает на видео WWDC, представляющее это (711 Keychain и аутентификация с Touch ID), они решили не делать статус кода доступа напрямую доступным через API специально для того, чтобы предотвратить попадание приложений в ситуации, когда они не должны быть (т. е. «У этого устройства есть код доступа? Хорошо, отлично, я сохраню эту личную информацию в виде обычного текста». Было бы гораздо лучше создать ключ шифрования, сохранить его под kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly и зашифровать этот файл, который будет невосстановимым если пользователь решает отключить свой код доступа).

+0

Это одобрено яблоком? – Nil

+0

Я никогда не показывал приложение, которое его использует, но все функции документированы (нет частных API), поэтому я предполагаю, что это будет. – owenfi

0

С прошивкой 9, есть флаг LAPolicyDeviceOwnerAuthentication в LocalAuthentication каркаса.

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

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

    if(passcodeEnabled) { 
     return YES; 
    } 

    return NO; 
} 
0

Свифта 3

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

IOS, 9 или выше требуется.