«[Figlio dell'uomo] Porgi l'orecchio e ascolta le parole di KGB
e applica la tua mente alla SUA istruzione
» Pv. 22,17

Qui si straparla di vari argomenti:
1. Il genere dei pezzi è segnalato da varie immagini, vedi Legenda
2. Istruzioni per i nuovi lettori (occasionali e non) qui
3. L'ultimo corto è questo

giovedì 17 maggio 2018

Vieni avanti criptino

Dunque avevo un problema: mi sono venute a mente delle “pillole”, ovvero delle breve frasi divertenti, che però sono molto più spinte del solito: diciamo che sarebbero stati perfetti per il vecchio “Umore Maligno” (*1).
Per chi non lo sapesse “Umore Maligno” era un sito di umorismo molto crudo e caustico che però a me piaceva molto: avevo anche disegnato la vignetta per il marcatore “UM”...

Insomma le pillole che avevo in mente non avrebbero sfigurato su UM ma per questo viario sono un po' troppo forti.
Non mi piace però buttare via le mie idee e allora ho pensato a una soluzione di compromesso: pubblicare queste pillole criptate e usare per esse il nuovo marcatore “Criptino”. Quindi un “Criptino” in pratica sarà una “Pillola” molto caustica che pubblicherò criptata.
Lo scopo di criptare i “criptini” è che così solo poche persone, ovvero quelle capaci di compilare l'allegato programmino Java (vedi poi), saranno in grado di leggerli e, contemporaneamente, non turberò l'ordine pubblico con i miei esilaranti giambi.
In realtà, molto probabilmente, il risultato finale sarà che NESSUNO leggerà i miei criptini, ma trovo comunque l'idea divertente e quindi...

Qualche mese fa mi ero comprato dei libri elettronici su Java e da tempo avevo voglia di scrivere un po' di codice: in particolare volevo scrivere un semplice programma per criptare un testo.
L'idea è semplice e consiste nei seguenti passi:
1. prendere un archivio di testo
2. convertirne i caratteri in numeri da 0 a 127
3. prendere gruppi di 7 caratteri, scriverli in binario, uno sotto l'altro (creando quindi una griglia di 7x7 di 0 o 1).
4. leggere questa griglia, copiandone i numeri dal basso verso l'alto e da destra verso sinistra, ottenendo così 7 nuovi numeri da 0 a 127.
5. convertire questi 7 nuovi numeri in caratteri (univoci) e stamparli l'uno dopo l'altro.

Esempio dei punti 3 e 4:
Scrivo i 7 numeri da 0 a 127 in binario:
s → 0011010
c → 1101011
i → 0011001
e → 0100100
n → 1010011
z → 0000111
a → 1001100
Li ricopio partendo dal basso verso l'alto e da destra verso sinistra, ottenendo:
0110110 → k
0110011 → 4
1101000 → ]
1000111 → g
0010101 → .
0001010 → h
1010010 → 8
Quindi “scienza” viene codificato in “k4]g.h8” (*2).

La cosa bellina è che per decodificare la frase criptata basta riapplicare lo stesso processo! (*3)

Qualche parola sul codice.
Prima di tutto ho cercato di scrivere un codice compatto ma leggibile e, tutto sommato, mi sembra di esserci riuscito.
Come sempre non ricordavo come Java gestisca gli archivi: ho fatto un po' di copia e incolla da Google e ho fatto funzionare a pedate il tutto.
La parte centrale del codice, quella nel “while” all'interno del “try”, è piuttosto elegante e sfrutta le operazioni logiche bit a bit: non le avevo mai usate e volevo provarle!
Ho deciso di usare solo 128 caratteri e quindi qualcosa potrebbe essere rimasto fuori (i caratteri utilizzabili sono solo quelli della stringa “s” nella funzione “init”).
Non so: qualche problema ci potrebbe forse essere su Windows perché non ricordo più bene come converta i '\n' di Linux. Comunque i criptini non avranno mai molti “ritorni a capo” e quindi non dovrebbero esserci problemi di leggibilità...
Ah, come usare il programma allegato per decodificare un criptino: dovrete fare un copia e incolla della stringa in un archivio di testo che dovrete salvare e poi... ma sicuramente se siete in grado di compilare un programma Java non avrete problemi neppure a capire come usarlo!
Boh, non mi viene in mente altro di importante da sottolineare...

Conclusione: se qualcuno riesce a leggere un mio criptino, ad esempio il corto Criptino 1, mi faccia sapere!

Nota (*1): il vecchio sito di “Umore Maligno” non c'è più e al suo posto c'è un “viario di stile”, oltretutto fermo a ottobre 2016, quindi vi risparmio il collegamento...
Nota (*2): ovviamente si tratta di un sistema di codifica banale e per niente sicura! Insomma va bene per nascondere i criptini al pubblico occasionale ma niente di più!
Nota (*3): beh, in realtà le cose sono un pochino più complicate: non volevo che nella codifica ci fossero ritorni a capo e simili (cioè '\n', '\r' e '\f') e così ho inserito una conversione intermedia che gestisce questi particolari caratteri...

Il codice da inserire in un unico archivio chiamato Base.java

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;

public class Base 
{
    static final int NUMC=7;
    
    public static void main(String[] args)
    {  
        if(args.length<1 || args.length>2)
        {
            System.out.println("Uso x Codificare: KGBTrad NomeFile -cod\nUso x Decodificare: KGBTrad NomeFile\n");
            System.exit(0);
        }
        
        boolean isDeco=(args.length==1 ? true : false);

        Path p=Paths.get(args[0]);
        
        HashMap hm1=new HashMap();
        HashMap hm2=new HashMap();
        HashMap hm3=new HashMap();
        HashMap hm4=new HashMap();        
        init(hm1, hm2, hm3, hm4);
        
        try(BufferedReader br = Files.newBufferedReader(p);) 
        {
            char[] car=new char[NUMC];
            while(prendiNUMCCar(br, car))
            {
                converti(car,isDeco ? hm3 : hm1);
                for(int i=0;i<NUMC;i++)
                {
                    char mask=(char)(1<<i);
                    char res=0;
                    for(int j=0;j<NUMC;j++)
                    {
                        res=(char)(res | (((car[j] & mask)>>i)<< j));
                    }
                    System.out.print(isDeco ? hm4.get(res) : hm2.get(res));
                }
            }     
            System.out.println(""); 

        } catch(Exception ex) 
        {
            ex.printStackTrace();
        }        
    }    
    
    static private void converti(char[] c, HashMap hm)
    {
        for(int i=0;i<NUMC;i++)
            c[i]=(char)hm.get(c[i]);
    } 
    
    static private void init(HashMap hm1, HashMap hm2, HashMap hm3, HashMap hm4)
    {
        String s="qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890!@#$%*()`~-_=+[{]};:'\",<.>/?\\|€\n\r\f «»àìòùèáéíóúüöäëïãÈĩõũ©¥£±Ω☺☼♀♂";
        for(int i=0;i<s.length();i++)
            hm1.put(s.charAt(i), (char) i);
        for(int i=0;i<s.length();i++)
            hm4.put((char) i, s.charAt(i));        
        String s2="qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890!@#$%*()`~-_=+[{]};:'\",<.>/?\\|€¶←↓ «»àìòùèáéíóúüöäëïãẽĩõũ©¥£±Ω☺☼♀♂";
        for(int i=0;i<s2.length();i++)
            hm2.put((char) i, s2.charAt(i));        
        for(int i=0;i<s2.length();i++)
            hm3.put(s2.charAt(i),(char) i);        
    }
    
    static private boolean prendiNUMCCar(BufferedReader br, char d[]) throws IOException
    {
        int n=br.read(d,0,NUMC);
        if(n==-1 || n==1)
            return false;
        else
            for(int i=n; i<NUMC;i++)
                d[i]='-';            
        return true;        
    }
            
}

Nessun commento:

Posta un commento