Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to save CryptoKey in LocalStorage?

I want to use Web Cryptography API on an already existing project. To encrypt and decrypt something I have to use an CryptoKey, but when I save to CryptoKey into localStorage it only saves the String (CryptoKey) instead of the object.

Is it possible to serialize / convert an CryptoKey in an simple type (string)?

My decrypting method is

function decryptDataWithAES(keyName)
{
    var decrypt_promise; 
    var aesKey = localStorage.getItem(keyName + 'key')
    var item = localStorage.getItem(keyName)
    var invokeVektor = localStorage.getItem(keyName + 'vector')
    console.log("aesKey", aesKey )

    crypto.subtle.decrypt({ name: "AES-CBC", iv: invokeVektor }, aesKey, item).then(function (result) {
        decrypted_data = new Uint8Array(result); decrypted_data = new Uint8Array(result);

        decrypt_promise = convertArrayBufferViewtoString(decrypted_data);
        console.log('decryptDataWithAES ' + decrypt_promise);
        return decrypt_promise; 
    },
        function(e){
            console.log(e.message);
        }
    );
}

The error message is of course:

Failed to execute 'decrypt' on 'SubtleCrypto': parameter 2 is not of type 'CryptoKey'. 2localStorageHandler.js:39 CryptoPromise[object CryptoKey]

If I decrypt without using localStorage there is no problem with encrypting the data.

like image 582
AntonDerProgrammierer Avatar asked May 17 '16 15:05

AntonDerProgrammierer


2 Answers

Consider using crypto.subtle.exportKey() and crypto.subtle.importKey() before saving it in localStorage, so your decryption code would be like this:

function decryptDataWithAES(keyName)
{
    var decrypt_promise; 

    // read raw value of aesKey
    var aesKey_RAW = localStorage.getItem(keyName + 'key')
    var importPromise = crypto.subtle.importKey('raw', aesKey_RAW, 'AES-CBC', true, ['encrypt','decrypt']);

    importPromise.then(function(aesKey){

    var item = localStorage.getItem(keyName)
    var invokeVektor = localStorage.getItem(keyName + 'vector')

        console.log("aesKey", aesKey )

        crypto.subtle.decrypt({ name: "AES-CBC", iv: invokeVektor }, aesKey, item).then(function (result) {
            decrypted_data = new Uint8Array(result); decrypted_data = new Uint8Array(result);

            decrypt_promise = convertArrayBufferViewtoString(decrypted_data);
            console.log('decryptDataWithAES ' + decrypt_promise);
            return decrypt_promise; 
        },
            function(e){
                console.log(e.message);
            }
        );

    }, function(e){ console.log(e.message) } );
}

To save your key in raw format in localStorage:

function saveKeyInLocalStorage(keyName, aesKey){
   var exportPromise = crypto.subtle.exportKey('raw',aesKey);
   exportPromise.then(function(aesKey_RAW){ 
        localStorage.setItem(keyName + 'key' , aesKey_RAW);
        console.log("saved.");
   });
}

Note that both exportKey() and importKey() methods returns a promise.

like image 70
Shadi Shaaban Avatar answered Nov 15 '22 07:11

Shadi Shaaban


Some of the keys cannot be exported in RAW format. But so far it seems the JWK (json web key) format is supported everywhere, so you can use it.

// to store the key:
window.crypto.subtle.exportKey("jwk", key)
.then(e=>localStorage.setItem("webkey",JSON.stringify(e)));

Similarly you can importKey() back, this varies depending on your key algo. For syntax, see https://github.com/diafygi/webcrypto-examples/

like image 22
Tomas M Avatar answered Nov 15 '22 08:11

Tomas M