Search code examples
javascriptcryptographycryptoapi

window.crypto.subtle.encrypt returns undefined


I am trying to encrypt a text using the Web Crypto API. The following is my code:

const generatedIv = generateIv();
let generatedKey;
generateKey()
  .then(key => {
    generatedKey = key;
    encryptData(encodeText(JSON.stringify(data)), generatedKey, generatedIv);
  }).then(encrypted => {
    console.log(encrypted) // Always returns undefined?
  }).catch(
    err => console.error(err)
  );

function encodeText(data) {
  if ('TextEncoder' in window) {
    return new TextEncoder('utf-8').encode(data);
  }
  return undefined;
}

function generateIv() {
  return window.crypto.getRandomValues(new Uint8Array(12));
}

function generateKey() {
  return window.crypto.subtle.generateKey({
    name: 'AES-GCM',
    length: 256
  }, true, [
    'encrypt',
    'decrypt'
  ]);
}

function encryptData(data, key, iv) {
  return window.crypto.subtle.encrypt({
    name: 'AES-GCM',
    iv: iv,
    tagLength: 128
  }, key, data);
}

For some reason, the console.log statement always prints out undefined. I've tried looking on the web for possible solutions, but I wasn't able to find any.

Is there something that I am doing wrong here? Thanks in advance! :)


Solution

  • const generatedIv = generateIv();
    let generatedKey;
    generateKey()
      .then(key => {
        generatedKey = key;
        // you need to return something if you want the next .then to get anything
        return encryptData(encodeText("Hello World"), generatedKey, generatedIv);
      }).then(encrypted => {
        console.log("encrypted is an ArrayBuffer:", encrypted instanceof ArrayBuffer)
      }).catch(
        err => console.error(err)
      );
    
    function encodeText(data) {
      if ('TextEncoder' in window) {
        return new TextEncoder('utf-8').encode(data);
      }
      return undefined;
    }
    
    function generateIv() {
      return window.crypto.getRandomValues(new Uint8Array(12));
    }
    
    function generateKey() {
      return window.crypto.subtle.generateKey({
        name: 'AES-GCM',
        length: 256
      }, true, [
        'encrypt',
        'decrypt'
      ]);
    }
    
    function encryptData(data, key, iv) {
      return window.crypto.subtle.encrypt({
        name: 'AES-GCM',
        iv: iv,
        tagLength: 128
      }, key, data);
    }

    Running the above, you should see encrypted is an ArrayBuffer: true - because that's what you'd expect the encrypted result is, an ArrayBuffer ... so, huzzah - a simple return was all that was required, to return a value (in this case the promise returned by window.crypto.subtle.encrypt) to the next .then ... otherwise known as promise chaining

    Have a great day