yarle-evernote-to-md
Version:
Yet Another Rope Ladder from Evernote
76 lines (65 loc) • 2.73 kB
text/typescript
var CryptoJS = require("crypto-js");
import * as crypto from 'crypto';
import * as base64 from 'base64-js';
// PBKDF2 implementation (modified for SHA256 support)
function pbkdf2(password: string, salt: Uint8Array, iterations: number, keyLength: number): Buffer {
return crypto.pbkdf2Sync(password, salt, iterations, keyLength, 'sha256');
}
// HMAC implementation
function hmacSHA256(key: Buffer, data: Uint8Array): Buffer {
const hmac = crypto.createHmac('sha256', key);
hmac.update(data);
return hmac.digest();
}
// AES decryption
function decryptAES(ciphertext: Uint8Array, key: Buffer, iv: Uint8Array): Buffer {
const decipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
let decrypted = decipher.update(ciphertext);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted;
}
interface EncryptedData {
salt: Uint8Array,
saltHmac: Uint8Array,
iv: Uint8Array,
cipherText: Uint8Array,
body: Uint8Array,
bodyHmac: Uint8Array
}
const extractDataFromEncryptedByteArray = (data: Uint8Array):EncryptedData => {
const START_INDEX = 4;
const TWO_BYTES = 16;
const START_SALTHMAC = START_INDEX + TWO_BYTES;
const START_IV = START_SALTHMAC + TWO_BYTES;
const START_CIPHERTEXT = START_IV + TWO_BYTES;
const FOUR_END_BYTES = -32
return {
salt: data.subarray(START_INDEX, START_SALTHMAC),
saltHmac: data.subarray(START_SALTHMAC, START_IV),
iv: data.subarray(START_IV, START_CIPHERTEXT),
cipherText: data.subarray(START_CIPHERTEXT, FOUR_END_BYTES),
body: data.subarray(0, FOUR_END_BYTES),
bodyHmac: data.subarray(FOUR_END_BYTES)
}
}
export const performDecryption = (encryptedText: string, passwords: Array<string>): string => {
try{
const encryptedDataByteArr = base64.toByteArray(encryptedText);
const encryptedData = extractDataFromEncryptedByteArray(encryptedDataByteArr);
// Use the password to generate a digest for the encrypted body
// If it matches the existing digest, assume the password is correct
for (const password of passwords){
const keyhmac = pbkdf2(password, encryptedData.saltHmac, 50000, 16);
const testhmac = hmacSHA256(keyhmac, encryptedData.body);
const matchHmac = crypto.timingSafeEqual(testhmac, encryptedData.bodyHmac);
if (matchHmac) {
const key = pbkdf2(password, encryptedData.salt, 50000, 16);
const decrypted = decryptAES(encryptedData.cipherText, key, encryptedData.iv);
return decrypted.toString()
}
}
}catch(e: any){
console.log(e.message)
}
return encryptedText;
}