Keychain Access

Hi, if anyone has a simple example of setting/getting value in keychain that would be great.

I’ve managed to get as far as storing something, but can’t retrieve it:

Running the following code to retrieve yields a successful result code, but no data. Any pointers appreciated, thx!

    CFStringRef keys[3];
    keys[0] = kSecClass;
    keys[1] = kSecAttrAccount;
    keys[2] = kSecValueData;
    
    CFTypeRef values[2];
    values[0] = kSecClassGenericPassword;
    values[1] = CFSTR( "trial_start_date" );

    CFDictionaryRef query;
    query = CFDictionaryCreate( kCFAllocatorDefault, (const void**) keys, (const void**) values, 2, nullptr, nullptr );

    CFDataRef res = nullptr;
    
    OSStatus result = SecItemCopyMatching( query, (CFTypeRef*)&res );

    bool ok = result == noErr;
    bool not_found = result == errSecItemNotFound;
    
    auto len = CFDataGetLength( res );
    auto data = CFDataGetBytePtr( res );

The fetch code is now crashing on the CFDataGetLength() call so I presume there’s something wrong with the code itself - so hard to find examples of this stuff…

ok, so I have this working on Mac now, and assumed would be the same on iOS, but the security chain API doesn’t appear to be available.

Any ideas what the iOS equiv of SecKeychainItemRef, SecKeychainItemCopyContent etc are?

Actually looks like I can’t add anything on iOS with SecItemAdd either - totally flumoxed with this - any help much appreciated. thx

Not sure about IOS, but on macOS i am using this, works great. You’l have to deal with C++/Objective-C integration, though.

hi, thx. not an objective C programmer unfortunately - and I’ve got everything working fine on Mac, but all fails on iOS, so might be the same with this anyway…

I’ve had a quick look through and can get the gist of what’s going on and suspect this would fail on iOS…

In case anyone else find this useful, here’s the code for setting/getting keychain entries that works on iOS: Setting:

    const auto str_service = CFStringCreateWithCString( nullptr, service.toStdString().c_str(), kCFStringEncodingASCII );
    const auto str_account = CFStringCreateWithCString( nullptr, account.toStdString().c_str(), kCFStringEncodingASCII );
    const auto data = CFDataCreate( nullptr, (const UInt8 *)date.toStdString().c_str(), (CFIndex)date.length() );

    CFMutableDictionaryRef query = CFDictionaryCreateMutable( nullptr, 0, nullptr, nullptr );
    CFDictionaryAddValue( query, kSecClass, kSecClassGenericPassword );
    CFDictionaryAddValue( query, kSecAttrService, str_service );
    CFDictionaryAddValue( query, kSecAttrAccount, str_account );
    CFDictionaryAddValue( query, kSecValueData, data );
    
    const auto res = SecItemAdd( query, nullptr );
    
    CFRelease( str_service );
    CFRelease( str_account );
    CFRelease( data );
and fetching:

        const auto str_service = CFStringCreateWithCString( nullptr, service.toStdString().c_str(), kCFStringEncodingASCII );
        const auto str_account = CFStringCreateWithCString( nullptr, account.toStdString().c_str(), kCFStringEncodingASCII );

        CFMutableDictionaryRef query = CFDictionaryCreateMutable( nullptr, 0, nullptr, nullptr );
        CFDictionaryAddValue( query, kSecClass, kSecClassGenericPassword );
        CFDictionaryAddValue( query, kSecAttrService, str_service );
        CFDictionaryAddValue( query, kSecAttrAccount, str_account );
        CFDictionaryAddValue( query, kSecReturnData, kCFBooleanTrue );

        CFDataRef ref = nullptr;
        
        const auto res = SecItemCopyMatching( query, (CFTypeRef*)&ref );

        CFRelease( str_service );
        CFRelease( str_account );

        if ( res == noErr && ref ) {
            const auto len = CFDataGetLength( ref );
            
            UInt8 data[ len ];
            CFDataGetBytes( ref, CFRangeMake( (CFIndex)0, len ), data );
            
            juce::String str( (char *)data, len );
            return str;
        }

        return "";
2 Likes