Il cifrario di Cesare è uno dei più antichi e semplici algoritmi crittografici di cifratura a sostituzione, prende nome da Giulio Cesare che si diceva lo utilizzasse per le sue comunicazioni segrete.
Il meccanismo del cifrario di Cesare è molto semplice ogni lettera del testo da cifrare viene sostituita da una lettera che si trova un numero fisso di posizioni più avanti nell'alfabeto.
Per decifrare il testo cifrato, si applica lo stesso principio ma al contrario: ogni lettera cifrata viene spostata indietro di un numero corrispondente alla chiave di cifratura (numero di caratteri spostati).

cifrario di Cesare - Wikipedia

Si può intuire che è davvero semplicissimo capire cosa c'è scritto anche se "cifrato", l'unica sarebbe attribuire altre lettere all'alfabeto ordinario in modo casuale, perché non farlo con Javascript?

Iniziamo a scrivere il codice!
Iniziamo ad inizializzare le variabili, normalAlphabet contiene l'alfabeto ordinario in minuscolo. shuffledAlphabet invece viene pescato dall'archiviazione locale (localStorage) se è stato memorizzato in precedenza altrimenti viene generato un nuovo alfabeto casuale e successivamente memorizzato.
localStorage viene usato per memorizzare nei cookie l'alfabeto in modo da mantenere l'ordine nell'alfabeto casuale anche se si aggiorna la pagina o si rientra dopo un po' di tempo.
In seguito dobbiamo rendere casuale la generazione dell'alfabeto cifrario, in questo caso con randomizeAlphabet() usando l'algoritmo di sort con una funzione di confronto casuale.
Definiamo encrypt() che viene richiamata quando l'utente fa clic su "Cifra", prende il testo inserito dall'utente (plaintext), lo trasforma in minuscolo e lo cifra carattere per carattere.
Poi ogni carattere viene cercato nell'alfabeto normale e viene sostituito con il corrispondente carattere nell'alfabeto casuale (se il carattere non è presente viene riscritto).
Definiamo decrypt() che viene richiamata quando l'utente fa clic su "Decifra", prende il testo cifrato inserito dall'utente (ciphertext), lo trasforma in minuscolo e lo decifra carattere per carattere.
Il comportamento di decrypt() per il resto è molto simile a encrypt().
Infine abbiamo showMapping() restituisce una mappatura generale dell'alfabeto normale rispetto all'alfabeto casuale, viene mostrata nell'area di testo dedicata (mapping).

Link Cifrario di Cesare

Codice:

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Cifrario di Cesare</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <h1>Cifrario di Cesare con lettere casuali</h1>
  <label for="text">Testo:</label><br>
  <textarea id="text" placeholder="Inserisci qui il testo"></textarea><br>
  <button onclick="encrypt()">Cifra</button>
  <button onclick="decrypt()">Decifra</button><br>
  <label for="result">Risultato:</label><br>
  <textarea id="result" readonly></textarea><br>
  <label for="mapping">Mappatura Alfabeto:</label><br>
  <textarea id="mapping" readonly></textarea>

  <script src="script.js"></script>
</body>
</html>

CSS:

body {
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  background-color: #f8f9fa;
  color: #333;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.container {
  max-width: 400px;
  margin: 50px auto;
  padding: 20px;
  background-color: #fff;
  border-radius: 8px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

h1 {
  font-size: 28px;
  margin-bottom: 20px;
  text-align: center;
}

label {
  display: block;
  font-size: 18px;
  margin-bottom: 5px;
}

textarea,
button {
  width: 80%;
  padding: 10px;
  font-size: 16px;
  margin-bottom: 20px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

textarea {
  height: 60px;
}

button {
  background-color: #ff7300;
  color: #fff;
  border: none;
  cursor: pointer;
}

button:hover {
  background-color: #ff0000;
}

textarea[readonly] {
  background-color: #f8f9fa;
  cursor: not-allowed;
}

Javascript:

let normalAlphabet = 'abcdefghijklmnopqrstuvwxyz';
let shuffledAlphabet = localStorage.getItem('shuffledAlphabet');

if (!shuffledAlphabet) {
  shuffledAlphabet = randomizeAlphabet();
  localStorage.setItem('shuffledAlphabet', shuffledAlphabet);
}

function randomizeAlphabet() {
  let alphabet = 'abcdefghijklmnopqrstuvwxyz';
  let shuffledAlphabet = alphabet.split('').sort(() => Math.random() - 0.5).join('');
  return shuffledAlphabet;
}

function encrypt() {
  let plaintext = document.getElementById('text').value.toLowerCase();
  let ciphertext = '';

  for (let i = 0; i < plaintext.length; i++) {
    let char = plaintext[i];
    let index = normalAlphabet.indexOf(char);
    if (index !== -1) {
      ciphertext += shuffledAlphabet[index];
    } else {
      ciphertext += char;
    }
  }

  document.getElementById('result').value = ciphertext;
}

function decrypt() {
  let ciphertext = document.getElementById('text').value.toLowerCase();
  let decryptedtext = '';

  for (let i = 0; i < ciphertext.length; i++) {
    let char = ciphertext[i];
    let index = shuffledAlphabet.indexOf(char);
    if (index !== -1) {
      decryptedtext += normalAlphabet[index];
    } else {
      decryptedtext += char;
    }
  }

  document.getElementById('result').value = decryptedtext;
}

// mappatura dell'alfabeto
function showMapping() {
  let mapping = '';
  for (let i = 0; i < normalAlphabet.length; i++) {
    mapping += `${normalAlphabet[i]} -> ${shuffledAlphabet[i]}\n`;
  }
  document.getElementById('mapping').value = mapping;
}

showMapping();

    Samueleex idea carina, come già detto questo è stato uno dei primi algoritmi di cifratura di cui si hanno notizie certe, quindi una soluzione di tutto rispetto per l'epoca, I secolo a.C. D'altra parte, si chiamava Giulio anche lui! 😀
    Diciamo questo, rispetto ad una traslazione rigida (+1 ovvero a->b oppure +2 ovvero a->c, e così via) è ovviamente più sicuro e funzionale un algoritmo più complesso e quindi difficile da decifrare; che sia di tipo random come in questo caso, oppure con sistemi più complessi ovvero una f(x) che non faccia semplicemente una traslazione rigida x+k (ovvero aggiungere +1, +2, +3 ad ogni lettera) ma che abbia magari una funzione dipendente dalla posizione, quadratica o altro che sia (un esempio sempre abbastanza semplice, x2+1 con la lettera numero 5 ovvero la "e", abbiamo 52+1 che è la 26° lettera dell'alfabeto, z; ovviamente per numeri che eccedono, poi il ciclo riparte dal primo elemento).
    Più è complessa la cifratura e più diventa praticamente impossibile per chi non ha la chiave, decifrare.
    Vedi anche discussione dedicata alla crittografia.

      Giulio_M Concordo e direi di iniziare con il cifrario polialfabetico!

      Cifrario polialfabetico

      Il cifrario polialfabetico è una tecnica di crittografia che sfrutta più alfabeti per cifrare il testo, sicuramente molto più sicuro rispetto ai cifrari monoalfabetici come il cifrario di Cesare.
      In questo caso diversi alfabeti sono utilizzati in sequenza per cifrare il testo in base a una chiave segreta. Quello più conosciuto è il cifrario di Vigenère che tramite tabella di Vigenèr si applica uno spostamento variabile in base ai caratteri della chiave.

      Come nel cifrario di Cesare, quando la pagina viene caricata per la prima volta viene salvata nei cookie localStorage ogni carattere della chiave generata in modo random.
      Generato casualmente propro dalla funzione randomizeAlphabet() che mescola l'alfabeto normale.
      La funzione encrypt() prende il testo inserito dall'utente e lo cifra con alfabeti diversi. Per farlo su ogni carattere viene calcolato un indice nella chiave (keyIndex) che tramite l'operatore modulo (%) si assicura che passi per la chiave in loop.
      La funzione decrypt() è molto simile a encrypt() ma funziona in modo inverso. showMapping() genera un quadro generale degli alfabeti.

      Codice:

      HTML e CSS invariato.

      Javascript:

      let normalAlphabet = 'abcdefghijklmnopqrstuvwxyz';
      let key = "KEY";
      let shuffledAlphabets = [];
      
      if (!localStorage.getItem('shuffledAlphabets')) {
        for (let i = 0; i < key.length; i++) {
          shuffledAlphabets.push(randomizeAlphabet());
        }
        localStorage.setItem('shuffledAlphabets', JSON.stringify(shuffledAlphabets));
      } else {
        shuffledAlphabets = JSON.parse(localStorage.getItem('shuffledAlphabets'));
      }
      
      function randomizeAlphabet() {
        let alphabet = 'abcdefghijklmnopqrstuvwxyz';
        let shuffledAlphabet = alphabet.split('').sort(() => Math.random() - 0.5).join('');
        return shuffledAlphabet;
      }
      
      function encrypt() {
        let plaintext = document.getElementById('text').value.toLowerCase();
        let ciphertext = '';
      
        for (let i = 0; i < plaintext.length; i++) {
          let char = plaintext[i];
          let charCode = char.charCodeAt(0);
          let keyIndex = i % key.length;
          let shuffledAlphabet = shuffledAlphabets[keyIndex];
          let index = normalAlphabet.indexOf(char);
      
          if (index !== -1) {
            ciphertext += shuffledAlphabet[index];
          } else {
            ciphertext += char;
          }
        }
      
        document.getElementById('result').value = ciphertext;
      }
      
      function decrypt() {
        let ciphertext = document.getElementById('text').value.toLowerCase();
        let decryptedtext = '';
      
        for (let i = 0; i < ciphertext.length; i++) {
          let char = ciphertext[i];
          let charCode = char.charCodeAt(0);
          let keyIndex = i % key.length;
          let shuffledAlphabet = shuffledAlphabets[keyIndex];
          let index = shuffledAlphabet.indexOf(char);
      
          if (index !== -1) {
            decryptedtext += normalAlphabet[index];
          } else {
            decryptedtext += char;
          }
        }
      
        document.getElementById('result').value = decryptedtext;
      }
      
      function showMapping() {
        let mapping = '';
        for (let i = 0; i < normalAlphabet.length; i++) {
          let row = `${normalAlphabet[i]} -> `;
          for (let j = 0; j < shuffledAlphabets.length; j++) {
            row += `${shuffledAlphabets[j][i]} `;
          }
          mapping += row + '\n';
        }
        document.getElementById('mapping').value = mapping;
      }
      
      showMapping();

      Cifrario matematico (su polinomio)

      Sfruttando la funzione quadratica y=ax2+bx+x, convertiamo i caratteri del testo in numeri utilizzando il codice ASCII. Quindi cifriamo o decifriamo tramite polinomio.
      Nel nostro caso nella cifratura si usa la funzione quadratica per trasformare il valore ASCII del carattere di input cioè sostituiamo il valore originale del carattere con il risultato della funzione quadratica.
      Nella decifratura usiamo la formula inversa della funzione quadratica per ottenere il valore ASCII originale del carattere partendo dal valore cifrato.
      Se per esempio abbiamo: y=2x^2+5x+3 e dobbiamo cifrare il codice ASCII 97 (che corrisponde ad 'a') sostituiremo il 97 alla x:y=2(97)^2+5(97)+3.

      Iniziamo a scrivere il codice, per la cifratura inizialmente si deve prendere il testo da decifrare posto nell'apposito campo di input con document.getElementById('text').value.toLowerCase(); e per uniformità lo convertiamo in minuscolo.
      Attraverso un for leggiamo ogni carattere del testo inserito, e per ogni carattere otteniamo valore ASCII con charCodeAt(i) e usiamo la funzione encryptChar() per cifrare il carattere e il risultato verrà aggiunto a ciphertext.
      La funzione per decriptare è molto simile alla cifratura, cambia soltanto l'applicazione di decryptChar().

      La funzione encryptChar() richiama la funzione quadratica y=ax2+bx+x, i coefficienti a,b,c sono impostati manualmente all'interno della funzione.
      La funzione quadratica viene applicata al codice ASCII del carattere in ingresso e il risultato ottenuto rappresenta il carattere cifrato.
      Nella funzione decryptChar() invece viene calcolata la radice quadrata dell'equazione quadratica inversa per ottenere il carattere originale (a,b,c rimangono uguali).
      Da notare che il polinomio in questione può avere 2 soluzioni, quindi ho scritto una condizione per scegliere sempre la radice quadrata positiva come risultato (in quanto il codice ASCII è sempre un valore positivo).

      Codice:

      HTML:

          <!DOCTYPE html>
          <html lang="en">
          <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Cifrario Matematico</title>
            <link rel="stylesheet" href="style.css">
          </head>
          <body>
            <div class="container">
              <h1>Cifrario Matematico</h1>
              <label for="text">Testo:</label>
              <textarea id="text" placeholder="Inserisci qui il testo"></textarea>
              <button onclick="encrypt()">Cifra</button>
              <button onclick="decrypt()">Decifra</button>
              <label for="result">Risultato:</label>
              <textarea id="result" readonly></textarea>
            </div>
            <script src="script.js"></script>
          </body>
          </html>

      CSS:

      body {
        font-family: Arial, sans-serif;
        text-align: center;
        background-color: #f2f2f2;
      }
      
      .container {
        width: 80%;
        margin: 50px auto;
        background-color: #fff;
        padding: 20px;
        border-radius: 10px;
        box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
      }
      
      textarea, button {
        display: block;
        width: calc(100% - 20px);
        margin: 10px auto;
        padding: 10px;
        font-size: 16px;
      }
      
      button {
        background-color: #ff7300;
        color: white;
        border: none;
        border-radius: 5px;
        cursor: pointer;
      }
      
      button:hover {
        background-color: #ff0000;
      }
      
      label {
        display: block;
        font-size: 18px;
        margin-top: 20px;
      }
      
      textarea {
        height: 150px;
      }
      
      #result {
        resize: vertical;
      }

      Javascript:

      function encrypt() {
        let plaintext = document.getElementById('text').value.toLowerCase();
        let ciphertext = '';
      
        for (let i = 0; i < plaintext.length; i++) {
          let charCode = plaintext.charCodeAt(i);
          let encryptedCharCode = encryptChar(charCode);
          ciphertext += String.fromCharCode(encryptedCharCode);
        }
      
        document.getElementById('result').value = ciphertext;
      }
      
      function decrypt() {
        let ciphertext = document.getElementById('text').value;
        let decryptedtext = '';
      
        for (let i = 0; i < ciphertext.length; i++) {
          let charCode = ciphertext.charCodeAt(i);
          let decryptedCharCode = decryptChar(charCode);
          decryptedtext += String.fromCharCode(decryptedCharCode);
        }
      
        document.getElementById('result').value = decryptedtext;
      }
      
      function encryptChar(charCode) {
      
        let a = 2;
        let b = 5;
        let c = 3;
      
        let encryptedCharCode = a * Math.pow(charCode, 2) + b * charCode + c;
      
        return encryptedCharCode;
      }
      
      function decryptChar(encryptedCharCode) {
        let a = 2;
        let b = 5;
        let c = 3;
      
        let rootTerm = Math.sqrt(Math.pow(b, 2) - 4 * a * (c - encryptedCharCode));
        let decryptedCharCode1 = (-b + rootTerm) / (2 * a);
        let decryptedCharCode2 = (-b - rootTerm) / (2 * a);
      
        return (decryptedCharCode1 >= 0) ? decryptedCharCode1 : decryptedCharCode2;
      }

      Powered by: FreeFlarum.
      (remove this footer)