simplify crypto

This commit is contained in:
cupcakearmy 2022-09-12 19:58:40 +02:00
parent 4fe5a52f2a
commit 972398fa66
No known key found for this signature in database
GPG Key ID: 3235314B4D31232F
4 changed files with 37 additions and 45 deletions

View File

@ -35,6 +35,31 @@ export class ArrayBufferUtils {
}
}
export class Keys {
public static async generateKey(size: 128 | 192 | 256 = 256): Promise<CryptoKey> {
const key = await window.crypto.subtle.generateKey(
{
name: 'AES-GCM',
length: size,
},
true,
['encrypt', 'decrypt']
)
return key
}
public static async export(key: CryptoKey): Promise<string> {
return Hex.encode(await window.crypto.subtle.exportKey('raw', key))
}
public static async import(key: string): Promise<CryptoKey> {
return window.crypto.subtle.importKey('raw', Hex.decode(key), { name: 'AES-GCM' }, true, [
'encrypt',
'decrypt',
])
}
}
export class Crypto {
private static ALG = 'AES-GCM'
private static DELIMITER = ':::'
@ -43,55 +68,22 @@ export class Crypto {
return window.crypto.getRandomValues(new Uint8Array(size))
}
public static getKeyFromString(password: string) {
return window.crypto.subtle.importKey(
'raw',
new TextEncoder().encode(password),
'PBKDF2',
false,
['deriveBits', 'deriveKey']
)
}
public static async getDerivedForKey(key: CryptoKey, salt: ArrayBuffer) {
const iterations = 100_000
return window.crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt,
iterations,
hash: 'SHA-512',
},
key,
{ name: this.ALG, length: 256 },
true,
['encrypt', 'decrypt']
)
}
public static async encrypt(plaintext: ArrayBuffer, key: CryptoKey): Promise<string> {
const salt = this.getRandomBytes(16)
const derived = await this.getDerivedForKey(key, salt)
const iv = this.getRandomBytes(16)
const iv = this.getRandomBytes(12) // AES-GCM needs a 96bit IV
const encrypted: ArrayBuffer = await window.crypto.subtle.encrypt(
{ name: this.ALG, iv },
derived,
key,
plaintext
)
const data = [
Hex.encode(salt),
Hex.encode(iv),
await ArrayBufferUtils.toString(encrypted),
].join(this.DELIMITER)
const data = [Hex.encode(iv), await ArrayBufferUtils.toString(encrypted)].join(this.DELIMITER)
return data
}
public static async decrypt(ciphertext: string, key: CryptoKey): Promise<ArrayBuffer> {
const splitted = ciphertext.split(this.DELIMITER)
const salt = Hex.decode(splitted[0])
const iv = Hex.decode(splitted[1])
const encrypted = await ArrayBufferUtils.fromString(splitted[2])
const derived = await this.getDerivedForKey(key, salt)
const plaintext = await window.crypto.subtle.decrypt({ name: this.ALG, iv }, derived, encrypted)
const iv = Hex.decode(splitted[0])
const encrypted = await ArrayBufferUtils.fromString(splitted[1])
const plaintext = await window.crypto.subtle.decrypt({ name: this.ALG, iv }, key, encrypted)
return plaintext
}
}

View File

@ -24,7 +24,7 @@
hidden = !hidden
}
function randomFN() {
value = Hex.encode(Crypto.getRandomBytes(20))
value = Hex.encode(Crypto.getRandomBytes(32))
}
</script>

View File

@ -5,7 +5,7 @@
import { Adapters } from '$lib/adapters'
import type { FileDTO, Note } from '$lib/api'
import { create, PayloadToLargeError } from '$lib/api'
import { Crypto, Hex } from '$lib/crypto'
import { Keys } from '$lib/crypto'
import { status } from '$lib/stores/status'
import { notify } from '$lib/toast'
import AdvancedParameters from '$lib/ui/AdvancedParameters.svelte'
@ -58,8 +58,8 @@
try {
loading = $t('common.encrypting')
const password = Hex.encode(Crypto.getRandomBytes(32))
const key = await Crypto.getKeyFromString(password)
const key = await Keys.generateKey()
const password = await Keys.export(key)
const data: Note = {
contents: '',

View File

@ -4,7 +4,7 @@
import { Adapters } from '$lib/adapters'
import { get, info } from '$lib/api'
import { Crypto } from '$lib/crypto'
import { Keys } from '$lib/crypto'
import Button from '$lib/ui/Button.svelte'
import Loader from '$lib/ui/Loader.svelte'
import ShowNote, { type DecryptedNote } from '$lib/ui/ShowNote.svelte'
@ -43,7 +43,7 @@
loading = $t('common.downloading')
const data = await get(id)
loading = $t('common.decrypting')
const key = await Crypto.getKeyFromString(password)
const key = await Keys.import(password)
switch (data.meta.type) {
case 'text':
note = {