beta.blog

Archive for January, 2025

Creating a macOS KeyChain entry in C

by 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
Leave a Comment : more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!