2

I want to encrypt/decrypt a string with a human readable password. The encrypted data should be decryptable knowing the password only. What is the recommended tool in 2020?

  1. symmetric encryption in the built-in SubtleCrypto interface require generated key (based on the examples I found), and they also need additional data for decryption (a counter, or iv value).
  2. related SO question is 6 years old

    const data = "Hello World";
    const key = "SuperSecret";
    
    const encrypted = encrypt(data, key);
    console.log(encrypted);  // gibberish
    
    const decrypted = decrypt(encrypted, key);
    console.log(decrypted);  // Hello World
    
3
  • there is an aes-cbc example on the linked page Commented May 30, 2020 at 12:00
  • 1
    Probably the best mature and carefully analyzed algorithm is the argon2 family. Unfortunately it's not widely implemented yet. The most widely available algorithm that is pretty good is pbkdf2 Commented May 30, 2020 at 12:01
  • The question you already found might be old but has some recent answers, and there's not been much innovation since. Please explain why you think these answers don't solve your problem. Btw, asking for recommendations is off-topic. Commented May 30, 2020 at 12:03

1 Answer 1

3

Here is an example, to achieve simple encrypt/decrypt

// derive string key
async function deriveKey(password) {
  const algo = {
    name: 'PBKDF2',
    hash: 'SHA-256',
    salt: new TextEncoder().encode('a-unique-salt'),
    iterations: 1000
  }
  return crypto.subtle.deriveKey(
    algo,
    await crypto.subtle.importKey(
      'raw',
      new TextEncoder().encode(password),
      {
        name: algo.name
      },
      false,
      ['deriveKey']
    ),
    {
      name: 'AES-GCM',
      length: 256
    },
    false,
    ['encrypt', 'decrypt']
  )
}

// Encrypt function
async function encrypt(text, password) {
  const algo = {
    name: 'AES-GCM',
    length: 256,
    iv: crypto.getRandomValues(new Uint8Array(12))
  }
  return {
    cipherText: await crypto.subtle.encrypt(
      algo,
      await deriveKey(password),
      new TextEncoder().encode(text)
    ),
    iv: algo.iv
  }
}

// Decrypt function
async function decrypt(encrypted, password) {
  const algo = {
    name: 'AES-GCM',
    length: 256,
    iv: encrypted.iv
  }
  return new TextDecoder().decode(
    await crypto.subtle.decrypt(
      algo,
      await deriveKey(password),
      encrypted.cipherText
    )
  )
}

// example
;(async () => {
  // encrypt
  const encrypted = await encrypt('Secret text', 'password')

  // the cipher text
  console.log(
    String.fromCharCode.apply(null, new Uint8Array(encrypted.cipherText))
  )

  // decrypt it
  const decrypted = await decrypt(encrypted, 'password')
  console.log(decrypted) // Secret text
})()

Sign up to request clarification or add additional context in comments.

2 Comments

Your deriveKey implementation ignores the algoName and length parameters.
I cant see it, please explain or update/edit

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.