PeculiarVentures/webcrypto

AES encrypt / decrypt with a passphrase

a-zog opened this issue · 8 comments

a-zog commented

Hi,

Great work !

I'm currently switching from CryptoJS and couldn't figure out how to reach this outcome:

var encrypted = CryptoJS.AES.encrypt("Message", "Secret Passphrase");
var decrypted = CryptoJS.AES.decrypt(encrypted, "Secret Passphrase");

Any hint please?

Thank you again for the quality of this repo

It's not clear which mechanism it uses. WebCrypto implements AES-CBC, AES-CTR, AES-ECB, and AES-GCM encryption mechanisms.

a-zog commented

Thank you for the quick response,
I've tried "AES-CBC" on CryptoJS.AES, how would it be implemented on WebCrypto ?
Params seemed confusing, didn't know where to input the "secret Passphrase"

@a-zog
Looks like crypto-js uses PBKDF2 mechanism for AES key derivation and use it for message encryption/decryption. But it's not clear which params and paddings it uses. If you could share this params I could repeat it using WebCrypto. WebCrypto implements PBKDF2 mechanism too

https://github.com/brix/crypto-js/blob/develop/src/cipher-core.js#L819-L822

a-zog commented

Great !

Sure, this is the legacy code I use to AES-CBC encrypt/decrypt :

const passphrase = "secret passphrase"
const valueToEncrypt = "a secret content to encrypt"

const CryptoJSAesJson = {
    stringify: function (cipherParams) {
        const j = {
            ct: cipherParams.ciphertext.toString(CryptoJS.enc.Base64)
        }
        if (cipherParams.iv) j.iv = cipherParams.iv.toString()
        if (cipherParams.salt) j.s = cipherParams.salt.toString()
        return JSON.stringify(j)
    },
    parse: function (jsonStr) {
        const j = JSON.parse(jsonStr)
        let cipherParams = CryptoJS.lib.CipherParams.create({
            ciphertext: CryptoJS.enc.Base64.parse(j.ct)
        })
        if (j.iv) cipherParams.iv = CryptoJS.enc.Hex.parse(j.iv)
        if (j.s) cipherParams.salt = CryptoJS.enc.Hex.parse(j.s)
        return cipherParams
    }
}

const decryptMe = CryptoJS.AES.encrypt(JSON.stringify(valueToEncrypt), passphrase, {
    format: CryptoJSAesJson
}).toString()

CryptoJS.AES.decrypt(decryptMe, passphrase, {
    format: CryptoJSAesJson
}).toString(CryptoJS.enc.Utf8)

Try something like this

const pbkdf2Key = await crypto.subtle.importKey(
  "raw",
  passwordView, // Password in Uint8Array format
  "PBKDF2",
  false,
  ["deriveKey", "deriveBits"]
);
const aesKey = await crypto.subtle.deriveKey(
  {
    name: "PBKDF2",
    salt: saltView, // Uint8Array
    iterations: 1000,
    hash: { name: "SHA-1" }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
  },
  pbkdf2Key,
  {
    name: "AES-CBC",
    length: 256, // can be  128, 192, or 256
  },
  false,
  ["encrypt", "decrypt"]);

const encryptedMessage = await crypto.subtle.encrypt(
  {
    name: "AES-CBC",
    iv: ivView, // Uint8Array,
  },
  key,
  messageView // Uint8Array
)
a-zog commented

Would you please guide me on what to fill the remaining variables? I'm still confused.

This is how I tried to do it:

const passwordView = Uint8Array("secret-key");
const ivView = Uint8Array("secret-key"); // how is this different from password?
const messageView = Uint8Array("my-secret-message");
const saltView = Uint8Array("any random string?");
const key = aesKey ?

Thanks

I see iv and salt params in your script. cipherParams.iv.toString() and cipherParams.salt.toString()

@a-zog What is in the cipherParams object?