Standard library - crypto

module crypto
  type binaryLike = string | binary | token
  def md5 : binaryLike -> binary
  def sha1 : binaryLike -> binary
  def sha256 : binaryLike -> binary
  def sha256_generic : data -> binary  // since PR#1822

  def hmacSha1 : binaryLike -> binaryLike -> binary // hmacSha1(key, msg)
  def hmacSha1Verify : binaryLike -> binaryLike -> binaryLike -> bool // hmacSha1Verify(key, msg, signature)
  def hmacSha256 : binaryLike -> binaryLike -> binary // hmacSha256(key, msg)
  def hmacSha256Verify : binaryLike -> binaryLike -> binaryLike -> bool // hmacSha256Verify(key, msg, signature)

  def rsaSha256 : binaryLike -> binaryLike -> binary // rsaSha256(key, msg); added in ABI 0.4

  def aesGcmEncrypt : binaryLike -> binaryLike -> binaryLike -> result(string, binary) // aesGcmEncrypt(key, additionalData, text)
  def aesGcmDecrypt : binaryLike -> binaryLike -> binaryLike -> result(string, binary) // aesGcmDecrypt(key, additionalData, ciphertext)
  def randomKey32 : null -> binary // randomKey32()

module end

The binaryLike type can be

md5, sha1, and sha256 are all hash functions, and return a byte array. To make this a string, you probably want to use something like msg |> crypto.md5 |> binary.toBase64. Note that the hashes contain arbitrary bytes, so you don’t want to simply interpret them as strings, you should encode to base64.

sha256_generic returns a hash value for any data input, not only binaries, strings, or tokens. For example, you could also get a hash value for an array of something. The algorithm for computing the hash value is implementation-defined, but involves computing the SHA-256 hash over all the input.

hmacSha1 and hmacSha256 are HMAC keyed hashes of a message: https://en.wikipedia.org/wiki/HMAC. Note that they likewise return raw bytes. hmacSha1Verify and hmacSha256Verify are the corresponding verification functions, which in addition to a key and a message take a MAC (signature) to verify.

rsaSha256 is an RSA-signed SHA-256 hash of a message. The key must be a PKCS#8 PEM-encoded string (typically found as a text file with the header -----BEGIN PRIVATE KEY-----). Note that RSA keys are sometimes provided in the slightly different RSA-specific PKCS#1 format, which is generally straightforward to convert to PKCS#8 with your crypto library of choice. PKCS#1 keys can be identified by their -----BEGIN RSA PRIVATE KEY----- header.

aesGcmEncrypt and aesGcmDecrypt implement AES+GCM symmetric key encryption with a 32-byte key. The core implementation is taken from https://github.com/gtank/cryptopasta@1f550f6f2f69009f6ae57347c188e0a67cd4e500. Generally you will want to pass "" for the second parameter (additional data); the value must match for corresponding encrypt/decrypt calls. The key, additional data, text, and ciphertext are all expected to be plain bytes, so you will probably want to wrap with binary.ofBase64 and binary.toBase64 on input/output. randomKey32 returns a random key (in bytes) suitable for these functions.