<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>gpg &amp;mdash; Cyberdyne Systems</title>
    <link>https://noblogo.org/aytin/tag:gpg</link>
    <description>&#34;Fare o non fare. Non c&#39;è provare!&#34;</description>
    <pubDate>Thu, 30 Apr 2026 06:56:52 +0000</pubDate>
    <item>
      <title>Device Mapper: LUKS + LVM</title>
      <link>https://noblogo.org/aytin/device-mapper-luks-lvm</link>
      <description>&lt;![CDATA[luks-lvm&#xA;(segue da &#34;Cenni sulla creazione di pool di storage con LVM&#34;)&#xA;...anche se è la base per una serie di sviluppi interessanti. &#xA;&#xA;Come ormai sappiamo, device mapper è il framework del kernel Linux col quale mappare dispositivi a blocchi fisici su dispositivi a blocchi logici, che costituisce la base per fornire funzionalità ulteriori quali:&#xA;!--more--&#xA;&#xA;volumi logici&#xA;raid&#xA;cifratura (Full Disk Encryption)&#xA;snapshot di volumi&#xA;&#xA;Scenario 1&#xA;È molto comune per es. cifrare l&#39;intero disco e &#34;affettarlo&#34; con volumi logici in base alle proprie esigenze di partizionamento .&#xA;&#xA;Il doppio vantaggio è dato da:&#xA;&#xA;offuscamento totale dello schema di partizionamento&#xA;estrema versatilità / flessibilità del partizionamento grazie ai volumi logici &#xA;&#xA;Come si agisce?&#xA;&#xA;si cifra il dispositivo fisico&#xA;si crea un gruppo di volumi avente come volume fisico il volume cifrato&#xA;si creano i volumi logici in base allo schema di partizionamento desiderato.&#xA;&#xA;luks-lvm&#xA;Passo 1 - Inizializzazione&#xA;Simulo il mio dispositivo fisico ricorrendo ai loop device.&#xA;&#xA;Il &#34;disco&#34; avrà una grandezza simbolica di 2 GiB, non avrà header detachable. L&#39;algoritmo di hash sarà sha512 e la chiave sarà da 512 bit. Il resto è il default di luks2 (argon2id come pbkdf, per maggiori dettagli vedi cryptsetup --help)&#xA;1. Preparazione disco &#34;fisico&#34;&#xA;fallocate -l 2g cipherdisk.img&#xA;&#xA;2. loop device che simula l&#39;attach del dispositivo&#xA;DEV=$(losetup -Pf --show cipherdisk.img)&#xA;&#xA;3. Inizializzazione cifratura&#xA;cryptsetup luksFormat  \&#xA;    --type luks2 \&#xA;    --hash sha512 \&#xA;    --key-size 512 \&#xA;    $DEV&#xA;Passo 2&#xA;Il passo successivo consiste nell&#39;apertura del dispositivo cifrato e nella definizione dello schema di partizionamento in volumi logici&#xA;1. apertura del disco cifrato&#xA;cryptsetup open \&#xA;    --type luks2 \&#xA;    $DEV cipherdisk&#xA;Nell&#39;apertura, device mapper fa la sua prima magia.&#xA;&#xA;Infatti, se osserviamo lo stato dei dispositivi, vedremo una situazione simile:&#xA;lsblk&#xA;...&#xA;loop9                7:9    Kib0     2G  0 loop  &#xA;└─cipherdisk      252:3    0     2G  0 crypt &#xA;...&#xA;Cio vuol dire che sopra il dispositivo fisico, /dev/loop9 in questo caso, device mapper ha &#34;poggiato&#34; cipherdisk (/dev/mapper/cipherdisk).&#xA;&#xA;Questo sarà il nostro volume fisico per definire gruppi di volume e, conseguentemente, i volumi logici.&#xA;2. creazione gruppo di volumi&#xA;vgcreate vglab /dev/mapper/cipherdisk&#xA;&#xA;3. creazione volumi logici&#xA;lvcreate -n lvlab1 vglab -L 700M&#xA;lvcreate -n lvlab2 vglab -L 600M&#xA;lvcreate -n lvlab3 vglab -l 100%FREE&#xA;La situazione dei dispositivi è ora questa:&#xA;lsblk&#xA;...&#xA;loop9                7:9    0     2G  0 loop  &#xA;└─cipherdisk      252:3    0     2G  0 crypt&#xA;  ├─vglab-lvlab1 252:4    0   700M  0 lvm&#xA;  ├─vglab-lvlab2 252:5    0   600M  0 lvm&#xA;  └─vglab-lvlab3 252:6    0   728M  0 lvm&#xA;...&#xA;Sopra /dev/loop9 c&#39;è cipherdisk (/dev/mapper/cipherdisk) e sopra di esso, i 3 volumi logici&#xA;&#xA;lvlab1 (/dev/mapper/vglab-lvlab1)&#xA;lvlab2 (/dev/mapper/vglab-lvlab2)&#xA;lvlab3 (/dev/mapper/vglab-lvlab3)&#xA;&#xA;Formatto e monto i volumi logici&#xA;4. formattazione dei 3 volumi logici&#xA;mkfs.ext4 /dev/mapper/vglab-lvlab1&#xA;mkfs.ext4 /dev/mapper/vglab-lvlab2&#xA;mkfs.ext4 /dev/mapper/vglab-lvlab3&#xA;&#xA;5. creo e preparo i punti di mmontaggio&#xA;mkdir disk1 disk2 disk3&#xA;mount -t ext4 -o user,noauto,rw  /dev/mapper/vglab-lvlab1 disk1&#xA;mount -t ext4 -o user,noauto,rw  /dev/mapper/vglab-lvlab2 disk2&#xA;mount -t ext4 -o user,noauto,rw  /dev/mapper/vglab-lvlab3 disk3&#xA;chown $USER disk1 disk2 disk3&#xA;&#xA;6. unmount di tutti i dispositivi&#xA;umount disk1 disk2 disk3&#xA;vgchange -an vglab&#xA;cryptsetup close cipherdisk&#xA;losetup -d $DEV&#xA;Passo 3&#xA;Infine, per completezza, gli script di mount e unmount del dispositivo.&#xA;mount&#xA;1. attach del dispositivo&#xA;DEV=$(losetup -Pf --show cipherdisk.img)&#xA;&#xA;2. Apre il disco cifrato &#xA;cryptsetup open \&#xA;    --type luks2 \&#xA;    $DEV cipherdisk&#xA;&#xA;3. monta il gruppo di volume&#xA;(opzionale. L&#39;apertura del disco cifrato dovrebbe montare &#xA;automaticamente il gruppo di volumi)&#xA;vgchange -ay vglab&#xA;&#xA;4. monta i volumi logici&#xA;mount -t ext4 -o user,noauto,rw  /dev/mapper/vglab-lvlab1 disk1&#xA;mount -t ext4 -o user,noauto,rw  /dev/mapper/vglab-lvlab2 disk2&#xA;mount -t ext4 -o user,noauto,rw  /dev/mapper/vglab-lvlab3 disk3&#xA;unmount&#xA;1. smonta i 3 dischi&#xA;umount disk1 disk2 disk3&#xA;&#xA;2. smonta il gruppo di volumi&#xA;vgchange -an vglab&#xA;&#xA;3. chiude il disco cifrato&#xA;cryptsetup close cipherdisk&#xA;&#xA;4. &#34;stacca&#34; il dispositivo fisico&#xA;losetup -d $DEV&#xA;&#xA;Questo è ciò che si farebbe normalmente quando si vuole il full disk encryption sul proprio pc. Ma con una piccola eccezione.&#xA;&#xA;In realtà ciò che viene cifrata è una partizione quasi completa del disco, perché almeno una piccola partizione, quella contenente il boot, /BOOT, deve essere in chiaro per consentire:&#xA;&#xA;a UEFI di avviare GRUB che conosce le partizioni,&#xA;GRUB provvederà all&#39;avvio del kernel,&#xA;l&#39;avvio del kernel con initramfs chiederà la password per sbloccare la partizione cifrata.&#xA;&#xA;La cifratura totale (che proprio totale non sarà perché /boot/efi deve rimanere in chiaro) eleva di molto la complessità del setup iniziale.&#xA;&#xA;Affidare a GRUB la gestione della cifratura potrebbe voler dire, oltre alla complessità della configurazione iniziale che dovrà far ricorso a moduli come cryptodisk, che bisognerà rinunciare ad Argon2 perché GRUB ancora non lo supporta pienamente e, a differenza del kernel, non ha sufficiente potenza per farlo lavorare come si deve.&#xA;&#xA;Un buon compromesso potrebbe essere il ricorso ad un dispositivo esterno, es. una pendrive, che contenga tutta la partizione /boot in chiaro, anche  l&#39;header del disco cifrato.&#xA;GRUB dovrà solo sapere dove si trovi il boot, il resto dell&#39;avvio viene affidato come di consueto al kernel.&#xA;Scenario 2&#xA;Rimanendo nell&#39;ambito dell&#39;esplorazione di device mapper e della cifratura di dispositivi esterni non avviabili, immaginiamo qualcosa di più estremo.&#xA;&#xA;Supponiamo di dover custodire un segreto in qualcosa che non sia un semplice vault cifrato.&#xA;&#xA;Per diminuire il rischio di compromettere un unico vault, decido di dividerlo in varie parti, come gli horcrux ma con 0 malignità. Ogni parte sarà cifrata con una sua chiave che affiderò ad una persona diversa, di mia fiducia. Solo io, titolare ultimo del segreto, avrò accesso ai dati e solo la mia chiave (come l&#39;Anello che li domina tutti) aprirà il vault.&#xA;&#xA;Supponiamo di avere 3 dispositivi fisici (che nel laboratoro saranno simulati da loop device come al solito) per altrettanti &#34;custodi&#34;, ognuno dei quali verrà cifrato con la chiave e con dei parametri da consegnare al &#34;custode&#34; specifico.&#xA;&#xA;I 3 dispositivi cifrati costituiranno un gruppo di volumi con un volume logico (dai requisiti posti non c&#39;è necessità di sfruttare la flessibilità di partizionamento dei volumi logici) che verrà cifrato con la mia chiave master.&#xA;&#xA;luks-lvm-luks&#xA;&#x9;&#xA;Ogni dispositivo, volume logico finale compreso, prima della cifratura, verrà inizializzato con del rumore casuale. Questo per impedire ad un&#39;analisi forense di risalire ad un qualunque pattern sul dispositivo raw.&#xA;&#xA;Caratteristiche di ogni cifratura:&#xA;&#xA;dispositivi inizializzati con rumore casuale&#xA;header detachable&#xA;offset custom&#xA;key-file&#xA;default di argon2id (controlla il tuo default con cryptsetup benchmark)&#xA;&#xA;Quando vorrò aprire il vault, sarà necessario che i 3 &#34;custodi&#34; aprano il loro &#34;pezzo&#34; e solo io potrò ricostruire e decifrare il volume con la mia chiave.&#xA;&#xA;L&#39;inzializzazione con rumore casuale dei dispositivo, tralasciando l&#39;uso di dd su /dev/urandom che sappiamo essere CPU-intensive, può essere fatta ricorrendo:&#xA;&#xA;ad openssl rand, come sappiamo da &#34;Come generare una password o un keyfile sicuri (Trilogia Della Password – 1 di 3&#34;&#xA;oppure usando furbescamente cryptsetup, con cui apriamo il dispositivo in modalità plain, senza header, e riempiendolo di zeri (da /dev/zero con dd) che, attraversando il motore di cifratura, verranno scritti sul dispositivo come dati casuali ad alta velocità.&#xA;&#xA;################################&#xA;Emulazione dei device fisici &#xA;################################&#xA;fallocate -l 512M cipherdisk1.img&#xA;fallocate -l 512M cipherdisk2.img&#xA;fallocate -l 512M cipherdisk3.img&#xA;&#xA;###########################&#xA;creazione dei 3 keyfile &#xA;###########################&#xA;keyfile del custode n° 1&#xA;dd if=/dev/urandom bs=1024 count=4 | \&#xA;    gpg --yes -o cipherdisk1.key.gpg -c \&#xA;        --s2k-mode 3 \&#xA;        --s2k-count 32505856 \&#xA;        --s2k-cipher-algo aes256 \&#xA;        --s2k-digest-algo sha512 \&#xA;        --force-mdc -&#xA;&#xA;keyfile del custode n° 2&#xA;dd if=/dev/urandom bs=1024 count=4 | \&#xA;    gpg --yes -o cipherdisk2.key.gpg -c \&#xA;        --s2k-mode 3 \&#xA;        --s2k-count 32505856 \&#xA;        --s2k-cipher-algo aes256 \&#xA;        --s2k-digest-algo sha512 \&#xA;        --force-mdc -&#xA;&#xA;keyfile del custode n° 3&#xA;dd if=/dev/urandom bs=1024 count=4 | \&#xA;    gpg --yes -o cipherdisk3.key.gpg -c \&#xA;        --s2k-mode 3 \&#xA;        --s2k-count 32505856 \&#xA;        --s2k-cipher-algo aes256 \&#xA;        --s2k-digest-algo sha512 \&#xA;        --force-mdc -&#xA;&#xA;keyfile master&#xA;dd if=/dev/urandom bs=1024 count=4 | \&#xA;    gpg --yes -o master.key.gpg -c \&#xA;        --s2k-mode 3 \&#xA;        --s2k-count 32505856 \&#xA;        --s2k-cipher-algo aes256 \&#xA;        --s2k-digest-algo sha512 \&#xA;        --force-mdc -&#xA;&#xA;##########################&#xA;cifratura dei 3 device &#xA;##########################&#xA;attach dispositivo&#xA;DEV1=$(losetup -Pf --show cipherdisk1.img)&#xA;&#xA;inizializzazione dev1 con rumore casuale&#xA;cryptsetup open --type plain ${DEV1} container --key-file /dev/urandom&#xA;dd if=/dev/zero of=/dev/mapper/container status=progress&#xA;cryptsetup close container&#xA;&#xA;cifratura dispositivo n° 1&#xA;gpg -d cipherdisk1.key.gpg | \&#xA;    cryptsetup luksFormat  \&#xA;        --type luks2 \&#xA;        --key-file - \&#xA;        --header header1.img \&#xA;        --offset 32768 \&#xA;        --hash sha512 \&#xA;        --key-size 512 \&#xA;        --cipher aes-xts-plain64 \&#xA;        ${DEV1}&#xA;&#xA;attach dispositivo&#xA;DEV2=$(losetup -Pf --show cipherdisk2.img)&#xA;&#xA;inizializzazione dev2 con rumore casuale&#xA;cryptsetup open --type plain ${DEV2} container --key-file /dev/urandom&#xA;dd if=/dev/zero of=/dev/mapper/container status=progress&#xA;cryptsetup close container&#xA;&#xA;cifratura dispositivo n° 2&#xA;gpg -d cipherdisk2.key.gpg | \&#xA;    cryptsetup luksFormat  \&#xA;        --type luks2 \&#xA;        --key-file - \&#xA;        --header header2.img \&#xA;        --offset 36864 \&#xA;        --hash sha512 \&#xA;        --key-size 512 \&#xA;        --cipher aes-xts-plain64 \&#xA;        ${DEV2}&#xA;&#xA;attach dispositivo&#xA;DEV3=$(losetup -Pf --show cipherdisk3.img)&#xA;&#xA;inizializzazione dev3 con rumore casuale&#xA;cryptsetup open --type plain ${DEV3} container --key-file /dev/urandom&#xA;dd if=/dev/zero of=/dev/mapper/container status=progress&#xA;cryptsetup close container&#xA;&#xA;cifratura dispositivo n° 3&#xA;gpg -d cipherdisk3.key.gpg | \&#xA;    cryptsetup luksFormat  \&#xA;        --type luks2 \&#xA;        --key-file - \&#xA;        --header header3.img \&#xA;        --offset 40960 \&#xA;        --hash sha512 \&#xA;        --key-size 512 \&#xA;        --cipher aes-xts-plain64 \&#xA;        ${DEV3}&#xA;&#xA;##############################&#xA;Creazione gruppo di volumi &#xA;##############################&#xA;&#34;apro&#34; il volume 1&#xA;gpg -d cipherdisk1.key.gpg | \&#xA;    cryptsetup open \&#xA;         --type luks2 \&#xA;         --header header1.img \&#xA;         --key-file - \&#xA;         ${DEV1} cipherdisk1&#xA;&#xA;&#34;apro&#34; il volume 2&#xA;gpg -d cipherdisk2.key.gpg | \&#xA;    cryptsetup open \&#xA;         --type luks2 \&#xA;         --header header2.img \&#xA;         --key-file - \&#xA;         ${DEV2} cipherdisk2&#xA;&#xA;&#34;apro&#34; il volume 3&#xA;gpg -d cipherdisk3.key.gpg | \&#xA;    cryptsetup open \&#xA;         --type luks2 \&#xA;         --header header3.img \&#xA;         --key-file - \&#xA;         ${DEV3} cipherdisk3&#xA;&#xA;Creo il mio gruppo di volumi con i 3 volumi &#34;fisici&#34;:&#xA;1. /dev/mapper/cipherdisk1&#xA;2. /dev/mapper/cipherdisk2&#xA;3. /dev/mapper/cipherdisk3&#xA;vgcreate vgmaster /dev/mapper/cipherdisk1  /dev/mapper/cipherdisk2  /dev/mapper/cipherdisk3&#xA;&#xA;creazione dell&#39;unico volume logico&#xA;lvcreate -n lvmaster vgmaster -l 100%FREE&#xA;&#xA;################################&#xA;cifratura e mount del master &#xA;################################&#xA;cifratura dispositivo master&#xA;dd if=/dev/urandom of=/dev/mapper/vgmaster-lvmaster bs=1M count=32 status=progress&#xA;gpg -d master.key.gpg | \&#xA;    cryptsetup luksFormat  \&#xA;        --type luks2 \&#xA;        --key-file - \&#xA;        --header headermaster.img \&#xA;&#x9;&#x9;--offset 65536 \&#xA;        --hash sha512 \&#xA;        --key-size 512 \&#xA;        --cipher aes-xts-plain64 \&#xA;        /dev/mapper/vgmaster-lvmaster&#xA;&#xA;apriamo il dispositivo master&#xA;gpg -d master.key.gpg | \&#xA;    cryptsetup open \&#xA;         --type luks2 \&#xA;         --header headermaster.img \&#xA;         --key-file - \&#xA;         /dev/mapper/vgmaster-lvmaster cipherdiskmaster&#xA;&#xA;e finalmente lo formattiamo&#xA;mkfs.ext4 /dev/mapper/cipherdiskmaster&#xA;&#xA;Test: montiamo il disco&#xA;mkdir -p /run/media/master/diskmaster&#xA;chown -R ${USER}:${USER} /run/media/master/diskmaster&#xA;mount -t auto /dev/mapper/cipherdiskmaster /run/media/master/diskmaster&#xA;&#xA;Infine chiudiamo tutto&#xA;umount /run/media/master/diskmaster&#xA;cryptsetup close cipherdiskmaster&#xA;vgchange -an vgmaster&#xA;cryptsetup close cipherdisk1&#xA;cryptsetup close cipherdisk2&#xA;cryptsetup close cipherdisk3&#xA;losetup -d ${DEV1} ${DEV2} ${DEV3}&#xA;Dopo aver appurato che tutto funzioni, consegno ad ogni &#34;custode&#34; dispositivo, keyfile e header.&#xA;&#xA;Se un attaccante dovesse entrare in possesso di uno o più dispositivi, troverebbe solo un mucchio di dati incomprensibili.&#xA;&#xA;Posto che riuscisse a decifrare il dispositivo, troverebbe un pezzo di un gruppo di volumi, cifrato e inutilizzabile.&#xA;&#xA;Il master a questo punto non dovrà fare altro che aprire e chiudere il vault, dopo aver riunito tutti i pezzi, come segue:&#xA;&#xA;Apertura del vault&#xA;Attach dei dispositivi&#xA;DEV1=$(losetup -Pf --show cipherdisk1.img)&#xA;DEV2=$(losetup -Pf --show cipherdisk2.img)&#xA;DEV3=$(losetup -Pf --show cipherdisk3.img)&#xA;&#xA;&#34;apro&#34; il volume 1&#xA;gpg -d cipherdisk1.key.gpg | \&#xA;    cryptsetup open \&#xA;         --type luks2 \&#xA;         --header header1.img \&#xA;         --key-file - \&#xA;         ${DEV1} cipherdisk1&#xA;&#xA;&#34;apro&#34; il volume 2&#xA;gpg -d cipherdisk2.key.gpg | \&#xA;    cryptsetup open \&#xA;         --type luks2 \&#xA;         --header header2.img \&#xA;         --key-file - \&#xA;         ${DEV2} cipherdisk2&#xA;&#xA;&#34;apro&#34; il volume 3&#xA;gpg -d cipherdisk3.key.gpg | \&#xA;    cryptsetup open \&#xA;         --type luks2 \&#xA;         --header header3.img \&#xA;         --key-file - \&#xA;         ${DEV3} cipherdisk3&#xA;&#xA;(facoltativo) apre il gruppo di volumi&#xA;vgchange -ay vgmaster&#xA;&#xA;&#34;apre&#34; il master volume&#xA;gpg -d master.key.gpg | \&#xA;    cryptsetup open \&#xA;         --type luks2 \&#xA;         --header headermaster.img \&#xA;         --key-file - \&#xA;         /dev/mapper/vgmaster-lvmaster cipherdiskmaster&#xA;&#xA;Monta il volume&#xA;mount -t auto /dev/mapper/cipherdiskmaster /run/media/master/diskmaster&#xA;Chiusura del vault&#xA;smonta il volume cifrato&#xA;umount /run/media/master/diskmaster&#xA;&#xA;chiusura del vault master&#xA;cryptsetup close cipherdiskmaster&#xA;&#xA;chiusura del gruppo di volumi&#xA;vgchange -an vgmaster&#xA;&#xA;chiusura dei singoli vault cifrati&#xA;cryptsetup close cipherdisk1&#xA;cryptsetup close cipherdisk2&#xA;cryptsetup close cipherdisk3&#xA;&#xA;deattach dei dispositivi&#xA;losetup -d ${DEV1} ${DEV2} ${DEV3}&#xA;&#xA;#cryptsetup #devicemapper #dmcrypt #gpg #loseup #luks #lvm #loopdevice #storage]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/fbedcc803-0ec729/JqVu1t3agiao/CSE9exMSdTVlv9adGCHXwSbkxvn9EPD0SPJNIsQo.jpg" alt="luks-lvm">
<em>(segue da <a href="https://noblogo.org/aytin/cenni-sulla-creazione-di-pool-di-storage-con-lvm/" rel="nofollow">“<strong>Cenni sulla creazione di pool di storage con LVM</strong>“</a>)</em>
...anche se è la base per una serie di sviluppi interessanti.</p>

<p>Come ormai sappiamo, <strong>device mapper</strong> è il framework del kernel Linux col quale mappare dispositivi a blocchi fisici su dispositivi a blocchi logici, che costituisce la base per fornire funzionalità ulteriori quali:
</p>
<ul><li>volumi logici</li>
<li>raid</li>
<li>cifratura (<strong>F</strong>ull <strong>D</strong>isk <strong>E</strong>ncryption)</li>
<li>snapshot di volumi</li></ul>

<h2 id="scenario-1">Scenario 1</h2>

<p>È molto comune per es. cifrare l&#39;intero disco e “affettarlo” con volumi logici in base alle proprie esigenze di partizionamento .</p>

<p>Il doppio vantaggio è dato da:</p>
<ol><li>offuscamento totale dello schema di partizionamento</li>
<li>estrema versatilità / flessibilità del partizionamento grazie ai volumi logici</li></ol>

<p>Come si agisce?</p>
<ol><li>si cifra il dispositivo fisico</li>
<li>si crea un gruppo di volumi avente come volume fisico il volume cifrato</li>
<li>si creano i volumi logici in base allo <strong>schema di partizionamento</strong> desiderato.</li></ol>

<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/fbedcc803-0ec729/e9tSS2DIxi6F/Bc8zWpFAR2KxQSK92F6I3Z6ocbA5E67bT3ziz1Ke.jpg" alt="luks-lvm"></p>

<h3 id="passo-1-inizializzazione">Passo 1 – Inizializzazione</h3>

<p>Simulo il mio dispositivo fisico ricorrendo ai <strong>loop device</strong>.</p>

<p>Il “disco” avrà una grandezza simbolica di 2 GiB, non avrà header detachable. L&#39;algoritmo di hash sarà sha512 e la chiave sarà da 512 bit. Il resto è il default di luks2 (argon2id come pbkdf, per maggiori dettagli vedi <code>cryptsetup --help</code>)</p>

<pre><code class="language-bash"># 1. Preparazione disco &#34;fisico&#34;
fallocate -l 2g cipher_disk.img

# 2. loop device che simula l&#39;attach del dispositivo
DEV=$(losetup -Pf --show cipher_disk.img)

# 3. Inizializzazione cifratura
cryptsetup luksFormat  \
    --type luks2 \
    --hash sha512 \
    --key-size 512 \
    $DEV
</code></pre>

<h3 id="passo-2">Passo 2</h3>

<p>Il passo successivo consiste nell&#39;apertura del dispositivo cifrato e nella definizione dello schema di partizionamento in volumi logici</p>

<pre><code class="language-bash"># 1. apertura del disco cifrato
cryptsetup open \
    --type luks2 \
    $DEV cipher_disk
</code></pre>

<p>Nell&#39;apertura, device mapper fa la sua prima magia.</p>

<p>Infatti, se osserviamo lo stato dei dispositivi, vedremo una situazione simile:</p>

<pre><code>lsblk
...
loop9                7:9    Kib0     2G  0 loop  
└─cipher_disk      252:3    0     2G  0 crypt 
...
</code></pre>

<p>Cio vuol dire che sopra il dispositivo fisico, <code>/dev/loop9</code>in questo caso, device mapper ha “poggiato” <strong>cipher_disk</strong> (<code>/dev/mapper/cipher_disk</code>).</p>

<p>Questo sarà il nostro volume fisico per definire gruppi di volume e, conseguentemente, i volumi logici.</p>

<pre><code class="language-bash"># 2. creazione gruppo di volumi
vgcreate vg_lab /dev/mapper/cipher_disk

# 3. creazione volumi logici
lvcreate -n lv_lab_1 vg_lab -L 700M
lvcreate -n lv_lab_2 vg_lab -L 600M
lvcreate -n lv_lab_3 vg_lab -l 100%FREE
</code></pre>

<p>La situazione dei dispositivi è ora questa:</p>

<pre><code>lsblk
...
loop9                7:9    0     2G  0 loop  
└─cipher_disk      252:3    0     2G  0 crypt
  ├─vg_lab-lv_lab_1 252:4    0   700M  0 lvm
  ├─vg_lab-lv_lab_2 252:5    0   600M  0 lvm
  └─vg_lab-lv_lab_3 252:6    0   728M  0 lvm
...
</code></pre>

<p>Sopra <code>/dev/loop9</code> c&#39;è <code>cipher_disk</code> (<code>/dev/mapper/cipher_disk</code>) e sopra di esso, i 3 volumi logici</p>
<ul><li><code>lv_lab_1</code> (<code>/dev/mapper/vg_lab-lv_lab_1</code>)</li>
<li><code>lv_lab_2</code> (<code>/dev/mapper/vg_lab-lv_lab_2</code>)</li>
<li><code>lv_lab_3</code> (<code>/dev/mapper/vg_lab-lv_lab_3</code>)</li></ul>

<p>Formatto e monto i volumi logici</p>

<pre><code class="language-bash"># 4. formattazione dei 3 volumi logici
mkfs.ext4 /dev/mapper/vg_lab-lv_lab_1
mkfs.ext4 /dev/mapper/vg_lab-lv_lab_2
mkfs.ext4 /dev/mapper/vg_lab-lv_lab_3

# 5. creo e preparo i punti di mmontaggio
mkdir disk_1 disk_2 disk_3
mount -t ext4 -o user,noauto,rw  /dev/mapper/vg_lab-lv_lab_1 disk_1
mount -t ext4 -o user,noauto,rw  /dev/mapper/vg_lab-lv_lab_2 disk_2
mount -t ext4 -o user,noauto,rw  /dev/mapper/vg_lab-lv_lab_3 disk_3
chown $USER disk_1 disk_2 disk_3

# 6. unmount di tutti i dispositivi
umount disk_1 disk_2 disk_3
vgchange -an vg_lab
cryptsetup close cipher_disk
losetup -d $DEV
</code></pre>

<h3 id="passo-3">Passo 3</h3>

<p>Infine, per completezza, gli script di mount e unmount del dispositivo.
<strong>mount</strong></p>

<pre><code class="language-bash"># 1. attach del dispositivo
DEV=$(losetup -Pf --show cipher_disk.img)

# 2. Apre il disco cifrato 
cryptsetup open \
    --type luks2 \
    $DEV cipher_disk

# 3. monta il gruppo di volume
# (opzionale. L&#39;apertura del disco cifrato dovrebbe montare 
# automaticamente il gruppo di volumi)
vgchange -ay vg_lab

# 4. monta i volumi logici
mount -t ext4 -o user,noauto,rw  /dev/mapper/vg_lab-lv_lab_1 disk_1
mount -t ext4 -o user,noauto,rw  /dev/mapper/vg_lab-lv_lab_2 disk_2
mount -t ext4 -o user,noauto,rw  /dev/mapper/vg_lab-lv_lab_3 disk_3
</code></pre>

<p><strong>unmount</strong></p>

<pre><code class="language-bash"># 1. smonta i 3 dischi
umount disk_1 disk_2 disk_3

# 2. smonta il gruppo di volumi
vgchange -an vg_lab

# 3. chiude il disco cifrato
cryptsetup close cipher_disk

# 4. &#34;stacca&#34; il dispositivo fisico
losetup -d $DEV
</code></pre>

<p>Questo è ciò che si farebbe normalmente quando si vuole il full disk encryption sul proprio pc. Ma con una piccola eccezione.</p>

<p>In realtà ciò che viene cifrata è una partizione quasi completa del disco, perché almeno una piccola partizione, quella contenente il boot, <code>/BOOT</code>, deve essere in chiaro per consentire:</p>
<ul><li>a UEFI di avviare GRUB che conosce le partizioni,</li>
<li>GRUB provvederà all&#39;avvio del kernel,</li>
<li>l&#39;avvio del kernel con initramfs chiederà la password per sbloccare la partizione cifrata.</li></ul>

<p>La cifratura totale (che proprio totale non sarà perché <code>/boot/efi</code> deve rimanere in chiaro) eleva di molto la complessità del setup iniziale.</p>

<p>Affidare a GRUB la gestione della cifratura potrebbe voler dire, oltre alla complessità della configurazione iniziale che dovrà far ricorso a moduli come <code>cryptodisk</code>, che bisognerà rinunciare ad Argon2 perché GRUB ancora non lo supporta pienamente e, a differenza del kernel, non ha sufficiente potenza per farlo lavorare come si deve.</p>

<p>Un buon compromesso potrebbe essere il ricorso ad un dispositivo esterno, es. una pendrive, che contenga tutta la partizione <code>/boot</code> in chiaro, anche  l&#39;header del disco cifrato.
GRUB dovrà solo sapere dove si trovi il boot, il resto dell&#39;avvio viene affidato come di consueto al kernel.</p>

<h2 id="scenario-2">Scenario 2</h2>

<p>Rimanendo nell&#39;ambito dell&#39;esplorazione di device mapper e della cifratura di dispositivi esterni non avviabili, immaginiamo qualcosa di più estremo.</p>

<p>Supponiamo di dover custodire un segreto in qualcosa che non sia un semplice vault cifrato.</p>

<p>Per diminuire il rischio di compromettere un unico vault, decido di dividerlo in varie parti, come gli horcrux ma con 0 malignità. Ogni parte sarà cifrata con una sua chiave che affiderò ad una persona diversa, di mia fiducia. Solo io, titolare ultimo del segreto, avrò accesso ai dati e solo la mia chiave (come l&#39;Anello che li domina tutti) aprirà il vault.</p>

<p>Supponiamo di avere 3 dispositivi fisici (che nel laboratoro saranno simulati da loop device come al solito) per altrettanti “custodi”, ognuno dei quali verrà cifrato con la chiave e con dei parametri da consegnare al “custode” specifico.</p>

<p>I 3 dispositivi cifrati costituiranno un gruppo di volumi con un volume logico (dai requisiti posti non c&#39;è necessità di sfruttare la flessibilità di partizionamento dei volumi logici) che verrà cifrato con la mia chiave master.</p>

<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/fbedcc803-0ec729/pnRafhfUlqts/Wl6xNlvrbnZJIjRVRbAIM0fmo6KZAnYoy1Wga0C2.jpg" alt="luks-lvm-luks"></p>

<p>Ogni dispositivo, volume logico finale compreso, prima della cifratura, verrà inizializzato con del rumore casuale. Questo per impedire ad un&#39;analisi forense di risalire ad un qualunque pattern sul dispositivo raw.</p>

<p>Caratteristiche di ogni cifratura:</p>
<ul><li>dispositivi inizializzati con rumore casuale</li>
<li>header detachable</li>
<li>offset custom</li>
<li>key-file</li>
<li>default di argon2id (controlla il tuo default con <code>cryptsetup benchmark</code>)</li></ul>

<p>Quando vorrò aprire il vault, sarà necessario che i 3 “custodi” aprano il loro “pezzo” e solo io potrò ricostruire e decifrare il volume con la mia chiave.</p>

<p>L&#39;inzializzazione con rumore casuale dei dispositivo, tralasciando l&#39;uso di <code>dd</code> su <code>/dev/urandom</code> che sappiamo essere CPU-intensive, può essere fatta ricorrendo:</p>
<ul><li>ad <code>openssl rand</code>, come sappiamo da <em><a href="https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di/" rel="nofollow">“<strong>Come generare una password o un keyfile sicuri (Trilogia Della Password – 1 di 3</strong>“</a></em></li>
<li>oppure usando furbescamente <strong>cryptsetup</strong>, con cui apriamo il dispositivo in modalità plain, senza header, e riempiendolo di zeri (da <code>/dev/zero</code> con <code>dd</code>) che, attraversando il motore di cifratura, verranno scritti sul dispositivo come dati casuali ad alta velocità.</li></ul>

<pre><code class="language-bash">################################
# Emulazione dei device fisici #
################################
fallocate -l 512M cipher_disk_1.img
fallocate -l 512M cipher_disk_2.img
fallocate -l 512M cipher_disk_3.img



###########################
# creazione dei 3 keyfile #
###########################
# keyfile del custode n° 1
dd if=/dev/urandom bs=1024 count=4 | \
    gpg --yes -o cipher_disk_1.key.gpg -c \
        --s2k-mode 3 \
        --s2k-count 32505856 \
        --s2k-cipher-algo aes256 \
        --s2k-digest-algo sha512 \
        --force-mdc -

# keyfile del custode n° 2
dd if=/dev/urandom bs=1024 count=4 | \
    gpg --yes -o cipher_disk_2.key.gpg -c \
        --s2k-mode 3 \
        --s2k-count 32505856 \
        --s2k-cipher-algo aes256 \
        --s2k-digest-algo sha512 \
        --force-mdc -

# keyfile del custode n° 3
dd if=/dev/urandom bs=1024 count=4 | \
    gpg --yes -o cipher_disk_3.key.gpg -c \
        --s2k-mode 3 \
        --s2k-count 32505856 \
        --s2k-cipher-algo aes256 \
        --s2k-digest-algo sha512 \
        --force-mdc -

# keyfile master
dd if=/dev/urandom bs=1024 count=4 | \
    gpg --yes -o master.key.gpg -c \
        --s2k-mode 3 \
        --s2k-count 32505856 \
        --s2k-cipher-algo aes256 \
        --s2k-digest-algo sha512 \
        --force-mdc -



##########################
# cifratura dei 3 device #
##########################
# attach dispositivo
DEV_1=$(losetup -Pf --show cipher_disk_1.img)

# inizializzazione dev_1 con rumore casuale
cryptsetup open --type plain ${DEV_1} container --key-file /dev/urandom
dd if=/dev/zero of=/dev/mapper/container status=progress
cryptsetup close container

# cifratura dispositivo n° 1
gpg -d cipher_disk_1.key.gpg | \
    cryptsetup luksFormat  \
        --type luks2 \
        --key-file - \
        --header header_1.img \
        --offset 32768 \
        --hash sha512 \
        --key-size 512 \
        --cipher aes-xts-plain64 \
        ${DEV_1}

# attach dispositivo
DEV_2=$(losetup -Pf --show cipher_disk_2.img)

# inizializzazione dev_2 con rumore casuale
cryptsetup open --type plain ${DEV_2} container --key-file /dev/urandom
dd if=/dev/zero of=/dev/mapper/container status=progress
cryptsetup close container

# cifratura dispositivo n° 2
gpg -d cipher_disk_2.key.gpg | \
    cryptsetup luksFormat  \
        --type luks2 \
        --key-file - \
        --header header_2.img \
        --offset 36864 \
        --hash sha512 \
        --key-size 512 \
        --cipher aes-xts-plain64 \
        ${DEV_2}

# attach dispositivo
DEV_3=$(losetup -Pf --show cipher_disk_3.img)

# inizializzazione dev_3 con rumore casuale
cryptsetup open --type plain ${DEV_3} container --key-file /dev/urandom
dd if=/dev/zero of=/dev/mapper/container status=progress
cryptsetup close container

# cifratura dispositivo n° 3
gpg -d cipher_disk_3.key.gpg | \
    cryptsetup luksFormat  \
        --type luks2 \
        --key-file - \
        --header header_3.img \
        --offset 40960 \
        --hash sha512 \
        --key-size 512 \
        --cipher aes-xts-plain64 \
        ${DEV_3}



##############################
# Creazione gruppo di volumi #
##############################
# &#34;apro&#34; il volume 1
gpg -d cipher_disk_1.key.gpg | \
    cryptsetup open \
         --type luks2 \
         --header header_1.img \
         --key-file - \
         ${DEV_1} cipher_disk_1

# &#34;apro&#34; il volume 2
gpg -d cipher_disk_2.key.gpg | \
    cryptsetup open \
         --type luks2 \
         --header header_2.img \
         --key-file - \
         ${DEV_2} cipher_disk_2

# &#34;apro&#34; il volume 3
gpg -d cipher_disk_3.key.gpg | \
    cryptsetup open \
         --type luks2 \
         --header header_3.img \
         --key-file - \
         ${DEV_3} cipher_disk_3

# Creo il mio gruppo di volumi con i 3 volumi &#34;fisici&#34;:
# 1. /dev/mapper/cipher_disk_1
# 2. /dev/mapper/cipher_disk_2
# 3. /dev/mapper/cipher_disk_3
vgcreate vg_master /dev/mapper/cipher_disk_1  /dev/mapper/cipher_disk_2  /dev/mapper/cipher_disk_3

# creazione dell&#39;unico volume logico
lvcreate -n lv_master vg_master -l 100%FREE



################################
# cifratura e mount del master #
################################
# cifratura dispositivo master
dd if=/dev/urandom of=/dev/mapper/vg_master-lv_master bs=1M count=32 status=progress
gpg -d master.key.gpg | \
    cryptsetup luksFormat  \
        --type luks2 \
        --key-file - \
        --header header_master.img \
		--offset 65536 \
        --hash sha512 \
        --key-size 512 \
        --cipher aes-xts-plain64 \
        /dev/mapper/vg_master-lv_master

# apriamo il dispositivo master
gpg -d master.key.gpg | \
    cryptsetup open \
         --type luks2 \
         --header header_master.img \
         --key-file - \
         /dev/mapper/vg_master-lv_master cipher_disk_master

# e finalmente lo formattiamo
mkfs.ext4 /dev/mapper/cipher_disk_master

# Test: montiamo il disco
mkdir -p /run/media/master/disk_master
chown -R ${USER}:${USER} /run/media/master/disk_master
mount -t auto /dev/mapper/cipher_disk_master /run/media/master/disk_master

# Infine chiudiamo tutto
umount /run/media/master/disk_master
cryptsetup close cipher_disk_master
vgchange -an vg_master
cryptsetup close cipher_disk_1
cryptsetup close cipher_disk_2
cryptsetup close cipher_disk_3
losetup -d ${DEV_1} ${DEV_2} ${DEV_3}
</code></pre>

<p>Dopo aver appurato che tutto funzioni, consegno ad ogni “custode” dispositivo, keyfile e header.</p>

<p>Se un attaccante dovesse entrare in possesso di uno o più dispositivi, troverebbe solo un mucchio di dati incomprensibili.</p>

<p>Posto che riuscisse a decifrare il dispositivo, troverebbe un pezzo di un gruppo di volumi, cifrato e inutilizzabile.</p>

<p>Il master a questo punto non dovrà fare altro che aprire e chiudere il vault, dopo aver riunito tutti i pezzi, come segue:</p>

<p><strong>Apertura del vault</strong></p>

<pre><code class="language-bash"># Attach dei dispositivi
DEV_1=$(losetup -Pf --show cipher_disk_1.img)
DEV_2=$(losetup -Pf --show cipher_disk_2.img)
DEV_3=$(losetup -Pf --show cipher_disk_3.img)

# &#34;apro&#34; il volume 1
gpg -d cipher_disk_1.key.gpg | \
    cryptsetup open \
         --type luks2 \
         --header header_1.img \
         --key-file - \
         ${DEV_1} cipher_disk_1

# &#34;apro&#34; il volume 2
gpg -d cipher_disk_2.key.gpg | \
    cryptsetup open \
         --type luks2 \
         --header header_2.img \
         --key-file - \
         ${DEV_2} cipher_disk_2

# &#34;apro&#34; il volume 3
gpg -d cipher_disk_3.key.gpg | \
    cryptsetup open \
         --type luks2 \
         --header header_3.img \
         --key-file - \
         ${DEV_3} cipher_disk_3

# (facoltativo) apre il gruppo di volumi
vgchange -ay vg_master

# &#34;apre&#34; il master volume
gpg -d master.key.gpg | \
    cryptsetup open \
         --type luks2 \
         --header header_master.img \
         --key-file - \
         /dev/mapper/vg_master-lv_master cipher_disk_master

# Monta il volume
mount -t auto /dev/mapper/cipher_disk_master /run/media/master/disk_master
</code></pre>

<p><strong>Chiusura del vault</strong></p>

<pre><code class="language-bash"># smonta il volume cifrato
umount /run/media/master/disk_master

# chiusura del vault master
cryptsetup close cipher_disk_master

# chiusura del gruppo di volumi
vgchange -an vg_master

# chiusura dei singoli vault cifrati
cryptsetup close cipher_disk_1
cryptsetup close cipher_disk_2
cryptsetup close cipher_disk_3

# deattach dei dispositivi
losetup -d ${DEV_1} ${DEV_2} ${DEV_3}
</code></pre>

<p><a href="/aytin/tag:cryptsetup" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">cryptsetup</span></a> <a href="/aytin/tag:devicemapper" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">devicemapper</span></a> <a href="/aytin/tag:dmcrypt" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">dmcrypt</span></a> <a href="/aytin/tag:gpg" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">gpg</span></a> <a href="/aytin/tag:loseup" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">loseup</span></a> <a href="/aytin/tag:luks" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">luks</span></a> <a href="/aytin/tag:lvm" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">lvm</span></a> <a href="/aytin/tag:loopdevice" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">loopdevice</span></a> <a href="/aytin/tag:storage" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">storage</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/device-mapper-luks-lvm</guid>
      <pubDate>Mon, 23 Feb 2026 10:58:17 +0000</pubDate>
    </item>
    <item>
      <title>Come generare una password o un keyfile sicuri (Trilogia Della Password - 1 di 3)</title>
      <link>https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di</link>
      <description>&lt;![CDATA[password&#xA;&#xA;La generazione di una password o di un keyfile si basa sulla casualità ossia sulla capacità del sistema di generare sequenze di simboli non prevedibili.&#xA;In questo contesto bisogna avere chiari 3 concetti legati fra loro: casualità, sorgente d&#39;entropia, entropia della password.&#xA;!--more--&#xA;&#xA;Definizioni varie&#xA;Entropia del kernel (CSPRNG)&#xA;Come generare password e keyfile&#xA;   Analisi&#xA;   Valutazione&#xA;   Conclusione&#xA;Bonus - Modalità paranoia&#xA;   Generazione password&#xA;   Generazione keyfile&#xA;   GPG Random&#xA;Riepilogo finale&#xA;   2) Keyfile binario&#xA;   3) Password complessa con caratteri stampabili&#xA;   5) Keyfile binario con openssl&#xA;&#xA;Definizioni varie&#xA;Casualità&#xA;In generale, posso parlare di casualità quando non riesco ad individuare un pattern o un&#39;organizzazione deterministica in una sequenza di dati.&#xA;&#xA;Da un punto di vista crittografico, una sequenza è considerata &#34;casuale&#34; se non esiste un algoritmo che possa prevedere il bit successivo con una probabilità superiore al 50% (puro caso).&#xA;&#xA;Sorgente d&#39;entropia&#xA;La casualità è resa possibile dalla sorgente d&#39;entropia che è il dispositivo o il processo fisico che genera il rumore grezzo per produrre dati casuali. È l&#39;origine dell&#39;incertezza e il suo grado di &#34;purezza&#34; è fondamentale per la produzione della casualità.&#xA;&#xA;Le sorgenti di entropia possono essere fisiche (TRNG) o software (PRNG). In quest&#39;ultimo caso si parla di pseudo-casualità perché si tratta di algoritmi che espandono un seed (un seme) casuale in una sequenza anche arbitrariamente lunga che sembra casuale.&#xA;&#xA;Bit di entropia di una sequenza&#xA;O entropia della sequenza, è la misura numerica di quanto sia imprevedibile la sequenza casuale di dati.&#xA;&#xA;Quindi:&#xA;&#xA;la sorgente di entropia è il nostro generatore di incertezza;&#xA;la casualità, la cui qualità dipende totalmente dalla prima, è il processo che produce la sequenza di dati;&#xA;l&#39;entropia, in termini di bit, che è funzione della lunghezza della sequenza e del set di simboli a disposizione, è la misura di quanto la sequenza sia crittograficamente non prevedibile.&#xA;&#xA;Entropia del kernel (CSPRNG)&#xA;Su una qualunque linuxbox il protagonista per la generazione dell&#39;entropia necessaria è ovviamente sua maestà il kernel, che è fatto per essere anche un CSPRNG, impronunciabile acronimo che sta per Cryptographically Secure Pseudo-Random Number Generator.&#xA;&#xA;Il kernel infatti, già dall&#39;avvio, raccoglie entropia (entropy harvesting), rumore casuale direttamente dall&#39;hardware (interrupt del disco, tastiera, mouse, istruzioni CPU come RDRAND). Questi dati grezzi vengono mescolati in un serbatoio (l&#39;entropy pool) da cui l&#39;algoritmo (ChaCha20) pesca per espandere questi dati in un flusso infinito di dati pseudo casuali.&#xA;&#xA;Per avere una misura di quanta casualità abbia il sistema possiamo ricorrere al seguente costrutto:&#xA;cat /proc/sys/kernel/random/entropyavail&#xA;un valore da 256 in poi ci dice abbiamo entropia sufficiente per generare chiavi e quant&#39;altro.&#xA;&#xA;Finita la parte di teoria, vediamo in quanti modi possiamo generare una password bella robusta o un keyfile.&#xA;Come generare password e keyfile&#xA;Per generare sequenze di dati casuali possiamo seguire 2 vie:&#xA;&#xA;attingere direttamente alla sorgente di entropia fornita dal kernel;&#xA;usare la sorgente per prelevare un seme e generare la sequenza casuale via software che è la via di openssl e di pwgen.&#xA;&#xA;Modalità&#xA;&#xA;dd if=/dev/urandom of=mykey.bin bs=4096 count=1 iflag=fullblock status=none&#xA;head -c 4K /dev/urandom   mykey.bin&#xA;tr -dc &#39;[:graph:]&#39;  /dev/urandom | head -c 4096  mykey.txt&#xA;pwgen -s 4095 1   mykey.txt&#xA;openssl rand -out mykey.bin 4096&#xA;&#xA;Analisi&#xA;Come si comportano questi procedimenti? Proviamo ad analizzarli.&#xA;&#xA;Casualità&#xA;Una prima distinzione va fatta sulla modalità di creazione della casualità.&#xA;&#xA;I primi 3 metodi fanno riferimento direttamente alla sorgente senza introdurre altre stratificazioni software. Sul piano teorico, rappresentano il punto più vicino alla casualità fisica che si possa avere su un computer.&#xA;&#xA;Openssl e pwgen no, sono due consumatori per /dev/urandom. &#xA;Devono prima pescare un seme da /dev/urandom.&#xA;Una volta ottenuto il seme, usano i propri algoritmi (quelli di openssl sono solitamente basati su AES-CTR o SHA2) per generare una sequenza infinita di numeri casuali.&#xA;Pwgen fa una cosa simile ma è stato progettato di base per costruire password pronunciabili (minore entropia intrinseca).&#xA;&#xA;Velocità&#xA;Openssl, fra tutti, è il più veloce, soprattutto se si ha l&#39;esigenza di produrre casualità per volumi di decine di giga o di tera.&#xA;Ciò è dovuto al fatto che openssl effettua pochissime syscall per prelevare il seme per poi spremere solo la cpu che, supportando quasi certamente le istruzioni hardware AES-NI, rende il processo poco impegnativo per la cpu stessa e brutalmene efficiente.&#xA;Agire solo sul kernel, pur conservando la purezza della casualità, causa un rallentamento notevole dovuto al grandissimo numero di syscall necessarie e dalla corrispondente attivazione degli algoritmi di cifratura. Inoltre, mentre dd può contare su un buffer relativamente più capiente, cat, tr, head o qualuque altro oggetto che &#34;beva&#34; direttamente da /dev/urandom, hanno dei buffer molto più piccoli a disposizione, 1MB vs 8-16KB, il cui rapporto funge da moltiplicatore sul numero di operazioni necessarie.&#xA;&#xA;Sicurezza&#xA;Tutti i procedimenti indicati, sono estremamente sicuri, anzi, crittograficamente sicuri. Fermo restando che vale sempre l&#39;osservazione fatta sopra sulla metrica dell&#39;entropia di una sequenza casuale: è funzione del set di caratteri e della lunghezza della sequenza. Conti alla mano, con un alfabeto di una settantina di caratteri, una sequenza di almeno 20 caratteri possiederà un&#39;entropia di circa 120 bit che la rendono impenetrabile per gli attuali sistemi di calcolo.&#xA;&#xA;Usare direttamente la sorgente d&#39;entropia, è sicuramente più vantaggioso perché ci fidiamo del kernel.&#xA;Inoltre è più isolato perché lavora a livello del kernel dove i processi utente, anche quelli malevoli, non possono accedere alle sue zone di memoria.&#xA;&#xA;Openssl, pwgen e tutti quelli che sono generatori secondari, possono incorrere in quella che si diefinisce duplicazione della casualità.&#xA;Se l&#39;applicazione non è scritta bene, c&#39;è il rischio che il processo, forkandosi, possa &#34;duplicare&#34; la casualità. In sostanza, i processi padre e figlio finiranno per produrre la stessa sequenza di simboli casuali. Una catastrofe.&#xA;Vecchie versioni di openssl, ante 1.1.1 per es., hanno sofferto di questa anomalia.&#xA;Valutazione&#xA;I metodi 1,2,5 producono un keyfile di dati binari, quindi con un entropia enorme quasi vicina all&#39;ottimo teorico.&#xA;Come detto, openssl è mostruosamente più veloce.&#xA;&#xA;Volendo essere purista, per un keyfile i metodi 1 e 2 (praticamente equivalenti) sono da preferire.&#xA;Per produrre tera di dati casuali (storage, test di rete) sicuramente openssl. Se il volume non dovesse essere esagerato e siamo paranoici, anche il metodo 1 può andare bene.&#xA;&#xA;Per la produzione di una password complessa con simboli stampabili (non necessariamente pronunciabile altrimenti l&#39;entropia sarebbe ancora più bassa) il metodo 3 è da preferire da un punto di vista matematico.&#xA;&#xA;Mettendo da parte openssl che fa comunque un ottimo lavoro (universalmente riconosciuto con tanto di certificazioni FIPS-2), voglio spendere due parole su pwgen.&#xA;pwgen, con il flag -s, crea delle sequenze completamente randomiche su un alfabeto di 62 caratteri.&#xA;Se la lunghezza della sequenza è   = 20, e quindi con un&#39;entropia teorica di ~115-120, avremo delle password abbastanza inviolabili dagli attuali sistemi di calcolo.&#xA;Usare il flag -y potrebbe sembrare una buona idea perché si forza ad estendere il set di caratteri.&#xA;Sicuramente da una parte aumenta l&#39;entropia della sequenza generata, visto che l&#39;alfabeto è molto più vasto. Dall&#39;altra però la forzatura va a compromettere l&#39;uniformità della distribuzione casuale dei simboli.&#xA;Conclusione&#xA;&#xA;password/keyfile stampabile: tr -dc &#39;[:graph:]&#39;  /dev/urandom | head -c [n]  mykey.txt&#xA;password/keyfile binario: head -c [n] /dev/urandom   mykey.bin (equivalentemente dd if=/dev/urandom of=mykey.bin bs=4096 count=1 iflag=fullblock status=none)&#xA;cancellazione disco: openssl rand [dimdisco] | dd of=/dev/sdX bs=1M status=progress&#xA;&#xA;Bonus - Modalità paranoia&#xA;Generazione password&#xA;Se non ci fidassimo della sorgente di casualità, possiamo aggiungere alla sorgente di entropia un nostro segreto personale e &#34;mescolarli&#34; attraverso una funzione sha256 o sha512 rendendo il tutto ancora crittograficamente sicuro.&#xA;&#xA;(head -c 4K /dev/urandom ; read -s -p &#34;Per aumentare l&#39;entropia inserisci una frase segreta o premi tasti a caso: &#34; secret) | sha512sum | cut -d&#39; &#39; -f1   mykey.txt.&#xA;&#xA;È certamente una password molto robusta per violare la quale occorrerebbe compromettere la sorgente d&#39;entropia e indovinare il segreto personale (N.B. stiamo facendo l&#39;ipotesi che si provi a rompere il meccanismo di generazione della chiave non che si provi l&#39;enumerazione attraverso un attacco brute-force).&#xA;&#xA;Generazione keyfile&#xA;Per produrre un keyfile di 4096 bytes con la stessa premessa, faremo uso di openssl.&#xA;&#xA;si genera esplicitamente un seme dalla sorgente di entropia del kernel&#xA;come prima, con sha2 si mescola  il seme con un nostro segreto&#xA;si dà in pasto ad openssl.&#xA;&#xA;Creiamo un seme unico mescolando /dev/urandom e il mio input con sha512&#xA;Usiamo quel seme per generare 4KB di dati casuali &#34;espansi&#34;&#xA;(head -c 256 /dev/urandom; read -s -p &#34;Per aumentare l&#39;entropia inserisci una frase segreta o premi tasti a caso: &#34; secret; echo &#34;$secret&#34;) | sha512sum | cut -d &#34; &#34; -f1 | openssl enc -aes-256-ctr -pbkdf2 -pass stdin -nosalt -in /dev/zero | head -c 4096   mykey.bin&#xA;L&#39;errore che compare alla fine è un falso negativo, dovuto al fatto che openssl sta ancora provando a scrivere dati e head li tronca all&#39;improvviso. &#xA;&#xA;Giusto due righe di spiegazione:&#xA;&#xA;head -c 256 /dev/urandom: preleva un po&#39; di dati casuali &#34;puri&#34;&#xA;read -sp secret: si inserisce una password, una frase o tasti schiacciati a caso per aumentare l&#39;entropia&#xA;sha512sum | cut -d &#34; &#34; -f1: si mescola tutto e si preleva solo l&#39;esadecimale di 64 bytes&#xA;openssl enc -aes-256-ctr -pbkdf2 -pass stdin -nosalt -in /dev/zero: openssl, che riceve il seme sullo stdin, fa la sua magia producendo un fiume di dati casuali&#xA;head -c 4096: tronca il &#34;fiume&#34; alla lunghezza voluta per il nostro keyfile&#xA;&#xA;Quindi:&#xA;&#xA;Contro i bug del kernel: se la nostra sorgente d&#39;entropia fosse compromessa e diventasse deterministica, occorrerebbe comunque conoscere il nostro segreto&#xA;Contro il keylogging: anche se il nostro segreto potesse essere svelato, la sorgente d&#39;entropia garantirebbe comunque l&#39;inviolabilità della nostra password&#xA;&#xA;GPG Random&#xA;Quando si parla di paranoia, un altro ottimo candidato per produrre password e keyfile è certamente GPG.&#xA;GPG non si llimita a copiare dati da /dev/urandom ma utilizza una propria libreria crittografica chiamata Libgcrypt, che implementa un generatore di numeri pseudocasuali, crittograficamente sicuro, molto sofisticato.&#xA;&#xA;A differenza di ciò che abbiamo visto finora, GPG permette di impostare un livello di qualità per la casualità da produrre.&#xA;&#xA;livello 0 (Debole): per scopi didatti, usato raramente.&#xA;livello 1 (Avanzato): adatto per chiavi di sessione e cifratura standard. Corrisponde ad una casualità di alta qualità&#xA;livello 2 (Forte): utilizzato per le chiavi a lungo termine (le chiavi private di GPG). È un livello estremamente conservativo. Se GPG valuta di non avere entropia sufficientemente fresca, si mette in attesa.&#xA;&#xA;GPG non si fida ciecamente del kernel e così Libgcrypt crea un proprio pool di entropia in user space.&#xA;&#xA;Libgcrypt pesca al solito un seme da /dev/urandom&#xA;il seme viene rimescolato con sha2 o aes&#xA;per evitare che i dati casuali finiscano sullo swap, libgcrypt usa pagine di memoria protetta (mlock)&#xA;&#xA;Impostando il livello 2, libgcrypt può decidere di scartare molti più dati se ritiene che il pool di entropia non sia abbastanza &#34;fresco&#34;. Inoltre, in virtù della sua diffidenza, non consegna mai tutto ciò che arriva dal pool di entropia del kernel così come viene, ma viene rimescolato con sha2 o simili e al livello 2 tutto questo, oltre che avvenire con molta più intensità, avviene anche con molta più frequenza (GPG &#34;chiede&#34; spesso bit freschi al kernel) per scongiurare l&#39;eventualità che un attaccante possa prevedere i bit successivi basandosi su quelli passati&#xA;&#xA;Inoltre, GPG salva una parte di questa entropia &#34;pregiata&#34; in ~/.gnupg/randomseed per avere una base di casualità sicura dalle sessioni precedenti nel caso in cui un computer, appena avviato, non avesse ancora accumulato sufficiente entropia.&#xA;&#xA;Si capisce bene come il livello di paranoia di GPG sia fuori scala ma per fortuna tutta questa potenza è totalmente nascosta sotto il cofano di GPG. Infatti per produrre il nostro keyfile binario basta:&#xA;gpg --dev-random 2 4096&#xA;Riepilogo finale&#xA;E dunque, 3 delle 5 modalità sopra descritte, la 2, la 3 e la 5, possono essere ripensate con l&#39;entropia di GPG invee che con quella tipica del kernel.&#xA;2) Keyfile binario&#xA;Kernel entropy&#xA;head -c 4K /dev/urandom   mykey.bin&#xA;&#xA;Libgcrypt entropy&#xA;gpg --dev-random 2 4096 -o mykeygpg.bin&#xA;&#xA;3) Password complessa con caratteri stampabili&#xA;Kernel entropy&#xA;tr -dc &#39;[:graph:]&#39;  /dev/urandom | head -c 4096  mykey.txt&#xA;&#xA;Libgcrypt entropy&#xA;gpg --gen-random 1 10000 | tr -dc &#39;A-Za-z0-9&#39; | head -c 4096   mykeygpg.txt&#xA;&#xA;5) Keyfile binario con openssl&#xA;Kernel entropy&#xA;openssl rand -out mykey.bin 4096&#xA;&#xA;Libgcrypt entropy&#xA;(gpg --gen-random 2 128) | openssl rand -out mykey_gpg.bin -rand /dev/stdin 4096&#xA;&#xA;#entropy #shannon #csprng #password #keyfile #dd #openssl #pwgen #AesCtr #AesNi #sha2 #gpg #bruteforce]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/ffe7c43a6-a8b5f2/hEKmIBrqD2NJ/bA54jpqPlJRapj7UnTRIhqtjGgMEgwrDWtH75WNu.jpg" alt="password"></p>

<p>La generazione di una password o di un keyfile si basa sulla <strong>casualità</strong> ossia sulla capacità del sistema di generare sequenze di simboli non prevedibili.
In questo contesto bisogna avere chiari 3 concetti legati fra loro: <strong>casualità</strong>, <strong>sorgente d&#39;entropia</strong>, <strong>entropia</strong> della password.
</p>
<ul><li><a href="#definizioni-varie" rel="nofollow">Definizioni varie</a></li>
<li><a href="#entropia-del-kernel-csprng" rel="nofollow">Entropia del kernel (CSPRNG)</a></li>
<li><a href="#come-generare-password-e-keyfile" rel="nofollow">Come generare password e keyfile</a>
<ul><li><a href="#analisi" rel="nofollow">Analisi</a></li>
<li><a href="#valutazione" rel="nofollow">Valutazione</a></li>
<li><a href="#conclusione" rel="nofollow">Conclusione</a></li></ul></li>
<li><a href="#bonus-modalit%C3%A0-paranoia" rel="nofollow">Bonus – Modalità paranoia</a>
<ul><li><a href="#generazione-password" rel="nofollow">Generazione password</a></li>
<li><a href="#generazione-keyfile" rel="nofollow">Generazione keyfile</a></li>
<li><a href="#gpg-random" rel="nofollow">GPG Random</a></li></ul></li>
<li><a href="#riepilogo-finale" rel="nofollow">Riepilogo finale</a>
<ul><li><a href="#2-keyfile-binario" rel="nofollow">2) Keyfile binario</a></li>
<li><a href="#3-password-complessa-con-caratteri-stampabili" rel="nofollow">3) Password complessa con caratteri stampabili</a></li>
<li><a href="#5-keyfile-binario-con-openssl" rel="nofollow">5) Keyfile binario con openssl</a></li></ul></li></ul>

<h2 id="definizioni-varie">Definizioni varie</h2>

<p><strong>Casualità</strong>
In generale, posso parlare di <strong>casualità</strong> quando non riesco ad individuare un pattern o un&#39;organizzazione deterministica in una sequenza di dati.</p>

<p>Da un punto di vista crittografico, una sequenza è considerata “casuale” se non esiste un algoritmo che possa prevedere il bit successivo con una probabilità superiore al 50% (puro caso).</p>

<p><strong>Sorgente d&#39;entropia</strong>
La casualità è resa possibile dalla sorgente d&#39;entropia che è il dispositivo o il processo fisico che genera il rumore grezzo per produrre dati casuali. È l&#39;origine dell&#39;incertezza e il suo grado di “purezza” è fondamentale per la produzione della casualità.</p>

<p>Le sorgenti di entropia possono essere fisiche (<strong>TRNG</strong>) o software (<strong>PRNG</strong>). In quest&#39;ultimo caso si parla di <strong>pseudo-casualità</strong> perché si tratta di algoritmi che espandono un seed (un seme) casuale in una sequenza anche arbitrariamente lunga che <strong>sembra</strong> casuale.</p>

<p><strong>Bit di entropia di una sequenza</strong>
O <strong>entropia della sequenza</strong>, è la misura numerica di quanto sia imprevedibile la sequenza casuale di dati.</p>

<p>Quindi:</p>
<ul><li>la <strong>sorgente di entropia</strong> è il nostro <strong>generatore</strong> di incertezza;</li>
<li>la <strong>casualità</strong>, la cui qualità dipende totalmente dalla prima, è il <strong>processo</strong> che produce la sequenza di dati;</li>
<li>l&#39;<strong>entropia</strong>, in termini di bit, che è funzione della lunghezza della sequenza e del set di simboli a disposizione, è la <strong>misura</strong> di quanto la sequenza sia crittograficamente non prevedibile.</li></ul>

<h2 id="entropia-del-kernel-csprng">Entropia del kernel (CSPRNG)</h2>

<p>Su una qualunque linuxbox il protagonista per la generazione dell&#39;entropia necessaria è ovviamente sua maestà il kernel, che è fatto per essere anche un <strong>CSPRNG</strong>, impronunciabile acronimo che sta per <strong>C</strong>ryptographically <strong>S</strong>ecure <strong>P</strong>seudo-<strong>R</strong>andom <strong>N</strong>umber <strong>G</strong>enerator.</p>

<p>Il kernel infatti, già dall&#39;avvio, raccoglie entropia (<strong>entropy harvesting</strong>), rumore casuale direttamente dall&#39;hardware (interrupt del disco, tastiera, mouse, istruzioni CPU come <strong>RDRAND</strong>). Questi dati grezzi vengono mescolati in un serbatoio (l&#39;<strong>entropy pool</strong>) da cui l&#39;algoritmo (<strong>ChaCha20</strong>) pesca per espandere questi dati in un flusso infinito di dati pseudo casuali.</p>

<p>Per avere una misura di quanta casualità abbia il sistema possiamo ricorrere al seguente costrutto:</p>

<pre><code class="language-bash">cat /proc/sys/kernel/random/entropy_avail
</code></pre>

<p>un valore da <strong>256</strong> in poi ci dice abbiamo entropia sufficiente per generare chiavi e quant&#39;altro.</p>

<p>Finita la parte di teoria, vediamo in quanti modi possiamo generare una password bella robusta o un keyfile.</p>

<h2 id="come-generare-password-e-keyfile">Come generare password e keyfile</h2>

<p>Per generare sequenze di dati casuali possiamo seguire 2 vie:</p>
<ol><li>attingere direttamente alla sorgente di entropia fornita dal kernel;</li>
<li>usare la sorgente per prelevare un seme e generare la sequenza casuale via software che è la via di openssl e di pwgen.</li></ol>

<p><strong>Modalità</strong></p>
<ol><li><code>dd if=/dev/urandom of=mykey.bin bs=4096 count=1 iflag=fullblock status=none</code></li>
<li><code>head -c 4K /dev/urandom &gt; mykey.bin</code></li>
<li><code>tr -dc &#39;[:graph:]&#39; &lt; /dev/urandom | head -c 4096 &gt; mykey.txt</code></li>
<li><code>pwgen -s 4095 1 &gt; mykey.txt</code></li>
<li><code>openssl rand -out mykey.bin 4096</code></li></ol>

<h3 id="analisi">Analisi</h3>

<p>Come si comportano questi procedimenti? Proviamo ad analizzarli.</p>

<p><strong>Casualità</strong>
Una prima distinzione va fatta sulla modalità di creazione della casualità.</p>

<p>I primi 3 metodi fanno riferimento direttamente alla sorgente senza introdurre altre stratificazioni software. Sul piano teorico, rappresentano il punto più vicino alla casualità fisica che si possa avere su un computer.</p>

<p><strong>Openssl</strong> e <strong>pwgen</strong> no, sono due <strong>consumatori</strong> per <code>/dev/urandom</code>.
Devono prima pescare un seme da /dev/urandom.
Una volta ottenuto il seme, usano i propri algoritmi (quelli di openssl sono solitamente basati su <strong>AES-CTR</strong> o <strong>SHA2</strong>) per generare una sequenza infinita di numeri casuali.
Pwgen fa una cosa simile ma è stato progettato di base per costruire password pronunciabili (minore entropia intrinseca).</p>

<p><strong>Velocità</strong>
<strong>Openssl</strong>, fra tutti, è il più veloce, soprattutto se si ha l&#39;esigenza di produrre casualità per volumi di decine di giga o di tera.
Ciò è dovuto al fatto che openssl effettua pochissime syscall per prelevare il seme per poi spremere solo la cpu che, supportando quasi certamente le istruzioni hardware <strong>AES-NI</strong>, rende il processo poco impegnativo per la cpu stessa e brutalmene efficiente.
Agire solo sul kernel, pur conservando la purezza della casualità, causa un rallentamento notevole dovuto al grandissimo numero di syscall necessarie e dalla corrispondente attivazione degli algoritmi di cifratura. Inoltre, mentre dd può contare su un buffer relativamente più capiente, cat, tr, head o qualuque altro oggetto che “beva” direttamente da <code>/dev/urandom</code>, hanno dei buffer molto più piccoli a disposizione, 1MB vs 8-16KB, il cui rapporto funge da moltiplicatore sul numero di operazioni necessarie.</p>

<p><strong>Sicurezza</strong>
Tutti i procedimenti indicati, sono estremamente sicuri, anzi, crittograficamente sicuri. Fermo restando che vale sempre l&#39;osservazione fatta sopra sulla metrica dell&#39;entropia di una sequenza casuale: è funzione del set di caratteri e della lunghezza della sequenza. Conti alla mano, con un alfabeto di una settantina di caratteri, una sequenza di almeno 20 caratteri possiederà un&#39;entropia di circa 120 bit che la rendono impenetrabile per gli attuali sistemi di calcolo.</p>

<p>Usare direttamente la sorgente d&#39;entropia, è sicuramente più vantaggioso perché ci fidiamo del kernel.
Inoltre è più isolato perché lavora a livello del kernel dove i processi utente, anche quelli malevoli, non possono accedere alle sue zone di memoria.</p>

<p>Openssl, pwgen e tutti quelli che sono <strong>generatori secondari</strong>, possono incorrere in quella che si diefinisce <strong>duplicazione della casualità</strong>.
Se l&#39;applicazione non è scritta bene, c&#39;è il rischio che il processo, forkandosi, possa “duplicare” la casualità. In sostanza, i processi padre e figlio finiranno per produrre la stessa sequenza di simboli casuali. Una catastrofe.
Vecchie versioni di openssl, ante 1.1.1 per es., hanno sofferto di questa anomalia.</p>

<h3 id="valutazione">Valutazione</h3>

<p>I metodi 1,2,5 producono un keyfile di dati binari, quindi con un entropia enorme quasi vicina all&#39;ottimo teorico.
Come detto, openssl è mostruosamente più veloce.</p>

<p>Volendo essere purista, per un keyfile i metodi 1 e 2 (praticamente equivalenti) sono da preferire.
Per produrre tera di dati casuali (storage, test di rete) sicuramente openssl. Se il volume non dovesse essere esagerato e siamo paranoici, anche il metodo 1 può andare bene.</p>

<p>Per la produzione di una password complessa con simboli stampabili (non necessariamente pronunciabile altrimenti l&#39;entropia sarebbe ancora più bassa) il metodo 3 è da preferire da un punto di vista matematico.</p>

<p>Mettendo da parte openssl che fa comunque un ottimo lavoro (universalmente riconosciuto con tanto di certificazioni FIPS-2), voglio spendere due parole su <strong>pwgen</strong>.
<strong>pwgen</strong>, con il flag <code>-s</code>, crea delle sequenze completamente randomiche su un alfabeto di 62 caratteri.
Se la lunghezza della sequenza è &gt;= 20, e quindi con un&#39;entropia teorica di ~115-120, avremo delle password abbastanza inviolabili dagli attuali sistemi di calcolo.
Usare il flag <code>-y</code> potrebbe sembrare una buona idea perché si forza ad estendere il set di caratteri.
Sicuramente da una parte aumenta l&#39;entropia della sequenza generata, visto che l&#39;alfabeto è molto più vasto. Dall&#39;altra però la forzatura va a compromettere l&#39;uniformità della distribuzione casuale dei simboli.</p>

<h3 id="conclusione">Conclusione</h3>
<ol><li><strong>password/keyfile stampabile</strong>: <code>tr -dc &#39;[:graph:]&#39; &lt; /dev/urandom | head -c [n] &gt; mykey.txt</code></li>
<li><strong>password/keyfile binario</strong>: <code>head -c [n] /dev/urandom &gt; mykey.bin</code> (equivalentemente <code>dd if=/dev/urandom of=mykey.bin bs=4096 count=1 iflag=fullblock status=none</code>)</li>
<li><strong>cancellazione disco</strong>: <code>openssl rand [dim_disco] | dd of=/dev/sdX bs=1M status=progress</code></li></ol>

<h2 id="bonus-modalità-paranoia">Bonus – Modalità paranoia</h2>

<h3 id="generazione-password">Generazione password</h3>

<p>Se non ci fidassimo della sorgente di casualità, possiamo aggiungere alla sorgente di entropia un nostro segreto personale e “mescolarli” attraverso una funzione sha256 o sha512 rendendo il tutto ancora crittograficamente sicuro.</p>

<pre><code class="language-bash">(head -c 4K /dev/urandom ; read -s -p &#34;Per aumentare l&#39;entropia inserisci una frase segreta o premi tasti a caso: &#34; secret) | sha512sum | cut -d&#39; &#39; -f1 &gt; mykey.txt.
</code></pre>

<p>È certamente una password molto robusta per violare la quale occorrerebbe compromettere la sorgente d&#39;entropia e indovinare il segreto personale (<strong>N.B.</strong> stiamo facendo l&#39;ipotesi che si provi a rompere il meccanismo di generazione della chiave non che si provi l&#39;enumerazione attraverso un attacco brute-force).</p>

<h3 id="generazione-keyfile">Generazione keyfile</h3>

<p>Per produrre un keyfile di 4096 bytes con la stessa premessa, faremo uso di openssl.</p>
<ol><li>si genera esplicitamente un seme dalla sorgente di entropia del kernel</li>
<li>come prima, con sha2 si mescola  il seme con un nostro segreto</li>
<li>si dà in pasto ad openssl.</li></ol>

<pre><code class="language-bash"># Creiamo un seme unico mescolando /dev/urandom e il mio input con sha512
# Usiamo quel seme per generare 4KB di dati casuali &#34;espansi&#34;
(head -c 256 /dev/urandom; read -s -p &#34;Per aumentare l&#39;entropia inserisci una frase segreta o premi tasti a caso: &#34; secret; echo &#34;$secret&#34;) | sha512sum | cut -d &#34; &#34; -f1 | openssl enc -aes-256-ctr -pbkdf2 -pass stdin -nosalt -in /dev/zero | head -c 4096 &gt; mykey.bin
</code></pre>

<p>L&#39;errore che compare alla fine è un falso negativo, dovuto al fatto che openssl sta ancora provando a scrivere dati e <code>head</code> li tronca all&#39;improvviso.</p>

<p>Giusto due righe di spiegazione:</p>
<ol><li><code>head -c 256 /dev/urandom</code>: preleva un po&#39; di dati casuali “puri”</li>
<li><code>read -sp secret</code>: si inserisce una password, una frase o tasti schiacciati a caso per aumentare l&#39;entropia</li>
<li><code>sha512sum | cut -d &#34; &#34; -f1</code>: si mescola tutto e si preleva solo l&#39;esadecimale di 64 bytes</li>
<li><code>openssl enc -aes-256-ctr -pbkdf2 -pass stdin -nosalt -in /dev/zero</code>: openssl, che riceve il seme sullo stdin, fa la sua magia producendo un fiume di dati casuali</li>
<li><code>head -c 4096</code>: tronca il “fiume” alla lunghezza voluta per il nostro keyfile</li></ol>

<p>Quindi:</p>
<ol><li><strong>Contro i bug del kernel</strong>: se la nostra sorgente d&#39;entropia fosse compromessa e diventasse deterministica, occorrerebbe comunque conoscere il nostro segreto</li>
<li><strong>Contro il keylogging</strong>: anche se il nostro segreto potesse essere svelato, la sorgente d&#39;entropia garantirebbe comunque l&#39;inviolabilità della nostra password</li></ol>

<h3 id="gpg-random">GPG Random</h3>

<p>Quando si parla di paranoia, un altro ottimo candidato per produrre password e keyfile è certamente <strong>GPG</strong>.
GPG non si llimita a copiare dati da <code>/dev/urandom</code> ma utilizza una propria libreria crittografica chiamata <strong>Libgcrypt</strong>, che implementa un generatore di numeri pseudocasuali, crittograficamente sicuro, molto sofisticato.</p>

<p>A differenza di ciò che abbiamo visto finora, GPG permette di impostare un livello di qualità per la casualità da produrre.</p>
<ol><li><strong>livello 0 (Debole)</strong>: per scopi didatti, usato raramente.</li>
<li><strong>livello 1 (Avanzato)</strong>: adatto per chiavi di sessione e cifratura standard. Corrisponde ad una casualità di alta qualità</li>
<li><strong>livello 2 (Forte)</strong>: utilizzato per le chiavi a lungo termine (le chiavi private di GPG). È un livello estremamente conservativo. Se GPG valuta di non avere entropia sufficientemente fresca, si mette in attesa.</li></ol>

<p>GPG non si fida ciecamente del kernel e così <strong>Libgcrypt crea un proprio pool di entropia</strong> in user space.</p>
<ol><li>Libgcrypt pesca al solito un seme da <code>/dev/urandom</code></li>
<li>il seme viene rimescolato con sha2 o aes</li>
<li>per evitare che i dati casuali finiscano sullo swap, libgcrypt usa <strong>pagine di memoria protetta</strong> (<strong>mlock</strong>)</li></ol>

<p>Impostando il livello 2, libgcrypt può decidere di scartare molti più dati se ritiene che il pool di entropia non sia abbastanza “fresco”. Inoltre, in virtù della sua diffidenza, <strong>non consegna mai</strong> tutto ciò che arriva dal pool di entropia del kernel così come viene, ma viene rimescolato con sha2 o simili e al livello 2 tutto questo, oltre che avvenire con molta più intensità, avviene anche con molta più frequenza (GPG “chiede” spesso bit freschi al kernel) per scongiurare l&#39;eventualità che un attaccante possa prevedere i bit successivi basandosi su quelli passati</p>

<p>Inoltre, GPG salva una parte di questa entropia “pregiata” in <code>~/.gnupg/random_seed</code> per avere una base di casualità sicura dalle sessioni precedenti nel caso in cui un computer, appena avviato, non avesse ancora accumulato sufficiente entropia.</p>

<p>Si capisce bene come il livello di paranoia di GPG sia fuori scala ma per fortuna tutta questa potenza è totalmente nascosta sotto il cofano di GPG. Infatti per produrre il nostro keyfile binario basta:</p>

<pre><code class="language-bash">gpg --dev-random 2 4096
</code></pre>

<h2 id="riepilogo-finale">Riepilogo finale</h2>

<p>E dunque, 3 delle 5 modalità sopra descritte, la 2, la 3 e la 5, possono essere ripensate con l&#39;entropia di GPG invee che con quella tipica del kernel.</p>

<h3 id="2-keyfile-binario">2) Keyfile binario</h3>
<ul><li><p><strong>Kernel entropy</strong></p>

<pre><code class="language-bash">head -c 4K /dev/urandom &gt; mykey.bin
</code></pre></li>

<li><p><strong>Libgcrypt entropy</strong></p>

<pre><code class="language-bash">gpg --dev-random 2 4096 -o mykey_gpg.bin
</code></pre></li></ul>

<h3 id="3-password-complessa-con-caratteri-stampabili">3) Password complessa con caratteri stampabili</h3>
<ul><li><p><strong>Kernel entropy</strong></p>

<pre><code class="language-bash">tr -dc &#39;[:graph:]&#39; &lt; /dev/urandom | head -c 4096 &gt; mykey.txt
</code></pre></li>

<li><p><strong>Libgcrypt entropy</strong></p>

<pre><code class="language-bash">gpg --gen-random 1 10000 | tr -dc &#39;A-Za-z0-9&#39; | head -c 4096 &gt; mykey_gpg.txt
</code></pre></li></ul>

<h3 id="5-keyfile-binario-con-openssl">5) Keyfile binario con openssl</h3>
<ul><li><p><strong>Kernel entropy</strong></p>

<pre><code class="language-bash">openssl rand -out mykey.bin 4096
</code></pre></li>

<li><p><strong>Libgcrypt entropy</strong></p>

<pre><code class="language-bash">(gpg --gen-random 2 128) | openssl rand -out mykey_gpg.bin -rand /dev/stdin 4096
</code></pre></li></ul>

<p><a href="/aytin/tag:entropy" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">entropy</span></a> <a href="/aytin/tag:shannon" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">shannon</span></a> <a href="/aytin/tag:csprng" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">csprng</span></a> <a href="/aytin/tag:password" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">password</span></a> <a href="/aytin/tag:keyfile" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">keyfile</span></a> <a href="/aytin/tag:dd" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">dd</span></a> <a href="/aytin/tag:openssl" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">openssl</span></a> <a href="/aytin/tag:pwgen" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">pwgen</span></a> <a href="/aytin/tag:AesCtr" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">AesCtr</span></a> <a href="/aytin/tag:AesNi" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">AesNi</span></a> <a href="/aytin/tag:sha2" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">sha2</span></a> <a href="/aytin/tag:gpg" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">gpg</span></a> <a href="/aytin/tag:bruteforce" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">bruteforce</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di</guid>
      <pubDate>Mon, 12 Jan 2026 14:39:55 +0000</pubDate>
    </item>
    <item>
      <title>Gestire la tua chiave GPG</title>
      <link>https://noblogo.org/aytin/gestire-la-tua-chiave-gpg</link>
      <description>&lt;![CDATA[gpg tools&#xA;&#xA;Esistono numerose gui che semplificano la gestione di una chiave gpg.&#xA;&#xA;Questo articolo ha lo scopo di semplificare la creazione di una chiave gpg attraverso la cli di GnuPG, senza entrare nel suo mare magnum di opzioni.&#xA;!--more--&#xA;&#xA;Indice&#xA;&#xA;a href=&#34;#premessa&#34;Premessa/a&#xA;a href=&#34;#gestione-della-chiave&#34;Gestione della chiave/a&#xA;a href=&#34;#come-proteggere-il-nostro-keyring&#34;Come proteggere il nostro keyring/a&#xA;a href=&#34;#cos-e-un-keyserver&#34;Cos&#39;è un keyerver/a&#xA;&#xA;----&#xA;&#xA;a id=premessa&#34;Premessa/a&#xA;Cosa NON è una chiave gpg?&#xA;Una coppia di chiavi, una pubblica e una privata basate sulla crittografia asimmetrica.&#xA;&#xA;Cos&#39;è una chiave gpg?&#xA;Non è solo una coppia di chiavi asimmetriche ma è un certificato.&#xA;Dal punto di vista delle informazioni, una chiave gpg contiene:&#xA;&#xA;informazioni identificative (nome, commento, email, foto, ecc)&#xA;informazioni non identificative (dati tecnici che fanno parte delle chiavi: scadenza, keyserver, algoritmi di hash e cifratura, revoker ecc.)&#xA;&#xA;Una chiave gpg, in definitiva, è costituita da: &#xA;&#xA;una chiave primaria (detta anche secret key o master key)&#xA;da una o più sottochiavi&#xA;da una serie di informazioni personali.&#xA;&#xA;Ognuna di queste &#34;chiavi&#34; è in realtà una coppia di chiavi asimmetriche dotate delle seguenti autorizzazioni: &#xA;&#xA;Certificazione: capacità della chiave di firmare, e quindi validare, le chiavi gpg di altri utenti.&#xA;Firma: capacità di firmare documenti.&#xA;Cifratura: capacità di cifrare documenti.&#xA;Autenticazione: capacità di autenticare l&#39;utente su alcuni protocolli come TLS o SSH.&#xA;&#xA;La certificazione, ossia la capacità di validare altre chiavi oltre la propria, è esclusiva della master key.&#xA;Le altre autorizzazioni possono essere delegate alle sottochiavi.&#xA;&#xA;Certificazioni e firma, garantiscono autenticazione, integrità e non ripudio del mittente.&#xA;La cifratura garantisce confidenzialità.&#xA;Le prime due sono da considerarsi più critiche e normalmente assegnate alla master key.&#xA;&#xA;Una chiave può avere una o più proprietà. Di default, gpg crea una master key con autorizzazioni per firma e certificazione e una sottochiave con autorizzazioni per cifratura.&#xA;a id=&#34;gestione-della-chiave&#34;Gestione della chiave/a&#xA;Per la creazione e la gestione della chiave nei suoi elementi principali, vedremo:&#xA;&#xA;come creare la chiave primaria&#xA;come aggiungere sottochiavi, uid&#xA;come modificare password o scadenza&#xA;come si certifica un&#39;altra chiave con la nostra (firma di chiave)&#xA;come si cancellano localmente uid, sottochiavi e firme&#xA;come si revoca un certificato, una sottochiave, un uid o una certificazione&#xA;come si usa un keyserver per la pubblicazione e la ricerca delle chiavi&#xA;&#xA;Creazione della chiave primaria&#xA;gpg --quick-gen-key uid algo auth expire, dove&#xA;- uid: &#34;uidname (comment) e-mail&#34;&#xA;- algo: uno fra &#39;gpg --with-colons --list-config&#39;&#xA;- auth: cert|encr|sign&#xA;- expire: 0 =  illimitato, ny|nm|nd =  n anni|mesi|giorni&#xA;gpg --quick-gen-key gandalf ed25519 cert 0&#xA;Crea una chiave gpg la cui secret key può solo certificare, l&#39;uid è composto dal solo nome gandalf e ha scadenza illimitata.&#xA;gpg -K&#xA;/home/gandalf/.gnupg/pubring.kbx&#xA;--------------------------------&#xA;sec   ed25519/0xE01BDCB6A3C6778B 2024-11-05 [C]&#xA;&#x9;  8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B&#xA;uid                   [ultimate] gandalf&#xA;Ecco la chiave appena creata, nella prima riga distinguiamo: &#xA;&#xA;&#34;sec&#34;, sta per secret key&#xA;algoritmo/KeyID&#xA;data di creazione&#xA;capability ([C]=certify). &#xA;&#xA;Nella riga successiva è visibile il fingerprint e nella terza, l&#39;uid (gandalf). Questi elementi, come il KeyID, servono per indirizzare la chiave.&#xA;&#xA;Una sintassi più completa sarebbe:&#xA;gpg --quick-gen-key &#34;nome (commento) e-mail&#34; algo cert|sign|encr scadenza&#xA;Per avere una lista degli algo:&#xA;gpg --with-colons --list-config&#xA;Aggiungere una sottochiave&#xA;Aggiungiamo le chiavi di firma e di cifratura con scadenza 5 anni e 1 anno rispettivamente&#xA;gpg --quick-addgen-key fpr algo auth expire&#xA;gpg --quick-add-key 8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B ed25519 sign 5y&#xA;gpg --quick-add-key 8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B cv25519 encr 1y&#xA;Come prima, oltre alla secret key, ora sono visibili le sottochiavi (ssb, Secret SubKey) di firma e cifratura con le evidenze per:&#xA;algoritmo, KeyID, creazione, capability ([S] per sign e [E] per encrypt) e scadenza.&#xA;gpg -K&#xA;/home/gandalf/.gnupg/pubring.kbx&#xA;--------------------------------&#xA;sec   ed25519/0xE01BDCB6A3C6778B 2024-11-05 [C]&#xA;&#x9;  8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B&#xA;uid                   [ultimo] gandalf&#xA;ssb   ed25519/0xA391F0548FB542DB 2024-11-05 [S] [scadenza: 2029-11-04]&#xA;ssb   cv25519/0xAAEF649D51D832E8 2024-11-05 [E] [scadenza: 2025-11-05]&#xA;Meccanismi di indirizzamento per una chiave&#xA;Una chiave può essere riferita attraverso l&#39;uid, il key ID o il fingerprint. Il riferimento è importante nelle operazioni di manipolazione della chiave.&#xA;gpg --with-subkey-fingerprint -K&#xA;/home/gandalf/.gnupg/pubring.kbx&#xA;--------------------------------&#xA;sec   ed25519/0xE01BDCB6A3C6778B 2024-11-05 [C]&#xA;&#x9;  8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B&#xA;uid                   [ultimate] gandalf&#xA;uid                   [ultimate] Gandalf Il Bianco (Questa è la chiave di Gandalf Il Bianco) gandalf@lotr.org&#xA;ssb   ed25519/0xA391F0548FB542DB 2024-11-05 [S] [expires: 2029-11-04]&#xA;&#x9;  87EF9CF3D5A4D78ADA80E364A391F0548FB542DB&#xA;ssb   cv25519/0xAAEF649D51D832E8 2024-11-05 [E] [expires: 2025-11-04]&#xA;&#x9;  4DD33D36C54E2247486C9DC7AAEF649D51D832E8&#xA;&#xA;0xE01BDCB6A3C6778B è il key ID della master key&#xA;8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B è il fingerprint della master key&#xA;gandalf è uno degli uid&#xA;&#xA;Aggiungere un uid&#xA;Aggiunge un nuovo uid in termini di nome-commento-email e lo battezza come primario.&#xA;gpg --quick-add-uid primaryuid newuid&#xA;gpg --quick-add-uid gandalf &#34;Gandalf Il Bianco (Questa è la chiave di Gandalf Il Bianco) gandalf@lotr.org&#34;&#xA;&#xA;gpg --quick-set-primary-uid primaryuid newuid&#xA;gpg --quick-set-primary-uid &#34;gandalf&#34; &#34;Gandalf Il Bianco (Questa è la chiave di Gandalf Il Bianco) gandalf@lotr.org&#34;&#xA;Firmare una chiave&#xA;&#xA;Ossia riconoscere una chiave gpg come valida attraverso la certificazione.&#xA;Pubblicare questa chiave sul keyserver, comunica al mondo che riconosciamo quella chiave come valida.&#xA;&#xA;Convalida tutti gli uid della chiave identificata da fpr&#xA;gpg --quick-sign-key fpr&#xA;gpg --quick-sign-key AD59879E1CB5D63E98F05FB9204621DACB1296E0&#xA;Convalida un uid specifico della chiave identificata da fpr&#xA;gpg --quick-sign-key fpr uid&#xA;gpg --quick-sign-key AD59879E1CB5D63E98F05FB9204621DACB1296E0 frodo&#xA;Modificare la password&#xA;Inserisce la password con cui tutte le chiavi private (master key e subkey) relative all&#39;uid indicato, vengono cifrate. Se la password viene lasciata vuota, la chiave non viene cifrata.&#xA;gpg --passwd uid|KeyID|fpr&#xA;gpg --passwd gandalf&#xA;Modificare la scadenza&#xA;Modifico le scadenze delle chiavi come segue:&#xA;&#xA;la master key da illimitata a 10 anni&#xA;la sottochiave di firma da 5 anni a 4 anni&#xA;la sottochiave di cifratura da 1 anno a 2 anni&#xA;&#xA;gpg --quick-set-expire fpr expire&#xA;gpg --quick-set-expire 8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B 10y&#xA;gpg --quick-set-expire 8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B 4y 87EF9CF3D5A4D78ADA80E364A391F0548FB542DB&#xA;gpg --quick-set-expire 8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B 2y 4DD33D36C54E2247486C9DC7AAEF649D51D832E8&#xA;gpg --with-subkey-fingerprint -K&#xA;/home/gandalf/.gnupg/pubring.kbx&#xA;--------------------------------&#xA;sec   ed25519/0xE01BDCB6A3C6778B 2024-11-05 [C] [expires: 2034-11-04]&#xA;&#x9;  8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B&#xA;uid                   [ultimate] gandalf&#xA;uid                   [ultimate] Gandalf Il Bianco (Questa è la chiave di Gandalf Il Bianco) gandalf@lotr.org&#xA;ssb   ed25519/0xA391F0548FB542DB 2024-11-05 [S] [expires: 2028-11-04]&#xA;&#x9;  87EF9CF3D5A4D78ADA80E364A391F0548FB542DB&#xA;ssb   cv25519/0xAAEF649D51D832E8 2024-11-05 [E] [expires: 2026-11-04]&#xA;&#x9;  4DD33D36C54E2247486C9DC7AAEF649D51D832E8&#xA;Cancellazione di elementi dal keyring&#xA;La cancellazione di elementi come uid, firme o sottochiavi ha effetto solo sul keyring locale.&#xA;Se la chiave è stata pubblicata su un repository, le cancellazioni non avranno alcun effetto.&#xA;Se si vuole inibire uno di questi elementi, si deve ricorrere alla revoca che è esportabile sui keyserver.&#xA;Cancellare una sottochiave&#xA;Cancella la sottochiave di firma&#xA;gpg --delete-secret-and-public-keys KeyID|fpr&#xA;gpg --delete-secret-and-public-keys 87EF9CF3D5A4D78ADA80E364A391F0548FB542DB!&#xA;o, equivalentemente&#xA;gpg --delete-secret-and-public-keys 0xA391F0548FB542DB!&#xA;Cancellare un uid&#xA;Cancella la seconda identità della chiave gandalf (0xA391F0548FB542DB)&#xA;gpg --edit-key [KeyID|fpr|uid]&#xA;gpg --edit-key gandalf&#xA;    uid 2&#xA;    deluid&#xA;    save&#xA;Cancellare una firma&#xA;Cancella tutte le firme del 2° uid che non siano self-signature.&#xA;gpg --edit-key [KeyID|fpr|uid]&#xA;gpg --edit-key gandalf&#xA;    uid 2&#xA;    delsig&#xA;    save&#xA;Operazioni di revoca&#xA;Per quel che riguarda le chiavi gpg (i certificati) di cui si possiede la chiave privata, l&#39;operazione di revoca può avvenire su uno degli elementi della chiave o sull&#39;intero certificato.&#xA;Revocare un uid&#xA;Revoco l&#39;uid (gandalf il grigio),&#xA;gpg --quick-revuid primaryuid uid &#xA;gpg --quick-revuid gandalf &#34;gandalf il grigio&#34;&#xA;Revocare una sottochiave&#xA;gpg --edit-key [KeyID|fpr|uid]&#xA;gpg --edit-key 0xA391F0548FB542DB&#xA;    key 1&#xA;    revkey&#xA;    save&#xA;Revocare una nostra certificazione&#xA;Così come validiamo le chiavi altrui con la nostra firma di certificazione, allo stesso modo possiamo revocarla.&#xA;&#xA;Revoco la mia firma su tutti gli uid di una chiave pubblica&#xA;gpg --quick-revoke-sig KeyID|fpr del firmato KeyID|fpr del firmante &#xA;gpg --quick-revoke-sig 0x204621DACB1296E0 0xE01BDCB6A3C6778B&#xA;Posso anche revocare la mia firma su un uid specifico&#xA;gpg --quick-revoke-sig KeyID|fpr del firmato KeyID|fpr del firmante uidi&#xA;gpg --quick-revoke-sig 0x204621DACB1296E0 0xE01BDCB6A3C6778B frodouid2&#xA;Revocare l&#39;intero certificato&#xA;Va a revocare non solo tutti gli uid e tutte le sottochiavi, ma anche la masterkey.&#xA;gpg --import 87EF9CF3D5A4D78ADA80E364A391F0548FB542DB.rev&#xA;Il certificato di revoca viene generato all&#39;atto della creazione della chiave.&#xA;Se non ci fosse, conviene sempre crearlo così che, se la master key venisse compromessa, saremmo almeno in grado di revocare l&#39;intero certificato.&#xA;gpg -o file --gen-rev fpr&#xA;gpg -o 87EF9CF3D5A4D78ADA80E364A391F0548FB542DB.rev --gen-rev 87EF9CF3D5A4D78ADA80E364A391F0548FB542DB&#xA;Le operazioni di revoca, nel mondo gpg, corrispondono alle maledizioni senza perdono, nel mondo di Harry Potter.&#xA;Non si torna indietro a meno di un backup, e se le revoche vengono pubblicate su un keyserver, diventano irreversibili.&#xA;Operazioni sul keyserver&#xA;Il caricamento delle chiavi su un keyserver costituisce la finalizzazione delle operazioni svolte finora.&#xA;&#xA;Il keyserver pubblica al mondo le nostre chiavi, la configurazione avviene nel file dirmngr.conf aggiungendo una riga (ad es. per keys.openpgp.org):&#xA;vi dirmngr.conf&#xA;&#xA;...&#xA;keyserver hkps://keys.openpgp.org&#xA;...&#xA;e ricaricando la configurazione:&#xA;gpgconf --reload dirmngr&#xA;Cerca&#xA;Cerca nel keyserver le chiavi con uid specificato. In caso di successo, chiede se possono essere aggiunte al keyring.&#xA;gpg --search-keys uid&#xA;gpg --search-keys 0xE01BDCB6A3C6778B 0x204621DACB1296E0&#xA;Per gli utilizzatori di keys.openpgp.org:&#xA;gpg --auto-key-locate keyserver --locate-keys uid&#xA;Invia&#xA;Invia una lista di chiavi al keyserver&#xA;gpg --send-keys KeyIDs|fpr&#xA;gpg --send-keys 0xE01BDCB6A3C6778B 0x204621DACB1296E0&#xA;Per gli utilizzatori di keys.openpgp.org:&#xA;Il classico send non è sufficiente perché non sarebbe possibile validare la mail di conferma. Si consiglia, non volendo usare l&#39;interfaccia web, di usare il seguente comando:&#xA;gpg --export KeyID|fpr|uid | curl -T - https://keys.openpgp.org&#xA;gpg --export 0xE01BDCB6A3C6778B | curl -T - https://keys.openpgp.org&#xA;che restituisce un link diretto alla pagina di verifica.&#xA;Ricevi&#xA;Scarica dal keyserver le chiavi&#xA;gpg --keyserver-options honor-keyserver-url --receive-keys KeyIDs|fpr&#xA;gpg --keyserver-options honor-keyserver-url --receive-keys 0xE01BDCB6A3C6778B 0x204621DACB1296E0&#xA;Scarica dal keyserver la chiave indicata dall&#39;uri&#xA;gpg --fetch-keys uri&#xA;gpg --fetch-keys https://keyserver.ubuntu.com/pks/lookup?search=0xE01BDCB6A3C6778B&amp;fingerprint=on&amp;op=index&#xA;Aggiorna&#xA;Per rinnovare tutte le chiavi pubbliche del keyring.&#xA;gpg --keyserver-options honor-keyserver-url --refresh-keys&#xA;a id=&#34;come-proteggere-il-nostro-keyring&#34;Come proteggere il nostro keyring/a&#xA;Come visto in precedenza, suggerisco di creare la master key per la sola certificazione e le due sottochiavi per firma e cifratura (anche quando la chiave primaria dovesse contenere altre autorizzazioni).&#xA;&#xA;Questo permetterebbe, volendo ma non è necessario, di ruotare più agevolmente le chiavi di firma e cifratura svincolandole dalla certificazione.&#xA;&#xA;Inoltre, così è più semplice rendere le chiavi gpg &#34;partially stripped&#34;, chiavi la cui sola secret key sia mancante della chiave privata, cosicché, se queste venissero smarrite o trafugate, la secret key in nostro possesso ci permetterebbe immediatamente di generare un certificato di revoca per le sottochiavi compromesse, generare delle nuove sottochiavi di firma e cifratura e di distribuire il tutto ad un keyserver.&#xA;&#xA;Chiavi gpg siffatte permetterebbero di svolgere le consuete operazioni di firma e cifratura documentale (quello che potremmo definire &#34;utilizzo giornaliero&#34;) ma impedirebbero qualunque operazione critica sulla propria chiave gpg (impossibilità di aggiungere, revocare sottochiavi o uid, di alterare scadenza o password ecc.) e su quelle altrui (certificare e quindi validare altre chiavi) upoichè è la chiave privata della master key a sigillare self-signed le informazioni della chiave gpg/u.&#xA;&#xA;In generale, posso estrarre la chiave privata da qualunque coppia di chiavi, siano esse sottochiavi o master key, ma non è uno scenario molto comune. Per estensione, eliminandole tutte otterremo un insieme di chiavi pubbliche (quella che otterrei anche con gpg --export uid|KeyID|fpr).&#xA;&#xA;Quello che invece ci interessa è eliminare la chiave privata della sola master key.&#xA;L&#39;eliminazione della chiave privata dalla master key, di per sè, non è un&#39;operazione particolarmente onerosa.&#xA;&#xA;La vera &#34;difficoltà&#34; risiede nel cambio di paradigma per l&#39;utente che l&#39;utilizzo di master key stripped comporta, perché avremo a che fare con un keyring da proteggere accuratamente e dei keyring da &#34;trincea&#34; da usare liberamente sui nostri device.&#xA;Realizzare un keyring per l&#39;uso quotidiano&#xA;Per farlo dobbiamo eliminare le chiavi private di tutte le master key del nostro keyring e per farlo dobbiamo fare un po&#39; di assunzioni.&#xA;&#xA;Come primo passo, bisogna spostare, se non è stato già fatto, il keryring dal pc/laptop/device ad un luogo sicuro (ad es. pendrive cifrata)&#xA;quindi si devono estrarre le chiavi private dalle master key e distribuirle dove possano servire &#xA;in caso di emergenza o se vi è necessità di modificare le chiavi, importare le chiavi gpg dal dispositivo sicuro, effettuare le modifiche, rigenerare e ridistribuire le nuove chiavi stripped&#xA;&#xA;Eliminazione della chiave privata dalla master key&#xA;La cancellazione della chiave privata impedisce alla master key o alla sottochiave  di esercitare pienamente le funzioni indicate dalle proprie autorizzazioni ossia certificazione, firma o decifratura.&#xA;&#xA;Per intervenire sulla singola chiave privata, occorre individuare il suo fingerprint o il suo keyid e usarlo per cancellare postponendo il carattere &#34;!&#34;. &#xA;&#xA;Ad es. sulla master key di gandalf:&#xA;gpg --delete-secret-keys 0x055D271BD85313D0!&#xA;Il carattere &#34;#&#34; (accanto a sec) vuol dire che la chiave privata è stata eliminata&#xA;gpg -K&#xA;/home/gandalf/ramfsgpg/pubring.kbx&#xA;-----------------------------------&#xA;sec#  ed25519/0xE01BDCB6A3C6778B 2024-11-05 [C]&#xA;&#x9;  8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B&#xA;uid                   [ultimo] gandalf&#xA;ssb   ed25519/0xA391F0548FB542DB 2024-11-05 [S] [scadenza: 2029-11-04]&#xA;ssb   cv25519/0xAAEF649D51D832E8 2024-11-05 [E] [scadenza: 2025-11-05]&#xA;Generalizzando, per realizzare il nostro keyring di lavoro si può agire, una tantum, in questo modo:&#xA;&#xA;1\. spostiamo il keyring di lavoro sul dispositivo sicuro&#xA;KEYRINGRAMFS=pathramfs&#xA;KEYRINGVAULT=pathpendrivecifrata&#xA;KEYRINGWORK=pathgpgdaily&#xA;export GNUPGHOME=${KEYRINGWORK}; cd $GNUPGHOME&#xA;&#xA;rsync -avp ${KEYRINGWORK}/ ${KEYRINGVAULT}/&#xA;2\. rendiamo il keyring stripped cancellando le chiavi private di tutte le master key.&#xA;for FPR in $(gpg --with-colons -K|grep sec -A 1|grep fpr|cut -d &#34;:&#34; -f 10); do &#xA;    gpg --batch --yes --delete-secret-keys &#34;${FPR}!&#34;&#xA;done&#xA;In seguito, come detto in precedenza, per lavorare sul keyring occorrerà ripristinarlo dal dispositivo sicuro, ad es. una pendrive cifrata.&#xA;&#xA;Per non lasciare tracce su altri device che non sia la pendrive cifrata, si possono seguire due strade.&#xA;&#xA;usare una distribuzione live (più sicura)&#xA;montare una partizione in ram su ramfs (non usa lo swap) su cui caricare il keyring.&#xA;&#xA;La prima via è certamente preferibile. Non c&#39;è alcun uso dei dispositivi di storage fisici della macchine, solo quelli volatili, ma presuppone che si possa avviare un SO da pendrive.&#xA;La seconda è più accessibile per certi versi ma presuppone che si possiedano i privilegi per montare una partizione su ram.&#xA;&#xA;Mostrerò la seconda via che è più articolata.&#xA;Lavorare con un keyring effimero&#xA;La strategia è quella di avere un keyring effimero montato su ramfs che farà da tramite fra il keyring master (su pendrive cifrata) e il keyring di lavoro.&#xA;&#xA;L&#39;obiettivo finale è quello di rendere strutturale il fatto di riuscire a compiere operazioni sul keyring usando il meno possibile i dispositivi di storage.&#xA;&#xA;0\. Init&#xA;KEYRINGRAMFS=pathramfs&#xA;KEYRINGVAULT=pathpendrivecifrata&#xA;KEYRINGWORK=pathgpgdaily&#xA;1\. Monto la partizione effimera&#xA;mkdir -p ${KEYRINGRAMFS}&#xA;sudo mount -t ramfs -o size=10M ramfs ${KEYRINGRAMFS}&#xA;sudo chown $(logname):$(logname) ${KEYRINGRAMFS}&#xA;2\. Esporto chiavi pubbliche e trust dal keyring di lavoro&#xA;gpg -o ${KEYRINGRAMFS}/keyringpubkeys.gpg --export&#xA;gpg --export-ownertrust   ${KEYRINGRAMFS}/keyringownertrust.txt&#xA;3\. Copio il keyring master sulla partizione effimera, modifico GNUPGHOME in modo che gpg lavori direttamente sulla partizione effimera. Su questo keyring effimero, completo l&#39;allineamento importando le chiavi pubbliche e il trust provenienti dal keyring di lavoro.&#xA;rsync -avp ${KEYRINGVAULT}/ ${KEYRINGRAMFS}/&#xA;export GNUPGHOME=${KEYRINGRAMFS}; cd $GNUPGHOME&#xA;gpg --import keyringpubkeys.gpg&#xA;gpg --import-ownertrust keyringownertrust.txt&#xA;4\. Eseguo le mie manipolazioni sul keyring effimero: uid, key, passwd, firme, revoche ecc.&#xA;...&#xA;[operazioni gpg]&#xA;...&#xA;5\. Copio il keyring master dalla partizione effimera alla pendrive cifrata &#xA;rsync -avp ${KEYRINGRAMFS}/ ${KEYRINGVAULT}/&#xA;6\. Rendo il keyring effimero di nuovo stripped&#xA;for FPR in $(gpg --with-colons -K|grep sec -A 1|grep fpr|cut -d &#34;:&#34; -f 10); do &#xA;    gpg --batch --yes --delete-secret-keys &#34;${FPR}!&#34;&#xA;done&#xA;7\. Ripristino il keyring di lavoro escludendo i certificati di revoca e cancellando la partizione effimera&#xA;rsync -avp --exclude openpgp-revocs.d ${KEYRINGRAMFS}/ ${KEYRINGWORK}/&#xA;export GNUPGHOME=${KEYRINGWORK}/&#xA;sudo umount ${KEYRINGRAMFS}; rmdir ${KEYRINGRAMFS}&#xA;La complessità di questa gestione può essere ridotta rendendo scriptabili i due blocchi (1,2,3) e (5,6,7), ad es. immaginando di avere a disposizione delle funzioni come gpg-vault [open|close|status], avendo la consapevolezza che, se usate male, possono essere delle operazioni distruttive.&#xA;a id=&#34;cos-e-un-keyserver&#34;Cos&#39;è un keyerver/a&#xA;Il keyserver è il luogo in cui pubblichiamo le nostre chiavi per renderle disponibili agli altri utenti.&#xA;&#xA;Inizialmente i keyserver avevano una logica p2p, distribuita e decentralizzata ottenuta con un&#39;implementazione chiamata SKS (Synchronizing Key Server) basata sulla rapida diffusione delle chiavi fra keyserver.&#xA;&#xA;I keyserver inizialmente servivano anche a realizzare il WOT (Web Of Trust) per la convalida delle chiavi.&#xA;&#xA;Col tempo, la mancanza di aggiornamenti del protocollo sks e la suscettibilità ad attacchi di tipo &#34;key poisoning&#34;, che possono rendere indisponibili interi certificati (ad es. riempiendo la chiave con innumerevoli firme contenenti tonnellate di dati tali da far crashare i client) o gli stessi keyserver (pubblicando quantitivi enormi di certificati non validi), amplificata dalle caratteristiche di sincronizzazione dei server, ne hanno decretato la fine.&#xA;&#xA;La realizzazione del WOT, tra l&#39;altro, offriva pubblicamente una tale quantità di chiavi che permetteva, da un lato, di tracciare interi social network basati sulle firme che vi venivano apposte, dall&#39;altro, di essere un formidabile serbatoio di email e altri dati sensibili a disposizione di attori malevoli, spammer e altro.&#xA;&#xA;Inoltre leggi recenti sulla privacy come GDPR, cozzavano contro la natura immutabile dei keyserver che, by design, aggiungono chiavi e non permettono la cancellazione.&#xA;Modelli recenti&#xA;I modelli di keyserver successivi mitigano (ma non risolvono completamente) queste debolezze:&#xA;&#xA;rinunciando alla federazione e alla distribuzione&#xA;sposando un modello basato sul controllo dell&#39;email prima dell&#39;accettazione della chiave&#xA;ricorrendo a limitazioni, filtri e valutazioni sulla bontà delle chiavi prima che queste vengano accettate.&#xA;&#xA;I principali modelli di keyserver sono:&#xA;&#xA;Hagrid&#xA;Mailvelope&#xA;HockeyPuck&#xA;&#xA;Sono stati tutti creati per sopperire ai limiti dei server SKS.&#xA;Hagrid&#xA;Il primo, basato su SequoiaPGP, ha una natura centralizzata (non sarà mai federato), è GDPR compliant ed ha dato luogo a keys.openpgp.org.&#xA;&#xA;I keyserver di questo tipo non aderiscono al modello WOT per ragioni di privacy e di efficienza. Sono quindi rifiutate le chiavi di terze parti, essenziali nel modello WOT, l&#39;accettazione della chiave pubblica è vincolata dalla verifica dell&#39;email, è possibile rimuovere le chiavi. Sono più resistenti agli attacchi di key poisoning.&#xA;Mailvelope&#xA;Ha dato luogo al keyserver keys.mailvelope.com, molto simile al primo e ne condivide la politica: no federazione, niente firme di terze parti e verifica dell&#39;email vincolante per l&#39;accettazione della chiave.&#xA;&#xA;A differenza di altri keyserver, il focus di Mailvelope è la semplificazione dell&#39;utilizzo della crittografia sull&#39;e-mail, che sia webmail, con i provider e i browser che supportano Mailvelope, o client, quando si integrino con le sue api.&#xA;Hockeypuck&#xA;È un ritorno alle origini, ha una natura federata ed è considerato l&#39;alternativa robusta ai server SKS. Uno fra i più noti server hockeypuck è certamente:&#xA;&#xA;keyserver.ubuntu.com&#xA;&#xA;il keyserver gestito dalla comunità Ubuntu che contiene le chiavi per i suoi pacchetti ma è anche aperto al pubblico.&#xA;&#xA;Un altro keyserver hockeypuck più di nicchia perché legato ad una specifica realtà tecnologica olandese è:&#xA;&#xA;pgp.surf.nl&#xA;&#xA;Sebbene possa essere meno aggiornato del primo, può essere usato liberamente per pubblicare le proprie chiavi.&#xA;&#xA;I keyserver di questo tipo, come il pool di server sks, anche se con un filtraggio più stringente, abbracciano il modello WOT con tutto quello che ne consegue.&#xA;Altri keyserver&#xA;Infine, per dovere di cronaca, bisogna citare due decani dei keyserver apparsi all&#39;alba di pgp e ormai non più utilizzabili per motivi di obsolescenza e di abbandono.&#xA;&#xA;pgp.mit.edu: uno dei primi repository a permettere la pubblicazione e la distribuzione di chiavi pubbliche, facente anche parte della rete SKS.&#xA;&#xA;global.pgp.com: l&#39;alternativa proprietaria, appartenente a PGP Corporation prima e Symantec dopo, era il repository centralizzato per la distribuzione di chiavi usato dall&#39;applicazione pgp.&#xA;&#xA;In conclusione, se la necessità è di utilizzare il WOT, allora la scelta è senza dubbio Hockeypuck quindi keyserver.ubuntu.com.&#xA;Se invece la privacy è prioritaria, Hagrid quindi keys.openpgp.org diventa la scelta obbligatoria, tanto che è il default sia di GPG che di OpenKeyChain&#xA;&#xA;#gpg #gnupg #crittografia #keyserver #hagrid #hockeypuck #mailvelope]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/0bb057b62-db9a0d/RPB3ST0CtANw/6HDoBJ1kvx62x1IB9N7jfgzjG2JcWJ5eRPNRPOF6.png" alt="gpg tools"></p>

<p>Esistono numerose gui che semplificano la gestione di una chiave gpg.</p>

<p>Questo articolo ha lo scopo di semplificare la creazione di una chiave gpg attraverso la cli di GnuPG, senza entrare nel suo mare magnum di opzioni.
</p>

<h2 id="indice">Indice</h2>
<ol><li><a href="#premessa" rel="nofollow">Premessa</a></li>
<li><a href="#gestione-della-chiave" rel="nofollow">Gestione della chiave</a></li>
<li><a href="#come-proteggere-il-nostro-keyring" rel="nofollow">Come proteggere il nostro keyring</a></li>
<li><a href="#cos-e-un-keyserver" rel="nofollow">Cos&#39;è un keyerver</a></li></ol>

<hr>

<h2 id="a-id-premessa-premessa-a"><a id="premessa&#34;">Premessa</a></h2>

<p>Cosa <strong>NON</strong> è una chiave gpg?
Una coppia di chiavi, una pubblica e una privata basate sulla crittografia asimmetrica.</p>

<p>Cos&#39;è una chiave gpg?
Non è solo una coppia di chiavi asimmetriche ma è un <strong>certificato</strong>.
Dal punto di vista delle informazioni, una chiave gpg contiene:</p>
<ul><li>informazioni <strong>identificative</strong> (nome, commento, email, foto, ecc)</li>
<li>informazioni <strong>non identificative</strong> (dati tecnici che fanno parte delle chiavi: scadenza, keyserver, algoritmi di hash e cifratura, revoker ecc.)</li></ul>

<p>Una <strong>chiave gpg</strong>, in definitiva, è costituita da:</p>
<ul><li>una <strong>chiave primaria</strong> (detta anche <strong>secret key</strong> o <strong>master key</strong>)</li>
<li>da una o più sottochiavi</li>
<li>da una serie di informazioni personali.</li></ul>

<p>Ognuna di queste “chiavi” è in realtà una coppia di chiavi asimmetriche dotate delle seguenti autorizzazioni:</p>
<ul><li><strong>Certificazione</strong>: capacità della chiave di <strong>firmare</strong>, e quindi <strong>validare</strong>, le chiavi gpg di altri utenti.</li>
<li><strong>Firma</strong>: capacità di <strong>firmare documenti</strong>.</li>
<li><strong>Cifratura</strong>: capacità di <strong>cifrare documenti</strong>.</li>
<li><strong>Autenticazione</strong>: capacità di <strong>autenticare l&#39;utente</strong> su alcuni protocolli come <strong>TLS</strong> o <strong>SSH</strong>.</li></ul>

<p>La certificazione, ossia la capacità di validare altre chiavi oltre la propria, è esclusiva della master key.
Le altre autorizzazioni possono essere delegate alle sottochiavi.</p>

<p>Certificazioni e firma, garantiscono <strong>autenticazione</strong>, <strong>integrità</strong> e <strong>non ripudio</strong> del mittente.
La cifratura garantisce <strong>confidenzialità</strong>.
Le prime due sono da considerarsi più critiche e normalmente assegnate alla master key.</p>

<p>Una chiave può avere una o più proprietà. Di default, gpg crea una master key con autorizzazioni per firma e certificazione e una sottochiave con autorizzazioni per cifratura.</p>

<h2 id="a-id-gestione-della-chiave-gestione-della-chiave-a"><a id="gestione-della-chiave">Gestione della chiave</a></h2>

<p>Per la creazione e la gestione della chiave nei suoi elementi principali, vedremo:</p>
<ul><li>come creare la chiave primaria</li>
<li>come aggiungere sottochiavi, uid</li>
<li>come modificare password o scadenza</li>
<li>come si certifica un&#39;altra chiave con la nostra (firma di chiave)</li>
<li>come si cancellano localmente uid, sottochiavi e firme</li>
<li>come si revoca un certificato, una sottochiave, un uid o una certificazione</li>
<li>come si usa un keyserver per la pubblicazione e la ricerca delle chiavi</li></ul>

<h3 id="creazione-della-chiave-primaria">Creazione della chiave primaria</h3>

<pre><code class="language-bash"># gpg --quick-gen-key &lt;uid&gt; &lt;algo&gt; &lt;auth&gt; &lt;expire&gt;, dove
# - &lt;uid&gt;: &#34;uid_name (comment) &lt;e-mail&gt;&#34;
# - &lt;algo&gt;: uno fra &#39;gpg --with-colons --list-config&#39;
# - &lt;auth&gt;: cert|encr|sign
# - &lt;expire&gt;: 0 =&gt; illimitato, ny|nm|nd =&gt; n anni|mesi|giorni
gpg --quick-gen-key gandalf ed25519 cert 0
</code></pre>

<p>Crea una chiave gpg la cui secret key può solo certificare, l&#39;uid è composto dal solo nome <code>gandalf</code> e ha scadenza illimitata.</p>

<pre><code class="language-bash">gpg -K
/home/gandalf/.gnupg/pubring.kbx
--------------------------------
sec   ed25519/0xE01BDCB6A3C6778B 2024-11-05 [C]
	  8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B
uid                   [ultimate] gandalf
</code></pre>

<p>Ecco la chiave appena creata, nella prima riga distinguiamo:</p>
<ul><li>“sec”, sta per <strong>sec</strong>ret key</li>
<li>algoritmo/KeyID</li>
<li>data di creazione</li>
<li>capability (<strong>[C]</strong>=certify).</li></ul>

<p>Nella riga successiva è visibile il <strong>fingerprint</strong> e nella terza, l&#39;uid (gandalf). Questi elementi, come il KeyID, servono per indirizzare la chiave.</p>

<p>Una sintassi più completa sarebbe:</p>

<pre><code class="language-bash">gpg --quick-gen-key &#34;nome (commento) &lt;e-mail&gt;&#34; algo cert|sign|encr &lt;scadenza&gt;
</code></pre>

<p>Per avere una lista degli algo:</p>

<pre><code class="language-bash">gpg --with-colons --list-config
</code></pre>

<h3 id="aggiungere-una-sottochiave">Aggiungere una sottochiave</h3>

<p>Aggiungiamo le chiavi di firma e di cifratura con scadenza 5 anni e 1 anno rispettivamente</p>

<pre><code class="language-bash"># gpg --quick-addgen-key &lt;fpr&gt; &lt;algo&gt; &lt;auth&gt; &lt;expire&gt;
gpg --quick-add-key 8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B ed25519 sign 5y
gpg --quick-add-key 8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B cv25519 encr 1y
</code></pre>

<p>Come prima, oltre alla secret key, ora sono visibili le sottochiavi (ssb, <strong>S</strong>ecret <strong>S</strong>ub<strong>K</strong>ey) di firma e cifratura con le evidenze per:
algoritmo, KeyID, creazione, capability ([S] per sign e [E] per encrypt) e scadenza.</p>

<pre><code class="language-bash">gpg -K
/home/gandalf/.gnupg/pubring.kbx
--------------------------------
sec   ed25519/0xE01BDCB6A3C6778B 2024-11-05 [C]
	  8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B
uid                   [ultimo] gandalf
ssb   ed25519/0xA391F0548FB542DB 2024-11-05 [S] [scadenza: 2029-11-04]
ssb   cv25519/0xAAEF649D51D832E8 2024-11-05 [E] [scadenza: 2025-11-05]
</code></pre>

<h3 id="meccanismi-di-indirizzamento-per-una-chiave">Meccanismi di indirizzamento per una chiave</h3>

<p>Una chiave può essere riferita attraverso l&#39;uid, il key ID o il fingerprint. Il riferimento è importante nelle operazioni di manipolazione della chiave.</p>

<pre><code class="language-bash">gpg --with-subkey-fingerprint -K
/home/gandalf/.gnupg/pubring.kbx
--------------------------------
sec   ed25519/0xE01BDCB6A3C6778B 2024-11-05 [C]
	  8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B
uid                   [ultimate] gandalf
uid                   [ultimate] Gandalf Il Bianco (Questa è la chiave di Gandalf Il Bianco) &lt;gandalf@lotr.org&gt;
ssb   ed25519/0xA391F0548FB542DB 2024-11-05 [S] [expires: 2029-11-04]
	  87EF9CF3D5A4D78ADA80E364A391F0548FB542DB
ssb   cv25519/0xAAEF649D51D832E8 2024-11-05 [E] [expires: 2025-11-04]
	  4DD33D36C54E2247486C9DC7AAEF649D51D832E8
</code></pre>
<ul><li><code>0xE01BDCB6A3C6778B</code> è il key ID della master key</li>
<li><code>8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B</code> è il fingerprint della master key</li>
<li><code>gandalf</code> è uno degli uid</li></ul>

<h3 id="aggiungere-un-uid">Aggiungere un uid</h3>

<p>Aggiunge un nuovo uid in termini di nome-commento-email e lo battezza come primario.</p>

<pre><code class="language-bash"># gpg --quick-add-uid &lt;primary_uid&gt; &lt;new_uid&gt;
gpg --quick-add-uid gandalf &#34;Gandalf Il Bianco (Questa è la chiave di Gandalf Il Bianco) &lt;gandalf@lotr.org&gt;&#34;

# gpg --quick-set-primary-uid &lt;primary_uid&gt; &lt;new_uid&gt;
gpg --quick-set-primary-uid &#34;gandalf&#34; &#34;Gandalf Il Bianco (Questa è la chiave di Gandalf Il Bianco) &lt;gandalf@lotr.org&gt;&#34;
</code></pre>

<h3 id="firmare-una-chiave">Firmare una chiave</h3>

<p>Ossia riconoscere una chiave gpg come valida attraverso la certificazione.
Pubblicare questa chiave sul keyserver, comunica al mondo che riconosciamo quella chiave come valida.</p>

<p>Convalida tutti gli uid della chiave identificata da <code>&lt;fpr&gt;</code></p>

<pre><code class="language-bash"># gpg --quick-sign-key &lt;fpr&gt;
gpg --quick-sign-key AD59879E1CB5D63E98F05FB9204621DACB1296E0
</code></pre>

<p>Convalida un uid specifico della chiave identificata da <code>&lt;fpr&gt;</code></p>

<pre><code class="language-bash"># gpg --quick-sign-key &lt;fpr&gt; &lt;uid&gt;
gpg --quick-sign-key AD59879E1CB5D63E98F05FB9204621DACB1296E0 frodo
</code></pre>

<h3 id="modificare-la-password">Modificare la password</h3>

<p>Inserisce la password con cui tutte le chiavi private (master key e subkey) relative all&#39;uid indicato, vengono cifrate. Se la password viene lasciata vuota, la chiave non viene cifrata.</p>

<pre><code class="language-bash"># gpg --passwd &lt;uid|KeyID|fpr&gt;
gpg --passwd gandalf
</code></pre>

<h3 id="modificare-la-scadenza">Modificare la scadenza</h3>

<p>Modifico le scadenze delle chiavi come segue:</p>
<ul><li>la master key da illimitata a 10 anni</li>
<li>la sottochiave di firma da 5 anni a 4 anni</li>
<li>la sottochiave di cifratura da 1 anno a 2 anni</li></ul>

<pre><code class="language-bash"># gpg --quick-set-expire &lt;fpr&gt; &lt;expire&gt;
gpg --quick-set-expire 8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B 10y
gpg --quick-set-expire 8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B 4y 87EF9CF3D5A4D78ADA80E364A391F0548FB542DB
gpg --quick-set-expire 8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B 2y 4DD33D36C54E2247486C9DC7AAEF649D51D832E8
</code></pre>

<pre><code class="language-bash">gpg --with-subkey-fingerprint -K
/home/gandalf/.gnupg/pubring.kbx
--------------------------------
sec   ed25519/0xE01BDCB6A3C6778B 2024-11-05 [C] [expires: 2034-11-04]
	  8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B
uid                   [ultimate] gandalf
uid                   [ultimate] Gandalf Il Bianco (Questa è la chiave di Gandalf Il Bianco) &lt;gandalf@lotr.org&gt;
ssb   ed25519/0xA391F0548FB542DB 2024-11-05 [S] [expires: 2028-11-04]
	  87EF9CF3D5A4D78ADA80E364A391F0548FB542DB
ssb   cv25519/0xAAEF649D51D832E8 2024-11-05 [E] [expires: 2026-11-04]
	  4DD33D36C54E2247486C9DC7AAEF649D51D832E8
</code></pre>

<h3 id="cancellazione-di-elementi-dal-keyring">Cancellazione di elementi dal keyring</h3>

<p>La cancellazione di elementi come uid, firme o sottochiavi ha effetto solo sul keyring locale.
Se la chiave è stata pubblicata su un repository, le cancellazioni non avranno alcun effetto.
Se si vuole inibire uno di questi elementi, si deve ricorrere alla <strong>revoca</strong> che è esportabile sui keyserver.</p>

<h4 id="cancellare-una-sottochiave">Cancellare una sottochiave</h4>

<p>Cancella la sottochiave di firma</p>

<pre><code class="language-bash"># gpg --delete-secret-and-public-keys &lt;KeyID|fpr&gt;
gpg --delete-secret-and-public-keys 87EF9CF3D5A4D78ADA80E364A391F0548FB542DB!
# o, equivalentemente
gpg --delete-secret-and-public-keys 0xA391F0548FB542DB!
</code></pre>

<h4 id="cancellare-un-uid">Cancellare un uid</h4>

<p>Cancella la seconda identità della chiave <code>gandalf</code> (<code>0xA391F0548FB542DB</code>)</p>

<pre><code class="language-bash"># gpg --edit-key [KeyID|fpr|uid]
gpg --edit-key gandalf
    uid 2
    deluid
    save
</code></pre>

<h4 id="cancellare-una-firma">Cancellare una firma</h4>

<p>Cancella tutte le firme del 2° uid che non siano self-signature.</p>

<pre><code class="language-bash"># gpg --edit-key [KeyID|fpr|uid]
gpg --edit-key gandalf
    uid 2
    delsig
    save
</code></pre>

<h3 id="operazioni-di-revoca">Operazioni di revoca</h3>

<p>Per quel che riguarda le chiavi gpg (i certificati) di cui si possiede la chiave privata, l&#39;operazione di revoca può avvenire su uno degli elementi della chiave o sull&#39;intero certificato.</p>

<h4 id="revocare-un-uid">Revocare un uid</h4>

<p>Revoco l&#39;uid (<code>gandalf il grigio</code>),</p>

<pre><code class="language-bash"># gpg --quick-revuid &lt;primary_uid&gt; &lt;uid&gt; 
gpg --quick-revuid gandalf &#34;gandalf il grigio&#34;
</code></pre>

<h4 id="revocare-una-sottochiave">Revocare una sottochiave</h4>

<pre><code class="language-bash"># gpg --edit-key [KeyID|fpr|uid]
gpg --edit-key 0xA391F0548FB542DB
    key 1
    revkey
    save
</code></pre>

<h4 id="revocare-una-nostra-certificazione">Revocare una nostra certificazione</h4>

<p>Così come validiamo le chiavi altrui con la nostra firma di certificazione, allo stesso modo possiamo revocarla.</p>

<p>Revoco la mia firma su tutti gli uid di una chiave pubblica</p>

<pre><code class="language-bash"># gpg --quick-revoke-sig &lt;KeyID|fpr del firmato&gt; &lt;KeyID|fpr del firmante&gt; 
gpg --quick-revoke-sig 0x204621DACB1296E0 0xE01BDCB6A3C6778B
</code></pre>

<p>Posso anche revocare la mia firma su un uid specifico</p>

<pre><code class="language-bash"># gpg --quick-revoke-sig &lt;KeyID|fpr del firmato&gt; &lt;KeyID|fpr del firmante&gt; &lt;uid_i&gt;
gpg --quick-revoke-sig 0x204621DACB1296E0 0xE01BDCB6A3C6778B frodo_uid2
</code></pre>

<h4 id="revocare-l-intero-certificato">Revocare l&#39;intero certificato</h4>

<p>Va a revocare non solo tutti gli uid e tutte le sottochiavi, ma anche la masterkey.</p>

<pre><code class="language-bash">gpg --import 87EF9CF3D5A4D78ADA80E364A391F0548FB542DB.rev
</code></pre>

<p>Il certificato di revoca viene generato all&#39;atto della creazione della chiave.
Se non ci fosse, conviene sempre crearlo così che, se la master key venisse compromessa, saremmo almeno in grado di revocare l&#39;intero certificato.</p>

<pre><code class="language-bash"># gpg -o &lt;file&gt; --gen-rev &lt;fpr&gt;
gpg -o 87EF9CF3D5A4D78ADA80E364A391F0548FB542DB.rev --gen-rev 87EF9CF3D5A4D78ADA80E364A391F0548FB542DB
</code></pre>

<p>Le operazioni di revoca, nel mondo gpg, corrispondono alle maledizioni senza perdono, nel mondo di Harry Potter.
Non si torna indietro a meno di un backup, e se le revoche vengono pubblicate su un keyserver, diventano irreversibili.</p>

<h3 id="operazioni-sul-keyserver">Operazioni sul keyserver</h3>

<p>Il caricamento delle chiavi su un keyserver costituisce la finalizzazione delle operazioni svolte finora.</p>

<p>Il keyserver pubblica al mondo le nostre chiavi, la configurazione avviene nel file <strong>dirmngr.conf</strong> aggiungendo una riga (ad es. per keys.openpgp.org):</p>

<pre><code class="language-bash">vi dirmngr.conf

...
keyserver hkps://keys.openpgp.org
...
</code></pre>

<p>e ricaricando la configurazione:</p>

<pre><code class="language-bash">gpgconf --reload dirmngr
</code></pre>

<h4 id="cerca">Cerca</h4>

<p>Cerca nel keyserver le chiavi con uid specificato. In caso di successo, chiede se possono essere aggiunte al keyring.</p>

<pre><code class="language-bash"># gpg --search-keys &lt;uid&gt;
gpg --search-keys 0xE01BDCB6A3C6778B 0x204621DACB1296E0
</code></pre>

<p><strong>Per gli utilizzatori di keys.openpgp.org:</strong></p>

<pre><code class="language-bash">gpg --auto-key-locate keyserver --locate-keys &lt;uid&gt;
</code></pre>

<h4 id="invia">Invia</h4>

<p>Invia una lista di chiavi al keyserver</p>

<pre><code class="language-bash"># gpg --send-keys &lt;KeyIDs|fpr&gt;
gpg --send-keys 0xE01BDCB6A3C6778B 0x204621DACB1296E0
</code></pre>

<p><strong>Per gli utilizzatori di keys.openpgp.org:</strong>
Il classico send non è sufficiente perché non sarebbe possibile validare la mail di conferma. Si consiglia, non volendo usare l&#39;interfaccia web, di usare il seguente comando:</p>

<pre><code class="language-bash"># gpg --export &lt;KeyID|fpr|uid&gt; | curl -T - https://keys.openpgp.org
gpg --export 0xE01BDCB6A3C6778B | curl -T - https://keys.openpgp.org
</code></pre>

<p>che restituisce un link diretto alla pagina di verifica.</p>

<h4 id="ricevi">Ricevi</h4>

<p>Scarica dal keyserver le chiavi</p>

<pre><code class="language-bash"># gpg --keyserver-options honor-keyserver-url --receive-keys &lt;KeyIDs|fpr&gt;
gpg --keyserver-options honor-keyserver-url --receive-keys 0xE01BDCB6A3C6778B 0x204621DACB1296E0
</code></pre>

<p>Scarica dal keyserver la chiave indicata dall&#39;uri</p>

<pre><code class="language-bash"># gpg --fetch-keys &lt;uri&gt;
gpg --fetch-keys https://keyserver.ubuntu.com/pks/lookup?search=0xE01BDCB6A3C6778B&amp;fingerprint=on&amp;op=index
</code></pre>

<h4 id="aggiorna">Aggiorna</h4>

<p>Per rinnovare tutte le chiavi pubbliche del keyring.</p>

<pre><code class="language-bash">gpg --keyserver-options honor-keyserver-url --refresh-keys
</code></pre>

<h2 id="a-id-come-proteggere-il-nostro-keyring-come-proteggere-il-nostro-keyring-a"><a id="come-proteggere-il-nostro-keyring">Come proteggere il nostro keyring</a></h2>

<p>Come visto in precedenza, suggerisco di creare la master key <strong>per la sola certificazione</strong> e le due sottochiavi per firma e cifratura (anche quando la chiave primaria dovesse contenere altre autorizzazioni).</p>

<p>Questo permetterebbe, volendo ma non è necessario, di ruotare più agevolmente le chiavi di firma e cifratura svincolandole dalla certificazione.</p>

<p>Inoltre, così è più semplice rendere le chiavi gpg “partially stripped”, chiavi la cui sola secret key sia mancante della chiave privata, cosicché, se queste venissero smarrite o trafugate, la secret key in nostro possesso ci permetterebbe immediatamente di generare un certificato di revoca per le sottochiavi compromesse, generare delle nuove sottochiavi di firma e cifratura e di distribuire il tutto ad un keyserver.</p>

<p>Chiavi gpg siffatte permetterebbero di svolgere le consuete operazioni di firma e cifratura documentale (quello che potremmo definire “utilizzo giornaliero”) ma impedirebbero qualunque operazione critica sulla propria chiave gpg (impossibilità di aggiungere, revocare sottochiavi o uid, di alterare scadenza o password ecc.) e su quelle altrui (certificare e quindi validare altre chiavi) <u><strong>poichè è la chiave privata della master key a sigillare self-signed le informazioni della chiave gpg</strong></u>.</p>

<p>In generale, posso estrarre la chiave privata da qualunque coppia di chiavi, siano esse sottochiavi o master key, ma non è uno scenario molto comune. Per estensione, eliminandole tutte otterremo un insieme di chiavi pubbliche (quella che otterrei anche con gpg —export ).</p>

<p>Quello che invece ci interessa è <strong>eliminare la chiave privata della sola master key</strong>.
L&#39;eliminazione della chiave privata dalla master key, di per sè, non è un&#39;operazione particolarmente onerosa.</p>

<p>La vera “difficoltà” risiede nel cambio di paradigma per l&#39;utente che l&#39;utilizzo di master key stripped comporta, perché avremo a che fare con un keyring da proteggere accuratamente e dei keyring da “trincea” da usare liberamente sui nostri device.</p>

<h3 id="realizzare-un-keyring-per-l-uso-quotidiano">Realizzare un keyring per l&#39;uso quotidiano</h3>

<p>Per farlo dobbiamo eliminare le chiavi private di tutte le master key del nostro keyring e per farlo dobbiamo fare un po&#39; di assunzioni.</p>
<ol><li>Come primo passo, bisogna spostare, se non è stato già fatto, il keryring dal pc/laptop/device ad un luogo sicuro (ad es. pendrive cifrata)</li>
<li>quindi si devono estrarre le chiavi private dalle master key e distribuirle dove possano servire</li>
<li>in caso di emergenza o se vi è necessità di modificare le chiavi, importare le chiavi gpg dal dispositivo sicuro, effettuare le modifiche, rigenerare e ridistribuire le nuove chiavi stripped</li></ol>

<h4 id="eliminazione-della-chiave-privata-dalla-master-key">Eliminazione della chiave privata dalla master key</h4>

<p>La cancellazione della chiave privata impedisce alla master key o alla sottochiave  di esercitare pienamente le funzioni indicate dalle proprie autorizzazioni ossia certificazione, firma o decifratura.</p>

<p>Per intervenire sulla singola chiave privata, occorre individuare il suo fingerprint o il suo keyid e usarlo per cancellare postponendo il carattere “!”.</p>

<p>Ad es. sulla master key di gandalf:</p>

<pre><code class="language-bash">gpg --delete-secret-keys 0x055D271BD85313D0!
</code></pre>

<p>Il carattere “#” (accanto a sec) vuol dire che la chiave privata è stata eliminata</p>

<pre><code class="language-bash">gpg -K
/home/gandalf/ramfs_gpg/pubring.kbx
-----------------------------------
sec#  ed25519/0xE01BDCB6A3C6778B 2024-11-05 [C]
	  8C8EC405954D4ABB32CFA431E01BDCB6A3C6778B
uid                   [ultimo] gandalf
ssb   ed25519/0xA391F0548FB542DB 2024-11-05 [S] [scadenza: 2029-11-04]
ssb   cv25519/0xAAEF649D51D832E8 2024-11-05 [E] [scadenza: 2025-11-05]
</code></pre>

<p>Generalizzando, per realizzare il nostro keyring di lavoro si può agire, una tantum, in questo modo:</p>

<p>1. spostiamo il keyring di lavoro sul dispositivo sicuro</p>

<pre><code class="language-bash">KEYRING_RAMFS=&lt;path_ramfs&gt;
KEYRING_VAULT=&lt;path_pendrive_cifrata&gt;
KEYRING_WORK=&lt;path_gpg_daily&gt;
export GNUPGHOME=${KEYRING_WORK}; cd $GNUPGHOME

rsync -avp ${KEYRING_WORK}/ ${KEYRING_VAULT}/
</code></pre>

<p>2. rendiamo il keyring stripped cancellando le chiavi private di tutte le master key.</p>

<pre><code class="language-bash">for FPR in $(gpg --with-colons -K|grep sec -A 1|grep fpr|cut -d &#34;:&#34; -f 10); do 
    gpg --batch --yes --delete-secret-keys &#34;${FPR}!&#34;
done
</code></pre>

<p>In seguito, come detto in precedenza, per lavorare sul keyring occorrerà ripristinarlo dal dispositivo sicuro, ad es. una pendrive cifrata.</p>

<p>Per non lasciare tracce su altri device che non sia la pendrive cifrata, si possono seguire due strade.</p>
<ol><li>usare una distribuzione live (più sicura)</li>
<li>montare una partizione in ram su ramfs (non usa lo swap) su cui caricare il keyring.</li></ol>

<p>La prima via è certamente preferibile. Non c&#39;è alcun uso dei dispositivi di storage fisici della macchine, solo quelli volatili, ma presuppone che si possa avviare un SO da pendrive.
La seconda è più accessibile per certi versi ma presuppone che si possiedano i privilegi per montare una partizione su ram.</p>

<p>Mostrerò la seconda via che è più articolata.</p>

<h4 id="lavorare-con-un-keyring-effimero">Lavorare con un keyring effimero</h4>

<p>La strategia è quella di avere un keyring effimero montato su ramfs che farà da tramite fra il keyring master (su pendrive cifrata) e il keyring di lavoro.</p>

<p>L&#39;obiettivo finale è quello di rendere strutturale il fatto di riuscire a compiere operazioni sul keyring usando il meno possibile i dispositivi di storage.</p>

<p>0. Init</p>

<pre><code class="language-bash">KEYRING_RAMFS=&lt;path_ramfs&gt;
KEYRING_VAULT=&lt;path_pendrive_cifrata&gt;
KEYRING_WORK=&lt;path_gpg_daily&gt;
</code></pre>

<p>1. Monto la partizione effimera</p>

<pre><code class="language-bash">mkdir -p ${KEYRING_RAMFS}
sudo mount -t ramfs -o size=10M ramfs ${KEYRING_RAMFS}
sudo chown $(logname):$(logname) ${KEYRING_RAMFS}
</code></pre>

<p>2. Esporto chiavi pubbliche e trust dal keyring di lavoro</p>

<pre><code class="language-bash">gpg -o ${KEYRING_RAMFS}/keyring_pubkeys.gpg --export
gpg --export-ownertrust &gt; ${KEYRING_RAMFS}/keyring_ownertrust.txt
</code></pre>

<p>3. Copio il keyring master sulla partizione effimera, modifico <code>GNUPGHOME</code> in modo che gpg lavori direttamente sulla partizione effimera. Su questo keyring effimero, completo l&#39;allineamento importando le chiavi pubbliche e il trust provenienti dal keyring di lavoro.</p>

<pre><code class="language-bash">rsync -avp ${KEYRING_VAULT}/ ${KEYRING_RAMFS}/
export GNUPGHOME=${KEYRING_RAMFS}; cd $GNUPGHOME
gpg --import keyring_pubkeys.gpg
gpg --import-ownertrust keyring_ownertrust.txt
</code></pre>

<p>4. Eseguo le mie manipolazioni sul keyring effimero: uid, key, passwd, firme, revoche ecc.</p>

<pre><code class="language-bash">...
[operazioni gpg]
...
</code></pre>

<p>5. Copio il keyring master dalla partizione effimera alla pendrive cifrata</p>

<pre><code class="language-bash">rsync -avp ${KEYRING_RAMFS}/ ${KEYRING_VAULT}/
</code></pre>

<p>6. Rendo il keyring effimero di nuovo stripped</p>

<pre><code class="language-bash">for FPR in $(gpg --with-colons -K|grep sec -A 1|grep fpr|cut -d &#34;:&#34; -f 10); do 
    gpg --batch --yes --delete-secret-keys &#34;${FPR}!&#34;
done
</code></pre>

<p>7. Ripristino il keyring di lavoro escludendo i certificati di revoca e cancellando la partizione effimera</p>

<pre><code class="language-bash">rsync -avp --exclude openpgp-revocs.d ${KEYRING_RAMFS}/ ${KEYRING_WORK}/
export GNUPGHOME=${KEYRING_WORK}/
sudo umount ${KEYRING_RAMFS}; rmdir ${KEYRING_RAMFS}
</code></pre>

<p>La complessità di questa gestione può essere ridotta rendendo scriptabili i due blocchi (1,2,3) e (5,6,7), ad es. immaginando di avere a disposizione delle funzioni come <strong>gpg-vault [open|close|status]</strong>, avendo la consapevolezza che, se usate male, possono essere delle operazioni distruttive.</p>

<h2 id="a-id-cos-e-un-keyserver-cos-è-un-keyerver-a"><a id="cos-e-un-keyserver">Cos&#39;è un keyerver</a></h2>

<p>Il keyserver è il luogo in cui pubblichiamo le nostre chiavi per renderle disponibili agli altri utenti.</p>

<p>Inizialmente i keyserver avevano una logica p2p, distribuita e decentralizzata ottenuta con un&#39;implementazione chiamata <strong>SKS</strong> (<strong>S</strong>ynchronizing <strong>K</strong>ey <strong>S</strong>erver) basata sulla rapida diffusione delle chiavi fra keyserver.</p>

<p>I keyserver inizialmente servivano anche a realizzare il <strong>WOT</strong> (<strong>W</strong>eb <strong>O</strong>f <strong>T</strong>rust) per la convalida delle chiavi.</p>

<p>Col tempo, la mancanza di aggiornamenti del protocollo sks e la suscettibilità ad attacchi di tipo “key poisoning”, che possono rendere indisponibili interi certificati (ad es. riempiendo la chiave con innumerevoli firme contenenti tonnellate di dati tali da far crashare i client) o gli stessi keyserver (pubblicando quantitivi enormi di certificati non validi), amplificata dalle caratteristiche di sincronizzazione dei server, ne hanno decretato la fine.</p>

<p>La realizzazione del WOT, tra l&#39;altro, offriva pubblicamente una tale quantità di chiavi che permetteva, da un lato, di tracciare interi social network basati sulle firme che vi venivano apposte, dall&#39;altro, di essere un formidabile serbatoio di email e altri dati sensibili a disposizione di attori malevoli, spammer e altro.</p>

<p>Inoltre leggi recenti sulla privacy come GDPR, cozzavano contro la natura immutabile dei keyserver che, by design, aggiungono chiavi e non permettono la cancellazione.</p>

<h3 id="modelli-recenti">Modelli recenti</h3>

<p>I modelli di keyserver successivi mitigano (ma non risolvono completamente) queste debolezze:</p>
<ul><li>rinunciando alla federazione e alla distribuzione</li>
<li>sposando un modello basato sul controllo dell&#39;email prima dell&#39;accettazione della chiave</li>
<li>ricorrendo a limitazioni, filtri e valutazioni sulla bontà delle chiavi prima che queste vengano accettate.</li></ul>

<p>I principali modelli di keyserver sono:</p>
<ul><li><strong>Hagrid</strong></li>
<li><strong>Mailvelope</strong></li>
<li><strong>HockeyPuck</strong></li></ul>

<p>Sono stati tutti creati per sopperire ai limiti dei server SKS.</p>

<h4 id="hagrid">Hagrid</h4>

<p>Il primo, basato su <strong>SequoiaPGP</strong>, ha una natura centralizzata (non sarà mai federato), è GDPR compliant ed ha dato luogo a <strong>keys.openpgp.org</strong>.</p>

<p>I keyserver di questo tipo non aderiscono al modello WOT per ragioni di privacy e di efficienza. Sono quindi rifiutate le chiavi di terze parti, essenziali nel modello WOT, l&#39;accettazione della chiave pubblica è vincolata dalla verifica dell&#39;email, è possibile rimuovere le chiavi. Sono più resistenti agli attacchi di key poisoning.</p>

<h4 id="mailvelope">Mailvelope</h4>

<p>Ha dato luogo al keyserver <strong>keys.mailvelope.com</strong>, molto simile al primo e ne condivide la politica: no federazione, niente firme di terze parti e verifica dell&#39;email vincolante per l&#39;accettazione della chiave.</p>

<p>A differenza di altri keyserver, il focus di Mailvelope è la semplificazione dell&#39;utilizzo della crittografia sull&#39;e-mail, che sia webmail, con i provider e i browser che supportano Mailvelope, o client, quando si integrino con le sue api.</p>

<h4 id="hockeypuck">Hockeypuck</h4>

<p>È un ritorno alle origini, ha una natura federata ed è considerato l&#39;alternativa robusta ai server SKS. Uno fra i più noti server hockeypuck è certamente:</p>
<ul><li><strong>keyserver.ubuntu.com</strong></li></ul>

<p>il keyserver gestito dalla comunità Ubuntu che contiene le chiavi per i suoi pacchetti ma è anche aperto al pubblico.</p>

<p>Un altro keyserver hockeypuck più di nicchia perché legato ad una specifica realtà tecnologica olandese è:</p>
<ul><li><strong>pgp.surf.nl</strong></li></ul>

<p>Sebbene possa essere meno aggiornato del primo, può essere usato liberamente per pubblicare le proprie chiavi.</p>

<p>I keyserver di questo tipo, come il pool di server sks, anche se con un filtraggio più stringente, abbracciano il modello WOT con tutto quello che ne consegue.</p>

<h4 id="altri-keyserver">Altri keyserver</h4>

<p>Infine, per dovere di cronaca, bisogna citare due decani dei keyserver apparsi all&#39;alba di pgp e ormai non più utilizzabili per motivi di obsolescenza e di abbandono.</p>

<p><strong>pgp.mit.edu</strong>: uno dei primi repository a permettere la pubblicazione e la distribuzione di chiavi pubbliche, facente anche parte della rete SKS.</p>

<p><strong>global.pgp.com</strong>: l&#39;alternativa proprietaria, appartenente a PGP Corporation prima e Symantec dopo, era il repository centralizzato per la distribuzione di chiavi usato dall&#39;applicazione pgp.</p>

<p>In conclusione, se la necessità è di utilizzare il WOT, allora la scelta è senza dubbio <strong>Hockeypuck</strong> quindi <strong>keyserver.ubuntu.com</strong>.
Se invece la privacy è prioritaria, <strong>Hagrid</strong> quindi <strong>keys.openpgp.org</strong> diventa la scelta obbligatoria, tanto che è il default sia di GPG che di OpenKeyChain</p>

<p><a href="/aytin/tag:gpg" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">gpg</span></a> <a href="/aytin/tag:gnupg" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">gnupg</span></a> <a href="/aytin/tag:crittografia" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">crittografia</span></a> <a href="/aytin/tag:keyserver" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">keyserver</span></a> <a href="/aytin/tag:hagrid" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">hagrid</span></a> <a href="/aytin/tag:hockeypuck" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">hockeypuck</span></a> <a href="/aytin/tag:mailvelope" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">mailvelope</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/gestire-la-tua-chiave-gpg</guid>
      <pubDate>Mon, 25 Nov 2024 15:00:37 +0000</pubDate>
    </item>
    <item>
      <title>Come creare un file container cifrato</title>
      <link>https://noblogo.org/aytin/come-creare-un-file-container</link>
      <description>&lt;![CDATA[cartella con lucchetto&#xA;smallia href=&#34;https://www.freepik.com/free-photo/yellow-folder-with-security-key954598.htm#query=file%20lock&amp;position=1&amp;fromview=keyword&amp;track=ais&amp;uuid=7a92782d-c3bf-42db-ac2c-6c63c46f9edd&#34;Image by d3images/a/i on Freepik/small&#xA;&#xA;Introduzione a cryptsetup + LUKS&#xA;Supponiamo di voler creare una piccola cassaforte digitale come faremmo con Veracrypt. Ma senza Veracrypt.&#xA;&#xA;Ciò sarà possibile grazie a dm-crypt.&#xA;dm-crypt è un modulo del kernel che usa il framework device mapper per fornire funzionalità trasparenti di crittografia per dispositivi a blocchi usando le crypto api del kernel. L’uso di device mapper consente, tra l’altro, di &#34;poggiare&#34; dm-crypt sopra ogni possibile mapping dei dispositivi e quindi può cifrare partizioni, volumi raid o volumi logici.&#xA;!--more--&#xA;Introduzione a cryptsetup + LUKS&#xA;  Inizializzazione&#xA;  Apertura&#xA;  Chiusura&#xA;Come creare il file vault&#xA;Header detachable e keyfile&#xA;Partizionare un &#34;volume&#34; cifrato&#xA;&#xA;\EDIT 02/03/2026\]: Riscrittura del par. 3 - &#34;Header detachable e keyfile&#34;, alla luce degli approfondimenti fatti con &#34;[Device Mapper: Luks + LVM&#34; e la &#34;Trilogia delle password - Vol. 1,2 e 3&#34;&#xA;&#xA;Poi, essendo a tutti gli effetti anche un dispositivo a blocchi (virtuale), può essere utilizzabile a sua volta come volume nel file system, come swap o come disco fisico per lvm.&#xA;&#xA;La configurazione della cifratura avviene di solito (non è l’unico modo ma è lo standard de facto) con l’utility cryptsetup + LUKS&#xA;&#xA;Come avviene di base la cifratura di un dispositivo?&#xA;&#xA;Le operazioni principali di cryptsetup (con estensioni LUKS) sono:&#xA;&#xA;luksFormat: stabilisce le modalità di cifratura (consigliato il default)&#xA;luksOpen: (deprecato. Si usa open \-\-type luks2) attiva la cifratura sul device associandolo (grazie a device mapper) ad un dispositivo a blocchi virtuale&#xA;luksClose (deprecato. Si usa close \-\-type luks2): disattiva la cifratura&#xA;&#xA;Inizializzazione&#xA;&#xA;attacco il dispositivo fisico, viene creata la entry per /dev/\id\dispositivo\a\blocchi\fisico\&#xA;cifratura del dispositivo a blocchi /dev/\id\dispositivo\a\blocchi\fisico\ con LUKS (cryptsetup luksFormat)&#xA;al di sopra del dispositivo a blocchi fisico, viene creato un dispositivo a blocchi virtuale, che troverò sotto /dev/mapper/\nome\fittizio\, che eroga le funzionalità di cifratura (cryptsetup open) al dispositivo a blocchi fisico sottostante.&#xA;Infine, partiziono e/o formatto nella maniera canonica il dispositivo a blocchi virtuale (cifrato) /dev/mapper/\nome\fittizio\.&#xA;&#xA;Apertura&#xA;&#xA;attacco il dispositivo, viene creata la entry per /dev/\id\dispositivo\a\blocchi\fisico\&#xA;attivo il dispositivo a blocchi virtuale che eroga le funzionalità di cifratura (cryptsetup open) e che creerà l’occorrenza sotto /dev/mapper/\nome\fittizio\&#xA;faccio il mount del dispositivo a blocchi virtuale /dev/mapper/ su un punto di montaggio che è una cartella che creerò per l’occasione&#xA;&#xA;Chiusura&#xA;&#xA;faccio l’unmount del punto di montaggio&#xA;chiudo il dispositivo a blocchi virtuale (cryptsetup close) /dev/mapper/\nome\fittizio\&#xA;stacco il dispositivo fisico&#xA;&#xA;Fermo restando che questi restano i passaggi generali per qualunque dispositivo fisico, per creare un file container cifrato come farebbe Veracrypt, basta che cryptsetup formatti un file invece che un dispositivo a blocchi e automaticamente assocerà il file al primo loop device disponibile.&#xA;È veramente semplicesmalla id=&#34;linknota1&#34; title=&#34;vai alla nota 1&#34; href=&#34;#nota1&#34;supstrong [1] /strong/sup/a/small.&#xA;&#xA;Come creare il file vault&#xA;Divido le operazioni in 3 fasi:&#xA;&#xA;Init: fase di inizializzazione del &#34;dispositivo&#34; (il file). Andrà fatta solo la prima volta.&#xA;Open e Close: sono le operazioni che farò ogniqualvolta dovrò usare il container.&#xA;&#xA;Gli oggetti su cui andrà a lavorare sono:&#xA;&#xA;discocifrato.img: il file container cifrato.&#xA;discocifrato: il nome con cui discocifrato.img (o meglio, la sua rappresentazione come loop device visibile con losetup) viene mappato da device mapper.&#xA;disco\in\chiaro: il punto di montaggio.&#xA;&#xA;Init&#xA;creazione di una cartella che sarà il nostro punto di mount&#xA;mkdir discoinchiaro&#xA; &#xA;creazione di un file vuoto di 2 GiB&#xA;sudo fallocate -l 2g discocifrato.img&#xA; &#xA;preparazione cifratura LUKS &#xA;sudo cryptsetup luksFormat \&#xA;     --type luks2 \&#xA;     --hash=sha512 \&#xA;     --key-size=512 \&#xA;     discocifrato.img&#xA; &#xA;creazione dispositivo a blocchi virtuale che eroga le funzionalità di cifratura&#xA;sudo cryptsetup open \&#xA;     --type luks2 \&#xA;     discocifrato.img discocifrato&#xA; &#xA;formattazione&#xA;sudo mkfs.ext4 /dev/mapper/discocifrato&#xA;Open&#xA;creazione dispositivo a blocchi virtuale&#xA;sudo cryptsetup open \&#xA;     --type luks2 &#xA;     discocifrato.img discocifrato&#xA; &#xA;monta il dispositivo nel punto di montaggio&#xA;sudo mount -t ext4 -o defaults /dev/mapper/discocifrato discoinchiaro&#xA;Close&#xA;smonta il dispositivo&#xA;sudo umount discoinchiaro&#xA; &#xA;chiudo il dispositivo a blocchi virtuale staccandolo dai loop device&#xA;sudo cryptsetup close discocifrato&#xA;Header detachable e keyfile&#xA;Alziamo il livello di paranoia aggiungendo una complessità ulteriore. Creeremo il file vault nel seguente modo:&#xA;&#xA;il vault sarà inizializzato con rumore casuale&#xA;header detachable&#xA;offset custom&#xA;keyfile invece che password&#xA;default di argon2id (controlla il tuo default con cryptsetup benchmark)&#xA;&#xA;L’apertura del volume cifrato sarà così vincolata alla disponibiltà sia del keyfile che dell’header, senza il quale il volume cifrato sarebbe comunque inservibile.&#xA;&#xA;La presenza di rumore casuale su tutto il vault nella fase di inizializzazione impedirà qualunque tentativo di risalire alla tipologia di informazioni memorizzate, l&#39;assenza di zeri impedirà di capire quanti sono i dati (cifrati) memorizzati.&#xA;&#xA;L&#39;offset custom aggiunge un ulteriore tassello perchè nasconde il punto in cui inizia il payload.&#xA;&#xA;Un keyfile di dati binari casuali è infinitamente più robusto di una password  e può esser conservato separatamente insieme all&#39;header. La cifratura simmetrica del keyfile aggiunge ulteriore protezione, fatta magari usando una passphrase ottenuta col metodo Diceware.&#xA;&#xA;Infine la cifratura di default di luks2, argon2id, che è notoriamente sia CPU bound che GPU bound.&#xA;&#xA;Creo il keyfile protetto da una cifratura simmetrica di gpgsmalla id=&#34;linknota2&#34; title=&#34;vai alla nota 2&#34; href=&#34;#nota2&#34;supstrong [2] /strong/sup/small/a:&#xA;Creazione di un keyfile di 4KiB basata sulla pseudocasualità di /dev/urandom&#xA;creazione del keyfile&#xA;dd if=/dev/urandom bs=1024 count=4 | \&#xA;    gpg --yes -o discocifrato.key.gpg -c \&#xA;        --s2k-mode 3 \&#xA;        --s2k-count 32505856 \&#xA;        --s2k-cipher-algo aes256 \&#xA;        --s2k-digest-algo sha512 \&#xA;        --force-mdc -&#xA;Inizializzo il vault con dati casuali e poi lo formatto creando l&#39;header detachable del volume cifrato fornendo il keyfile invece della passphrase classica:&#xA;inizializzazione vault con dati casuali&#xA;Apro il vault in modalità &#39;plain&#39; senza header&#xA;sudo cryptsetup open \&#xA;    --type plain \&#xA;    --key-file /dev/urandom \&#xA;    --cipher aes-xts-plain64 \&#xA;    --key-size 512 \ &#xA;    discocifrato.img container&#xA;&#xA;scrivo degli zeri a cui, attraverso il motore di cifratura,&#xA;corrisponderanno dati casuali sul vault.&#xA;dd if=/dev/zero of=/dev/mapper/container status=progress&#xA;cryptsetup close container&#xA;&#xA;Formattazione vault&#xA;gpg -d discocifrato.key.gpg | \&#xA;    sudo cryptsetup luksFormat \&#xA;        --type luks2 \&#xA;        --key-file - \&#xA;        --header header.img \&#xA;        --offset 32768 \&#xA;        --hash sha512 \&#xA;        --key-size 512 \&#xA;        --cipher aes-xts-plain64 \&#xA;        discocifrato.img&#xA;Ed è così che l’apertura del volume cifrato è ora vincolata al possesso dell’header e del keyfile:&#xA;attivazione dispositivo a blocchi virtuale passando header e keyfile protetto da gpg&#xA;gpg -d discocifrato.key.gpg | \&#xA;    sudo cryptsetup open \&#xA;        --type luks2 \&#xA;&#x9;--header header.img \&#xA;&#x9;--key-file - \&#xA;&#x9;discocifrato.img discocifrato&#xA;Provando ad aprire container cifrato senza fornire l’header (non tanto il keyfile che è una passphrase evoluta) succede questo:&#xA;sudo cryptsetup open \&#xA;    --type luks2 \&#xA;    discocifrato.img discocifrato&#xA;Il dispositivo discocifrato.img non è un dispositivo LUKS valido.&#xA;Infine, un&#39;annotazione doverosa.&#xA;&#xA;Visto che il livello di paranoia abbiamo detto essere elevato, sarebbe consigliabile prestare una certa attenzione alla scelta dei nomi.&#xA;&#xA;Quelli usati finora avevano uno scopo &#34;didattico&#34;, che chiarisse il loro scopo  con un nome parlante.&#xA;&#xA;i nomi dei file relativi a header e keyfile sarebbe bene non fossero qualcosa del tpo &#34;header.img&#34; o &#34;discocifratokey.gpg&#34; che rivelano troppo esplicitamente la presenza di un disco cifrato o addirittura dello stesso LUKS. Meglio usare nomi più decontestualizzati, che so... &#34;sys-module-virtio.bin&#34; per l&#39;header e &#34;boot-vmlinuz-06.blob&#34; per il keyfile e via dicendo.&#xA;Partizionare un &#34;volume&#34; cifrato&#xA;Per concludere, visto che prima ho accennato al fatto che dm-crypt, grazie al sottosistema device mapper, fa in modo che i dispositivi a blocchi (virtuali) mascherino i dispositivo a blocchi sottostanti (un file montato su un loop device, nel nostro caso), i dispositivi a blocchi mappati possono anche essere partizionati invece che sempicemente formattati. O potrebbe essere volumi fisici di un gruppo di volumi LVM, and so on…&#xA;&#xA;Difficilmente avremo bisogno di partizionare un file container cifrato, è solo l’occasione per speculare un po’ su quello che potrebbe succedere su un device fisico.&#xA;Init&#xA;mkdir discoinchiaro&#xA;sudo fallocate -l 2g discocifrato.img&#xA;sudo cryptsetup luksFormat --hash=sha512 --key-size=512 discocifrato.img&#xA;sudo cryptsetup open --type luks2 discocifrato.img discocifrato&#xA; &#xA;Creo 1 partizione primaria da 600 MiB, una estesa da 1400 MiB&#xA;contenente 2 partizioni logiche da 600 MiB e 829 MiB (mancano i&#xA;16 MiB dell&#39;intestazione luks e i 3 MiB delle intestazioni delle&#xA;partizioni primarie ed estese per un totale di 2GiB tondi tondi)&#xA;sudo fdisk /dev/mapper/discocifrato&#xA;n,,,,+600M,n,e,,,,n,,+600M,n,,,w&#xA; &#xA;il partizionamento potrebbe richiedere l&#39;esecuzione di partprobe&#xA;affinché il kernel carichi la tabella delle partizioni aggiornata&#xA;sudo partprobe /dev/mapper/discocifrato&#xA;&#xA;stato delle partizioni&#xA;sudo fdisk -l /dev/mapper/discocifrato&#xA;Disk /dev/mapper/discocifrato: 1,98 GiB, 2130706432 bytes, 520192 sectors&#xA;Units: sectors of 1 * 4096 = 4096 bytes&#xA;Sector size (logical/physical): 4096 bytes / 4096 bytes&#xA;I/O size (minimum/optimal): 4096 bytes / 4096 bytes&#xA;Disklabel type: dos&#xA;Disk identifier: 0x6d65a06f&#xA;&#xA;Device                     Boot  Start    End Sectors  Size Id Type&#xA;/dev/mapper/discocifrato1         256 153855  153600  600M 83 Linux&#xA;/dev/mapper/discocifrato2      153856 520191  366336  1,4G  5 Extended&#xA;/dev/mapper/discocifrato5      154112 307711  153600  600M 83 Linux&#xA;/dev/mapper/discocifrato6      307968 520191  212224  829M 83 Linux&#xA;&#xA;procedo con la formattazione&#xA;sudo mkfs.ext4 /dev/mapper/discocifrato1 #formatto la partizione&#xA;sudo mkfs.ext4 /dev/mapper/discocifrato5 #formatto la partizione&#xA;sudo mkfs.ext4 /dev/mapper/discocifrato6 #formatto la partizione&#xA;Rispetto all’init di prima, invece che formattare subito il device &#34;fisico&#34;, l’ho partizionato. Esattamente come avrei fatto con un dispositivo realmente fisico.&#xA;Open&#xA;sudo cryptsetup open --type luks2 discocifrato.img discocifrato&#xA; &#xA;di nuovo, potrebbe essere necessario a meno di non riavviare&#xA;sudo partprobe /dev/mapper/discocifrato&#xA; &#xA;mount delle partizioni&#xA;sudo mount -t ext4 -o defaults /dev/mapper/discocifrato1 discoinchiaro1&#xA;sudo mount -t ext4 -o defaults /dev/mapper/discocifrato5 discoinchiaro2&#xA;sudo mount -t ext4 -o defaults /dev/mapper/discocifrato6 discoinchiaro3&#xA;Close&#xA;sudo umount discoinchiaro1&#xA;sudo umount discoinchiaro2&#xA;sudo umount discoinchiaro3&#xA;sudo cryptsetup close discocifrato1&#xA;sudo cryptsetup close discocifrato2&#xA;sudo cryptsetup close discocifrato5&#xA;sudo cryptsetup close discocifrato6&#xA;sudo cryptsetup close discocifrato&#xA;&#xA;Note:&#xA;small&#xA;&#xA;cryptsetup --open luks2 e cryptsetup --close luks2, a id=&#34;nota1&#34;/aquando applicate direttamente al file container, includono implicitamente la parte di accoppiamento al loop device.&#xA;    In altre parole,&#xA;    &#xA;        cryptsetup open --type luks2 discocifrato.img discocifrato&#xA;        equivale a &#xA;        cryptsetup open --type luks2 $(losetup -Pf --show discocifrato.img) discocifrato&#xA;        e&#xA;        cryptsetup close --type luks2 discocifrato&#xA;        equivale aa href=&#34;#linknota1&#34; title=&#34;torna su&#34;supb [↵] /b/sup/a&#xA;        cryptsetup close --type luks2 discocifrato&#xA;    losetup -D&#xA;    a id=&#34;nota2&#34;/aSe si incorre in questo errore usando gpg:&#xA;&#xA;        gpg: cancelled by user&#xA;    gpg: error creating passphrase: Operation cancelled&#xA;    gpg: symmetric encryption of &#39;[stdin]&#39; failed: Operation cancelled&#xA;        vuol dire che la variabile d’ambiente GPGTTY non ha lo stesso valore del comando tty. Per ovviare basta settare correttamente la variabile:&#xA;        GPGTTY=$(tty)&#xA;    export GPGTTY&#xA;        come suggerito dalla documentazione GnuPG a href=&#34;#linknota2&#34; title=&#34;torna su&#34;supb [↵] /b/sup/a&#xA;&#xA;/small&#xA;&#xA;#cryptsetup #devicemapper #dmcrypt #gpg #loseup #luks #lvm #loopdevice #storage]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://cyberdynesystem.files.wordpress.com/2024/05/yellow-folder-with-security-key.png" alt="cartella con lucchetto">
<small><i><a href="https://www.freepik.com/free-photo/yellow-folder-with-security-key_954598.htm#query=file%20lock&amp;position=1&amp;from_view=keyword&amp;track=ais&amp;uuid=7a92782d-c3bf-42db-ac2c-6c63c46f9edd" rel="nofollow">Image by d3images</a></i> on Freepik</small></p>

<h2 id="introduzione-a-cryptsetup-luks">Introduzione a cryptsetup + LUKS</h2>

<p>Supponiamo di voler creare una piccola cassaforte digitale come faremmo con Veracrypt. Ma senza Veracrypt.</p>

<p>Ciò sarà possibile grazie a <strong>dm-crypt</strong>.
dm-crypt è un modulo del kernel che usa il framework <strong>device mapper</strong> per fornire funzionalità trasparenti di crittografia per dispositivi a blocchi usando le crypto api del kernel. L’uso di device mapper consente, tra l’altro, di “poggiare” dm-crypt sopra ogni possibile mapping dei dispositivi e quindi può cifrare partizioni, volumi raid o volumi logici.

1. <a href="#introduzione-a-cryptsetup-luks" rel="nofollow">Introduzione a cryptsetup + LUKS</a>
  2. <a href="#inizializzazione" rel="nofollow">Inizializzazione</a>
  2. <a href="#apertura" rel="nofollow">Apertura</a>
  2. <a href="#chiusura" rel="nofollow">Chiusura</a>
1. <a href="#come-creare-il-file-vault" rel="nofollow">Come creare il file vault</a>
1. <a href="#header-detachable-e-keyfile" rel="nofollow">Header detachable e keyfile</a>
1. <a href="#partizionare-un-volume-cifrato" rel="nofollow">Partizionare un “volume” cifrato</a></p>

<p><strong>[EDIT 02/03/2026]: Riscrittura del par. 3 – “Header detachable e keyfile”, alla luce degli approfondimenti fatti con “<a href="https://noblogo.org/aytin/device-mapper-luks-lvm" rel="nofollow">Device Mapper: Luks + LVM</a>” e la “Trilogia delle password – Vol. <a href="https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di" rel="nofollow">1</a>,<a href="https://noblogo.org/aytin/come-valutare-la-resistenza-di-una-password-trilogia-della-password-2-di-3" rel="nofollow">2</a> e <a href="https://noblogo.org/aytin/archiviare-le-password-in-sicurezza-con-kdf-password-hashing-trilogia-della" rel="nofollow">3</a>“</strong></p>

<p>Poi, essendo a tutti gli effetti anche un dispositivo a blocchi (virtuale), può essere utilizzabile a sua volta come volume nel file system, come swap o come disco fisico per lvm.</p>

<p>La configurazione della cifratura avviene di solito (non è l’unico modo ma è lo standard de facto) con l’utility <strong>cryptsetup + LUKS</strong></p>

<p>Come avviene di base la cifratura di un dispositivo?</p>

<p>Le operazioni principali di cryptsetup (con estensioni LUKS) sono:</p>
<ul><li><strong>luksFormat</strong>: stabilisce le modalità di cifratura (consigliato il default)</li>
<li><strong>luksOpen</strong>: (deprecato. Si usa <strong>open --type luks2</strong>) attiva la cifratura sul device associandolo (grazie a device mapper) ad un dispositivo a blocchi virtuale</li>
<li><strong>luksClose</strong> (deprecato. Si usa <strong>close --type luks2</strong>): disattiva la cifratura</li></ul>

<h3 id="inizializzazione">Inizializzazione</h3>
<ul><li>attacco il dispositivo fisico, viene creata la entry per <em>/dev/&lt;id_dispositivo_a_blocchi_fisico&gt;</em></li>
<li>cifratura del dispositivo a blocchi <em>/dev/&lt;id_dispositivo_a_blocchi_fisico&gt;</em> con LUKS (<strong>cryptsetup luksFormat</strong>)</li>
<li>al di sopra del dispositivo a blocchi fisico, viene creato un dispositivo a blocchi virtuale, che troverò sotto <em>/dev/mapper/&lt;nome_fittizio&gt;</em>, che eroga le funzionalità di cifratura (<strong>cryptsetup open</strong>) al dispositivo a blocchi fisico sottostante.</li>
<li>Infine, partiziono e/o formatto nella maniera canonica il dispositivo a blocchi virtuale (cifrato) <em>/dev/mapper/&lt;nome_fittizio&gt;</em>.</li></ul>

<h3 id="apertura">Apertura</h3>
<ul><li>attacco il dispositivo, viene creata la entry per <em>/dev/&lt;id_dispositivo_a_blocchi_fisico&gt;</em></li>
<li>attivo il dispositivo a blocchi virtuale che eroga le funzionalità di cifratura (<strong>cryptsetup open</strong>) e che creerà l’occorrenza sotto <em>/dev/mapper/&lt;nome_fittizio&gt;</em></li>
<li>faccio il mount del dispositivo a blocchi virtuale <em>/dev/mapper/</em> su un punto di montaggio che è una cartella che creerò per l’occasione</li></ul>

<h3 id="chiusura">Chiusura</h3>
<ul><li>faccio l’unmount del punto di montaggio</li>
<li>chiudo il dispositivo a blocchi virtuale (<strong>cryptsetup close</strong>) <em>/dev/mapper/&lt;nome_fittizio&gt;</em></li>
<li>stacco il dispositivo fisico</li></ul>

<p>Fermo restando che questi restano i passaggi generali per qualunque dispositivo fisico, per creare un <strong>file container cifrato</strong> come farebbe Veracrypt, basta che cryptsetup <strong>formatti un file</strong> invece che un dispositivo a blocchi e automaticamente assocerà il file al primo loop device disponibile.
È veramente semplice<small><a id="link_nota_1" title="vai alla nota 1" href="#nota_1" rel="nofollow"><sup><strong> [1] </strong></sup></a></small>.</p>

<h2 id="come-creare-il-file-vault">Come creare il file vault</h2>

<p>Divido le operazioni in 3 fasi:</p>
<ul><li><strong>Init</strong>: fase di inizializzazione del “dispositivo” (il file). Andrà fatta solo la prima volta.</li>
<li><strong>Open</strong> e <strong>Close</strong>: sono le operazioni che farò ogniqualvolta dovrò usare il container.</li></ul>

<p>Gli oggetti su cui andrà a lavorare sono:</p>
<ul><li><strong>disco_cifrato.img</strong>: il file container cifrato.</li>
<li><strong>disco_cifrato</strong>: il nome con cui disco_cifrato.img (o meglio, la sua rappresentazione come loop device visibile con <strong>losetup</strong>) viene mappato da device mapper.</li>
<li><strong>disco_in_chiaro</strong>: il punto di montaggio.</li></ul>

<pre><code class="language-bash">## Init
# creazione di una cartella che sarà il nostro punto di mount
mkdir disco_in_chiaro
 
# creazione di un file vuoto di 2 GiB
sudo fallocate -l 2g disco_cifrato.img
 
# preparazione cifratura LUKS 
sudo cryptsetup luksFormat \
     --type luks2 \
     --hash=sha512 \
     --key-size=512 \
     disco_cifrato.img
 
# creazione dispositivo a blocchi virtuale che eroga le funzionalità di cifratura
sudo cryptsetup open \
     --type luks2 \
     disco_cifrato.img disco_cifrato
 
# formattazione
sudo mkfs.ext4 /dev/mapper/disco_cifrato
</code></pre>

<pre><code class="language-bash">## Open
# creazione dispositivo a blocchi virtuale
sudo cryptsetup open \
     --type luks2 
     disco_cifrato.img disco_cifrato
 
# monta il dispositivo nel punto di montaggio
sudo mount -t ext4 -o defaults /dev/mapper/disco_cifrato disco_in_chiaro
</code></pre>

<pre><code class="language-bash">## Close
# smonta il dispositivo
sudo umount disco_in_chiaro
 
# chiudo il dispositivo a blocchi virtuale staccandolo dai loop device
sudo cryptsetup close disco_cifrato
</code></pre>

<h2 id="header-detachable-e-keyfile">Header detachable e keyfile</h2>

<p>Alziamo il livello di paranoia aggiungendo una complessità ulteriore. Creeremo il file vault nel seguente modo:</p>
<ol><li>il vault sarà inizializzato con rumore casuale</li>
<li>header detachable</li>
<li>offset custom</li>
<li>keyfile invece che password</li>
<li>default di argon2id (controlla il tuo default con cryptsetup benchmark)</li></ol>

<p>L’apertura del volume cifrato sarà così vincolata alla disponibiltà sia del keyfile che dell’header, senza il quale il volume cifrato sarebbe comunque inservibile.</p>

<p>La presenza di rumore casuale su tutto il vault nella fase di inizializzazione impedirà qualunque tentativo di risalire alla tipologia di informazioni memorizzate, l&#39;assenza di zeri impedirà di capire quanti sono i dati (cifrati) memorizzati.</p>

<p>L&#39;offset custom aggiunge un ulteriore tassello perchè nasconde il punto in cui inizia il payload.</p>

<p>Un keyfile di dati binari casuali è infinitamente più robusto di una password  e può esser conservato separatamente insieme all&#39;header. La cifratura simmetrica del keyfile aggiunge ulteriore protezione, fatta magari usando una passphrase ottenuta col <strong><a href="https://noblogo.org/aytin/come-valutare-la-resistenza-di-una-password-trilogia-della-password-2-di-3#metodo-diceware" rel="nofollow">metodo Diceware</a>.</strong></p>

<p>Infine la cifratura di default di luks2, argon2id, che è notoriamente sia CPU bound che GPU bound.</p>

<p>Creo il keyfile protetto da una cifratura simmetrica di gpg<small><a id="link_nota_2" title="vai alla nota 2" href="#nota_2" rel="nofollow"><sup><strong> [2] </strong></sup></small></a>:</p>

<pre><code class="language-bash">## Creazione di un keyfile di 4KiB basata sulla pseudocasualità di /dev/urandom
# creazione del keyfile
dd if=/dev/urandom bs=1024 count=4 | \
    gpg --yes -o disco_cifrato.key.gpg -c \
        --s2k-mode 3 \
        --s2k-count 32505856 \
        --s2k-cipher-algo aes256 \
        --s2k-digest-algo sha512 \
        --force-mdc -
</code></pre>

<p>Inizializzo il vault con dati casuali e poi lo formatto creando l&#39;header detachable del volume cifrato fornendo il keyfile invece della passphrase classica:</p>

<pre><code class="language-bash"># inizializzazione vault con dati casuali
# Apro il vault in modalità &#39;plain&#39; senza header
sudo cryptsetup open \
    --type plain \
    --key-file /dev/urandom \
    --cipher aes-xts-plain64 \
    --key-size 512 \ 
    disco_cifrato.img container

# scrivo degli zeri a cui, attraverso il motore di cifratura,
# corrisponderanno dati casuali sul vault.
dd if=/dev/zero of=/dev/mapper/container status=progress
cryptsetup close container

# Formattazione vault
gpg -d disco_cifrato.key.gpg | \
    sudo cryptsetup luksFormat \
        --type luks2 \
        --key-file - \
        --header header.img \
        --offset 32768 \
        --hash sha512 \
        --key-size 512 \
        --cipher aes-xts-plain64 \
        disco_cifrato.img
</code></pre>

<p>Ed è così che l’apertura del volume cifrato è ora <strong>vincolata al possesso dell’header e del keyfile</strong>:</p>

<pre><code class="language-bash"># attivazione dispositivo a blocchi virtuale passando header e keyfile protetto da gpg
gpg -d disco_cifrato.key.gpg | \
    sudo cryptsetup open \
        --type luks2 \
	--header header.img \
	--key-file - \
	disco_cifrato.img disco_cifrato
</code></pre>

<p>Provando ad aprire container cifrato <strong>senza fornire l’header</strong> (non tanto il keyfile che è una passphrase evoluta) succede questo:</p>

<pre><code class="language-bash">sudo cryptsetup open \
    --type luks2 \
    disco_cifrato.img disco_cifrato
Il dispositivo disco_cifrato.img non è un dispositivo LUKS valido.
</code></pre>

<p>Infine, un&#39;annotazione doverosa.</p>

<p>Visto che il livello di paranoia abbiamo detto essere elevato, sarebbe consigliabile prestare una certa attenzione alla scelta dei nomi.</p>

<p>Quelli usati finora avevano uno scopo “didattico”, che chiarisse il loro scopo  con un nome parlante.</p>

<p>i nomi dei file relativi a header e keyfile sarebbe bene non fossero qualcosa del tpo “header.img” o “discocifrato_key.gpg” che rivelano troppo esplicitamente la presenza di un disco cifrato o addirittura dello stesso LUKS. Meglio usare nomi più decontestualizzati, che so... “<code>sys-module-virtio.bin</code>” per l&#39;header e “<code>boot-vmlinuz-06.blob</code>” per il keyfile e via dicendo.</p>

<h2 id="partizionare-un-volume-cifrato">Partizionare un “volume” cifrato</h2>

<p>Per concludere, visto che prima ho accennato al fatto che dm-crypt, grazie al sottosistema device mapper, fa in modo che i dispositivi a blocchi (virtuali) mascherino i dispositivo a blocchi sottostanti (un file montato su un loop device, nel nostro caso), i dispositivi a blocchi mappati possono anche essere partizionati invece che sempicemente formattati. O potrebbe essere volumi fisici di un gruppo di volumi LVM, and so on…</p>

<p>Difficilmente avremo bisogno di partizionare un file container cifrato, è solo l’occasione per speculare un po’ su quello che potrebbe succedere su un device fisico.</p>

<pre><code class="language-bash">## Init
mkdir disco_in_chiaro
sudo fallocate -l 2g disco_cifrato.img
sudo cryptsetup luksFormat --hash=sha512 --key-size=512 disco_cifrato.img
sudo cryptsetup open --type luks2 disco_cifrato.img disco_cifrato
 
# Creo 1 partizione primaria da 600 MiB, una estesa da 1400 MiB
# contenente 2 partizioni logiche da 600 MiB e 829 MiB (mancano i
# 16 MiB dell&#39;intestazione luks e i 3 MiB delle intestazioni delle
# partizioni primarie ed estese per un totale di 2GiB tondi tondi)
sudo fdisk /dev/mapper/disco_cifrato
n,,,,+600M,n,e,,,,n,,+600M,n,,,w
 
# il partizionamento potrebbe richiedere l&#39;esecuzione di partprobe
# affinché il kernel carichi la tabella delle partizioni aggiornata
sudo partprobe /dev/mapper/disco_cifrato

# stato delle partizioni
sudo fdisk -l /dev/mapper/disco_cifrato
Disk /dev/mapper/disco_cifrato: 1,98 GiB, 2130706432 bytes, 520192 sectors
Units: sectors of 1 * 4096 = 4096 bytes
Sector size (logical/physical): 4096 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: dos
Disk identifier: 0x6d65a06f

Device                     Boot  Start    End Sectors  Size Id Type
/dev/mapper/disco_cifrato1         256 153855  153600  600M 83 Linux
/dev/mapper/disco_cifrato2      153856 520191  366336  1,4G  5 Extended
/dev/mapper/disco_cifrato5      154112 307711  153600  600M 83 Linux
/dev/mapper/disco_cifrato6      307968 520191  212224  829M 83 Linux

#procedo con la formattazione
sudo mkfs.ext4 /dev/mapper/disco_cifrato1 #formatto la partizione
sudo mkfs.ext4 /dev/mapper/disco_cifrato5 #formatto la partizione
sudo mkfs.ext4 /dev/mapper/disco_cifrato6 #formatto la partizione
</code></pre>

<p>Rispetto all’init di prima, invece che formattare subito il device “fisico”, l’ho partizionato. Esattamente come avrei fatto con un dispositivo realmente fisico.</p>

<pre><code class="language-bash">## Open
sudo cryptsetup open --type luks2 disco_cifrato.img disco_cifrato
 
# di nuovo, potrebbe essere necessario a meno di non riavviare
sudo partprobe /dev/mapper/disco_cifrato
 
# mount delle partizioni
sudo mount -t ext4 -o defaults /dev/mapper/disco_cifrato1 disco_in_chiaro_1
sudo mount -t ext4 -o defaults /dev/mapper/disco_cifrato5 disco_in_chiaro_2
sudo mount -t ext4 -o defaults /dev/mapper/disco_cifrato6 disco_in_chiaro_3
</code></pre>

<pre><code class="language-bash">## Close
sudo umount disco_in_chiaro_1
sudo umount disco_in_chiaro_2
sudo umount disco_in_chiaro_3
sudo cryptsetup close disco_cifrato1
sudo cryptsetup close disco_cifrato2
sudo cryptsetup close disco_cifrato5
sudo cryptsetup close disco_cifrato6
sudo cryptsetup close disco_cifrato
</code></pre>

<p><strong>Note:</strong>
<small></p>
<ol><li><p><code>cryptsetup --open luks2</code> e <code>cryptsetup --close luks2</code>, <a id="nota_1"></a>quando applicate direttamente al file container, includono implicitamente la parte di accoppiamento al loop device.
In altre parole,</p>

<pre><code class="language-bash">cryptsetup open --type luks2 disco_cifrato.img disco_cifrato
</code></pre>

<p>equivale a</p>

<pre><code class="language-bash">cryptsetup open --type luks2 $(losetup -Pf --show disco_cifrato.img) disco_cifrato
</code></pre>

<p>e</p>

<pre><code class="language-bash">cryptsetup close --type luks2 disco_cifrato
</code></pre>

<p>equivale a<a href="#link_nota_1" title="torna su" rel="nofollow"><sup><b> [↵] </b></sup></a></p>

<pre><code class="language-bash">cryptsetup close --type luks2 disco_cifrato
losetup -D
</code></pre></li>

<li><p><a id="nota_2"></a>Se si incorre in questo errore usando gpg:</p>

<pre><code class="language-bash">gpg: cancelled by user
gpg: error creating passphrase: Operation cancelled
gpg: symmetric encryption of &#39;[stdin]&#39; failed: Operation cancelled
</code></pre>

<p>vuol dire che la variabile d’ambiente <code>GPG_TTY</code> non ha lo stesso valore del comando tty. Per ovviare basta settare correttamente la variabile:</p>

<pre><code class="language-bash">GPG_TTY=$(tty)
export GPG_TTY
</code></pre>

<p>come suggerito dalla <a href="https://www.gnupg.org/documentation/manuals/gnupg/Invoking-GPG_002dAGENT.html#Invoking-GPG_002dAGENT" rel="nofollow">documentazione GnuPG</a> <a href="#link_nota_2" title="torna su" rel="nofollow"><sup><b> [↵] </b></sup></a></p></li></ol>

<p></small></p>

<p><a href="/aytin/tag:cryptsetup" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">cryptsetup</span></a> <a href="/aytin/tag:devicemapper" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">devicemapper</span></a> <a href="/aytin/tag:dmcrypt" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">dmcrypt</span></a> <a href="/aytin/tag:gpg" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">gpg</span></a> <a href="/aytin/tag:loseup" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">loseup</span></a> <a href="/aytin/tag:luks" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">luks</span></a> <a href="/aytin/tag:lvm" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">lvm</span></a> <a href="/aytin/tag:loopdevice" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">loopdevice</span></a> <a href="/aytin/tag:storage" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">storage</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/come-creare-un-file-container</guid>
      <pubDate>Fri, 10 May 2024 21:32:57 +0000</pubDate>
    </item>
    <item>
      <title>Gestione TOTP in bash</title>
      <link>https://noblogo.org/aytin/gestione-totp-in-bash</link>
      <description>&lt;![CDATA[totp&#xA;&#xA;In una giornata in cui avevo un po’ di tempo da investire, ho ripreso la versione 2 dello script &#34;Generazione OTP via bash&#34;, e ho deciso di renderlo un po’ più flessibile introducendo una logica crud. Anzi, il termine corretto dovrebbe essere &#34;dave&#34; (Delete, Add, View, Edit).&#xA;!--more--&#xA;Che altro aggiungere?&#xA;&#xA;Il file è ancora un insieme di coppie chiave-valore (nome account e chiave privata).&#xA;Il separatore è il simbolo &#34;:&#34;. Ma può essere configurato cambiando il valore della variabile &#34;DELIMITER&#34;.&#xA;Lo script è discretamente commentato così, in futuro, riuscirò a ricordare perché ho fatto quello che ho fatto (tipo &#34;Memento&#34;).&#xA;Le opzioni di gpg per la cifratura/decifratura del file sono configurabili nello script modificando il valore delle variabili &#34;GPG\ENC\OPTIONS&#34; e &#34;GPG\DEC\OPTIONS&#34;.&#xA;L’uso di getopts, mi rendo conto, è solo un esercizio di stile. Non è molto utile per come l’ho usato, visto che ogni optarg corrisponde ad un’operazione autoconclusiva.&#xA;Ero partito per rimpiazzare ogni costrutto if con combinazioni di lista and / lista or ma le condizioni risultavano talmente complesse da rendere il codice francamente molto più incomprensibile di adesso. In alternativa avrei potuto delegare l’esecuzione delle condizioni ad un insieme di funzioni con una stratificazione tale da ricadere nel punto precedente: offuscamento permanente del codice che va a vanificare l’intenzione iniziale di semplificare il codice e renderlo più leggibile.&#xA;&#xA;!/usr/local/bin/bash&#xA;&#xA;init() {&#xA;    # CODICI D&#39;ERRORE&#xA;    DECRYPTERR=64&#xA;    INVALIDOPTIONERR=65&#xA;    INVALIDACCOUNTERR=66&#xA;    ACCOUNTNOTFOUNDERR=67&#xA;    ACCOUNTNAMEEMPTYERR=68&#xA;    ACCOUNTEXISTSERR=69&#xA;    INVALIDKEYERR=70&#xA;&#xA;    # Colorscheme&#xA;    LIGHTGREEN=&#39;\033[1;32m&#39;&#xA;    LIGHTRED=&#39;\033[1;31m&#39;&#xA;    NC=&#39;\033[0m&#39;&#xA;&#xA;    # Path del file cifrato contentente i codici 2FA&#xA;    KEYS2FAFILE=&#34;path/fileenc.gpg&#34;&#xA;&#xA;    # Separatore delle coppie chiave-valore&#xA;    DELIMITER=&#34;:&#34;&#xA;&#xA;    # path gpg e opzioni di cifratura/decifratura&#xA;    GPGTTY=$(tty)&#xA;    export GPGTTY&#xA;&#xA;    #GPGCOMMAND=&#34;/usr/local/bin/gpg&#34;&#xA;    GPGENCOPTIONS=&#34;--yes -c --s2k-cipher-algo aes256 --s2k-digest-algo sha512 --s2k-mode 3 --s2k-count 260000 - &#34;&#xA;    GPGDECOPTIONS=&#39;-d&#39;&#xA;&#xA;    # Caratteri consentiti nel nome account&#xA;    PATTERN=&#39;^[a-zA-Z0-9.-]+$&#39;;&#xA;&#xA;    # Su MacOS è disponibile &#34;pbcopy&#34;, su nix &#34;xsel&#34;&#xA;    case &#34;$(sysctl hw.targettype 2  /dev/null)&#34; in&#xA;        &#34;&#34;)&#xA;            CLIPBOARD=&#34;xsel -bi&#34;&#xA;            GPGCOMMAND=&#34;/usr/bin/gpg&#34;;;&#xA;         )&#xA;            CLIPBOARD=&#34;pbcopy&#34;&#xA;            GPGCOMMAND=&#34;/usr/local/bin/gpg&#34;;;&#xA;    esac&#xA;&#xA;    # Decifra e carica in ram il contenuto del file cifrato.&#xA;    echo &#34;Decifratura del file degli account in corso...&#34;&#xA;    KEYS2FAFILEDEC=$(${GPGCOMMAND} ${GPGDECOPTIONS} &#34;${KEYS2FAFILE}&#34; 2  /dev/null)&#xA;&#xA;    # Se la password non è corretta, restituisce un errore.&#xA;    [[ -z &#34;${KEYS2FAFILEDEC}&#34; ]] &amp;&amp; { errmsg &#34;${DECRYPTERR}&#34; 1; }&#xA;    infomsg &#34;Fatto.&#34;&#xA;}&#xA;&#xA;getaccount() {&#xA;    ACCOUNTSTDIO=&#34;$1&#34;&#xA;&#xA;    # Check nome account vuoto&#xA;    [[ -z &#34;${ACCOUNTSTDIO}&#34; ]] &amp;&amp; return &#34;${ACCOUNTNAMEEMPTYERR}&#34;&#xA;&#xA;    # Check caratteri invalidi nel nome account&#xA;    [[ ! &#34;${ACCOUNTSTDIO}&#34; =~ $PATTERN ]] &amp;&amp; return &#34;${INVALIDACCOUNTERR}&#34;&#xA;&#xA;    # Estrae l&#39;elemento contenente l&#39;id dato in input&#xA;    OTPLINE=$(echo &#34;${KEYS2FAFILEDEC}&#34; | grep &#34;${ACCOUNTSTDIO}:&#34;)&#xA;&#xA;    # Se l&#39;account non esiste, restituisce un errore&#xA;    [[ -z &#34;${OTPLINE}&#34; ]] &amp;&amp; return &#34;${ACCOUNTNOTFOUNDERR}&#34;&#xA;&#xA;    ACCOUNT=$(echo $OTPLINE | cut -d&#34;${DELIMITER}&#34; -f 1)&#xA;    KEY=$(echo $OTPLINE | cut -d&#34;${DELIMITER}&#34; -f 2)&#xA;}&#xA;&#xA;cryptaccountfile() {&#xA;    ACCOUNTFILE=&#34;$1&#34;&#xA;    echo -e &#34;\nCifratura del file degli account in corso...&#34;&#xA;    ${GPGCOMMAND} -o &#34;$KEYS2FAFILE&#34; ${GPGENCOPTIONS} &lt;&lt;&lt; $(echo -e &#34;${ACCOUNTFILE}&#34;)&#xA;}&#xA;&#xA;noparam() {&#xA;    clear&#xA;    help&#xA;    exit 0&#xA;}&#xA;&#xA;Visualizza messaggi di errore su stdio&#xA;errmsg() {&#xA;    if [[ $# -ne 2 ]]; then&#xA;        echo -r&#34;${LIGHTRED}[DEBUG] [errmsg] Numero di parametri non corretto.${NC}.&#34;; exit 1&#xA;    else&#xA;        case $1 in&#xA;            &#34;${DECRYPTERR}&#34;            ) echo -e &#34;${LIGHTRED}[ERRORE] Impossibile decriptare il file.${NC}&#34;;;&#xA;            &#34;${INVALIDOPTIONERR}&#34;     ) echo -e &#34;${LIGHTRED}[ERRORE] Opzione \&#34;$OPTARG\&#34; non valida.${NC}&#34;;;&#xA;            &#34;${INVALIDACCOUNTERR}&#34;    ) echo -e &#34;${LIGHTRED}ERRORE] Rilevati caratteri non consentiti.\nI caratteri ammessi sono: [a-z[0-9].-${NC}&#34;;;&#xA;            &#34;${ACCOUNTNOTFOUNDERR}&#34;  ) echo -e &#34;${LIGHTRED}[ERRORE] Account non trovato${NC}&#34;;;&#xA;            &#34;${ACCOUNTNAMEEMPTYERR}&#34; ) echo -e &#34;${LIGHTRED}[ERRORE] Nome account vuoto.${NC}&#34;;;&#xA;            &#34;${ACCOUNTEXISTSERR}&#34;     ) echo -e &#34;${LIGHTRED}[ERRORE] Nome account già esistente${NC}&#34;;;&#xA;            &#34;${INVALIDKEYERR}&#34;        ) echo -e &#34;${LIGHTRED}[ERRORE] Chiave privata nulla o non corretta.\nLa chiave privata deve essere base32.\n${NC}&#34;;;&#xA;            ) echo -e &#34;${LIGHTRED}[ERRORE] Errore generico.${NC}&#34;;;&#xA;        esac&#xA;&#xA;        [[ $2 -eq 1 ]] &amp;&amp; exit $2;&#xA;    fi&#xA;}&#xA;&#xA;Visualizza messaggi info su stdio&#xA;infomsg() {&#xA;    echo -e &#34;${LIGHTGREEN}$1${NC}&#34;&#xA;}&#xA;&#xA;continuemsg() {&#xA;    case $1 in&#xA;        &#34;insert&#34;    ) ACTION=&#34;creato&#34;;;&#xA;        &#34;edit&#34;      ) ACTION=&#34;modificato&#34;;;&#xA;        &#34;delete&#34;    ) ACTION=&#34;cancellato&#34;;;&#xA;    esac&#xA;&#xA;    echo -n &#34;L&#39;account \&#34;${ACCOUNT}\&#34; sta per essere ${ACTION}. Vuoi continuare? [y|N]: &#34;; read ANSWER;&#xA;}&#xA;&#xA;continueyn() {&#xA;        ANSWER=&#34;0&#34;&#xA;        while [[ &#34;${ANSWER}&#34; != &#34;y&#34; ]]; do&#xA;            [[ -z &#34;${ANSWER}&#34; || &#34;${ANSWER}&#34; == &#34;N&#34; ]] &amp;&amp; { echo &#34;Operazione annullata&#34;; exit; }&#xA;            [[ &#34;${ANSWER}&#34; != &#34;y&#34; || &#34;${ANSWER}&#34; != &#34;N&#34; ]] &amp;&amp; continuemsg &#34;$1&#34;&#xA;        done&#xA;}&#xA;&#xA;totp() {&#xA;    # Se la&#39;ccount non esiste o è invalido, esco con errore&#xA;    getaccount &#34;$1&#34;; RETCODE=$?&#xA;    case &#34;${RETCODE}&#34; in&#xA;        &#34;${ACCOUNTNOTFOUNDERR}&#34;  ) errmsg &#34;${ACCOUNTNOTFOUNDERR}&#34; 1;;&#xA;        &#34;${INVALIDACCOUNTERR}&#34;    ) errmsg &#34;${INVALIDACCOUNTERR}&#34; 1;;&#xA;    esac&#xA;&#xA;    echo -e &#34;\nCopia OTP nella clipboard...&#34;&#xA;    # Calcola l&#39;otp e lo trasferisce nella clipboard con xsel&#xA;    oathtool --totp -b &#34;${KEY}&#34; | $CLIPBOARD&#xA;    infomsg &#34;Fatto.&#34;&#xA;    exit&#xA;}&#xA;&#xA;insert() {&#xA;    # Se l&#39;account non esiste o è invalido, esco con errore&#xA;    getaccount &#34;$1&#34;; RETCODE=$?&#xA;    case &#34;${RETCODE}&#34; in&#xA;        0                           ) errmsg &#34;${ACCOUNTEXISTSERR}&#34; 1;;&#xA;        &#34;${INVALIDACCOUNTERR}&#34;    ) errmsg &#34;${INVALIDACCOUNTERR}&#34; 1;;&#xA;    esac&#xA;&#xA;    ACCOUNT=&#34;$1&#34;&#xA;&#xA;    # Inserisci la chiave&#xA;    echo -en &#34;Nuovo account: ${ACCOUNT}\nInserisci la nuova chiave privata: &#34;; read KEY&#xA;    while [[ -z &#34;${KEY}&#34; || ! $(echo ${KEY} | oathtool -b - 2  /dev/null) ]]; do&#xA;        errmsg &#34;${INVALIDKEYERR}&#34; 0&#xA;        echo -n &#34;Inserisci la chiave privata: &#34;; read KEY&#xA;    done&#xA;&#xA;    infomsg &#34;\nNuovo account:        ${ACCOUNT}\nNuova chiave privata: ${KEY}&#34;&#xA;    continueyn &#34;insert&#34;&#xA;&#xA;    # Appendo il nuovo record nel file degli account&#xA;    KEYS2FAFILEDEC+=&#34;\n${ACCOUNT}${DELIMITER}${KEY}&#34;&#xA;    infomsg &#34;L&#39;account \&#34;${ACCOUNT}\&#34; è stato creato con successo.&#34;&#xA;&#xA;    # Cifratura del file degli account&#xA;    cryptaccountfile &#34;${KEYS2FAFILEDEC}&#34;&#xA;    infomsg &#34;Fatto.&#34;&#xA;    exit&#xA;}&#xA;&#xA;edit() {&#xA;    # Se la&#39;ccount non esiste o è invalido, esco con errore&#xA;    getaccount &#34;$1&#34;; RETCODE=$?&#xA;    case &#34;${RETCODE}&#34; in&#xA;        &#34;${ACCOUNTNOTFOUNDERR}&#34;  ) errmsg &#34;${ACCOUNTNOTFOUNDERR}&#34; 1;;&#xA;        &#34;${INVALIDACCOUNTERR}&#34;    ) errmsg &#34;${INVALIDACCOUNTERR}&#34; 1;;&#xA;    esac&#xA;&#xA;    # Faccio una copia dell&#39;account per un eventuale ripristino durante&#xA;    # la fase di input&#xA;    ACCOUNTTEMP=&#34;${ACCOUNT}&#34;&#xA;    ACCOUNTMOD=&#34;${ACCOUNT}&#34;&#xA;&#xA;    # Inserisco il nuovo nome account.&#xA;    # 1. Se è vuoto: è la conferma dell&#39;account inserito all&#39;inizio e proseguo&#xA;    # 2. Se il nome è invalido: sollevo un&#39;eccezione e reitero&#xA;    # 3. Se il nome è valido:&#xA;    #    a. Se è un nome nuovo: acquisisco il nuovo nome, recupero nome e chiave dell&#39;account di partenza e proseguo&#xA;    #    b. Sè è lo stesso nome di partenza: è la conferma dell&#39;account iniziale e proseguo&#xA;    #    c. Se è un altro nome esistente o invalido: come il punto 2.&#xA;    while true; do&#xA;        echo&#xA;        echo -en &#34;Account: ${ACCOUNT}\nInserisci nuovo nome account: &#34;; read ACCOUNTMOD;&#xA;        getaccount &#34;${ACCOUNTMOD}&#34;; RETCODE=$?&#xA;        case &#34;${RETCODE}&#34; in&#xA;            # Punto 1.&#xA;            &#34;${ACCOUNTNAMEEMPTYERR}&#34; ) ACCOUNTMOD=&#34;${ACCOUNT}&#34;; break;;&#xA;            # Punto 2&#xA;            &#34;${INVALIDACCOUNTERR}&#34;    ) errmsg &#34;${INVALIDACCOUNTERR}&#34; 0;;&#xA;            # Punto 3a.&#xA;            &#34;${ACCOUNTNOTFOUNDERR}&#34;  ) getaccount &#34;${ACCOUNTTEMP}&#34;; break;;&#xA;            # Punti 3b e 3c, rispettivamente&#xA;            0                           ) [[ &#34;${ACCOUNTMOD}&#34; == &#34;${ACCOUNTTEMP}&#34; ]] &amp;&amp; break \&#xA;                                                                                 || { getaccount &#34;${ACCOUNTTEMP}&#34;; errmsg &#34;${ACCOUNTEXISTSERR}&#34; 0; };;&#xA;        esac&#xA;    done&#xA;&#xA;    [[ &#34;${ACCOUNT}&#34; != &#34;${ACCOUNTMOD}&#34; &amp;&amp; ! -z &#34;${ACCOUNTMOD}&#34; ]] &amp;&amp; msg=&#34;\nL&#39;account \&#34;${ACCOUNT}\&#34; è stato modificato in \&#34;${ACCOUNTMOD}\&#34;.&#34; \&#xA;                                                                    || msg=&#34;\nNessuna modifica rilevata.\n&#34;&#xA;    infomsg &#34;${msg}&#34;&#xA;&#xA;    # Modifica la chiave privata&#xA;    KEYMOD=&#34;${KEY}&#34;&#xA;    echo&#xA;&#xA;    while true; do&#xA;        echo -en &#34;Chiave privata: ${KEY}\nInserisci la nuova chiave privata: &#34;; read KEYMOD&#xA;        if [[ -z $KEYMOD ]]; then&#xA;            KEYMOD=&#34;${KEY}&#34;; break&#xA;        elif [[ ! $(echo &#34;${KEYMOD}&#34; | oathtool -b - 2  /dev/null) ]]; then&#xA;            errmsg &#34;${INVALIDKEYERR}&#34; 0; KEYMOD=&#34;${KEY}&#34;&#xA;        else&#xA;            break&#xA;        fi&#xA;    done&#xA;&#xA;    # Se c&#39;è stata almeno una modifica (account/key), sovrascrivo il record. Altrimenti esco senza fare nulla.&#xA;    if [[ &#34;${ACCOUNT}&#34; != &#34;${ACCOUNTMOD}&#34; || &#34;${KEY}&#34; != &#34;${KEYMOD}&#34; ]]; then&#xA;        # Conferma modifica&#xA;&#xA;        infomsg &#34;\nAccount:              ${ACCOUNT}\nChiave privata:       ${KEY}\nNuovo account:        ${ACCOUNTMOD}\nNuova chiave privata: ${KEYMOD}\n&#34;&#xA;        continueyn &#34;edit&#34;&#xA;&#xA;        # Modifica del file degli account&#xA;        KEYS2FAFILEDECTEMP=$(sed &#34;s/${ACCOUNT}${DELIMITER}${KEY}/${ACCOUNTMOD}${DELIMITER}${KEYMOD}/&#34; &lt;&lt;&lt; &#34;${KEYS2FAFILEDEC}&#34;)&#xA;        infomsg &#34;L&#39;account \&#34;${ACCOUNT}\&#34; è stato modificato con successo.&#34;&#xA;&#xA;        # Cifratura del file degli account&#xA;        cryptaccountfile &#34;${KEYS2FAFILEDECTEMP}&#34;&#xA;    else&#xA;        infomsg &#34;Nessuna modifica rilevata.&#34;&#xA;    fi&#xA;    infomsg &#34;Fatto.&#34;&#xA;}&#xA;&#xA;delete() {&#xA;    if getaccount &#34;$1&#34;; then&#xA;        # Conferma eliminazione&#xA;        infomsg &#34;\nAccount:              ${ACCOUNT}\nChiave privata:       ${KEY}\n&#34;&#xA;        continueyn &#34;delete&#34;&#xA;&#xA;        # Cancellazione account&#xA;        KEYS2FAFILEDECTEMP=$(sed &#34;/$ACCOUNT/d&#34; &lt;&lt;&lt; &#34;${KEYS2FAFILEDEC}&#34;)&#xA;        infomsg &#34;L&#39;account \&#34;$ACCOUNT\&#34; è stato eliminato.&#34;&#xA;&#xA;        # Cifratura del nuovo file degli account&#xA;        cryptaccountfile &#34;${KEYS2FAFILEDECTEMP}&#34;&#xA;        infomsg &#34;Fatto.&#34;&#xA;    else&#xA;        errmsg &#34;${ACCOUNTNOTFOUNDERR}&#34; 1&#xA;    fi&#xA;}&#xA;&#xA;list() {&#xA;    echo&#xA;    while read LINE; do&#xA;        cut -d&#34;${DELIMITER}&#34; -f 1 &lt;&lt;&lt; &#34;${LINE}&#34;&#xA;    done &lt;&lt;&lt; &#34;${KEYS2FAFILEDEC}&#34;&#xA;}&#xA;&#xA;help() {&#xA;cat&lt;&lt;EOF&#xA;Usa come: ./totp.sh [options] ARG&#xA;dove:&#xA;    [options]&#xA;        -l restituisce la lista degli account.&#xA;        -t nomeaccount restituisce l&#39;otp per quell&#39;account.&#xA;        -i nomeaccount inserisce un nuovo account.&#xA;        -d nomeaccount cancella nomeaccount.&#xA;        -e nomeaccount modifica nomeaccount.&#xA;        -h stampa questa pagina di help.&#xA;&#xA;ESEMPI:&#xA;    RESTITUISCE LA LISTA DEGLI ACCOUNT&#xA;    totp.sh -l&#xA;&#xA;    INSERISCE UN ACCOUNT&#xA;    totp.sh -i dropbox&#xA;&#xA;    CANCELLA UN ACCOUNT&#xA;    totp.sh -d megaupload&#xA;&#xA;    MODIFICA UN ACCOUNT&#xA;    totp.sh -e paypal&#xA;&#xA;    GENERA OTP&#xA;    totp.sh -t firefoxsync&#xA;EOF&#xA;}&#xA;&#xA;main() {&#xA;    init&#xA;    while getopts &#34;lt:i:e:d:&#34; opt; do&#xA;        case $opt in&#xA;            l ) list ;;&#xA;            t ) totp $OPTARG ;;&#xA;            i ) insert $OPTARG ;;&#xA;            e ) edit $OPTARG ;;&#xA;            d ) delete $OPTARG ;;&#xA;            ) clear;errmsg &#34;${INVALIDOPTIONERR}&#34; 1;;&#xA;        esac&#xA;    done&#xA;    shift $(($OPTIND - 1))&#xA;}&#xA;&#xA;[[ $# -eq 0 || $# -eq 1 &amp;&amp; &#34;$1&#34; == &#34;-h&#34; ]] &amp;&amp; noparam || main $*&#xA;&#xA;#bash #totp #cryptography #gpg #scripting]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/7c649620b-69b6c5/x5Ykru5oywKu/RE9KMTKwgIzhwDrkGnZqsTThRVvDSlNlyB2XwSv4.webp" alt="totp"></p>

<p>In una giornata in cui avevo un po’ di tempo da investire, ho ripreso la versione 2 dello script “<a href="https://noblogo.org/aytin/generazione-otp-via-bash" rel="nofollow">Generazione OTP via bash</a>”, e ho deciso di renderlo un po’ più flessibile introducendo una logica <strong>crud</strong>. Anzi, il termine corretto dovrebbe essere “<strong>dave</strong>” (<strong>D</strong>elete, <strong>A</strong>dd, <strong>V</strong>iew, <strong>E</strong>dit).

Che altro aggiungere?</p>
<ul><li>Il file è ancora un insieme di coppie chiave-valore (nome account e chiave privata).</li>
<li>Il separatore è il simbolo “<strong>:</strong>”. Ma può essere configurato cambiando il valore della variabile “<strong>DELIMITER</strong>”.</li>
<li>Lo script è discretamente commentato così, in futuro, riuscirò a ricordare perché ho fatto quello che ho fatto (tipo “Memento”).</li>
<li>Le opzioni di gpg per la cifratura/decifratura del file sono configurabili nello script modificando il valore delle variabili “<strong>GPG_ENC_OPTIONS</strong>” e “<strong>GPG_DEC_OPTIONS</strong>”.</li>
<li>L’uso di <strong>getopts,</strong> mi rendo conto, è solo un esercizio di stile. Non è molto utile per come l’ho usato, visto che ogni optarg corrisponde ad un’operazione autoconclusiva.</li>
<li>Ero partito per rimpiazzare ogni costrutto <strong>if</strong> con combinazioni di lista and / lista or ma le condizioni risultavano talmente complesse da rendere il codice francamente molto più incomprensibile di adesso. In alternativa avrei potuto delegare l’esecuzione delle condizioni ad un insieme di funzioni con una stratificazione tale da ricadere nel punto precedente: offuscamento permanente del codice che va a vanificare l’intenzione iniziale di semplificare il codice e renderlo più leggibile.</li></ul>

<pre><code class="language-bash">
#!/usr/local/bin/bash


init() {
    # CODICI D&#39;ERRORE
    DECRYPT_ERR=64
    INVALID_OPTION_ERR=65
    INVALID_ACCOUNT_ERR=66
    ACCOUNT_NOT_FOUND_ERR=67
    ACCOUNT_NAME_EMPTY_ERR=68
    ACCOUNT_EXISTS_ERR=69
    INVALID_KEY_ERR=70

    # Colorscheme
    LIGHT_GREEN=&#39;\033[1;32m&#39;
    LIGHT_RED=&#39;\033[1;31m&#39;
    NC=&#39;\033[0m&#39;

    # Path del file cifrato contentente i codici 2FA
    KEYS_2FA_FILE=&#34;&lt;path/file_enc.gpg&gt;&#34;

    # Separatore delle coppie chiave-valore
    DELIMITER=&#34;:&#34;

    # path gpg e opzioni di cifratura/decifratura
    GPG_TTY=$(tty)
    export GPG_TTY

    #GPG_COMMAND=&#34;/usr/local/bin/gpg&#34;
    GPG_ENC_OPTIONS=&#34;--yes -c --s2k-cipher-algo aes256 --s2k-digest-algo sha512 --s2k-mode 3 --s2k-count 260000 - &#34;
    GPG_DEC_OPTIONS=&#39;-d&#39;

    # Caratteri consentiti nel nome account
    PATTERN=&#39;^[a-zA-Z0-9._-]+$&#39;;

    # Su MacOS è disponibile &#34;pbcopy&#34;, su *nix &#34;xsel&#34;
    case &#34;$(sysctl hw.targettype 2&gt;/dev/null)&#34; in
        &#34;&#34;)
            CLIPBOARD=&#34;xsel -bi&#34;
            GPG_COMMAND=&#34;/usr/bin/gpg&#34;;;
         *)
            CLIPBOARD=&#34;pbcopy&#34;
            GPG_COMMAND=&#34;/usr/local/bin/gpg&#34;;;
    esac

    # Decifra e carica in ram il contenuto del file cifrato.
    echo &#34;Decifratura del file degli account in corso...&#34;
    KEYS_2FA_FILE_DEC=$(${GPG_COMMAND} ${GPG_DEC_OPTIONS} &#34;${KEYS_2FA_FILE}&#34; 2&gt;/dev/null)

    # Se la password non è corretta, restituisce un errore.
    [[ -z &#34;${KEYS_2FA_FILE_DEC}&#34; ]] &amp;&amp; { err_msg &#34;${DECRYPT_ERR}&#34; 1; }
    info_msg &#34;Fatto.&#34;
}


get_account() {
    ACCOUNT_STDIO=&#34;$1&#34;

    # Check nome account vuoto
    [[ -z &#34;${ACCOUNT_STDIO}&#34; ]] &amp;&amp; return &#34;${ACCOUNT_NAME_EMPTY_ERR}&#34;

    # Check caratteri invalidi nel nome account
    [[ ! &#34;${ACCOUNT_STDIO}&#34; =~ $PATTERN ]] &amp;&amp; return &#34;${INVALID_ACCOUNT_ERR}&#34;

    # Estrae l&#39;elemento contenente l&#39;id dato in input
    OTP_LINE=$(echo &#34;${KEYS_2FA_FILE_DEC}&#34; | grep &#34;${ACCOUNT_STDIO}:&#34;)

    # Se l&#39;account non esiste, restituisce un errore
    [[ -z &#34;${OTP_LINE}&#34; ]] &amp;&amp; return &#34;${ACCOUNT_NOT_FOUND_ERR}&#34;

    ACCOUNT=$(echo $OTP_LINE | cut -d&#34;${DELIMITER}&#34; -f 1)
    KEY=$(echo $OTP_LINE | cut -d&#34;${DELIMITER}&#34; -f 2)
}


crypt_account_file() {
    ACCOUNT_FILE=&#34;$1&#34;
    echo -e &#34;\nCifratura del file degli account in corso...&#34;
    ${GPG_COMMAND} -o &#34;$KEYS_2FA_FILE&#34; ${GPG_ENC_OPTIONS} &lt;&lt;&lt; $(echo -e &#34;${ACCOUNT_FILE}&#34;)
}


no_param() {
    clear
    help
    exit 0
}


# Visualizza messaggi di errore su stdio
err_msg() {
    if [[ $# -ne 2 ]]; then
        echo -r&#34;${LIGHT_RED}[DEBUG] [err_msg] Numero di parametri non corretto.${NC}.&#34;; exit 1
    else
        case $1 in
            &#34;${DECRYPT_ERR}&#34;            ) echo -e &#34;${LIGHT_RED}[ERRORE] Impossibile decriptare il file.${NC}&#34;;;
            &#34;${INVALID_OPTION_ERR}&#34;     ) echo -e &#34;${LIGHT_RED}[ERRORE] Opzione \&#34;$OPTARG\&#34; non valida.${NC}&#34;;;
            &#34;${INVALID_ACCOUNT_ERR}&#34;    ) echo -e &#34;${LIGHT_RED}[ERRORE] Rilevati caratteri non consentiti.\nI caratteri ammessi sono: [a-z][A-Z][0-9].-_${NC}&#34;;;
            &#34;${ACCOUNT_NOT_FOUND_ERR}&#34;  ) echo -e &#34;${LIGHT_RED}[ERRORE] Account non trovato${NC}&#34;;;
            &#34;${ACCOUNT_NAME_EMPTY_ERR}&#34; ) echo -e &#34;${LIGHT_RED}[ERRORE] Nome account vuoto.${NC}&#34;;;
            &#34;${ACCOUNT_EXISTS_ERR}&#34;     ) echo -e &#34;${LIGHT_RED}[ERRORE] Nome account già esistente${NC}&#34;;;
            &#34;${INVALID_KEY_ERR}&#34;        ) echo -e &#34;${LIGHT_RED}[ERRORE] Chiave privata nulla o non corretta.\nLa chiave privata deve essere base32.\n${NC}&#34;;;
            *                           ) echo -e &#34;${LIGHT_RED}[ERRORE] Errore generico.${NC}&#34;;;
        esac

        [[ $2 -eq 1 ]] &amp;&amp; exit $2;
    fi
}


# Visualizza messaggi info su stdio
info_msg() {
    echo -e &#34;${LIGHT_GREEN}$1${NC}&#34;
}


continue_msg() {
    case $1 in
        &#34;insert&#34;    ) ACTION=&#34;creato&#34;;;
        &#34;edit&#34;      ) ACTION=&#34;modificato&#34;;;
        &#34;delete&#34;    ) ACTION=&#34;cancellato&#34;;;
    esac

    echo -n &#34;L&#39;account \&#34;${ACCOUNT}\&#34; sta per essere ${ACTION}. Vuoi continuare? [y|N]: &#34;; read ANSWER;
}


continue_yn() {
        ANSWER=&#34;0&#34;
        while [[ &#34;${ANSWER}&#34; != &#34;y&#34; ]]; do
            [[ -z &#34;${ANSWER}&#34; || &#34;${ANSWER}&#34; == &#34;N&#34; ]] &amp;&amp; { echo &#34;Operazione annullata&#34;; exit; }
            [[ &#34;${ANSWER}&#34; != &#34;y&#34; || &#34;${ANSWER}&#34; != &#34;N&#34; ]] &amp;&amp; continue_msg &#34;$1&#34;
        done
}


totp() {
    # Se la&#39;ccount non esiste o è invalido, esco con errore
    get_account &#34;$1&#34;; RET_CODE=$?
    case &#34;${RET_CODE}&#34; in
        &#34;${ACCOUNT_NOT_FOUND_ERR}&#34;  ) err_msg &#34;${ACCOUNT_NOT_FOUND_ERR}&#34; 1;;
        &#34;${INVALID_ACCOUNT_ERR}&#34;    ) err_msg &#34;${INVALID_ACCOUNT_ERR}&#34; 1;;
    esac

    echo -e &#34;\nCopia OTP nella clipboard...&#34;
    # Calcola l&#39;otp e lo trasferisce nella clipboard con xsel
    oathtool --totp -b &#34;${KEY}&#34; | $CLIPBOARD
    info_msg &#34;Fatto.&#34;
    exit
}


insert() {
    # Se l&#39;account non esiste o è invalido, esco con errore
    get_account &#34;$1&#34;; RET_CODE=$?
    case &#34;${RET_CODE}&#34; in
        0                           ) err_msg &#34;${ACCOUNT_EXISTS_ERR}&#34; 1;;
        &#34;${INVALID_ACCOUNT_ERR}&#34;    ) err_msg &#34;${INVALID_ACCOUNT_ERR}&#34; 1;;
    esac

    ACCOUNT=&#34;$1&#34;

    # Inserisci la chiave
    echo -en &#34;Nuovo account: ${ACCOUNT}\nInserisci la nuova chiave privata: &#34;; read KEY
    while [[ -z &#34;${KEY}&#34; || ! $(echo ${KEY} | oathtool -b - 2&gt;/dev/null) ]]; do
        err_msg &#34;${INVALID_KEY_ERR}&#34; 0
        echo -n &#34;Inserisci la chiave privata: &#34;; read KEY
    done

    info_msg &#34;\nNuovo account:        ${ACCOUNT}\nNuova chiave privata: ${KEY}&#34;
    continue_yn &#34;insert&#34;

    # Appendo il nuovo record nel file degli account
    KEYS_2FA_FILE_DEC+=&#34;\n${ACCOUNT}${DELIMITER}${KEY}&#34;
    info_msg &#34;L&#39;account \&#34;${ACCOUNT}\&#34; è stato creato con successo.&#34;

    # Cifratura del file degli account
    crypt_account_file &#34;${KEYS_2FA_FILE_DEC}&#34;
    info_msg &#34;Fatto.&#34;
    exit
}


edit() {
    # Se la&#39;ccount non esiste o è invalido, esco con errore
    get_account &#34;$1&#34;; RET_CODE=$?
    case &#34;${RET_CODE}&#34; in
        &#34;${ACCOUNT_NOT_FOUND_ERR}&#34;  ) err_msg &#34;${ACCOUNT_NOT_FOUND_ERR}&#34; 1;;
        &#34;${INVALID_ACCOUNT_ERR}&#34;    ) err_msg &#34;${INVALID_ACCOUNT_ERR}&#34; 1;;
    esac

    # Faccio una copia dell&#39;account per un eventuale ripristino durante
    # la fase di input
    ACCOUNT_TEMP=&#34;${ACCOUNT}&#34;
    ACCOUNT_MOD=&#34;${ACCOUNT}&#34;

    # Inserisco il nuovo nome account.
    # 1. Se è vuoto: è la conferma dell&#39;account inserito all&#39;inizio e proseguo
    # 2. Se il nome è invalido: sollevo un&#39;eccezione e reitero
    # 3. Se il nome è valido:
    #    a. Se è un nome nuovo: acquisisco il nuovo nome, recupero nome e chiave dell&#39;account di partenza e proseguo
    #    b. Sè è lo stesso nome di partenza: è la conferma dell&#39;account iniziale e proseguo
    #    c. Se è un altro nome esistente o invalido: come il punto 2.
    while true; do
        echo
        echo -en &#34;Account: ${ACCOUNT}\nInserisci nuovo nome account: &#34;; read ACCOUNT_MOD;
        get_account &#34;${ACCOUNT_MOD}&#34;; RET_CODE=$?
        case &#34;${RET_CODE}&#34; in
            # Punto 1.
            &#34;${ACCOUNT_NAME_EMPTY_ERR}&#34; ) ACCOUNT_MOD=&#34;${ACCOUNT}&#34;; break;;
            # Punto 2
            &#34;${INVALID_ACCOUNT_ERR}&#34;    ) err_msg &#34;${INVALID_ACCOUNT_ERR}&#34; 0;;
            # Punto 3a.
            &#34;${ACCOUNT_NOT_FOUND_ERR}&#34;  ) get_account &#34;${ACCOUNT_TEMP}&#34;; break;;
            # Punti 3b e 3c, rispettivamente
            0                           ) [[ &#34;${ACCOUNT_MOD}&#34; == &#34;${ACCOUNT_TEMP}&#34; ]] &amp;&amp; break \
                                                                                 || { get_account &#34;${ACCOUNT_TEMP}&#34;; err_msg &#34;${ACCOUNT_EXISTS_ERR}&#34; 0; };;
        esac
    done

    [[ &#34;${ACCOUNT}&#34; != &#34;${ACCOUNT_MOD}&#34; &amp;&amp; ! -z &#34;${ACCOUNT_MOD}&#34; ]] &amp;&amp; msg=&#34;\nL&#39;account \&#34;${ACCOUNT}\&#34; è stato modificato in \&#34;${ACCOUNT_MOD}\&#34;.&#34; \
                                                                    || msg=&#34;\nNessuna modifica rilevata.\n&#34;
    info_msg &#34;${msg}&#34;

    # Modifica la chiave privata
    KEY_MOD=&#34;${KEY}&#34;
    echo

    while true; do
        echo -en &#34;Chiave privata: ${KEY}\nInserisci la nuova chiave privata: &#34;; read KEY_MOD
        if [[ -z $KEY_MOD ]]; then
            KEY_MOD=&#34;${KEY}&#34;; break
        elif [[ ! $(echo &#34;${KEY_MOD}&#34; | oathtool -b - 2&gt;/dev/null) ]]; then
            err_msg &#34;${INVALID_KEY_ERR}&#34; 0; KEY_MOD=&#34;${KEY}&#34;
        else
            break
        fi
    done

    # Se c&#39;è stata almeno una modifica (account/key), sovrascrivo il record. Altrimenti esco senza fare nulla.
    if [[ &#34;${ACCOUNT}&#34; != &#34;${ACCOUNT_MOD}&#34; || &#34;${KEY}&#34; != &#34;${KEY_MOD}&#34; ]]; then
        # Conferma modifica

        info_msg &#34;\nAccount:              ${ACCOUNT}\nChiave privata:       ${KEY}\nNuovo account:        ${ACCOUNT_MOD}\nNuova chiave privata: ${KEY_MOD}\n&#34;
        continue_yn &#34;edit&#34;

        # Modifica del file degli account
        KEYS_2FA_FILE_DEC_TEMP=$(sed &#34;s/${ACCOUNT}${DELIMITER}${KEY}/${ACCOUNT_MOD}${DELIMITER}${KEY_MOD}/&#34; &lt;&lt;&lt; &#34;${KEYS_2FA_FILE_DEC}&#34;)
        info_msg &#34;L&#39;account \&#34;${ACCOUNT}\&#34; è stato modificato con successo.&#34;

        # Cifratura del file degli account
        crypt_account_file &#34;${KEYS_2FA_FILE_DEC_TEMP}&#34;
    else
        info_msg &#34;Nessuna modifica rilevata.&#34;
    fi
    info_msg &#34;Fatto.&#34;
}


delete() {
    if get_account &#34;$1&#34;; then
        # Conferma eliminazione
        info_msg &#34;\nAccount:              ${ACCOUNT}\nChiave privata:       ${KEY}\n&#34;
        continue_yn &#34;delete&#34;

        # Cancellazione account
        KEYS_2FA_FILE_DEC_TEMP=$(sed &#34;/$ACCOUNT/d&#34; &lt;&lt;&lt; &#34;${KEYS_2FA_FILE_DEC}&#34;)
        info_msg &#34;L&#39;account \&#34;$ACCOUNT\&#34; è stato eliminato.&#34;

        # Cifratura del nuovo file degli account
        crypt_account_file &#34;${KEYS_2FA_FILE_DEC_TEMP}&#34;
        info_msg &#34;Fatto.&#34;
    else
        err_msg &#34;${ACCOUNT_NOT_FOUND_ERR}&#34; 1
    fi
}


list() {
    echo
    while read LINE; do
        cut -d&#34;${DELIMITER}&#34; -f 1 &lt;&lt;&lt; &#34;${LINE}&#34;
    done &lt;&lt;&lt; &#34;${KEYS_2FA_FILE_DEC}&#34;
}


help() {
cat&lt;&lt;EOF
Usa come: ./totp.sh [options] ARG
dove:
    [options]
        -l restituisce la lista degli account.
        -t &lt;nome_account&gt; restituisce l&#39;otp per quell&#39;account.
        -i &lt;nome_account&gt; inserisce un nuovo account.
        -d &lt;nome_account&gt; cancella &lt;nome_account&gt;.
        -e &lt;nome_account&gt; modifica &lt;nome_account&gt;.
        -h stampa questa pagina di help.

ESEMPI:
    RESTITUISCE LA LISTA DEGLI ACCOUNT
    totp.sh -l

    INSERISCE UN ACCOUNT
    totp.sh -i dropbox

    CANCELLA UN ACCOUNT
    totp.sh -d megaupload

    MODIFICA UN ACCOUNT
    totp.sh -e paypal

    GENERA OTP
    totp.sh -t firefoxsync
EOF
}


main() {
    init
    while getopts &#34;lt:i:e:d:&#34; opt; do
        case $opt in
            l ) list ;;
            t ) totp $OPTARG ;;
            i ) insert $OPTARG ;;
            e ) edit $OPTARG ;;
            d ) delete $OPTARG ;;
            * ) clear;err_msg &#34;${INVALID_OPTION_ERR}&#34; 1;;
        esac
    done
    shift $(($OPTIND - 1))
}

[[ $# -eq 0 || $# -eq 1 &amp;&amp; &#34;$1&#34; == &#34;-h&#34; ]] &amp;&amp; no_param || main $*

</code></pre>

<p><a href="/aytin/tag:bash" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">bash</span></a> <a href="/aytin/tag:totp" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">totp</span></a> <a href="/aytin/tag:cryptography" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">cryptography</span></a> <a href="/aytin/tag:gpg" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">gpg</span></a> <a href="/aytin/tag:scripting" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">scripting</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/gestione-totp-in-bash</guid>
      <pubDate>Wed, 21 Feb 2024 15:37:02 +0000</pubDate>
    </item>
  </channel>
</rss>