Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions docs/1_pure_tricks/HowTo_decrypt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# HowTo: Decrypt data

Decryption is an operation, the reverse of the encryption operation. To encrypt with a secret key, you need to know both password and initialization vector used to encrypt the data.

Since iv is placed in an encrypted data string, the `decryptData()` function accepts the password and the string.
First, it is necessary to split encrypted string to separate the `iv` and the encrypted data. Then convert `iv` to _UTF-8_ and encrypted string to Base64 format. Since the data encrypted with `btoa()`, `atob()` is used to decrypt the data, which returns the original string.
```javascript

async function decryptData(data, password) {
const [ivText, cipherB64url] = data.split('.'); //split encrypted data to get iv and cipher
const iv = hexStringToUint8(ivText);
const cipher = atob(fromBase64url(cipherB64url));
return await decryptAESGCM(password, iv, cipher);

function fromBase64url(base64urlStr) {
base64urlStr = base64urlStr.replace(/-/g, '+').replace(/_/g, '/');
if (base64urlStr.length % 4 === 2)
return base64urlStr + '==';
if (base64urlStr.length % 4 === 3)
return base64urlStr + '=';
return base64urlStr;
}

}
```
The next step is `decryptAESGCM()` which does the opposite of the `encryptAESGCM()` function described in [HowTo: encrypt](HowTo_encrypt.md).

```javascript
async function passHash(pw) {
return cachedPassHash || (cachedPassHash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(pw)));
}

function hexStringToUint8(str) {
return new Uint8Array(str.match(/.{2}/g).map(byte => parseInt(byte, 16)));
}

async function makeKeyAESGCM(password, iv) {
const pwHash = await passHash(password); //small value generated by a hash function from a whole message
const alg = { name: 'AES-GCM', iv: iv }; // specify algorithm to use
return await crypto.subtle.importKey('raw', pwHash, alg, false, ['decrypt', 'encrypt']); //make crypto key
}

async function decryptAESGCM(password, iv, ctStr) {
const key = await makeKeyAESGCM(password, iv); //make crypto key
const ctUint8 = new Uint8Array(ctStr.match(/[\s\S]/g).map(ch => ch.charCodeAt(0))); // ciphertext as Uint8Array
const plainBuffer = await crypto.subtle.decrypt({ name: key.algorithm.name, iv: iv }, key, ctUint8); // decrypt ciphertext using key
return new TextDecoder().decode(plainBuffer); // return the plaintext
}
```

# Reference

* [MDN: atob()](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/atob)