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.forUserto 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.forMachineto 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
stringpassword to only allow users who know the supplied password to decrypt the message (min 12 characters). - an
objectdescribing the algorithm and its options, we currently support algorithms:aes-gcmandaes-cbc(see examples below). nullorundefinedor 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:
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
// 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
// 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.
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;
encodingwhich determines howsecretandcontentare encoded to bytes and how the resulting code is decoded to a string (unlessbase64=true) – default isUTF8algorithmdetermines the underlying hashing func; options are here – default isHMACSHA256base64whether or not encode the result as Base64 (default istrue)
Hash
Generates a SHA hash.
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;
encodingwhich determines howsecretandcontentare encoded to bytes and how the resulting code is decoded to a string (unlessbase64=true) – default isUTF8algorithmdetermines the underlying hashing func; options are here – default isSHA1base64whether or not encode the result as Base64 (default istrue)hexoption to get a hexadecimal output. Iftruethen we encode the hash as a hex string and return it. The hex option takes precedence overbase64and 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:
| Algorithm | Encryption | Note |
|---|---|---|
| A256KW | A256GCM | Symetric |
| A256KW | A256CBC-HS512 | Symetric |
| RSA-OAEP-256 | A256GCM | Asymmetric |
| RSA-OAEP-256 | A256CBC-HS512 | Asymmetric |
| RSA-OAEP | A256GCM | Unsafe, Asymmetric |
| RSA-OAEP | A256CBC-HS512 | Unsafe, Asymmetric |
| A192KW | A192GCM | Unsafe, Symmetric |
| A192KW | A192CBC-HS384 | Unsafe, Symmetric |
| A128KW | A128GCM | Unsafe, Symmetric |
| A128KW | A128CBC-HS256 | Unsafe, 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
crypto.jweEncrypt(plainText: string, options: CryptoJweOptions): stringReturns
- A JWE Compact string
Options jweEncrypt accepts the following options:
algorithm(required) - The key management algorithm (algin the JWE header),encryption(required) - The content encryption algorithm (encin 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
//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
crypto.jweDecrypt(jweCompact: string, , options: CryptoJweOptions): stringOptions 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
//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
var header = crypto.jweReadHeader(jweCompact: string);Example
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
crypto.jweEncryptUnsafe(plainText: string, options: CryptoJweOptions): stringSee 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
crypto.jweDecryptUnsafe(jweCompact: string, options: CryptoJweOptions): stringSee jweDecrypt
