Specification: Ballerina Crypto Library

Owners: @shafreenAnfar @bhashinee
Reviewers: @shafreenAnfar
Created: 2022/08/23
Updated: 2022/08/25
Edition: Swan Lake

Introduction

This is the specification for the Crypto standard library of Ballerina language, which provides Crypto functionalities.

The Crypto library specification has evolved and may continue to evolve in the future. The released versions of the specification can be found under the relevant GitHub tag.

If you have any feedback or suggestions about the library, start a discussion via a GitHub issue or in the Discord server. Based on the outcome of the discussion, the specification and implementation can be updated. Community feedback is always welcome. Any accepted proposal, which affects the specification is stored under /docs/proposals. Proposals under discussion can be found with the label type/proposal in GitHub.

The conforming implementation of the specification is released and included in the distribution. Any deviation from the specification is considered a bug.

Contents

  1. Overview
  2. Hash
  3. HMAC
  4. Decode private/public key
  5. Encrypt-Decrypt
  6. Sign and Verify

1. Overview

The Ballerina crypto library facilitates APIs to do operations like hashing, HMAC generation, checksum generation, encryption, decryption, signing data digitally, verifying digitally signed data, etc., with different cryptographic algorithms.

2. Hash

The crypto library supports generating hashes with 5 different hash algorithms MD5, SHA1, SHA256, SHA384, and SHA512. Also, it supports generating the CRC32B checksum.

2.1. MD5

This API can be used to create the MD5 hash of the given data.

string dataString = "Hello Ballerina";
byte[] data = dataString.toBytes();
byte[] hash = crypto:hashMd5(data);

2.2. SHA1

This API can be used to create the SHA-1 hash of the given data.

string dataString = "Hello Ballerina";
byte[] data = dataString.toBytes();
byte[] hash = crypto:hashSha1(data);

2.3. SHA256

This API can be used to create the SHA-256 hash of the given data.

string dataString = "Hello Ballerina";
byte[] data = dataString.toBytes();
byte[] hash = crypto:hashSha256(data);

2.4. SHA384

This API can be used to create the SHA-384 hash of the given data.

string dataString = "Hello Ballerina";
byte[] data = dataString.toBytes();
byte[] hash = crypto:hashSha384(data);

2.5. SHA512

This API can be used to create the SHA-512 hash of the given data.

string dataString = "Hello Ballerina";
byte[] data = dataString.toBytes();
byte[] hash = crypto:hashSha512(data);

2.6. CRC32B

This API can be used to create the Hex-encoded CRC32B value of the given data.

string stringData = "Hello Ballerina";
byte[] data = stringData.toBytes();
string checksum = crypto:crc32b(data);

3. HMAC

The crypto library supports generating HMAC with 5 different hash algorithms: MD5, SHA1, SHA256, SHA384, and SHA512.

3.1. MD5

This API can be used to create HMAC using the MD5 hash function of the given data.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
string secret = "some-secret";
byte[] key = secret.toBytes();
byte[] hmac = check crypto:hmacMd5(data, key);

3.2. SHA1

This API can be used to create HMAC using the SHA-1 hash function of the given data.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
string secret = "some-secret";
byte[] key = secret.toBytes();
byte[] hmac = crypto:hmacSha1(data, key);

3.3. SHA256

This API can be used to create HMAC using the SHA-256 hash function of the given data.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
string secret = "some-secret";
byte[] key = secret.toBytes();
byte[] hmac = check crypto:hmacSha256(data, key);

3.4. SHA384

This API can be used to create HMAC using the SHA-384 hash function of the given data.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
string secret = "some-secret";
byte[] key = secret.toBytes();
byte[] hmac = check crypto:hmacSha384(data, key);

3.5. SHA512

This API can be used to create HMAC using the SHA-512 hash function of the given data.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
string secret = "some-secret";
byte[] key = secret.toBytes();
byte[] hmac = check crypto:hmacSha512(data, key);

4. Decode private/public key

The crypto library supports decoding the RSA private key from a .p12 file and a key file in the PEM format. Also, it supports decoding a public key from a .p12 file and a certificate file in the X509 format. Additionally, this supports building an RSA public key with the modulus and exponent parameters.

4.1. Decode RSA Private key from PKCS12 file

This API can be used to decode the RSA private key from the given PKCS#12 file.

crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PrivateKey privateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword");

4.2. Decode RSA Private key using Private key and Password

This API can be used to decode the RSA private key from the given private key and private key password.

string keyFile = "/path/to/private.key";
crypto:PrivateKey privateKey = check crypto:decodeRsaPrivateKeyFromKeyFile(keyFile, "keyPassword");

4.3. Decode RSA Public key from PKCS12 file

This API can be used to decode the RSA public key from the given PKCS#12 archive file.

crypto:TrustStore trustStore = {
    path: "/path/tp/truststore.p12",
    password: "truststorePassword"
};
crypto:PublicKey publicKey = check crypto:decodeRsaPublicKeyFromTrustStore(trustStore, "keyAlias");

4.4. Decode RSA Public key from the certificate file

This API can be used to decode the RSA public key from the given public certificate file.

string certFile = "/path/to/public.cert";
crypto:PublicKey publicKey = check crypto:decodeRsaPublicKeyFromCertFile(certFile);

4.5. Decode EC Private key from PKCS12 file

This API can be used to decode the EC private key from the given PKCS#12 file.

crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PrivateKey privateKey = check crypto:decodeEcPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword");

4.6. Decode EC Private key using Private key and Password

This API can be used to decode the EC private key from the given private key and private key password.

string keyFile = "/path/to/private.key";
crypto:PrivateKey privateKey = check crypto:decodeEcPrivateKeyFromKeyFile(keyFile, "keyPassword");

4.7. Decode EC Public key from PKCS12 file

This API can be used to decode the RSA public key from the given PKCS#12 archive file.

crypto:TrustStore trustStore = {
    path: "/path/tp/truststore.p12",
    password: "truststorePassword"
};
crypto:PublicKey publicKey = check crypto:decodeEcPublicKeyFromTrustStore(trustStore, "keyAlias");

4.8. Decode EC Public key from the certificate file

This API can be used to decode the EC public key from the given public certificate file.

string certFile = "/path/to/public.cert";
crypto:PublicKey publicKey = check crypto:decodeEcPublicKeyFromCertFile(certFile);

4.9. Build RSA Public key from modulus and exponent parameters

This API can be used to build the RSA public key from the given modulus and exponent parameters.

string modulus = "luZFdW1ynitztkWLC6xKegbRWxky-5P0p4ShYEOkHs30QI2VCuR6Qo4Bz5rTgLBrky03W1GAVrZxuvKRGj9V9-" +
        "PmjdGtau4CTXu9pLLcqnruaczoSdvBYA3lS9a7zgFU0-s6kMl2EhB-rk7gXluEep7lIOenzfl2f6IoTKa2fVgVd3YKiSGsy" +
        "L4tztS70vmmX121qm0sTJdKWP4HxXyqK9neolXI9fYyHOYILVNZ69z_73OOVhkh_mvTmWZLM7GM6sApmyLX6OXUp8z0pkY-v" +
        "T_9-zRxxQs7GurC4_C1nK3rI_0ySUgGEafO1atNjYmlFN-M3tZX6nEcA6g94IavyQ";
string exponent = "AQAB";
crypto:PublicKey publicKey = check crypto:buildRsaPublicKey(modulus, exponent);

5. Encrypt-Decrypt

The crypto library supports both symmetric key encryption/decryption and asymmetric key encryption/decryption. The RSA algorithm can be used for asymmetric-key encryption/decryption with the use of private and public keys. The AES algorithm can be used for symmetric-key encryption/decryption with the use of a shared key.

5.1. Encryption

5.1.1. RSA

This API can be used to create the RSA-encrypted value of the given data.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PublicKey publicKey = check crypto:decodeRsaPublicKeyFromTrustStore(keyStore, "keyAlias");
byte[] cipherText = check crypto:encryptRsaEcb(data, publicKey);

5.1.2. AES-CBC

This API can be used to create the AES-CBC-encrypted value for the given data.

string dataString = "Hello Ballerina!";
byte[] data = dataString.toBytes();
byte[16] key = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
foreach int i in 0...15 {
    key[i] = <byte>(check random:createIntInRange(0, 255));
}
byte[16] initialVector = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
foreach int i in 0...15 {
    initialVector[i] = <byte>(check random:createIntInRange(0, 255));
}
byte[] cipherText = check crypto:encryptAesCbc(data, key, initialVector);

5.1.3. AES-ECB

This API can be used to create the AES-ECB-encrypted value for the given data.

string dataString = "Hello Ballerina!";
byte[] data = dataString.toBytes();
byte[16] key = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
foreach int i in 0...15 {
    key[i] = <byte>(check random:createIntInRange(0, 255));
}
byte[] cipherText = check crypto:encryptAesEcb(data, key);

5.1.4. AES-GCM

This API can be used to create the AES-GCM-encrypted value for the given data.

string dataString = "Hello Ballerina!";
byte[] data = dataString.toBytes();
byte[16] key = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
foreach int i in 0...15 {
    key[i] = <byte>(check random:createIntInRange(0, 255));
}
byte[16] initialVector = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
foreach int i in 0...15 {
    initialVector[i] = <byte>(check random:createIntInRange(0, 255));
}
byte[] cipherText = check crypto:encryptAesGcm(data, key, initialVector);

5.2. Decryption

5.2.1. RSA-ECB

This API can be used to create the RSA-decrypted value for the given RSA-encrypted data.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PublicKey publicKey = check crypto:decodeRsaPublicKeyFromTrustStore(keyStore, "keyAlias");
crypto:PrivateKey privateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword");
byte[] cipherText = check crypto:encryptRsaEcb(data, publicKey);
byte[] plainText = check crypto:decryptRsaEcb(cipherText, privateKey);

5.2.2. AES-CBC

This API can be used to create the AES-CBC-decrypted value for the given AES-CBC-encrypted data.

string dataString = "Hello Ballerina!";
byte[] data = dataString.toBytes();
byte[16] key = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
foreach int i in 0...15 {
    key[i] = <byte>(check random:createIntInRange(0, 255));
}
byte[16] initialVector = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
foreach int i in 0...15 {
    initialVector[i] = <byte>(check random:createIntInRange(0, 255));
}
byte[] cipherText = check crypto:encryptAesCbc(data, key, initialVector);
byte[] plainText = check crypto:decryptAesCbc(cipherText, key, initialVector);

5.2.3. AES-ECB

This API can be used to create the AES-ECB-decrypted value for the given AES-ECB-encrypted data.

string dataString = "Hello Ballerina!";
byte[] data = dataString.toBytes();
byte[16] key = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
foreach int i in 0...15 {
    key[i] = <byte>(check random:createIntInRange(0, 255));
}
byte[] cipherText = check crypto:encryptAesEcb(data, key);
byte[] plainText = check crypto:decryptAesEcb(cipherText, key);

5.2.4. AES-GCM

This API can be used to create the AES-GCM-decrypted value for the given AES-GCM-encrypted data.

string dataString = "Hello Ballerina!";
byte[] data = dataString.toBytes();
byte[16] key = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
foreach int i in 0...15 {
    key[i] = <byte>(check random:createIntInRange(0, 255));
}
byte[16] initialVector = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
foreach int i in 0...15 {
    initialVector[i] = <byte>(check random:createIntInRange(0, 255));
}
byte[] cipherText = check crypto:encryptAesGcm(data, key, initialVector);
byte[] plainText = check crypto:decryptAesGcm(cipherText, key, initialVector);

6. Sign and Verify

The crypto library supports signing data using the RSA private key and verification of the signature using the RSA public key. This supports MD5, SHA1, SHA256, SHA384, and SHA512 digesting algorithms as well.

6.1. Sign messages

6.1.1. RSA-MD5

This API can be used to create the RSA-MD5 based signature value for the given data.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PrivateKey privateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword");
byte[] signature = check crypto:signRsaMd5(data, privateKey);

6.1.2. RSA-SHA1

This API can be used to create the RSA-SHA1 based signature value for the given data.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PrivateKey privateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword");
byte[] signature = check crypto:signRsaSha1(data, privateKey);

6.1.3. RSA-SHA256

This API can be used to create the RSA-SHA256 based signature value for the given data.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PrivateKey privateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword");
byte[] signature = check crypto:signRsaSha256(data, privateKey);

6.1.4. RSA-SHA384

This API can be used to create the RSA-SHA384 based signature value for the given data.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PrivateKey privateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword");
byte[] signature = check crypto:signRsaSha384(data, privateKey);

6.1.5. RSA-SHA512

This API can be used to create the RSA-SHA512 based signature value for the given data.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PrivateKey privateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword");
byte[] signature = check crypto:signRsaSha512(data, privateKey);

6.1.6. SHA384withECDSA

This API can be used to create the SHA384withECDSA based signature value for the given data.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PrivateKey privateKey = check crypto:decodeEcPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword");
byte[] signature = check crypto:signSha384withEcdsa(data, privateKey);

6.1.7. SHA256withECDSA

This API can be used to create the SHA256withECDSA based signature value for the given data.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PrivateKey privateKey = check crypto:decodeEcPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword");
byte[] signature = check crypto:signSha256withEcdsa(data, privateKey);

6.2. Verify signature

6.2.1. RSA-MD5

This API can be used to verify the RSA-MD5 based signature.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PrivateKey privateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword")
byte[] signature = check crypto:signRsaMd5(data, privateKey);
crypto:PublicKey publicKey = check crypto:decodeRsaPublicKeyFromTrustStore(keyStore, "keyAlias");
boolean validity = check crypto:verifyRsaMd5Signature(data, signature, publicKey);

6.2.2. RSA-SHA1

This API can be used to verify the RSA-SHA1 based signature.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PrivateKey privateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword");
byte[] signature = check crypto:signRsaSha1(data, privateKey);
crypto:PublicKey publicKey = check crypto:decodeRsaPublicKeyFromTrustStore(keyStore, "keyAlias");
boolean validity = check crypto:verifyRsaSha1Signature(data, signature, publicKey);

6.2.3. RSA-SHA256

This API can be used to verify the RSA-SHA256 based signature.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PrivateKey privateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword");
byte[] signature = check crypto:signRsaSha256(data, privateKey);
crypto:PublicKey publicKey = check crypto:decodeRsaPublicKeyFromTrustStore(keyStore, "keyAlias");
boolean validity = check crypto:verifyRsaSha256Signature(data, signature, publicKey);

6.2.4. RSA-SHA384

This API can be used to verify the RSA-SHA384 based signature.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PrivateKey privateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword");
byte[] signature = check crypto:signRsaSha384(data, privateKey);
crypto:PublicKey publicKey = check crypto:decodeRsaPublicKeyFromTrustStore(keyStore, "keyAlias");
boolean validity = check crypto:verifyRsaSha384Signature(data, signature, publicKey);

6.2.5. RSA-SHA512

This API can be used to verify the RSA-SHA512 based signature.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PrivateKey privateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword");
byte[] signature = check crypto:signRsaSha512(data, privateKey);
crypto:PublicKey publicKey = check crypto:decodeRsaPublicKeyFromTrustStore(keyStore, "keyAlias");
boolean validity = check crypto:verifyRsaSha512Signature(data, signature, publicKey);

6.2.6. SHA384withECDSA

This API can be used to verify the SHA384withECDSA based signature.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PrivateKey privateKey = check crypto:decodeEcPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword");
byte[] signature = check crypto:signSha384withEcdsa(data, privateKey);
crypto:PublicKey publicKey = check crypto:decodeEcPublicKeyFromTrustStore(keyStore, "keyAlias");
boolean validity = check crypto:verifySha384withEcdsaSignature(data, signature, publicKey);

6.2.7. SHA256withECDSA

This API can be used to verify the SHA256withECDSA based signature.

string input = "Hello Ballerina";
byte[] data = input.toBytes();
crypto:KeyStore keyStore = {
    path: "/path/to/keyStore.p12",
    password: "keyStorePassword"
};
crypto:PrivateKey privateKey = check crypto:decodeEcPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword");
byte[] signature = check crypto:signSha256withEcdsa(data, privateKey);
crypto:PublicKey publicKey = check crypto:decodeEcPublicKeyFromTrustStore(keyStore, "keyAlias");
boolean validity = check crypto:verifySha256withEcdsaSignature(data, signature, publicKey);