mostly works now, except for decrypting the file, but not getting any helpful error messages from SubtleCrypto to fix this

main
Johannes Bülow 2023-01-04 18:08:58 +01:00
parent 917797c9be
commit dfcacf7bbf
5 changed files with 78 additions and 56 deletions

View File

@ -2,10 +2,18 @@
import EncryptButton from './lib/EncryptButton.svelte'
import PasswordButton from './lib/PasswordButton.svelte';
import DecryptButton from './lib/DecryptButton.svelte';
import { errorMessage } from './lib/generalStore';
let errorMessageContent
errorMessage.subscribe( value => {
errorMessageContent = value;
});
</script>
<main>
<h1>Encrypt and decrypt files</h1>
{errorMessageContent}
<div class="container">
<EncryptButton />

View File

@ -1,7 +1,7 @@
<script lang="ts">
import { onMount } from 'svelte';
import { escape } from 'svelte/internal';
import { decrypt, encrypt } from './cryptlib';
import { decryptFileContent } from './cryptlib';
let filename: string = "";
let originalFilename: string;
@ -44,23 +44,18 @@
return;
}
readFileContent(file).then((fileContent) => {
decrypt(atob(fileContent)).then(decryptedContent => {
console.log("Decrypted Base64: ", decryptedContent)
console.log(decodeURIComponent(decryptedContent));
const decodedData = decodeURIComponent(escape(atob((decryptedContent))));
const outputArray = new Uint8Array(decodedData.length)
for (let i = 0; i < decodedData.length; i++) {
outputArray[i] = decodedData.charCodeAt(i); // Populate the array with the decoded data
}
const outputFile = new Blob([outputArray], { type: 'application/octet-stream'});
let url = URL.createObjectURL(outputFile);
let a = document.createElement("a");
a.href = url;
a.download = originalFilename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
let outputFile: Blob;
decryptFileContent(fileContent).then((outputArray) => {
console.log(outputArray)
outputFile = new Blob([outputArray], { type: 'application/octet-stream'});
});
let url = URL.createObjectURL(outputFile);
let a = document.createElement("a");
a.href = url;
a.download = originalFilename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
});
}

View File

@ -1,7 +1,7 @@
<script lang="ts">
import { onMount } from 'svelte';
import { encrypt } from './cryptlib';
let filename: string;
import { encryptFile } from './cryptlib';
let filename: string = "";
function convertToBase64(blob: File): Promise<string> {
return new Promise((resolve, reject) => {
@ -17,7 +17,16 @@
});
}
function downloadAsFile(string) {
let encrypted_file: Blob = new Blob([string], {type: "text/plain"});
let url = URL.createObjectURL(encrypted_file);
let a = document.createElement("a");
a.href = url;
a.download = filename + ".crypt";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
let file: File | undefined;
@ -34,22 +43,12 @@
}
filename = file.name;
console.log("Uploaded ", filename)
convertToBase64(file).then((base64) => {
encrypt(base64).then((encrypted_content => {
console.log(encrypted_content)
let encrypted_b64: string = btoa(unescape(encodeURIComponent(encrypted_content)));
let encrypted_file: Blob = new Blob([encrypted_b64], {type: "text/plain"});
let url = URL.createObjectURL(encrypted_file);
let a = document.createElement("a");
a.href = url;
a.download = filename + ".crypt";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}));
encryptFile(file).then(base64String => {
downloadAsFile(base64String)
})
}
</script>
<style>
.upload-button {

View File

@ -1,9 +1,10 @@
//import crypto from 'crypto'
import { globalPassword } from './pwgen';
import { errorMessage } from './generalStore';
let password: string;
let salt;
let ciphertext;
let iv;
let salt: Uint8Array;
let ciphertext: BufferSource;
let iv: Uint8Array;
globalPassword.subscribe(value => {
password = value;
})
@ -33,12 +34,14 @@ function getKeyMaterial() {
/*
Given some key material and some random salt
derive an AES-GCM key using PBKDF2.
Using the Password itself as salt isn't really a great idea, but this is not a hyper secure implementation yet
*/
function getKey(keyMaterial, salt) {
function getKey(keyMaterial: CryptoKey) {
let enc = new TextEncoder();
return window.crypto.subtle.deriveKey(
{
"name": "PBKDF2",
salt: salt,
salt: enc.encode(password),
"iterations": 100000,
"hash": "SHA-256"
},
@ -55,13 +58,12 @@ to encrypt the message.
Update the "ciphertextValue" box with a representation of part of
the ciphertext.
*/
export async function encrypt(string: string) {
let dec = new TextDecoder();
export async function encryptFile(file: File) {
let keyMaterial = await getKeyMaterial();
salt = window.crypto.getRandomValues(new Uint8Array(16));
let key = await getKey(keyMaterial, salt);
let key = await getKey(keyMaterial);
iv = window.crypto.getRandomValues(new Uint8Array(12));
let encoded = getStringEncoding(string);
const fileReader = new FileReader();
let byteArray = await file.arrayBuffer();
ciphertext = await window.crypto.subtle.encrypt(
{
@ -69,11 +71,10 @@ export async function encrypt(string: string) {
iv: iv
},
key,
encoded
byteArray
);
let decodedCiphertext = dec.decode(ciphertext);
return decodedCiphertext
const base64Encoded = btoa(String.fromCharCode(... new Uint8Array(ciphertext)));
return base64Encoded
}
/*
@ -84,25 +85,39 @@ update the "decryptedValue" box with the decrypted value.
If there was an error decrypting,
update the "decryptedValue" box with an error message.
*/
export async function decrypt(encryptedContent) {
export async function decryptFileContent(base64Encoded: string) {
//prepare cryptography
let keyMaterial = await getKeyMaterial();
let key = await getKey(keyMaterial, salt);
console.log(keyMaterial)
let key = await getKey(keyMaterial);
//Remove anything form the Base64 String that isn't base64
const cleanString = base64Encoded.replace(/[^A-Za-z0-9+/=]/g, '');
// create Uint8 Array from base64 string
let encryptedString = atob(cleanString)
console.log(encryptedString)
const encryptedContent = new Uint8Array(encryptedString.length)
for (let i = 0; i < encryptedString.length; i++) {
encryptedContent[i] = encryptedString.charCodeAt(i); // Populate the array with the decoded data
}
console.log(encryptedContent)
const encryptedContentBuffer: ArrayBuffer = encryptedContent.buffer;
try {
let decrypted = await window.crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv
iv: iv
},
key,
encryptedContent
encryptedContentBuffer
);
let dec = new TextDecoder();
return dec.decode(decrypted);
return decrypted;
} catch (e) {
console.log(e)
return `Decryption error: ${e}`
errorMessage.set(`Can not decrypt file: ${e}`)
}
}
// Hacked together version of https://github.com/mdn/dom-examples/blob/main/web-crypto/derive-key/pbkdf2.jshttps://gist.github.com/ChaoLiangSuper/0e13f77712b68682f0d8ebabb2d63aa8

View File

@ -1,3 +1,8 @@
import { writable} from 'svelte/store';
export let filename = writable("Encrypted.b64");
export let filename = writable("Encrypted.b64");
export let encryptSource = writable<File>();
export let encryptTarget = writable();
export let decryptSource = writable();
export let decryptDestination = writable<File>();
export let errorMessage = writable<string>("");