Encryption Algorithm
Enterprise Kitchen uses the AES-256 encryption algorithm along with the CTR Cipher Mode.
To encrypt data with this algorithm:
Data—waiting for encryption
Password—32 bytes
Initialization Vector—16 bytes
Password
While a password format is not yet established, the overall vision is that the Secret Key value is set and sourced from Portal API.
Because raw passwords typically do not meet the length and entropy requirements for cryptographic keys, it is required to derive a key from the Secret Key before using a password for AES-256 encryption. Use the PBKDF2 algorithm to derive a Secret Key.
Benefits of Secret Key Derivation:
Length: AES-256 requires a 256-bit (32-byted) key, but secret key can be shorter
Security: PBKDF2 increases the security by incorporating a salt and multiple iterations to thwart brute force attacks
Initialization Vector
An Initialization Vector (IV) is a fixed-size input to a cryptographic algorithm that typically has a random or pseudorandom requirement. Since sharing the IV is an essential part of the encryption and decryption process and because is not secret, the IV has the following requirements:
Unique and unpredictable for each encryption operation
Only transmitted openily along with the ciphertext or HTTP request meta information
A key point of an IV is its fixed-size. This is determined by the block size of the encryption algorithm—for AES, the block size is 128 bits (16 bytes)
Data for Encryption
The raw payload that a POS intends to send to Enterprise Kitchen.
Encryption Example
A Node.js example, showing a possible encryption method:
const crypto = require("crypto");
async function generateDerivedKey(password, saltbase) {
const textEncoder = new TextEncoder();
const encodedPassword = textEncoder.encode(password);
// Derive a key from the password using PBKDF2
const passwordKey = await crypto.subtle.importKey(
"raw",
encodedPassword,
{ name: "PBKDF2" },
false,
["deriveKey"]
);
const salt = textEncoder.encode(saltbase);
const derivedKey = await crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: salt,
iterations: 100000,
hash: "SHA-256",
},
passwordKey,
{ name: "AES-CTR", length: 256 },
true,
["encrypt", "decrypt"]
);
return derivedKey;
}
async function encryptText(plainText, password, siteId) {
// Convert the plain text and password to Uint8Array
const textEncoder = new TextEncoder();
const encodedText = textEncoder.encode(plainText);
// generate derived key
const derivedKey = await generateDerivedKey(password, siteId);
// Generate a random IV
const iv = crypto.getRandomValues(new Uint8Array(16));
// Encrypt the text using AES-CTR
const encryptedContent = await crypto.subtle.encrypt(
{
name: "AES-CTR",
counter: iv,
length: 64,
},
derivedKey,
encodedText
);
// Convert the encrypted content and IV to hex strings
const encryptedArray = new Uint8Array(encryptedContent);
const encryptedHex = Array.from(encryptedArray)
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
const ivHex = Array.from(iv)
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
return { encryptedHex, ivHex };
}
async function decryptText(encryptedHex, ivHex, password, siteId) {
// Convert the encrypted text, IV and password to Uint8Array
const textEncoder = new TextEncoder();
const encryptedArray = new Uint8Array(
encryptedHex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))
);
const iv = new Uint8Array(
ivHex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))
);
const derivedKey = await generateDerivedKey(password, siteId);
// Decrypt the text using AES-CTR
const decryptedContent = await crypto.subtle.decrypt(
{
name: "AES-CTR",
counter: iv,
length: 64,
},
derivedKey,
encryptedArray
);
// Convert the decrypted content to a string
const textDecoder = new TextDecoder();
const decryptedText = textDecoder.decode(decryptedContent);
return decryptedText;
}
(async function () {
const secret_key = "secret"; //this value is a secret phrase from the Portal
const siteId = "6621401d146e98f840719201"; //site id value should be used as a salt for derived key
const { encryptedHex, ivHex } = await encryptText(
"text to be encrypted",
secret_key,
siteId
);
const result = await decryptText(encryptedHex, ivHex, secret_key, siteId);
console.log(result);
})();