Skip to content

Crypto

The Crypto module can be used to encrypt/decrypt secrets and other sensitive information. It can be used together with e.g. the Table module to keep passwords or similar items for use in flows but not visible for other than the intended users.
There are also JWE support methods to encrypt/decrypt data using JSON Web Encryption (JWE). This can be used to send and receive encrypted data to/from other systems in a safe manner.

Encrypt

Make an encrypted string from the given input and access-scope. Access-scope can be:

  • Crypto.forUser to allow only the current logged in user to decrypt the information. Decryption may happen on a different machine or using a different application than Manatee, but only the current logged in Windows user will be able to do the decrypt.
  • Crypto.forMachine to only allow users on the current machine to decrypt. Again decrypting is not limited to Manatee - any program on the local machine will be able to decrypt.
  • a string password to only allow users who know the supplied password to decrypt the message (min 12 characters).
  • an object describing the algorithm and its options, we currently support algorithms: aes-gcm and aes-cbc (see examples below).
  • null or undefined or no argument given to make the encrypted string decryptable only by the Manatee application across all users and all machines.

Notes on Crypto.forUser and Crypto.forMachine

If you use Crypto.forUser or Crypto.forMachine then you will actually be able to decrypt using either scope on the same machine with the same user. This works because the encrypted blob contains the original access-scope which is used to switch decryption method automatically. The following example demonstrates this:

js
var encryptedString = Crypto.encrypt("my secret", Crypto.forUser);
var decryptedString = Crypto.decrypt(encryptedString, Crypto.forMachine);
// decryptedString === "my secret"

You still will not be able to decrypt using the same scope on a different machine (if Crypto.forMachine) or logged in as another user (if Crypto.forUser).

Examples

javascript
// for the current user
var encryptedString = Crypto.encrypt("my secret", Crypto.forUser);

// for the current machine
encryptedString = Crypto.encrypt("my secret", Crypto.forMachine);

// for users with the correct password
encryptedString = Crypto.encrypt("my secret", "password12345678");

// with a specified algorithm and password
var encrypted = Crypto.encrypt("my secret", {
  algorithm: "aes-gcm", // or "aes-cbc"
  password: "thel0ng3rth3b3tterf0rp455w0rds000000",
});

// for Manatee eyes only
encryptedString = Crypto.encrypt("my secret");

Decrypt

Take an ecnrypted string and decrypt. Supply it with the same access-scope used when the string was encrypted.

Examples

javascript
// for the current user
var originalString = Crypto.decrypt(encryptedString, Crypto.forUser);
// for the current machine
originalString = Crypto.decrypt(encryptedString, Crypto.forMachine);
// for users with the correct password
originalString = Crypto.decrypt(encryptedString, "password12345678");
// for Manatee eyes only
originalString = Crypto.decrypt(encryptedString);

HMAC

Generates a HMAC auth code.

js
var authCode = Crypto.hmac("secret-goes-here", "content-to-sign-goes-here", {
  encoding: "UTF8",
  algorithm: "HMACSHA256",
  base64: true,
});
// or using the defaults; encoding = UTF8, algorithm: HMACSHA256, base64: true
authCode = Crypto.hmac("secret-goes-here", "content-to-sign-goes-here");

The optional arguments are;

  • encoding which determines how secret and content are encoded to bytes and how the resulting code is decoded to a string (unless base64 = true) – default is UTF8
  • algorithm determines the underlying hashing func; options are here – default is HMACSHA256
  • base64 whether or not encode the result as Base64 (default is true)

Hash

Generates a SHA hash.

js
var hash = Crypto.hash("content-to-encode", { encoding: "UTF8", algorithm: "SHA1" base64: true });
// or with hexadecimal output
var hex = Crypto.hash("hello", { algorithm: "MD5", hex: true });
// hex is "5d41402abc4b2a76b9719d911017c59"

The optional arguments are;

  • encoding which determines how secret and content are encoded to bytes and how the resulting code is decoded to a string (unless base64 = true) – default is UTF8
  • algorithm determines the underlying hashing func; options are here – default is SHA1
  • base64 whether or not encode the result as Base64 (default is true)
  • hex option to get a hexadecimal output. If true then we encode the hash as a hex string and return it. The hex option takes precedence over base64 and encoding since it is expected to be used more often.

JWE

Crypto provides helpers for encrypting and decrypting data using JWE (JSON Web Encryption) in Compact Serialization format.

JWE Compact is a URL-safe string consisting of five dot-separated Base64Url parts:

BASE64URL(ProtectedHeader).BASE64URL(EncryptedKey).BASE64URL(IV).BASE64URL(Ciphertext).BASE64URL(Tag)

This makes it suitable for transport in JSON, configuration, and many APIs. (If you place it inside a URL query string, you should still URL-encode it.) We provide support for both symmetric and asymmetric algorithms. There are recommended safe combinations for each algorithm. Symmetric uses a single secret (a KEK=Key Encryption Key), asymmetric uses a public/private key pair.

More information about JWE can be found here:
https://auth0.com/docs/secure/tokens/access-tokens/json-web-encryption

We support the following algorithms and encryptions:

AlgorithmEncryptionNote
A256KWA256GCMSymetric
A256KWA256CBC-HS512Symetric
RSA-OAEP-256A256GCMAsymmetric
RSA-OAEP-256A256CBC-HS512Asymmetric
RSA-OAEPA256GCMUnsafe, Asymmetric
RSA-OAEPA256CBC-HS512Unsafe, Asymmetric
A192KWA192GCMUnsafe, Symmetric
A192KWA192CBC-HS384Unsafe, Symmetric
A128KWA128GCMUnsafe, Symmetric
A128KWA128CBC-HS256Unsafe, Symmetric

The combination marked unsafe are outdated and should not be used, unless required by legacy systems. To use the unsafe version you must call the jweEncryptUnsafe or jweDecryptUnsafe methods. Using other combinations, or using an unsafe combination with the standard methods will result in an exception.

jweEncrypt

Encrypts a plaintext string into a JWE Compact token.

Signature

js
crypto.jweEncrypt(plainText: string, options: CryptoJweOptions): string

Returns

  • A JWE Compact string

Options jweEncrypt accepts the following options:

  • algorithm (required) - The key management algorithm (alg in the JWE header),
  • encryption (required) - The content encryption algorithm (enc in the JWE header),
  • kekBase64 (required for symmetric algorithm) - The key encryption key (KEK),
  • publicRsaBase64 (required for asymmetric algorithm) - The recipient’s public RSA key,
  • kid (optional) - The key identifier (kid in the JWE header),

Example

js
//Symmetric
const optsSym = {
  algorithm: "A256KW",
  encryption: "A256CBC-HS512",
  kid: "SystemX-Enc-2024.6",  // optional key identifier
  kekBase64: secrets.get("my-jwe-kek")
};
const jweSym = crypto.jweEncrypt("Hello", optsSym);

//Asymmetric
const optsAsym = {
  algorithm: "RSA-OAEP-256",
  encryption: "A256CBC-HS512",
  kid: "SystemX-Enc-2024.6",  // optional key identifier
  publicRsaBase64: secrets.get("my-jwe-public-rsa")     // public for encryption
};
const jweAsym = crypto.jweEncrypt("Hello", optsAsym);

Note Some systems may require that you pass a kid (key identifier) in the header. This is typically used to help the recipient choose the correct key.


jweDecrypt

Decrypts a JWE Compact token.

Signature

js
crypto.jweDecrypt(jweCompact: string, , options: CryptoJweOptions): string

Options jweDecrypt accepts the following options:

  • kekBase64 (required for symmetric algorithm) - The key encryption key (KEK) same as used for encryption,
  • privateRsaBase64 (required for asymmetric algorithm) - The recipient’s private RSA key,

Returns

  • The decrypted plaintext string

Example

js
//Symmetric
const optsSym = {
  kekBase64: secrets.get("my-jwe-kek")
};
const plaintext1 = crypto.jweEncrypt(jweSym, optsSym);

//Asymmetric
const optsAsym = {
  privateRsaBase64: secrets.get("my-jwe-private-rsa")       // private for decryption
};
const plaintext2 = crypto.jweEncrypt(jweAsym, optsAsym);

Note Symmetric uses the same secret (KEK) for both encryption and decryption. Asymmetric uses the recipient’s private key for decryption. Also, sending in Algorithm, Encryption, and Key Identifier (kid) is not required because the are part of the jweCompact.

jweReadHeader

Reads (parses) the protected header of a JWE Compact token without decrypting it.

This is useful when you need to inspect which algorithm and encryption are used, or which key identifier (kid) the token refers to, before deciding which secret to use for decryption.

Signature

js
var header = crypto.jweReadHeader(jweCompact: string);

Example

js
const optsSym = {
  algorithm: "A256KW",
  encryption: "A256CBC-HS512",
  kid: "2026.1",
  kekBase64: secrets.get("my-jwe-kek")
};
const jweSym = crypto.jweEncrypt("Hello", optsSym);

var header = crypto.jweReadHeader(jweSym);

// header === { algorithm: "A256KW", encryption: "A256CBC-HS512", kid: "2026.1" }

jweEncryptUnsafe

Same as jweEncrypt, but allows a wider set of algorithm/encryption combinations intended for legacy compatibility. You should only use this when you must interoperate with an older external system.

Signature

js
crypto.jweEncryptUnsafe(plainText: string, options: CryptoJweOptions): string

See jweEncrypt

jweDecryptUnsafe

Same as jweDecrypt, but allows a wider set of algorithm/encryption combinations intended for legacy compatibility. You should only use this when you must interoperate with an older external system.

Signature

js
crypto.jweDecryptUnsafe(jweCompact: string, options: CryptoJweOptions): string

See jweDecrypt