wip
This commit is contained in:
parent
bd4a475923
commit
9a164b984a
36 changed files with 2500 additions and 77 deletions
72
static/js/crypto.mjs
Normal file
72
static/js/crypto.mjs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue