Advanced Encryption Standard

Cipher Block Chaining Mode

Part 2. AES Secret Key Format

An instance of Key/CryptoKey cannot be sent to a receiving party directly. It should be first transformed into a format suitable for persistent storage or the network transfer. Additional cryptographic techniques can be applied to protect the keying material: for example, the client encrypts the generated key with the server's public key, and the corresponding private key is employed on the server side for decryption.

The exportKey() method of the SubtleCrypto allows the client code to convert an AES key into a binary buffer or a JSON object.

Secret Key As ArrayBuffer

Let's return to the AES example from the previous article and redefine it slightly: after the key is generated, it will be exported as an opaque sequence of bytes. The raw format is specified as the first argument of the exportKey(). The second argument is the created key:

crypto.subtle.generateKey(algorithm, isExtractable, keyOperations).then(exportSecretKey, keyGenerationFailure);

function exportSecretKey(key) {
 crypto.subtle.exportKey("raw", key).then(
  function(buffer) {
   console.info("The secret key has been exported successfully.");
   . . .
  },
  function(eObj) {
   console.error("The secret key cannot be exported: "+eObj.message.toLowerCase()+".");
  }
 );
}

The buffer is an ArrayBuffer containing 32 bytes of the key material. It can be saved as a local file by using the Blob constructor, an object URL and a hyperlink with the download attribute:

var blob=new Blob([buffer]);
var link=document.createElement("a");
link.href=URL.createObjectURL(blob);
link.download="secret-key.dat"; // file will have a size of 32 bytes
link.textContent="save the secret key";
document.body.appendChild(link);

The secret key stored locally can be transformed into other data formats through the use of various desktop tools:

base64 secret-key.dat>secret-key-base64.dat

To protect the key file by means of asymmetric cryptography, commands of openssl are employed:

openssl genrsa -out rsa.pem 2048
openssl rsa -in rsa.pem -out public-key.pem -pubout
openssl rsautl -in secret-key.dat -out secret-key.dat.enc -inkey public-key.pem -pubin -encrypt

Programming languages allowing the system administrator to create console applications can modify the saved key, too. Here's an example of Python code converting the key file into its hexadecimal counterpart:

import binascii
import string

sk=open("secret-key.dat", "r") # opening the file in the 'read' mode
raw=sk.read() # reading all file data: the bytes are returned as a string object
sk.close()

hx=string.upper(binascii.b2a_hex(raw)) # hexadecimal representation of key file data

skh=open("secret-key-hex.dat", "w") # creating a new file: "w" stands for 'write' mode
skh.write(hx) # writing the hexadecimal value
skh.close() # flushing the internal buffer and closing the file

JSON Web Key

Representation of symmetric keys is not restricted to opaque key material only: as an alternative, the secret key can be formatted as a JSON Web Key object. In this case the exportKey() function is provided with the jwk string argument:

crypto.subtle.generateKey(algorithm, isExtractable, keyOperations).then(exportSecretKeyAsJWK, keyGenerationFailure);

function exportSecretKeyAsJWK(key) {
 crypto.subtle.exportKey("jwk", key).then(
  function(jwk) {
   console.info("The secret key has been exported successfully.");
   console.log(jwk); // JSON object
   console.log(JSON.stringify(jwk));
  },
  function(eObj) {
   console.error("The secret key cannot be exported: "+eObj.message.toLowerCase()+".");
  }
 );
}

The exported JSON object has the following properties:

  • alg identifying the algorithm intended for use with the key; AES CBC with the key length of 256 bits is designated by the A256CBC value;
  • the boolean ext showing that the key is extractable;
  • k - the secret key represented as the Base64-encoded octet sequence;
  • key_ops - the key operations parameter assuming the form of the ["encrypt", "decrypt"] array;
  • the key type parameter declared as kty; it has the value of oct (octet sequence); the value vindicates that the JSON object signifies a symmetric key.

Calling the static stringify() method of the JSON object could return the following representation of the secret key:

{"alg": "A256CBC", "ext": true, "k": "NjTYc6xYLTPJ2IlPc3Y8FHQVKSYWejZe7p2xucPUZsA", "key_ops": ["encrypt","decrypt"], "kty": "oct"}