Archive for January, 2025
Creating a macOS KeyChain entry in C
by admin on Jan.05, 2025, under News
The following example shows how we can create a macOS KeyChain entry to store and retrieve secrets.
// clang keychain.c -o keychain -framework Security -framework CoreFoundation #include <stdio.h> #include <stdlib.h> #include <string.h> #include <Security/Security.h> // Function to store a password in the keychain void store_password(const char *service, const char *account, const char *password) { CFStringRef serviceRef = CFStringCreateWithCString(NULL, service, kCFStringEncodingUTF8); CFStringRef accountRef = CFStringCreateWithCString(NULL, account, kCFStringEncodingUTF8); CFStringRef passwordRef = CFStringCreateWithCString(NULL, password, kCFStringEncodingUTF8); CFDictionaryRef attributes = CFDictionaryCreate(NULL, (const void *[]){ kSecClass, kSecAttrService, kSecAttrAccount, kSecValueData }, (const void *[]){ kSecClassGenericPassword, serviceRef, accountRef, CFDataCreate(NULL, (const UInt8 *)password, strlen(password)) }, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); OSStatus status = SecItemAdd(attributes, NULL); if (status == errSecSuccess) { printf("Password stored successfully.\n"); } else if (status == errSecDuplicateItem) { printf("Password for this service and account already exists. Updating...\n"); CFDictionaryRef query = CFDictionaryCreate(NULL, (const void *[]){ kSecClass, kSecAttrService, kSecAttrAccount }, (const void *[]){ kSecClassGenericPassword, serviceRef, accountRef }, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionaryRef updateAttributes = CFDictionaryCreate(NULL, (const void *[]){ kSecValueData }, (const void *[]){ CFDataCreate(NULL, (const UInt8 *)password, strlen(password)) }, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); status = SecItemUpdate(query, updateAttributes); if (status == errSecSuccess) { printf("Password updated successfully.\n"); } else { fprintf(stderr, "Failed to update password. Error code: %d\n", (int)status); } CFRelease(query); CFRelease(updateAttributes); } else { fprintf(stderr, "Failed to store password. Error code: %d\n", (int)status); } CFRelease(attributes); CFRelease(serviceRef); CFRelease(accountRef); CFRelease(passwordRef); } // Function to retrieve a password from the keychain void retrieve_password(const char *service, const char *account) { CFStringRef serviceRef = CFStringCreateWithCString(NULL, service, kCFStringEncodingUTF8); CFStringRef accountRef = CFStringCreateWithCString(NULL, account, kCFStringEncodingUTF8); CFDictionaryRef query = CFDictionaryCreate(NULL, (const void *[]){ kSecClass, kSecAttrService, kSecAttrAccount, kSecReturnData }, (const void *[]){ kSecClassGenericPassword, serviceRef, accountRef, kCFBooleanTrue }, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFTypeRef result = NULL; OSStatus status = SecItemCopyMatching(query, &result); if (status == errSecSuccess) { CFDataRef passwordData = (CFDataRef)result; printf("Password retrieved: %.*s\n", (int)CFDataGetLength(passwordData), CFDataGetBytePtr(passwordData)); CFRelease(passwordData); } else if (status == errSecItemNotFound) { printf("Password not found for service: %s and account: %s\n", service, account); } else { fprintf(stderr, "Failed to retrieve password. Error code: %d\n", (int)status); } CFRelease(query); CFRelease(serviceRef); CFRelease(accountRef); } int main() { const char *service = "example.com"; const char *account = "user@example.com"; const char *password = "mypassword123"; // Store the password in the Keychain store_password(service, account, password); // Retrieve the password from the Keychain retrieve_password(service, account); return 0; }
We may compile it using clang:
clang keychain.c -o keychain -framework Security -framework CoreFoundation