73 lines
1.9 KiB
JavaScript
73 lines
1.9 KiB
JavaScript
export default class Crypto {
|
|
constructor(key) {//{{{
|
|
if(key === null)
|
|
throw new Error("No key provided")
|
|
|
|
if(typeof key === 'string')
|
|
this.key = sjcl.codec.base64.toBits(base64_key)
|
|
else
|
|
this.key = key
|
|
|
|
this.aes = new sjcl.cipher.aes(this.key)
|
|
}//}}}
|
|
|
|
static generate_key() {//{{{
|
|
return sjcl.random.randomWords(8)
|
|
}//}}}
|
|
static pass_to_key(pass, salt = null) {//{{{
|
|
if(salt === null)
|
|
salt = sjcl.random.randomWords(4) // 128 bits (16 bytes)
|
|
let key = sjcl.misc.pbkdf2(pass, salt, 10000)
|
|
|
|
return {
|
|
salt,
|
|
key,
|
|
}
|
|
}//}}}
|
|
|
|
encrypt(plaintext_data_in_bits, counter, return_encoded = true) {//{{{
|
|
// 8 bytes of random data, (1 word = 4 bytes) * 2
|
|
// with 8 bytes of byte encoded counter is used as
|
|
// IV to guarantee a non-repeated IV (which is a catastrophe).
|
|
// Assumes counter value is kept unique. Counter is taken from
|
|
// Postgres sequence.
|
|
let random_bits = sjcl.random.randomWords(2)
|
|
let iv_bytes = sjcl.codec.bytes.fromBits(random_bits)
|
|
for (let i = 0; i < 8; ++i) {
|
|
let mask = 0xffn << BigInt(i*8)
|
|
let counter_i_byte = (counter & mask) >> BigInt(i*8)
|
|
iv_bytes[15-i] = Number(counter_i_byte)
|
|
}
|
|
let iv = sjcl.codec.bytes.toBits(iv_bytes)
|
|
|
|
let encrypted = sjcl.mode['ccm'].encrypt(
|
|
this.aes,
|
|
plaintext_data_in_bits,
|
|
iv,
|
|
)
|
|
|
|
// Returning 16 bytes (4 words) IV + encrypted data.
|
|
if(return_encoded)
|
|
return sjcl.codec.base64.fromBits(
|
|
iv.concat(encrypted)
|
|
)
|
|
else
|
|
return iv.concat(encrypted)
|
|
}//}}}
|
|
decrypt(encrypted_base64_data) {//{{{
|
|
try {
|
|
let encoded = sjcl.codec.base64.toBits(encrypted_base64_data)
|
|
let iv = encoded.slice(0, 4) // in words (4 bytes), not bytes
|
|
let encrypted_data = encoded.slice(4)
|
|
return sjcl.mode['ccm'].decrypt(this.aes, encrypted_data, iv)
|
|
} catch(err) {
|
|
if(err.message == `ccm: tag doesn't match`)
|
|
throw('Decryption failed')
|
|
else
|
|
throw(err)
|
|
}
|
|
}//}}}
|
|
}
|
|
|
|
// vim: foldmethod=marker
|