If you’ve been following my recent posts, you’re probably well aware that I’ve been doing a lot of playing with Web APIs–particularly with iTunes and Amazon Web Services. I love the concept of API as User Interface and I love the new ways established companies are providing Web-based utilities.

Because the World Wide Web is such an open place, many Web API services demand that you authenticate your requests. Requests must come from the proper parties and sent without loss of message integrity.

Cryptographic hash functions like SHA-1 (a Secure Hash Algorithm) allow you to electronically “sign” your requests with a personal ID key. Amazon, for example, assigns you both an access key and a secret access key. The former identifies you publicly, and the latter identifies your signed requests.

Here’s the code I use to sign my Amazon Web Services headers using SHA-1. I then produce a Base64 rendition of that hash.

You can find your own Amazon Web Services keys by visiting the AWS homepage and hover over the peach-colored “Your Web Services Account” button on the top-left of the page. Chose View Access Key Identifiers from the pop-up.

As with all my code, caveat emptor. You can download this source here.

// From Erica Sadun, 15 March 2006
// cc signheader.c -w -o signheader  -lcurl -lcrypto

#include <stdio.h>
#include <string.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <curl/curl.h>

#define SECRETKEY "PUT KEY HERE"
#define SLEN 1024

main(argc, argv)
int argc;
char *argv[];
{
    int riz, howlong;
    unsigned char headertext[SLEN], signature[SLEN];

    if (argc < 2)
    {
        printf("Usage: %s uri-encoded-headersn", argv[0]);
        exit(-1);
    }

    // Decode header
    sprintf(headertext, "%s", curl_unescape(argv[1], strlen(argv[1])));

    // Encrypt it
   doEncrypt(headertext, signature);

   printf("%sn", signature);
}

void doEncrypt(kString, sigString)
unsigned char *kString;
char *sigString;
{
    HMAC_CTX hctx;
    BIO *bio, *b64;
    char *sigptr;
    long siglen = -1;
    char *signature = NULL;
    unsigned int rizlen;
    unsigned char skey[SLEN], results[SLEN]; 

   // Initialize SHA1 encryption
    sprintf(skey, "%s", SECRETKEY);
    HMAC_CTX_init(&hctx);
    HMAC_Init(&hctx, skey, (int)strlen((char *)skey), EVP_sha1());

    // Encrypt
    HMAC(EVP_sha1(), skey, (int)strlen((char *)skey),
	(unsigned char *)kString, (int)strlen((char *)kString),
	results, &rizlen);

    // Base 64 Encode
    b64 = BIO_new(BIO_f_base64());
    bio = BIO_new(BIO_s_mem());
    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
    bio = BIO_push(b64, bio);
    BIO_write(bio, results, rizlen);
    BIO_flush(bio);

    siglen = BIO_get_mem_data(bio, &sigptr);
    signature = malloc(siglen+1);
    memcpy (signature, sigptr, siglen);
    signature[siglen] = '\0';
    sprintf(sigString, "%s", signature);

    // Clean up Encryption, Encoding
    BIO_free_all(bio);
    HMAC_CTX_cleanup(&hctx);
}