Hear from Slack, the ACLU, TED, & more at our customer summit in San Francisco Register
LOG IN SIGN UP
Documentation

Cryptographic- and hashing-related VCL functions

  Last updated May 10, 2017

Fastly provides several functions in VCL for cryptographic- and hashing-related purposes. It is based very heavily on Kristian Lyngstøl's digest vmod for Varnish 3 (which means you can also refer to that documentation for more detail).

Functions

Function Description
digest.awsv4_hmac(<secret_access_key>, <yyyymmdd>, <aws_region>, <aws_service>, <string_to_sign>) Returns an AWSv4 message authentication code based on the supplied secret_access_key and string_to_sign. This function automatically prepends "AWS4" in front of the secret access key (the first function parameter) as required by the protocol. This function does not support binary data for its secret_access_key or string_to_sign parameters. See the example.
digest.hmac_md5(<key>,<message>) Hash-based message authentication code using MD5. Returns a hex-encoded string prepended with 0x.
digest.hmac_md5_base64(<key>, <message>) Hash-based message authentication code using MD5. Returns a base64-encoded string.
digest.hmac_sha1(<key>, <message>) Hash-based message authentication code using SHA1. Returns a hex-encoded string prepended with 0x.
digest.hmac_sha1_base64(<key>, <message>) Hash-based message authentication code using SHA1. Returns a base64-encoded string.
digest.hmac_sha256(<key>, <message>)) Hash-based message authentication code using SHA256. Returns a hex-encoded string prepended with 0x.
digest.hmac_sha256_base64(<key>, <message>) Hash-based message authentication code using SHA256. Returns a base64-encoded string.
digest.base64(<string>) Base64 encoding. Returns the base64-encoded version of the input-string.
digest.base64url(<string>) Base64 encoding. Returns the base64-encoded version of the input-string. Replaces +/ with -_ for url safety.
digest.base64url_nopad(<string>) Base64 encoding. Returns the base64-encoded version of the input-string. Replaces +/ with -_ for url safety. Has no length padding.
digest.base64_decode(<string>) Decode Base64. Returns a string.
digest.base64url_decode(<string>) Decode Base64 with url safe characters in. Returns a string.
digest.base64url_nopad_decode(<string>) Decode Base64 with url safe characters. Returns a string. Identical to base64_url_decode.
digest.hash_sha1(<string>) Use the SHA1 hash. Returns a hex-encoded string.
digest.hash_sha224(<string>) Use the SHA224 hash. Returns a hex-encoded string.
digest.hash_sha256(<string>) Use the SHA256 hash. Returns a hex-encoded string.
digest.hash_sha384(<string>) Use the SHA384 hash. Returns a hex-encoded string.
digest.hash_sha512(<string>) Use the SHA512 hash. Returns a hex-encoded string.
digest.hash_md5(<string>) Use the MD5 hash. Returns a hex-encoded string.
digest.hash_crc32(<string>) Use a 32 bit Cyclic Redundancy Checksum. Returns a hex-encoded string.
digest.hash_crc32b(<string>) A reversed CRC32 (for compatibility with some PHP applications). Returns a hex-encoded string.
digest.rsa_verify(ID hash_method, STRING_LIST public_key, STRING_LIST payload, STRING_LIST digest [, ID base64_method ]) A boolean function that returns true if the RSA digest using public_key of payload matches digest. The hash_method parameter selects the digest function to use. It can be sha256, sha384, sha512, or default (default is equivalent to sha256). The base64_method parameter is optional. It can be standard, url, url_nopad, or default (default is equivalent to url_nopad).
digest.secure_is_equal(STRING_LIST s1, STRING_LIST s2) A boolean function that returns true if s1 and s2 are equal. The comparison is done in constant time to defend against timing attacks.
digest.time_hmac_md5(<base64 encoded key>, <interval>, <offset>) Time based One Time Password using MD5. Returns base64 encoded output.
digest.time_hmac_sha1(<base64 encoded key>, <interval>, <offset>) Time based One Time Password using SHA1. Returns base64 encoded output.
digest.time_hmac_sha256(<base64 encoded key>, <interval>, <offset>) Time based One Time Password using SHA256. Returns base64 encoded output.

Notes

In base64 decoding, the output theoretically could be in binary but is interpreted as a string. So if the binary output contains '\0' then it could be truncated.

The time based One-Time Password algorithm initializes the HMAC using the key and appropriate hash type. Then it hashes the message

(<time now in seconds since UNIX epoch> / <interval>) + <offset>

as a 64bit unsigned integer (little endian) and base64 encodes the result.

Examples

One-Time Password Validation (Token Authentication)

Use this to validate tokens with a URL format like the following:

http://cname-to-fastly/video.mp4?6h2YUl1CB4C50SbkZ0E6U3dZGjh+84dz3+Zope2Uhik=

Example implementations for token generation in various languages can be found in GitHub.

Example VCL

sub vcl_recv {
#FASTLY recv

  set req.http.token = regsub(req.url, ".*\?(.*)$", "\1");
  if (req.http.token != digest.time_hmac_sha256("RmFzdGx5IFRva2VuIFRlc3Q=", 60, 0) &&
  req.http.token != digest.time_hmac_sha256("RmFzdGx5IFRva2VuIFRlc3Q=", 60, -1)) {
    error 403;
  }
}

Signature

set resp.http.x-data-sig = digest.hmac_sha256("secretkey",resp.http.x-data);

Base64 decoding

A snippet like this in vcl_error would set the response body to the value of the request header field named x-parrot after base64-decoding the value:

synthetic digest.base64_decode(req.http.x-parrot);

However, if the base64-decoded string contains a NUL byte (0x00), then that byte and any bytes following it will not be included in the response. Keep that in mind if you intend to send a synthetic response that contains binary data. There is currently no way to send a synthetic response containing a NUL byte.

AWSv4 message authentication

Use the following format:

STRING awsv4_hmac(STRING key, STRING date_stamp, STRING region, STRING service, STRING string)

Example VCL

set resp.http.sig = digest.awsv4_hmac(
    "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
    "20120215",
    "us-east-1",
    "iam",
    "hello");

Back to Top