Using RSA-SHA1 with Salesforce Crypto Class

This is a rather obscure post but it will definitely come in handy to someone trying to use the RSA-SHA1 algorithm with the Salesforce Crypto class. I'm spent the past two days trying to hook up OAuth using Apex and various Google Services. The standard HMAC-SHA1 algorithm is fairly straight forward with OAuth and Google but when you are required to register a domain and upload a certificate... well things get somewhat hairy. There's very little documentation on the RSA-SHA2 algorithm and I could only find one relevant post on the topic.

According to the Crypto docs, the arguments for the sign method are an algorithm name (i.e., RSA-SHA1), an input Blob (the string to encrypt) and a privateKey Blob. The value of privateKey must be decoded using the EncodingUtilbase64Decode method, and should be in RSA's PKCS #8 (1.2) Private-Key Information Syntax Standard form.

The sample code from the docs doesn't help determining how to obtain the privateKey:

String algorithmName = 'RSA';
String key = 'pkcs8 format private key';
Blob privateKey = EncodingUtil.base64Decode(key);
Blob input = Blob.valueOf('12345qwerty');
Crypto.sign(algorithmName, input, privateKey);

So after a couple of days of trial and error, swearing and sticking needles in my eyes, I finally came up with the solution for Google. It may not apply to other services but the methodology is roughly the same for the privateKey.

The first step is to generate a self-signing public certificate and private key. You can find more info here. Open terminal and run the following:

openssl req -x509 -nodes -days 365 -newkey rsa:1024 -sha1 -subj '/C=US/ST=CA/L=San Mateo/CN=www.appirio.com' -keyout key-mycompanyrsa.pem -out cert-mycompanyrsa.pem

This will spit out a cert file (cert-mycompanyrsa.pem) and private key file (key-mycompanyrsa.pem). Then upload the cert to your domain for the Google account. This will generate a consumer key and a consumer secret for your application.

Now here was my mistake. I was opening the private key file (key-mycompanyrsa.pem) and using the contents of this file in my Apex code for the privateKey Blob value. Google was choking when creating the OAuth request token saying that the signature was incorrect: signature_invalid.

Here's the fix. You need to use the private key file (key-mycompanyrsa.pem) with the openssl pkcs8 command to process the private keys into PKCS#8 format.

Open terminal again and run:

openssl pkcs8 -topk8 -nocrypt -in key-mycompanyrsa.pem -outform PEM

This will display a new private key in terminal and THIS is the value you use for the privateKey argument for the sign method. Just copy everything betweek the "begin" line and "end" line.