iOS 钥匙串访问

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23395572/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 00:03:12  来源:igfitidea点击:

iOS Keychain Access

ioskeychain

提问by PruitIgoe

I am using the SSKeyChain library to store and access a password in the keychain. I'm testing in the iPhone Simulator and I can write and access the keychain. But when I close out the app (Double click the home button, swipe app up so it is no longer in background) I cannot access the data in Keychain. My understanding was that, unless specifically deleted this data would remain there. Am I wrong in that or is it possible I am not storing the data properly?

我正在使用 SSKeyChain 库来存储和访问钥匙串中的密码。我正在 iPhone 模拟器中进行测试,我可以编写和访问钥匙串。但是当我关闭应用程序(双击主页按钮,向上滑动应用程序使其不再在后台)时,我无法访问钥匙串中的数据。我的理解是,除非特别删除,否则这些数据将保留在那里。我错了还是我没有正确存储数据?

A second question is, should this data be encrypted or does Keychain take care of that already? If it should be encrypted any suggestions of how?

第二个问题是,这些数据应该加密还是 Keychain 已经处理了?如果应该加密,有什么建议吗?

Here's my code:

这是我的代码:

- (void)viewDidLoad
{
    [super viewDidLoad];

    /*
    Let sskeychain know how the keychain values can be accessed - these are the options:

    kSecAttrAccessibleWhenUnlocked  Only accessible when device is unlocked.
    kSecAttrAccessibleAfterFirstUnlock  Accessible while locked. But if the device is restarted it must first be unlocked for data to be accessible again.
    kSecAttrAccessibleAlways    Always accessible.
    kSecAttrAccessibleWhenUnlockedThisDeviceOnly    Only accessible when device is unlocked. Data is not migrated via backups.
    kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly    Accessible while locked. But if the device is restarted it must first be unlocked for data to be accessible again. Data is not migrated via backups.
    kSecAttrAccessibleAlwaysThisDeviceOnly  Always accessible. Data is not migrated via backups.
    */

    [SSKeychain setAccessibilityType:kSecAttrAccessibleWhenUnlocked];

    txtUserName = [[UITextField alloc] initWithFrame:CGRectMake((self.view.frame.size.width/2)-100.0, 200.0, 200.0, 30.0)];
    txtUserName.placeholder = @"User Name";
    txtUserName.font = [UIFont fontWithName:@"Avenir" size:18.0];
    txtUserName.layer.cornerRadius = 8.0f;
    txtUserName.backgroundColor = [UIColor whiteColor];
    txtUserName.layer.borderWidth = 1.0;
    [self.view addSubview:txtUserName];

    txtSignon = [[UITextField alloc] initWithFrame:CGRectMake((self.view.frame.size.width/2)-100.0, txtUserName.frame.origin.y + txtUserName.frame.size.height + 20.0, 200.0, 30.0)];
    txtSignon.placeholder = @"Password";
    txtSignon.font = [UIFont fontWithName:@"Avenir" size:18.0];
    txtSignon.layer.cornerRadius = 8.0f;
    txtSignon.backgroundColor = [UIColor whiteColor];
    txtSignon.layer.borderWidth = 1.0;
    txtSignon.secureTextEntry = YES;
    [self.view addSubview:txtSignon];

    UIButton* btnSubmit = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [btnSubmit setTitle:@"Submit" forState:UIControlStateNormal];
    [btnSubmit addTarget:self action:@selector(storeValues:) forControlEvents:UIControlEventTouchUpInside];
    [btnSubmit setFrame:CGRectMake((self.view.frame.size.width/2)-100, txtSignon.frame.origin.y + txtSignon.frame.size.height + 20.0, 200.0, 30.0)];
    [self.view addSubview:btnSubmit];

    UIButton* btnGetData = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [btnGetData setTitle:@"Get Stored Credentials" forState:UIControlStateNormal];
    [btnGetData addTarget:self action:@selector(getStoredValues:) forControlEvents:UIControlEventTouchUpInside];
    [btnGetData setFrame:CGRectMake((self.view.frame.size.width/2)-100, btnSubmit.frame.origin.y + btnSubmit.frame.size.height + 20.0, 200.0, 30.0)];
    [self.view addSubview:btnGetData];


}

- (void) storeValues : (UIButton*) myButton {

    [self.view endEditing:YES];

    //get the saved values
    NSString* strUserName = txtUserName.text;
    NSString* strUserPass = txtSignon.text;

    self.strStoredUserName = strUserName;

    //pass them along to the keychain
    [SSKeychain setPassword:strUserPass forService:@"com.sanofi.us" account:strUserName];

    UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Success" message:@"Your user name and password were stored in the devices keychain!" delegate:nil cancelButtonTitle:@"Okay" otherButtonTitles:nil, nil];
    [alert show];

    txtUserName.text = @"";
    txtSignon.text = @"";


}

- (void) getStoredValues : (UIButton*) myButton {

    NSString* strUserName = self.strStoredUserName;

    // Access that token when needed
    NSString* strPassword = [SSKeychain passwordForService:@"com.sanofi.us" account:strUserName];

    if (strPassword) {
        UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Success" message:[NSString stringWithFormat:@"Your credentials stored in the keychain are:\nUsername: %@\nPassword: %@", strUserName, strPassword] delegate:nil cancelButtonTitle:@"Okay" otherButtonTitles:nil, nil];
        [alert show];
    }

}

回答by NSDestr0yer

This code looks correct and the data should be sticking around unless the simulator is being reset. Are you able to test on a device?

这段代码看起来是正确的,除非模拟器被重置,否则数据应该会一直存在。你能在设备上测试吗?

To answer the second question, depending on your device and iOS version the keychain passwords are either encrypted using 3DES or AES, however the exact implementation can change in the future.

要回答第二个问题,根据您的设备和 iOS 版本,钥匙串密码使用 3DES 或 AES 进行加密,但确切的实现方式将来可能会发生变化。

回答by sundance

For Swift, you can use KeychainAccess, which is a bit easier to use:

对于 Swift,您可以使用KeychainAccess,它更易于使用:

// Create keychain object
let keychain = Keychain(service: "com.company.AppName")

// Store value in keychain
keychain["password"] = "test"

// Retrieve value from keychain
let password = keychain["password"]

According to the current iOS 11 security guidekeychain items are encrypted with AES 128.

根据当前的 iOS 11 安全指南,钥匙串项目使用 AES 128 加密。

Components of a Keychain item: Along with the access group, each Keychain item contains administrative metadata (such as “created” and “last updated” timestamps). It also contains SHA-1 hashes of the attributes used to query for the item (such as the account and server name) to allow lookup without decrypting each item. And finally, it contains the encryption data, which includes the following: ? Version number ? Access control list (ACL) data ? Value indicating which protection class the item is in ? Per-item key wrapped with the protection class key ? Dictionary of attributes describing the item (as passed to SecItemAdd), encoded as a binary plist and encrypted with the per-item key The encryption is AES 128 in GCM (Galois/Counter Mode); the access group is included in the attributes and protected by the GMAC tag calculated during encryption.

钥匙串项目的组成部分:与访问组一起,每个钥匙串项目都包含管理元数据(例如“创建”和“上次更新”时间戳)。它还包含用于查询项目(例如帐户和服务器名称)的属性的 SHA-1 哈希值,以允许在不解密每个项目的情况下进行查找。最后,它包含加密数据,其中包括以下内容: ? 版本号?访问控制列表 (ACL) 数据 ? 指示项目属于哪个保护级别的值?用保护类密钥包装的每项密钥 ? 描述项目的属性字典(传递给 SecItemAdd),编码为二进制 plist 并使用每个项目的密钥加密 加密是 GCM 中的 AES 128(Galois/计数器模式);访问组包含在属性中,并受加密期间计算的 GMAC 标记保护。