Fix #4: Add encryption details to homepage

This commit is contained in:
Loïc Gremaud 2024-10-05 16:10:44 +02:00
parent 0806207b89
commit a53be04acf
Signed by: Legrems
GPG Key ID: D4620E6DF3E0121D
4 changed files with 195 additions and 4 deletions

View File

@ -79,8 +79,12 @@ BOWER_INSTALLED_APPS = [
"https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js", "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://cdn.jsdelivr.net/npm/@mdi/font@7.4.47/css/materialdesignicons.min.css",
"https://fonts.cdnfonts.com/css/jetbrains-mono", "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 = [ MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware", "django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.sessions.middleware.SessionMiddleware",

View File

@ -34,6 +34,14 @@
} }
</style> </style>
<!-- highlight.js-->
<link rel="stylesheet" href="{% static "default.min/index.css" %}">
<script src="{% static "highlight.min/index.js" %}"></script>
<script type="text/javascript">
hljs.highlightAll()
</script>
</head> </head>
<body> <body>
<v-app class="font"> <v-app class="font">
@ -43,15 +51,192 @@
<v-container class="container-xs"> <v-container class="container-xs">
<v-row justify="center"> <v-row justify="center">
<v-dialog v-model="dialog" persistent max-width="290">
<div class="card mt-4 pt-2 ps-lg-2">
<h5 class="card-header">{% trans "K356 Project" %}</h5>
<div class="card-body">
<h2>{% trans "Encryption" %}</h2>
<p>{% 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." %}</p>
<div class="accordion" id="enca">
<div class="accordion-item">
<h2 class="accordion-header" id="eh1">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#e1" aria-controls="e1">
{% trans "Encryption" %}
</button>
</h2>
<div id="e1" class="accordion-collapse collapse" aria-labelledby="eh1" data-bs-parent="#enca">
<div class="accordion-body">
{% blocktrans %}
Your data are encrypted using <code>RSA-OAEP</code> algorithm.
{% endblocktrans %}
<pre><code class="language-js">
const operations = crypto.subtle
async encrypt (data) {
return btoa(arrayBufferToString(await operations.encrypt(
{ name: "RSA-OAEP" },
publicKey,
stringToArrayBuffer(data),
)))
}
</code></pre>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="eh2">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#e2" aria-controls="e2">
{% trans "Decryption" %}
</button>
</h2>
<div id="e2" class="accordion-collapse collapse" aria-labelledby="eh2" data-bs-parent="#enca">
<div class="accordion-body">
{% blocktrans %}
Your date are decrypted using the same algorithm, using your own private key.
{% endblocktrans %}
<pre><code class="language-js">
const operations = crypto.subtle
async decrypt (armored_data) {
return arrayBufferToString(await operations.decrypt(
{ name: "RSA-OAEP" },
privateKey,
stringToArrayBuffer(atob(armored_data))
))
}
</code></pre>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="eh3">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#e3" aria-controls="e3">
{% trans "Key wrapping" %}
</button>
</h2>
<div id="e3" class="accordion-collapse collapse" aria-labelledby="eh3" data-bs-parent="#enca">
<div class="accordion-body">
{% blocktrans %}
In order to keep your private/public key pair secret, they are wrapped using a <code>AES-GCM</code> key derived from you password.
{% endblocktrans %}
<pre><code class="language-js">
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,
)
}
</code></pre>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="eh4">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#e4" aria-controls="e3">
{% trans "Key derivation" %}
</button>
</h2>
<div id="e4" class="accordion-collapse collapse" aria-labelledby="eh4" data-bs-parent="#enca">
<div class="accordion-body">
{% blocktrans %}
Your public/private key are not stored as-is. They are wrapped using a <code>AES-GCM</code> key, derivated from your password.
A custom salt is used, <i>unique per user</i>, to generate your wrapping key.
{% endblocktrans %}
<pre><code class="language-js">
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"]
)
}
</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card mt-4 pt-2 ps-lg-2">
<h5 class="card-header">{% trans "Login / register" %}</h5>
<div class="card-body d-flex">
<button type="button" class="btn btn-secondary flex-grow-1 flex-shrink-1" @click="dialog = true">{% trans "Click here to login/register" %}</button>
</div>
</div>
</v-row>
<v-row justify="center">
<v-dialog v-model="dialog" max-width="290" class="modal">
<v-card> <v-card>
<v-card-title class="text-h5"> <v-card-title class="text-h5">
{% trans "Login" %} {% trans "Login / Register" %}
</v-card-title> </v-card-title>
<v-card-text> <v-card-text>
{% trans "Select login option" %} {% trans "Select option" %}
<v-list-item> <v-list-item>
<v-list-item-content> <v-list-item-content>

View File

@ -1,6 +1,8 @@
{% include "vue/plugins.js" %} {% include "vue/plugins.js" %}
{% if settings.DEBUG %}
Vue.config.devtools = true Vue.config.devtools = true
{% endif %}
Vue.use(VueRouter) Vue.use(VueRouter)
Vue.use(Vuex) Vue.use(Vuex)

View File

@ -12,6 +12,6 @@ const approuter = new Vue({
vuetify: new Vuetify(), vuetify: new Vuetify(),
el: "#main", el: "#main",
data: { data: {
dialog: true, dialog: false,
}, },
}) })