From a53be04acf69cec7791053599994a7374c835f3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Gremaud?= Date: Sat, 5 Oct 2024 16:10:44 +0200 Subject: [PATCH] Fix #4: Add encryption details to homepage --- k356/app/settings.py | 4 + k356/templates/login.html | 191 +++++++++++++++++++++++++++++++++++- k356/templates/vue/index.js | 2 + k356/templates/vue/login.js | 2 +- 4 files changed, 195 insertions(+), 4 deletions(-) diff --git a/k356/app/settings.py b/k356/app/settings.py index d6fc5e9..c3c2562 100644 --- a/k356/app/settings.py +++ b/k356/app/settings.py @@ -79,8 +79,12 @@ BOWER_INSTALLED_APPS = [ "https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js", "https://cdn.jsdelivr.net/npm/@mdi/font@7.4.47/css/materialdesignicons.min.css", "https://fonts.cdnfonts.com/css/jetbrains-mono", + "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css", + "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js", + # "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/python.min.js", ] + MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", diff --git a/k356/templates/login.html b/k356/templates/login.html index 4ffb73d..5da44b1 100644 --- a/k356/templates/login.html +++ b/k356/templates/login.html @@ -34,6 +34,14 @@ } + + + + + + @@ -43,15 +51,192 @@ - + +
+
{% trans "K356 Project" %}
+
+

{% trans "Encryption" %}

+

{% trans "Your data are secure in an encrypted way, accessible solely by you. The data are purely encrypted and decrypted in the front-end. The back-end has no access to the encryption key, so there is no way for an intruder to decrypt your data." %}

+ +
+ +
+

+ +

+
+
+ {% blocktrans %} + Your data are encrypted using RSA-OAEP algorithm. + {% endblocktrans %} + +

+const operations = crypto.subtle
+
+async encrypt (data) {
+
+    return btoa(arrayBufferToString(await operations.encrypt(
+        { name: "RSA-OAEP" },
+        publicKey,
+        stringToArrayBuffer(data),
+    )))
+
+}
+                                                    
+ +
+
+
+ +
+

+ +

+
+
+ {% blocktrans %} + Your date are decrypted using the same algorithm, using your own private key. + {% endblocktrans %} + +

+const operations = crypto.subtle
+
+async decrypt (armored_data) {
+
+    return arrayBufferToString(await operations.decrypt(
+        { name: "RSA-OAEP" },
+        privateKey,
+        stringToArrayBuffer(atob(armored_data))
+    ))
+
+}
+                                                    
+
+
+
+ +
+

+ +

+
+
+ {% blocktrans %} + In order to keep your private/public key pair secret, they are wrapped using a AES-GCM key derived from you password. + {% endblocktrans %} + +

+const operations = crypto.subtle
+
+async wrapKey (key, wrappingKey, iv) => {
+
+    return btoa(arrayBufferToString(await operations.wrapKey(
+        "jwk",
+        key,
+        wrappingKey, 
+        {name: "AES-GCM", iv: stringToArrayBuffer(iv)}
+    )))
+
+}
+
+async unwrapKey (unwrappingKey, armored_jwk_data, iv, args) => {
+
+    return await operations.unwrapKey(
+        "jwk",
+        stringToArrayBuffer(atob(armored_jwk_data)),
+        unwrappingKey,
+        {name: "AES-GCM", iv: stringToArrayBuffer(iv)},
+        {
+            name: "RSA-OAEP",
+            hash: "SHA-256",
+        },
+        true,
+        args,
+    )
+}
+                                                    
+
+
+
+ +
+

+ +

+
+
+ {% blocktrans %} + Your public/private key are not stored as-is. They are wrapped using a AES-GCM key, derivated from your password. + A custom salt is used, unique per user, to generate your wrapping key. + {% endblocktrans %} + +

+
+const operations = crypto.subtle
+
+async deriveKeyFromPassphrase(passphrase, salt) => {
+
+    const encoder = new TextEncoder();
+    const keyFromPassword = await operations.importKey(
+        "raw",
+        encoder.encode(passphrase),
+        "PBKDF2",
+        false,
+        ["deriveKey"]
+    )
+
+    return await operations.deriveKey(
+        {
+            name: "PBKDF2",
+            salt: stringToArrayBuffer(salt),
+            iterations: pbkdf2_iterations,
+            hash: "SHA-256",
+        },
+        keyFromPassword,                       
+        {
+            name: "AES-GCM",
+            length: 256
+        },
+        true,
+        ["wrapKey", "unwrapKey"]
+    )
+}
+                                                    
+
+
+
+ +
+
+
+ +
+
{% trans "Login / register" %}
+
+ +
+
+ +
+ + + - {% trans "Login" %} + {% trans "Login / Register" %} - {% trans "Select login option" %} + {% trans "Select option" %} diff --git a/k356/templates/vue/index.js b/k356/templates/vue/index.js index 5e65dec..1d979b5 100644 --- a/k356/templates/vue/index.js +++ b/k356/templates/vue/index.js @@ -1,6 +1,8 @@ {% include "vue/plugins.js" %} +{% if settings.DEBUG %} Vue.config.devtools = true +{% endif %} Vue.use(VueRouter) Vue.use(Vuex) diff --git a/k356/templates/vue/login.js b/k356/templates/vue/login.js index fd19b33..301eafb 100644 --- a/k356/templates/vue/login.js +++ b/k356/templates/vue/login.js @@ -12,6 +12,6 @@ const approuter = new Vue({ vuetify: new Vuetify(), el: "#main", data: { - dialog: true, + dialog: false, }, })