Chiffrer côté client avec Web Crypto

Voir la vidéo

Dans ce tutoriel je vous propose de découvrir l'API Web Crypto qui vous permet l'accès aux fonctionnalité cryptographiques côté client.

Génération de la clef

La première étape pour chiffrer et déchiffrer les fichiers est de générer une clef. On n'utilisera pas directement la clef envoyé par l'utilisateur mais on va dériver une clef. Cela permet d'éviter de révéler le mot de passe de l'utilisateur si le système venait à être cassé.

const encoder = new TextEncoder();
const algo = {
  name: "AES-GCM",
  length: 256,
};
async function getEncryptionKey(value, salt) {
  const masterPassword = await crypto.subtle.importKey(
    "raw",
    encoder.encode(value),
    { name: "PBKDF2" },
    false,
    ["deriveKey"]
  );
  return await crypto.subtle.deriveKey(
    {
      name: "PBKDF2",
      salt: encoder.encode(salt),
      iterations: 1000,
      hash: { name: "SHA-1" },
    },
    masterPassword,
    algo,
    false,
    ["encrypt", "decrypt"]
  );
}

Chiffrer le fichier

Une fois la clef obtenue on peut l'utiliser pour chiffrer le fichier.

const file = inputFile.files[0];
if (!file) {
  alert("Vous devez sélectionner un fichier");
  return;
}
const encryptedFile = await crypto.subtle.encrypt(
  { ...algo, iv: encoder.encode(file.name) },
  ENCRYPTION_KEY,
  await file.arrayBuffer()
);
const formData = new FormData();
formData.append("file", new Blob([encryptedFile]), file.name);
await fetch("/upload.php", {
  method: "post",
  body: formData,
});
form.reset();

Déchiffrer le fichier

Lors du clic sur un lien on récupère le fichier depuis le serveur et on le decode à la volée pour le faire télécharger à l'utilisateur.

/**
 * @param {ArrayBuffer} file
 * @param {string} filename
 */
function downloadFile (file, filename) {
  const a = document.createElement('a')
  a.href = window.URL.createObjectURL(new Blob([file]))
  a.download = filename
  a.click()
}

document.querySelectorAll(".list-group a").forEach((a) => {
  a.addEventListener("click", async (e) => {
    e.preventDefault();
    const href = a.getAttribute("href");
    const hrefParts = href.split("/");
    const filename = hrefParts[hrefParts.length - 1];
    const response = await fetch(href);
    const fileData = await response.arrayBuffer();
    const file = await crypto.subtle.decrypt(
      { ...algo, iv: encoder.encode(filename) },
      await getEncryptionKey(),
      fileData
    );
    downloadFile(file, filename);
  });
});
Publié
Technologies utilisées
Auteur :
Grafikart
Partager