In this tutorial I will show you how create a symmetric key using a passphrase and then encrypt or decrypt data using that generated key.
Converting String to Array Buffer and Array Buffer to String
To encrypt text or binary data you first need to convert it to an array buffer type so that Web Cryptography API can encrypt it.
Here is code to convert a string to an array buffer
{
var bytes = new Uint8Array(str.length);
for (var iii = 0; iii < str.length; iii++)
{
bytes[iii] = str.charCodeAt(iii);
}
return bytes;
}
After decrypting, Web Cryptography API returns original string as an array buffer. So we need to convert the array buffer to an string.
{
var str = "";
for (var iii = 0; iii < buffer.byteLength; iii++)
{
str += String.fromCharCode(buffer[iii]);
}
return str;
}
Generating Symmetric Public Key from Passphrase
Here is the code to generate key for encryption and decryption using a passphrase
var key = null;
crypto.subtle.digest({name: "SHA-256"}, convertStringToArrayBufferView(password)).then(function(result){
window.crypto.subtle.importKey("raw", result, {name: "AES-CBC"}, false, ["encrypt", "decrypt"]).then(function(e){
key = e;
}, function(e){
console.log(e);
});
});
Here I am first generating 256 bit hash of the passphrase because AES-CBC algorithm’s key size has to be 128 bit, 192 bit or 256 bit. This hash value is the symmetric encryption key now.
Then I am using importKey
to create a key object from the hash value. importKey
is actually meant to be used to import a key which was exported using exportKey
. Here I am pretending the hash value was exported using exportKey
Encrypting String
Here is the code to encrypt an JavaScript string using the retrieved key
var data = "narayan prusty";
var encrypted_data = null;
function encrypt_data()
{
crypto.subtle.encrypt({name: "AES-CBC", iv: vector}, key, convertStringToArrayBufferView(data)).then(
function(result){
encrypted_data = new Uint8Array(result);
},
function(e){
console.log(e.message);
}
);
}
Decrypting String
Here is the code to decrypt an encrypt array buffer using the same key which was used for encryption
function decrypt_data()
{
crypto.subtle.decrypt({name: "AES-CBC", iv: vector}, key, encrypted_data).then(
function(result){
decrypted_data = new Uint8Array(result);
console.log(convertArrayBufferViewtoString(decrypted_data));
},
function(e){
console.log(e.message);
}
);
}
Complete Code
Here is complete code together for testing or to play with
{
var bytes = new Uint8Array(str.length);
for (var iii = 0; iii < str.length; iii++)
{
bytes[iii] = str.charCodeAt(iii);
}
return bytes;
}
function convertArrayBufferViewtoString(buffer)
{
var str = "";
for (var iii = 0; iii < buffer.byteLength; iii++)
{
str += String.fromCharCode(buffer[iii]);
}
return str;
}
var password = "password";
var key = null;
crypto.subtle.digest({name: "SHA-256"}, convertStringToArrayBufferView(password)).then(function(result){
window.crypto.subtle.importKey("raw", result, {name: "AES-CBC"}, false, ["encrypt", "decrypt"]).then(function(e){
key = e;
encrypt_data();
}, function(e){
console.log(e);
});
});
var vector = crypto.getRandomValues(new Uint8Array(16));
var data = "narayan prusty";
var encrypted_data = null;
function encrypt_data()
{
crypto.subtle.encrypt({name: "AES-CBC", iv: vector}, key, convertStringToArrayBufferView(data)).then(
function(result){
encrypted_data = new Uint8Array(result);
decrypt_data();
},
function(e){
console.log(e.message);
}
);
}
var decrypted_data = null;
function decrypt_data()
{
crypto.subtle.decrypt({name: "AES-CBC", iv: vector}, key, encrypted_data).then(
function(result){
decrypted_data = new Uint8Array(result);
console.log(convertArrayBufferViewtoString(decrypted_data));
},
function(e){
console.log(e.message);
}
);
}