mostly works now, except for decrypting the file, but not getting any helpful error messages from SubtleCrypto to fix this
parent
917797c9be
commit
dfcacf7bbf
|
@ -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 />
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
|
@ -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>("");
|
Loading…
Reference in New Issue