Encrypting secrets for GitHub's API with Perl and libsodium
The GitHub API for Secrets uses libsodium to exchange the secret. I request the public key for my repository, I encrypt my secret with my repository’s public key, and I send it back to GitHub. My repository can then decode it with its secret key (which I don’t know).
The API docs have examples in Node, Python, Ruby, and C#. I worked out an example in Perl which takes the Base64 encoded public key as provided by the API and returns the Base64 encoded secret I need to send back.
sub _nacl_encrypt ($plain, $public_key_base64) {
state $rc = require Sodium::FFI;
my $key_bin = Sodium::FFI::sodium_base642bin($public_key_base64);
my $crypted = Sodium::FFI::crypto_box_seal( $plain, $key_bin );
return Sodium::FFI::sodium_bin2base64($crypted);
}
This requires a pull request I created for Sodium::FFI to add
crypto_box_seal
, although you could do a lot more work to use crypto_box_easy
.
A bonus treat
While testing this, I wanted a way to look at the secret in GitHub Actions
so I knew that I had uploaded what I intended. However, GitHub masks
anything it thinks is a secret by replacing the secret’s text with ***
.
Inside the action, I output the secret’s text with spaces between every character:
jobs:
update-ranges:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Show secret
run: |
echo $ | sed 's/./& /g'
As an aside, it’s pretty easy to discover secrets this way. I simply output enough text until I find text that GitHub Actions decides it should mask. For things like personal access tokens, that’s a lot of combinations. But for other things,