Crypto

This document describes the Crypto library available in the JavaScript environment for app serivices.

Table of content

Object Crypto
Functions hash
hmac
cipher
ecdh
ecdsa

Object Hash
Functions update
final

Object Hmac
Functions update
final

Object Cipher
Members iv
getIv
crypt
close

Object Ecdh
Members public
secret
close

Object ECDSA
Members public
private
sign
verify
close

Examples Encrypting and signing a JS object

Crypto

hash

Creates a Hash object that can be used for the calculation of cryptographic hashes.

The objects allocates persistent memory in the JavaScript Runtime until the final function is called.

Parameters

string algorithmThe hash algorithm to be used. Supported values are "SHA224", "SHA256", "SHA384", "SHA512", "SHA512_224", "SHA512_256", "SHA1", "MD5", "MD4".

Return value

HashAn object that can be used for the hash calculation.
var digest = Crypto.hash("SHA256").update("data1").update("data2").final();
hmac

Creates a Hmac object that can be used for the calculation of a hash-based message authentication code.

The objects allocates persistent memory in the JavaScript Runtime until the final function is called.

Parameters

string algorithmThe hash algorithm to be used. Supported values are "SHA224", "SHA256", "SHA384", "SHA512", "SHA512_224", "SHA512_256", "SHA1", "MD5", "MD4".
string/Uint8Array keyThe password or key that shall be used for the calculation.

Return value

HmacAn object that can be used for the HMAC calculation.
var mac = Crypto.hmac("SHA256","password").update("data1").update("data2").final();
cipher

Creates a Cipher object that can be used for the encryption / decryption.

The objects allocates persistent memory in the JavaScript Runtime until close or crypt with last=true is called.

Note: Cryptography is non-trivial. It's easy to make small mistakes on application level that break security completely. Don't just use the library functions but make sure you have a good understanding how to use the specific algorithm and mode.

Parameters

string algorithmThe cryptographic algorithm to be used. Supported values are "AES", "RC4", "DES".
string modeThe mode of operation to be used.
Supported modes for "AES" are "ECB", "CTR", "CBC", "CTS", "CFB". null defaults to "ECB".
Supported modes for "DES" are "CBC".
Use null for "RC4".
string/Uint8Array key The key for encryption/decryption.
For "AES" a key of 16 bytes (AES-128), 24 bytes (AES-192) or 32 bytes (AES-256) is needed. The function accepts both hexstrings and binary keys given as a Uint8Array.
For "DES" a key of 8 bytes (64 bit) is needed. The function accepts both hexstrings and binary keys given as a Uint8Array.
For "RC4" a key of arbitrary length can be used. It can be specified as a string (password) or as a binary key given as a Uint8Array.
Important: Never reuse the same key for "RC4". As RC4 is a stream cipher, the key needs to be globally unique to maintain security.
Important: Never reuse the same key/iv combination for "AES" in "CTR" mode. As AES-CTR is a stream cipher, the key/iv combination needs to be globally unique to maintain security.
bool encrypt true for encryption (default).
false for decryption
Note: For stream ciphers like RC4 or AES-CTR there is no difference between encryption and decryption, so both values give the same result.

Return value

cipherAn object that can be used for performing the encryption or decryption.
var ciphertext = Crypto.cipher("RC4", null, "password").crypt("secretdata");
var decrypted = Crypto.cipher("RC4", null, "password").crypt(ciphertext);
ecdh

Creates an Ecdh object that can be used for Diffie-Hellman key agreement using elliptic curves.

The supported curve is Secp256r1 also known as P-256.

The objects allocates persistent memory in the JavaScript Runtime until close or secret is called.

Return value

EcdhAn object that can be used for performing the ECDH key agreement.
var ecdh = Crypto.ecdh();
var localPublicKey = ecdh.public();
var remotePublicKey = "aec36e41791fabfc2ddd3223a8ef59a658a9e30cd92a5d241bbf4c18684a4a61c9aa0d1d9d3181d3022d2f64c7663000915622d4e670cce86737bb00cab5de91";
var sharedSecret = ecdh.secret(remotePublicKey);
ecdsa

Creates an ECDSA object that can be used for the Elliptic Curve Digital Signature Algorithm.

The objects allocates persistent memory in the JavaScript Runtime until close is called.

Parameters

string algorithmThe signature algorithm to be used. Supported value is "ES256".
string/Uint8Array privateKey Optional. The private key to use for signing. Can be provided as a hexstring or a Uint8Array.
If omitted, signing is not possible.
string/Uint8Array publicKey Optional. The public key to use for verification. Can be provided as a hexstring or a Uint8Array.
If omitted, verification is not possible.

Remarks

If both privateKey and publicKey are omitted (or null), a new key pair will be generated. You can then retrieve them using the private() and public() methods.

Return value

ECDSAAn object that can be used for signing and verification.
// Generate a new key pair
var ecdsa = Crypto.ecdsa("ES256", null, null); 
var newPrivateKey = ecdsa.private(true);
var newPublicKey = ecdsa.public(true);
ecdsa.close();

// Create an object for verification only
var ecdsaVerify = Crypto.ecdsa("ES256", null, newPublicKey);

// Create an object for signing only
var ecdsaSign = Crypto.ecdsa("ES256", newPrivateKey, null);

Hash

update
Includes a chunk of data into the hash calculation.

Parameters

string/Uint8Array keyThe input data. The function accepts both strings and binary data as Uint8Array.

Return value

HashA reference to the object itself. Useful for method chaining.
final
Caluclates the hash value.

Parameters

bool binaryOptional, defaulting to false. Specifies if the function should return the hash value as a hexstring or as a binary Uint8Array.

Return value

string/Uint8ArrayThe calculated hash value as a hexstring or Uint8Array, depending on the binary parameter.

Remarks

Calling this function will delete the object and free all associated memory in the JavaScript Runtime.

var digestHexString = Crypto.hash("SHA256").update("data1").update("data2").final();
var digestBinary = Crypto.hash("SHA256").update("data1").update("data2").final(true);

Hmac

update
Includes a chunk of data into the HMAC calculation.

Parameters

string/Uint8Array keyThe input data. The function accepts both strings and binary data as Uint8Array.

Return value

HmacA reference to the object itself. Useful for method chaining.
final
Caluclates the HMAC value.

Parameters

bool binaryOptional, defaulting to false. Specifies if the function should return the hash value as a hexstring or as a binary Uint8Array.

Return value

string/Uint8ArrayThe calculated hash value as a hexstring or Uint8Array, depending on the binary parameter.

Remarks

Calling this function will delete the object and free all associated memory in the JavaScript Runtime.

var hacHexString = Crypto.hmac("SHA256","password").update("data1").update("data2").final();
var hmacBinary = Crypto.hmac("SHA256","password").update("data1").update("data2").final(true);

Cipher

iv

Sets an explicit initialization vector. If the function is never called, an IV consisting of null bytes is used.
The following modes of operation use an initialization vector: "CTR", "CFB", "CBC", "CTS".
"AES" uses an initialization vector of 16 bytes
"DES" uses an initialization vecrot of 8 bytes

Parameters

string/Uint8Array ivThe initialzation vector to be used from the next crypt operation. The function accepts both hexstrings and binary data as Uint8Array.

Return value

cipherA reference to the object itself. Useful for method chaining.
getIv

Returns the current IV.

Parameters

bool binaryOptional, defaulting to false. Specifies if the function should return a hexstring or a binary Uint8Array.

Return value

string/Uint8ArrayThe current IV value as a hexstring or Uint8Array, depending on the binary parameter.
crypt
Encrypts or decrypts a chunk of data.

Parameters

string/Uint8Array data The data to be encrypted/decrypted.
For encryption the functions accepts strings or binary data as Uint8Array.
For decryption the function accepts hexstrings or binary data as Uint8Array.
Depending on the algorithm and mode of operation there are restrictions on the data size that can be processed.
"RC4" allows arbitrary data sizes.
"AES" in "CTR" or "CTS" mode allow arbitary data sizes.
All other modes of "AES" expect multiples of 16 bytes
"DES" expects multiples of 8 bytes
bool binary Optional, defaulting to false.
If false, the function will return a hexstring for encryption and a string for decryption.
Otherwise the function will return binary data as a Uint8Array.
bool last Optional, defaulting to true.
If true, the Cipher object will be deleted after the operation, along with all associated data in the JavaScript Runtime.
if false, the object can be reused for encrypting / decrypting additional chunks of data.

Return value

string/Uint8ArrayThe encrypted/decrypted data a string/hexstring or Uint8Array, depending on the binary parameter.
var key = "73757065727375706572736563726574";
var iv = "00000000000000000000000000000000";
var plaintext = "This is the secret text to be encrypted";

// encryption using AES-128 in CTR mode
var ciphertext = Crypto.cipher("AES", "CTR", key, true).iv(iv).crypt(plaintext);

// decryption using AES-128 in CTR mode
var decrypted = Crypto.cipher("AES", "CTR", key, false).iv(iv).crypt(ciphertext);

// now decrypted contains the plain text again
close
Deletes the object and frees all associated data in the JavaScript Runtime. Can be used to dispose the object, as an alternative to calling close with last set to true.

Ecdh

public

Returns the local 64 byte public key for the ECDHE key agreement. The public key is sent to the remote party.

Parameters

bool binaryOptional, defaulting to false. Specifies if the function should return a hexstring or a binary Uint8Array.

Return value

string/Uint8ArrayThe local public key as a hexstring or Uint8Array, depending on the binary parameter.
secret

Calculates a 32 byte shared secret using the remote public key.

Parameters

string/Uint8Array remotePublicKey The public key of the remote party.
Must be 64 bytes of data.
The functions accepts both hexstrings or binary data as Uint8Array.
bool binary Optional, defaulting to false.
If true, the function will return a Uint8Array. Otherwise the function will return a hexstring.

Return value

string/Uint8ArrayThe 32 byte shared secret as a hexstring or Uint8Array, depending on the binary parameter.
// This example illustrates how two parties (A and B) can calculate a shared secret.
var a = Crypto.ecdh();
var b = Crypto.ecdh();

// A and B calculate their public key and send it to each other
var publicA = a.public();
var publicB = b.public();

// A and B calculate the same shared secret using the public key of the remote party
var secretA = a.secret(publicB);
var secretB = b.secret(publicA);

log(secretA == secretB); // true
close
Deletes the object and frees all associated data in the JavaScript Runtime. Can be used to dispose the object, if secret was not called.

ECDSA

public

Returns the public key from the ECDSA object. This is useful when a key pair has been generated automatically.

Parameters

bool binaryOptional, defaulting to false. Specifies if the function should return a hexstring or a binary Uint8Array.

Return value

string/Uint8ArrayThe public key as a hexstring or Uint8Array, depending on the binary parameter.
private

Returns the private key from the ECDSA object. This is useful when a key pair has been generated automatically.

Parameters

bool binaryOptional, defaulting to false. Specifies if the function should return a hexstring or a binary Uint8Array.

Return value

string/Uint8ArrayThe private key as a hexstring or Uint8Array, depending on the binary parameter.
// Generate a new key pair and retrieve the keys
var ecdsa = Crypto.ecdsa("ES256", null, null);
var privateKey = ecdsa.private(true); // get as Uint8Array
var publicKey = ecdsa.public(); // get as hex string
ecdsa.close();
sign

Signs a chunk of data using the private key.

Parameters

string/Uint8Array data The data to be signed. The function accepts strings or binary data as Uint8Array.
bool binary Optional, defaulting to false.
If true, the function will return the signature as a Uint8Array. Otherwise the function will return a hexstring.

Return value

string/Uint8ArrayThe signature as a hexstring or Uint8Array, depending on the binary parameter.
// Example of creating a JWT signature
var header = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9";
var payload = "eyJpc3MiOiJqd3QtdG9vbCIsInN1YiI6InVzZXIxMjMiLCJpYXQiOjE3NTEzNjY0MjksImV4cCI6MTc1MTM3MDAyOSwiZGF0YSI6IkhlbGxvLCBKV1QhIn0";
var textToSign = Encoding.stringToBin(header + "." + payload);
var privateKey = Encoding.hexToBin("fc7682132...4ce"); // Your private key

var ecdsa = Crypto.ecdsa("ES256", privateKey, null);
var signature = ecdsa.sign(textToSign, true); // Get signature as Uint8Array
var jwt_signature = Encoding.binToBase64Url(signature);
ecdsa.close();

var jwt = header + "." + payload + "." + jwt_signature;
verify

Verifies a signature against a chunk of data using the public key.

Parameters

string/Uint8Array signature The signature to verify. The function accepts hexstrings or binary data as Uint8Array.
string/Uint8Array data The data that was originally signed. The function accepts strings or binary data as Uint8Array.

Return value

boolReturns true if the signature is valid, otherwise false.
// Example of verifying a JWT
var jwt = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJqd3QtdG9vbCIsInN1YiI6InVzZXIxMjMiLCJpYXQiOjE3NTExMjQ2NDUsImV4cCI6MTc1MTEyODI0NSwiZGF0YSI6IkhlbGxvLCBKV1QhIn0.JczPUqYLV0Cr3LzI5hnVrUjVgjO_-XeMrIlSxuXQGRn9t7s6FBXtNkO-8dl1YvSJGg4xC7gH_7smoan0bKPKAA";
var parts = jwt.split('.');
var text = Encoding.stringToBin(parts[0] + "." + parts[1]);
var signature = Encoding.base64UrlToBin(parts[2]);
var publicKey = Encoding.hexToBin("04d1dc4c38ad561530d4c53793ed6efba223cb1fe0c171104c2b03621cdd954c66bc2cfabcba8b4fb126c45973c47ef783fb5f3a39ac3a145e105911d062ca6197");

var ecdsa = Crypto.ecdsa("ES256", null, publicKey);
var valid = ecdsa.verify(signature, text); // returns true if valid
ecdsa.close();

log("JWT Signature is valid: " + valid);
close
Deletes the object and frees all associated data in the JavaScript Runtime. It's important to call this function when the object is no longer needed to prevent memory leaks.

Example: Encrypting and signing a JS object

Let's make up an example that brings everything together. For that let's create a function that does the following:
function encryptObject(obj, passphrase) {
    // serialize the object
    var plaintext = JSON.stringify(obj);
    // calculate HMAC
    var hmac = Crypto.hmac("SHA256", passphrase).update(plaintext).final();
    // create random 128-Bit IV
    var iv = Random.bytes(16);
    // create 256-Bit encryption key from passphrase by hashing it using SHA256
    var key = Crypto.hash("SHA256").update(passphrase).final();
    // encrypt
    var ciphertext = Crypto.cipher("AES", "CTR", key, true).iv(iv).crypt(plaintext);
    
    return {
        iv: iv,
        data: ciphertext,
        hmac: hmac
    };
}
Next, let's create the corresponding decryption function.
function decryptObject(obj, passphrase) {
    if (!obj || !obj.iv || !obj.data || !obj.hmac) return null;

    // create 256-Bit encryption key from passphrase by hashing it using SHA256
    var key = Crypto.hash("SHA256").update(passphrase).final();
    // decrypt
    var plaintext = Crypto.cipher("AES", "CTR", key, false).iv(obj.iv).crypt(obj.data);
    // calculate HMAC
    var hmac = Crypto.hmac("SHA256", passphrase).update(plaintext).final();

    // check if decryption was successfull
    if (hmac == obj.hmac) {
        return JSON.parse(plaintext);
    }
    
    return null;
}
We can test it with the following code.

var passphrase = "D4s 1s7 d4s H4us v0m N1c0l4us!!1";

var input = { text: "Hi, this is top secret. We should protect it.", x: 42 };
log("input:     " + JSON.stringify(input));

var encrypted = encryptObject(input, passphrase);
log("encrypted: " + JSON.stringify(encrypted));

var decrypted = decryptObject(encrypted, passphrase);
log("decrypted: " + JSON.stringify(decrypted));
In the log we can see an output like that:

JS: input:     {"text":"Hi, this is top secret. We should protect it.","x":42}
JS: encrypted: {"iv":"357bf81d63418a6fdedce56558667d29","data":"f0a454da39d7306770afc7ea781904b2d49b4adb9d4f1790898d28145503a8d2183e4c53ec4e696a95938ee1c25bf5d29b24851c45a31fc6e13842887b267c","hmac":"9502652073243900ae42a4b864b05d17c3ec18b0983e3aa9ae76099be5642bac"}
JS: decrypted: {"text":"Hi, this is top secret. We should protect it.","x":42}