Important item in Keychain seems to have disappeared (after years)

I had the following code in a program that I used to encrypt some important files. I haven't run it in a few years. It used to work, and now it seems the password is mysteriously gone from my Keychain! The return value is now errSecItemNotFound.

I'm upset with myself for not backing up the key/password somewhere else. Is there anywhere this could be hiding? Did Apple move it somewhere? I know they created this "Passwords" app in recent years, but I don't see anything in there with the "account" string I used. I run the app from Xcode, so maybe it is in the "container" data somewhere? I do see keychain files under ~/Library.

Maybe there is a way to look through old Time Machine backups. Ug. So stressful.

Just looking for pointers on where the data might be, and why it might have disappeared. Unfortunately it was not a "guessable" password, it was a generated 256 bit key, base64 encoded. Perhaps I could crack that with brute force if I'm determined enough...


public static func queryGenericPasswordAsString(account: String) throws -> String {
    let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
                                kSecMatchLimit as String: kSecMatchLimitOne,
                                kSecAttrAccount as String: account,
                                kSecReturnAttributes as String: true,
                                kSecReturnData as String: true]
    var item: CFTypeRef?
    let status = SecItemCopyMatching(query as CFDictionary, &item)
    guard status != errSecItemNotFound else { throw KeychainError.noPassword }
    ...    
}
Answered by DTS Engineer in 829202022

I’m presuming this is on the Mac. That’s important, because the keychain is much more complex on the Mac than it is on iOS. See TN3137 On Mac keychain APIs and implementations.

I have some generic advice about how to use the keychain effectively:

Looking at your code, I don’t see anything fundamentally wrong with it.

The code doesn’t opt in to the data protection keychain, so it’s gonna be using the file-based keychain. Moreover, it’s likely that you created the item in the default keychain, which is usually the login keychain. Given that, you should be able to look for the keychain item using Keychain Access. That’ll tell you whether it’s there or not.

If it’s not, you can’t fix that with code. You’ll have to find a keychain with the item in it. I have hints and tips on how to do that, for very different reasons, in The Care and Feeding of Developer ID.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I’m presuming this is on the Mac. That’s important, because the keychain is much more complex on the Mac than it is on iOS. See TN3137 On Mac keychain APIs and implementations.

I have some generic advice about how to use the keychain effectively:

Looking at your code, I don’t see anything fundamentally wrong with it.

The code doesn’t opt in to the data protection keychain, so it’s gonna be using the file-based keychain. Moreover, it’s likely that you created the item in the default keychain, which is usually the login keychain. Given that, you should be able to look for the keychain item using Keychain Access. That’ll tell you whether it’s there or not.

If it’s not, you can’t fix that with code. You’ll have to find a keychain with the item in it. I have hints and tips on how to do that, for very different reasons, in The Care and Feeding of Developer ID.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Yes, it's on macOS. I'm trying to piece together exactly what code I was running at the time, a few years ago, but I think the code that created the item may have used the data protection keychain, which you mentioned.

var query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
                            kSecAttrAccount as String: account,
                            kSecUseDataProtectionKeychain as String: true,
                            kSecValueData as String: password]
if let label = label {
    query[kSecAttrLabel as String] = label
}
let status = SecItemAdd(query as CFDictionary, nil)

A quick test suggests that even if I add it like that, the snippet in my original post, with SecItemCopyMatching, finds the item that was created, even though it doesn't have that kSecUseDataProtectionKeychain key in its query.

A second piece of info: in ~/Library/Keychains, there is a file named login_renamed_1.keychain-db from 2022. I don't know what creates a file like this, but I wonder if it's from a password reset/change that I did on my MacBook. When I try to open it in Keychain Access, it appears in the left nav, but I don't think it's completely open / searchable, because I can't "unlock" it. It's not accepting my current MacBook password. Does that mean it is locked by my previous MacBook password and might contain the missing password item?

If so, it's going to be very difficult for me to remember that password, but maybe not impossible. I almost remember it - it was a certain word or two with a few extra characters thrown in. That might be "crackable", unlike the random 256 bit key I'm trying to find.

Important item in Keychain seems to have disappeared (after years)
 
 
Q