<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Cyberdyne Systems</title>
    <link>https://noblogo.org/aytin/</link>
    <description>&#34;Fare o non fare. Non c&#39;è provare!&#34;</description>
    <pubDate>Thu, 30 Apr 2026 06:55:56 +0000</pubDate>
    <item>
      <title>Ridimensionare volumi LVM</title>
      <link>https://noblogo.org/aytin/ridimensionare-volumi-lvm</link>
      <description>&lt;![CDATA[lvm&#xA;Supponiamo di avere 3 volumi logici, ad es. vol1, vol2, vol3 e di voler aumentare il secondo a discapito degli altri due.&#xA;&#xA;Un’esigenza analoga, su un filesystem partizionato in 3 parti in maniera canonica, è un mezzo incubo perché il ridimensionamento della partizione centrale prevede un discreto numero di salti mortali per manenere la contiguità e per non rischiare di lasciare buchetti inutilizzabili fra una partizione e l’altra. &#xA;!--more--&#xA;&#xA;1. Cose che è bene ricordare quando si manipolano i volumi logici&#xA;2. Scenario 1: Estensione e riduzione di volumi logici&#xA;   2.1. Step 0: curiosità&#xA;   2.2. Step 1: Smontare i dischi&#xA;   2.3. Step 2: Riduzione del filesystem&#xA;   2.4. Step 3: Ridimensionare i volumi logici&#xA;   2.5. Step 4: Estendere il volume logico&#xA;   2.6. Step 5: Bonus&#xA;3. Scenario 2: Estensione e riduzione di gruppi di volume&#xA;4. Conclusione&#xA;&#xA;Provo a buttare giù due righe su quello che mi verrebbe di fare:&#xA;&#xA;riduco la prima partizione&#xA;riduco la terza partizione&#xA;sposto la terza partizione fino alla fine del disco&#xA;sposto la seconda partizione fino alla fine della prima partizione&#xA;estendo la seconda partizione fino alla fine della prima&#xA;&#xA;Tutto questo tenendo presente che l’unità minima allocabile è il blocco (512 bytes) e che l’operazione che mi fa più paura è il move della partizione. parted non ha un comando “move” diretto. La procedura richiede di calcolare i nuovi settori, spostare i dati e aggiornare la tabella delle partizioni.&#xA;&#xA;Senza una GUI come quella di gparted, bisogna farsi letteralmente i conti con carta e penna prima di agire e c’è il rischio, comunque molto alto, di commettere errori che sarebbero disastrosi.&#xA;&#xA;LVM, al confronto, è una boccata d’ossigeno.&#xA;&#xA;LVM dà la possibilità di ridimensionare volumi in maniera più semplice rispetto al partizionamento più tradizionale perché la dimensione della partizione è disaccoppiata da concetti di contiguità e dalla geometria del disco.&#xA;&#xA;Nel caso del partizionamento tradizionale infatti le partizioni sono dei blocchi di settori consecutivi in cui ogni partizione inizia in un settore finisce in un altro.&#xA;&#xA;Con LVM invece l’approccio è radicalmente diverso. La minima unità allocabile è l’extent (default 4 MiB) che serve per mappare un volume fisico in un volume logico.&#xA;&#xA;Se immaginiamo che il volume fisico possa essere spezzettato in altrettanti extents in una sorta di “paniere”, il volume group, il volume logico non è altro che un insieme di questi extents pescati dal volume group (senza alcuna pretesa d’ordinamento) a cui posso:&#xA;&#xA;aggiungere extents prelevandoli dal volume group&#xA;levare extents riponendoli nel volume group (o assegnandoli ad altri volumi logici).&#xA;&#xA;Queste proprietà conferiscono una grande flessibilità alle operazioni di riduzione ed estensione dei volumi.&#xA;&#xA;1. Cose che è bene ricordare quando si manipolano i volumi logici.&#xA;&#xA;Partizioni&#xA;Quando si riduce o aumenta un filesystem, è bene smontare le partizioni e volumi logici.&#xA;&#xA;Ridurre un volume logico&#xA;Quando si riduce un volume logico, si deve:&#xA;&#xA;fare un check del filesystem&#xA;ridurre il filesystem&#xA;ridurre il volume logico&#xA;&#xA;Estendere un volume logico&#xA;Quando si aumenta un volume logico, al contrario, si deve:&#xA;&#xA;estendere il volume logico&#xA;estendere il filesystem&#xA;fare un check del filesystem&#xA;&#xA;Calcolare lo spazio allocabile&#xA;Un volume logico è composto da un insieme di extents, blocchi grandi di default 4 MiB, che sono la minima unità allocabile. Un volume logico è quindi sempre corrispondente ad un multiplo di 4 MiB, n extents di cui n\-1 allocabili, il rimanente per i metadati. Ad es. un volume logico di 2 GiB è composta da 512 extents di cui 511 allocabili.&#xA;&#xA;La potenza di due&#xA;Si deve tenere sempre presente che, nella matematica del calcolo dello spazio, si considerano le potenze di 2. Non di 10. Quindi un GiB equivale a 1024 MiB, non a 1000. Di conseguenza, se dividessi un GiB in due parti uguali avrei 2 blocchi da 512 MiB non da 500.&#xA;&#xA;Estensione e riduzione&#xA;Nelle istruzioni di estensione (lvextend) e riduzione (lvreduce) possiamo scegliere ciò che va specificato fra 4 modalità:&#xA;&#xA;il numero totale di extents&#xA;il delta in aggiunta o in diminuzione degli extents (a seconde che l’operazione sia rispettivamente di estensione o di riduzione)&#xA;la dimensione totale espressa in KiB-MiB-GiB-TiB&#xA;come prima, il delta in aggiunta o in diminuzione della dimensione espresso in KiB-MiB-GiB-TiB&#xA;&#xA;2. Scenario 1: Estensione e riduzione di volumi logici&#xA;Supponiamo di avere un disco da 2 GiB (2048 MiB) diviso in 3 volumi logici da 550 MiB, 350 MiB e 1148 MiB di e di volerne ridurre due per ampliare il terzo.&#xA;&#xA;Vogliamo ridurre il primo di 150 MiB, il terzo di 330 MiB e aumentare corrispondentemente il secondo volume di 480 MiB.&#xA;&#xA;Prepariamo il laboratorio col solito file appiccicato ad un loop device. Su quello definirò il volume group, il mio “paniere” di extents.&#xA;creazione device&#xA;fallocate -l 2GiB disk1.img&#xA;&#xA;creazione device e volum group&#xA;vgcreate vglab $(losetup -Pf --show disk1.img)&#xA;&#xA;creazione volumi logici&#xA;lvcreate -n lvlab1 vglab -L 550M&#xA;lvcreate -n lvlab2 vglab -L 350M&#xA;lvcreate -n lvlab3 vglab -l 100%FREE&#xA;&#xA;formattazione volumi logici&#xA;mkfs.ext4 /dev/vglab/lvlab1&#xA;mkfs.ext4 /dev/vglab/lvlab2&#xA;mkfs.ext4 /dev/vglab/lvlab3&#xA;&#xA;mount dei volumi&#xA;mkdir vol1 vol2 vol3&#xA;mount -t ext4 -o defaults /dev/vglab/lvlab1 vol1&#xA;mount -t ext4 -o defaults /dev/vglab/lvlab2 vol2&#xA;mount -t ext4 -o defaults /dev/vglab/lvlab3 vol3&#xA;2.1. Step 0: curiosità&#xA;Prima di cominciare esaminiamo un po’ di dati, ad es. di quanti extents sono composti i nostri oggetti.&#xA;pvdisplay /dev/loop9&#xA;  --- Physical volume ---&#xA;  PV Name               /dev/loop9&#xA;  VG Name               vglab&#xA;  PV Size               2,00 GiB / not usable 4,00 MiB&#xA;  Allocatable           yes (but full)&#xA;  PE Size               4,00 MiB&#xA;  Total PE              511&#xA;  Free PE               0&#xA;  Allocated PE          511&#xA;  PV UUID               YmLOru-bIdL-iqGb-vJfI-RsTk-yhv7-vSJhkX&#xA;pvdisplay mi dà informazioni sul disco fisico che andrò ad aggiungere nel volume group. Fra queste:&#xA;&#xA;PV Name: il nome del device, /dev/loop9&#xA;VG Name: è il nome del gruppo di volume, vglab, visibile solo perché abbiamo creato il gruppo di volume direttamente sul dispositivo invece che passare prima da pvcreate.&#xA;PV Size: 2 GiB, la dimensione del nostro “disco”&#xA;PE Size: dove PE sta Physical Extent, è di 4 MiB&#xA;Total PE sono i PE totali e sono 511, come previsto.&#xA;&#xA;vgdisplay vglab&#xA;  --- Volume group ---&#xA;  VG Name               vglab&#xA;  System ID&#xA;  Format                lvm2&#xA;  Metadata Areas        1&#xA;  Metadata Sequence No  1&#xA;  VG Access             read/write&#xA;  VG Status             resizable&#xA;  MAX LV                0&#xA;  Cur LV                0&#xA;  Open LV               0&#xA;  Max PV                0&#xA;  Cur PV                1&#xA;  Act PV                1&#xA;  VG Size               &lt;2,00 GiB&#xA;  PE Size               4,00 MiB&#xA;  Total PE              511&#xA;  Alloc PE / Size       0 / 0&#xA;  Free  PE / Size       511 / &lt;2,00 GiB&#xA;  VG UUID               6D89ck-c2Ni-XlMN-5Was-rh5j-vi2t-5juCXt&#xA;vgdisplay mi dà informazioni sul gruppo di volumi. Fra queste, disitnguiamo&#xA;&#xA;VG Name: il nome del volume group, già visto in pvdisplay, vglab&#xA;VG Size: la dimensione del volume group, minore di 2 GiB perché ci sono i metadati da considerari&#xA;PE Size: la dimensione di un extent, 4 MiB&#xA;Total PE / Size: Il numero totale di extent allocabili, che conferma VG Size, pari a 511 invece che 512.&#xA;Alloc PE: il numero totale di extent allocati, momento della creazione del volume group è 0&#xA;Free PE / Size: il numero totale di extent liberi, prima della creazione dei volumi logici è 511&#xA;&#xA;Cosa succede quando creerò i volumi logici? Che cambia il numero di PE liberi e allocati. Siccome userò tutti gli extent disponibili, i valori per Alloc PE e Free PE si invertiranno rispetto a prima.&#xA;&#xA;Infatti dopo la creazione dei volumi logici, vgdisplay mi dirà:&#xA;vgdisplay vglab&#xA;  --- Volume group ---&#xA;  VG Name               vglab&#xA;  ...&#xA;  Alloc PE / Size       511 / &lt;2,00 GiB&#xA;  Free  PE / Size       0 / 0&#xA;  ...  &#xA;511 extents allocati come confermato dai dati desumibili dei 3 volumi logici&#xA;lvdisplay vglab&#xA; --- Logical volume ---&#xA;  LV Path                /dev/vglab/lvlab1&#xA;  LV Name                lvlab1&#xA;  VG Name                vglab&#xA;...&#xA;  LV Size                552,00 MiB&#xA;  Current LE             138&#xA;...&#xA; --- Logical volume ---&#xA;  LV Path                /dev/vglab/lvlab2&#xA;  LV Name                lvlab2&#xA;  VG Name                vglab&#xA;...&#xA;  LV Size                352,00 MiB&#xA;  Current LE             88&#xA;...&#xA; --- Logical volume ---&#xA;  LV Path                /dev/vglab/lvlab3&#xA;  LV Name                lvlab2&#xA;  VG Name                vglab&#xA;...&#xA;  LV Size                1,11 GiB&#xA;  Current LE             285&#xA;...&#xA;Per il primo, il secondo e il terzo volume logico abbiamo rispettivamente:&#xA;&#xA;138, 88, 285 extents corrispondenti a&#xA;552 MiB, 352 MiB e 1140 MiB (1,11 GiB)&#xA;per un totale di 2044 MiB, al netto dei metadati.&#xA;&#xA;Possiamo notare subito che le dimensioni non corrispondono a quanto indicato in lvcreate.&#xA;lvcreate -n lvlab1 vglab -L 550M&#xA;lvcreate -n lvlab2 vglab -L 350M&#xA;lvcreate -n lvlab3 vglab -l 100%FREE&#xA;Questo succede perché vengono sempre approssimate all’extent più vicino. Ecco perché il primo e il secondo volume sono diventati di 552 (138 extents) e 352 MiB (88 extents).&#xA;&#xA;Sempre ricordando la particolarità dei multipli di 4 MiB legati a LVM, anche la riduzione di 150 MiB e di 330 MiB dei due volumi saranno approssimate sempre all’extent più vicino (152 MiB=38 extents e 332=83 extents). Questo dettaglio si rivelerà fondamentale quando dovremo ridimensionare il filesystem.&#xA;&#xA;Con questa rinnovata consapevolezza cominciamo a ridimensionare.&#xA;2.2. Step 1: Smontare i dischi&#xA;umount /dev/vglab/lvlab1&#xA;umount /dev/vglab/lvlab2&#xA;umount /dev/vglab/lvlab3&#xA;2.3. Step 2: Riduzione del filesystem&#xA;Se dovessi ridimensionare solo il filesystem, sarebbe sufficiente considerare dimensioni che siano potenze di 2 e non di 10.&#xA;&#xA;Ma sapendo che sotto c’è un LVM, sappiamo che per mantenere l’allineamento fra filesystem e volumi logici, oltre che potenze di due le dimensioni devono essere anche multipli di 4MiB.&#xA;&#xA;Ecco perché anche nel resize reale del filesystem non dovrò levare 150 MiB e 330 MiB ma 148 MiB (37 PE) e 328 (82 PE) (è buona norma approssimare per difetto all’extent più vicino per maggior prudenza) per un totale effettivo di 476 MiB (119 PE)&#xA;&#xA;Il filesystem del primo volume sarà dunque di 552 MiB - 148 MiB = 404 MiB. Il filesystem del terzo volume sarà di 1140 MiB - 328 MiB = 812 MiB.&#xA;check dei filesystem&#xA;e2fsck -f /dev/vglab/lvlab1&#xA;e2fsck -f /dev/vglab/lvlab2&#xA;e2fsck -f /dev/vglab/lvlab3&#xA;&#xA;Riduco il primo filesystem di 148 MiB&#xA;resize2fs /dev/vglab/lvlab1 404M&#xA;&#xA;Riduco il terzo filesystem di 328 MiB&#xA;resize2fs /dev/vglab/lvlab3 812M&#xA;2.4. Step 3: Ridimensionare i volumi logici&#xA;La riduzione del volume logico può essere fatta in 4 modi come sappiamo, ad es. sul primo volume:&#xA;il numero totale di extents, 138 PE - 37 PE = 101 PE&#xA;lvreduce -l 101 /dev/vglab/lvlab1 #oppure&#xA;&#xA;il numero di exrtents da sottrarre, 38 PE&#xA;lvreduce -l -37 /dev/vglab/lvlab1 #oppure&#xA;&#xA;la dimensione totale da ottenere, 404 MiB&#xA;lvreduce -L 404M /dev/vglab/lvlab1 #oppure&#xA;&#xA;il numero di MiB da sottrarre, 148 MiB&#xA;lvreduce -L -148M /dev/vglab/lvlab1 #oppure&#xA;Per maggior chiarezza userò il size assoluto in modo da farlo corrispondere a resize2fs&#xA;Riduco il primo volume logico di 148 Mib&#xA;lvreduce -L 404M /dev/vglab/lvlab1&#xA;&#xA;Riduco il terzo volume logico di 328 Mib&#xA;lvreduce -L 812M /dev/vglab/lvlab3&#xA;Verifichiamo quanti siano i PE residui&#xA;vgdisplay vglab | grep &#34;Free  PE&#34;&#xA; Free  PE / Size       119 / 476,00 MiB&#xA;119 extents, come previsto.&#xA;2.5. Step 4: Estendere il volume logico&#xA;Dopo aver ridotto il primo e il terzo volume, non ci rimane che estendere il secondo in base alla scaletta indicata prima:&#xA;&#xA;si estende il secondo volume logico&#xA;si estende il filesystem&#xA;si esegue il check fnale del filesystem&#xA;&#xA;L’estensione del volume, come ormai ben sappiamo, non sarà di 480 MiB ma di 476 MiB (37 PE + 82 PE = 119 PE) per via degli arrotondamenti effettuati nella riduzione degli altri volumi logici.&#xA;specifico gli extent che so essere residui&#xA;lvextend -l +119 /dev/vglab/lvlab2&#xA;o, equivalentemente&#xA;lvextend -L +476M /dev/vglab/lvlab2&#xA;&#xA;estendo il filesystem&#xA;resize2fs /dev/vglab/lvlab2 828M&#xA;&#xA;check filesystem&#xA;e2fsck -f /dev/vglab/lvlab2&#xA;2.6. Step 5: Bonus&#xA;Come premio per essere arrivato in fondo, posso rivelare come fare in un colpo solo tutte le operazioni descritte sopra.&#xA;&#xA;È vero che c&#39;è poco da considerare, giusto tenere a mente che su LVM ogni oggetto è multiplo di 4 MiB e che bisogna ridimensionare filesystem e volumi logici in ugual modo per non generare pericolose anomalie, ma tutte le operazioni che ho descritto nei passi 2-4 possono essere fatte con un unico comando che provvederà ad eseguire nell&#39;ordine corretto e con le giuste approssimazioni:&#xA;&#xA;il check del filesystem&#xA;il ridimensionamento del filesystem&#xA;il ridimensionamento dei volumi logici&#xA;&#xA;Dunque, tutto il pippone atomico precedente può essere condensato in un unico, solido comando:&#xA;Riduce il primo volume logico e il filesystem&#xA;lvreduce -r -L -150M /dev/vglab/lvlab1&#xA;&#xA;Riduce il terzo volume logico e il filesystem&#xA;lvreduce -r -L -330M /dev/vglab/lvlab3&#xA;&#xA;Estende il secondo volume logico e il filesystem&#xA;lvextend -r -l +119 /dev/vglab/lvlab2&#xA;Ora spieghiamo il perché soprattutto dell&#39;extend, che è interessante.&#xA;&#xA;Diciamo che è tutto molto guidato e le eventuali correzioni da apportare, senza spaccarsi troppo il cervello, sono suggerite con estrema chiarezza, basta leggere.&#xA;lvreduce -r -L -150M /dev/vglab/lvlab1&#xA; Rounding size to boundary between physical extents: 148.00 MiB.&#xA;  File system ext4 found on vglab/lvlab1.&#xA;  File system size (552.00 MiB) is larger than the requested size (404.00 MiB).&#xA;  File system reduce is required using resize2fs.&#xA;...&#xA;  Size of logical volume vglab/lvlab1 changed from 552.00 MiB (138 extents) to 404.00 MiB (101 extents).&#xA;  Logical volume vglab/lvlab1 successfully resized.&#xA;Ci dice innanzitutto che:&#xA;&#xA;c&#39;è stato un arrotondamento a 148 MiB (37 extents);&#xA;il filesystem è più grande del volume richiesto pertanto va subito ridimensionato;&#xA;infine si ridimensiona il volume logico da 552 MiB (138 extents) a 404 MiB (101 extents).&#xA;&#xA;Anche il secondo lvreduce ha un risultato analogo&#xA;lvreduce -r -L -330M /dev/vglab/lvlab3&#xA;  Rounding size to boundary between physical extents: 328.00 MiB.&#xA;  File system ext4 found on vglab/lvlab3.&#xA;  File system size (1.11 GiB) is larger than the requested size (812.00 MiB).&#xA;  File system reduce is required using resize2fs.&#xA;...&#xA;  Size of logical volume vglab/lvlab3 changed from 1.11 GiB (285 extents) to 812.00 MiB (203 extents).&#xA;  Logical volume vglab/lvlab3 successfully resized.&#xA;&#xA;anche qui abbiamo un arrotondamento a 328 MiB (82 extents);&#xA;il filesystem è più grande del volume richiesto pertanto va subito ridimensionato;&#xA;infine si ridimensiona il volume logico da 1140 MiB (285 extents) a 812 MiB (203 extents).&#xA;&#xA;È facilissimo desumere che la massima dimensione dell&#39;estensione sia 148 MiB + 328 MiB = 476 MiB (119 extents), basta fare una somma.&#xA;&#xA;Ma supponiamo di essere particolarmente distratti e proviamo ad estendere considerando le quantità iniziali: 150 MiB + 330 MiB = 480 MiB&#xA;lvextend -r -L +480M /dev/vglab/lvlab2&#xA;  File system ext4 found on vglab/lvlab2.&#xA;  File system fsck will be run before extend.&#xA;  Insufficient free space: 120 extents needed, but only 119 available&#xA;Nonostante la mia distrazione, come si può vedere, non si producono danni perché l&#39;ouput è categorico: &#34;non faccio nulla. Se vuoi, puoi aumentare al max di 476 MiB (119 extents)&#34;.&#xA;Non ci sono danni e anzi c&#39;è pure il suggerimento risolutivo.&#xA;&#xA;Ed ecco spiegato il mio extend di prima.&#xA;3. Scenario 2: Estensione e riduzione di gruppi di volume&#xA;Esaminiamo le possibilità di aggiungere o rimuovere dispositivi ad un volume group esistente.&#xA;&#xA;Ricreiamo il laboratorio partendo da 3 dischi, poi aggiungeremo due nuovi dischi e ne rimuoveremo altrettanti, il tutto senza intaccare l&#39;integrità dei dati.&#xA;&#xA;creazione di 5 device&#xA;for i in {1..9}: do fallocate -l 1GiB disk${i}.img; done&#xA;&#xA;creazione del gruppo di volumi con 3 device&#xA;vgcreate vglab \&#xA;  $(losetup -Pf --show disk1.img) \&#xA;  $(losetup -Pf --show disk2.img) \&#xA;  $(losetup -Pf --show disk3.img)&#xA;&#xA;crezione di 3 volumi logici&#xA;lvcreate -n lvlab1 vglab -l 300&#xA;lvcreate -n lvlab2 vglab -l 250&#xA;lvcreate -n lvlab3 vglab -l 100%FREE&#xA;&#xA;formattazione dei 3 dispositivi&#xA;mkfs.ext4 /dev/vglab/lvlab1&#xA;mkfs.ext4 /dev/vglab/lvlab2&#xA;mkfs.ext4 /dev/vglab/lvlab3&#xA;Ecco come sono distribuiti i volumi logici all&#39;interno dei dischi fisici&#xA;lsblk -o NAME,FSTYPE,SIZE,TYPE&#xA;  NAME               FSTYPE        SIZE      TYPE&#xA;  loop9              LVM2member     1G      loop&#xA;  └─vglab-lvlab1                1,2G      lvm&#xA;  loop10             LVM2member     1G      loop&#xA;  ├─vglab-lvlab1                1,2G      lvm&#xA;  └─vglab-lvlab3                860M      lvm&#xA;  loop11             LVM2member     1G      loop&#xA;  ├─vglab-lvlab2               1000M      lvm&#xA;  └─vglab-lvlab3                860M      lvm&#xA;Il gruppo di volumi è composto da 3 volumi fisici tutti attivi&#xA;vgdisplay vglab |grep PV&#xA;  Max PV                0&#xA;  Cur PV                3&#xA;  Act PV                3&#xA;Andiamo ad estendere il nostro gurppo di volumi con altri due device&#xA;vgextend vglab $(losetup -Pf --show disk4.img) $(losetup -Pf --show disk5.img)&#xA;I nuovi dischi sono visibili in fondo, come si può vedere anche da  vgdisplay che mostra i 5 dischi tutti attivi. &#xA;lsblk -o NAME,FSTYPE,SIZE,TYPE&#xA;  NAME               FSTYPE        SIZE      TYPE&#xA;  loop9              LVM2member     1G      loop&#xA;  └─vglab-lvlab1                1,2G      lvm&#xA;  loop10             LVM2member     1G      loop&#xA;  ├─vglab-lvlab1                1,2G      lvm&#xA;  └─vglab-lvlab3                860M      lvm&#xA;  loop11             LVM2member     1G      loop&#xA;  ├─vglab-lvlab2               1000M      lvm&#xA;  └─vglab-lvlab3                860M      lvmchan&#xA;  loop12             LVM2member     1G      loop&#xA;  loop13             LVM2member     1G      loop&#xA;&#xA;vgdisplay vglab |grep PV&#xA;  Max PV                0&#xA;  Cur PV                5&#xA;  Act PV                5&#xA;Potremo usare i nuovi dischi per estendere i volumi logici esistenti ma li impiegheremo invece per rimpiazzare i primi due dischi. &#xA;&#xA;pvmove distribuisce tutti gli extents del disco fra tutti i volumi fisici che hanno spazio a sufficienza. Se non dovesse essercene, restituirà un messaggio d&#39;errore.&#xA;pvmove /dev/loop9&#xA;  /dev/loop9: Moved: 3,14%&#xA;  /dev/loop9: Moved: 100,00%&#xA;Alla fine dell&#39;operazione il disco s&#39;è liberato di tutti i suoi extents e può essere rimosso&#xA;lsblk -o NAME,FSTYPE,SIZE,TYPE&#xA;  NAME               FSTYPE        SIZE      TYPE&#xA;  loop9              LVM2member     1G      loop&#xA;  loop10             LVM2member     1G      loop&#xA;  ├─vglab-lvlab1                1,2G      lvm&#xA;  └─vglab-lvlab3                860M      lvm&#xA;  loop11             LVM2member     1G      loop&#xA;  ├─vglab-lvlab2               1000M      lvm&#xA;  └─vglab-lvlab3                860M      lvm&#xA;  loop12             LVM2member     1G      loop&#xA;  └─vglab-lvlab1                1,2G      lvm&#xA;  loop13             LVM2member     1G      loop&#xA;Prima si estrae il volume fisico dal gruppo di volumi e poi si rimuove il volume fisico e così può essere scollegato.&#xA;vgreduce vglab /dev/loop9&#xA;pvremove /dev/loop9&#xA;Verifichiamo che il volume fisico non sia più presente.&#xA;vgdisplay vglab |grep PV&#xA;  Max PV                0&#xA;  Cur PV                4&#xA;  Act PV                4&#xA;Procediamo allo stesso modo col secondo disco.&#xA;pvmove /dev/loop10&#xA;  /dev/loop10: Moved: 9,80%&#xA;  /dev/loop10: Moved: 17,65%&#xA;  /dev/loop10: Moved: 100,00%&#xA;&#xA;vgreduce vglab /dev/loop10&#xA;  Removed &#34;/dev/loop10&#34; from volume group &#34;vglab&#34;&#xA;&#xA;pvremove /dev/loop10&#xA;  Labels on physical volume &#34;/dev/loop10&#34; successfully wiped.&#xA;In conclusione possiamo vedere il gruppo di volumi con solo 3 dischi, gli altri due completamente disimpegnati col gruppo di volumi ricostituitosi attorno ai 3 dischi rimanenti. E tutto spostando semplicemente gli extents dove c&#39;era disponibilità in maniera totalmente trasparente per il filesystem.&#xA;vgdisplay vglab |grep PV&#xA;  Max PV                0&#xA;  Cur PV                3&#xA;  Act PV                3&#xA;&#xA;lsblk -o NAME,FSTYPE,SIZE,TYPE&#xA;  NAME               FSTYPE        SIZE      TYPE&#xA;  loop9                              1G      loop&#xA;  loop10                             1G      loop&#xA;  loop11             LVM2member     1G      loop&#xA;  ├─vglab-lvlab2               1000M      lvm&#xA;  └─vglab-lvlab3                860M      lvm&#xA;  loop12             LVM2member     1G      loop&#xA;  └─vglab-lvlab1                1,2G      lvm&#xA;  loop13             LVM2member     1G      loop&#xA;  ├─vglab-lvlab1                1,2G      lvm&#xA;  └─vglab-lvlab_3                860M      lvm&#xA;4. Conclusione&#xA;Ho solo sfiorato la complessità e le capacità offerte da LVM.&#xA;&#xA;L&#39;estensione e la riduzione di volumi logici e di gruppi di volumi sono scenari di base. Tuttavia sono sufficienti per mostrare come sia semplice, con i volumi logici, compiere operazioni che con un filesystem partizionato in maniera classica sarebbero complicatissime.&#xA;&#xA;#lvm #volumegroup #logicalvolume #filesystem #devicemapper]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/31410d826-759a86/YynFD6sqFGzb/E2tgEVkaEtWT6Ucn0rqMrtk9qnJlr5p9nLl9m5pu.jpg" alt="lvm">
Supponiamo di avere 3 volumi logici, ad es. vol1, vol2, vol3 e di voler aumentare il secondo a discapito degli altri due.</p>

<p>Un’esigenza analoga, su un filesystem partizionato in 3 parti in maniera canonica, è un mezzo incubo perché il ridimensionamento della partizione centrale prevede un discreto numero di salti mortali per manenere la contiguità e per non rischiare di lasciare buchetti inutilizzabili fra una partizione e l’altra.
</p>
<ul><li><a href="#1-cose-che-%C3%A8-bene-ricordare-quando-si-manipolano-i-volumi-logici" rel="nofollow">1. Cose che è bene ricordare quando si manipolano i volumi logici</a></li>
<li><a href="#2-scenario-1-estensione-e-riduzione-di-volumi-logici" rel="nofollow">2. Scenario 1: Estensione e riduzione di volumi logici</a>
<ul><li><a href="#2-1-step-0-curiosit%C3%A0" rel="nofollow">2.1. Step 0: curiosità</a></li>
<li><a href="#2-2-step-1-smontare-i-dischi" rel="nofollow">2.2. Step 1: Smontare i dischi</a></li>
<li><a href="#2-3-step-2-riduzione-del-filesystem" rel="nofollow">2.3. Step 2: Riduzione del filesystem</a></li>
<li><a href="#2-4-step-3-ridimensionare-i-volumi-logici" rel="nofollow">2.4. Step 3: Ridimensionare i volumi logici</a></li>
<li><a href="#2-5-step-4-estendere-il-volume-logico" rel="nofollow">2.5. Step 4: Estendere il volume logico</a></li>
<li><a href="#2-6-step-5-bonus" rel="nofollow">2.6. Step 5: Bonus</a></li></ul></li>
<li><a href="#3-scenario-2-estensione-e-riduzione-di-gruppi-di-volume" rel="nofollow">3. Scenario 2: Estensione e riduzione di gruppi di volume</a></li>
<li><a href="#4-conclusione" rel="nofollow">4. Conclusione</a></li></ul>

<p>Provo a buttare giù due righe su quello che mi verrebbe di fare:</p>
<ol><li>riduco la prima partizione</li>
<li>riduco la terza partizione</li>
<li>sposto la terza partizione fino alla fine del disco</li>
<li>sposto la seconda partizione fino alla fine della prima partizione</li>
<li>estendo la seconda partizione fino alla fine della prima</li></ol>

<p>Tutto questo tenendo presente che l’unità minima allocabile è il blocco (512 bytes) e che l’operazione che mi fa più paura è il move della partizione. <code>parted</code> non ha un comando “move” diretto. La procedura richiede di calcolare i nuovi settori, spostare i dati e aggiornare la tabella delle partizioni.</p>

<p>Senza una GUI come quella di <strong>gparted</strong>, bisogna farsi letteralmente i conti con carta e penna prima di agire e c’è il rischio, comunque molto alto, di commettere errori che sarebbero disastrosi.</p>

<p>LVM, al confronto, è una boccata d’ossigeno.</p>

<p>LVM dà la possibilità di ridimensionare volumi in maniera più semplice rispetto al partizionamento più tradizionale perché la dimensione della partizione è disaccoppiata da concetti di contiguità e dalla geometria del disco.</p>

<p>Nel caso del partizionamento tradizionale infatti le partizioni sono dei blocchi di settori consecutivi in cui ogni partizione inizia in un settore finisce in un altro.</p>

<p>Con LVM invece l’approccio è radicalmente diverso. La minima unità allocabile è l’<strong>extent</strong> (default 4 MiB) che serve per mappare un volume fisico in un volume logico.</p>

<p>Se immaginiamo che il volume fisico possa essere spezzettato in altrettanti extents in una sorta di “paniere”, il <strong>volume group</strong>, il volume logico non è altro che un insieme di questi extents pescati dal volume group (senza alcuna pretesa d’ordinamento) a cui posso:</p>
<ul><li>aggiungere extents prelevandoli dal volume group</li>
<li>levare extents riponendoli nel volume group (o assegnandoli ad altri volumi logici).</li></ul>

<p>Queste proprietà conferiscono una grande flessibilità alle operazioni di riduzione ed estensione dei volumi.</p>

<h2 id="1-cose-che-è-bene-ricordare-quando-si-manipolano-i-volumi-logici">1. Cose che è bene ricordare quando si manipolano i volumi logici.</h2>

<p><strong>Partizioni</strong>
Quando si riduce o aumenta un filesystem, è bene smontare le partizioni e volumi logici.</p>

<p><strong>Ridurre un volume logico</strong>
Quando si riduce un volume logico, si deve:</p>
<ol><li>fare un check del filesystem</li>
<li>ridurre il filesystem</li>
<li>ridurre il volume logico</li></ol>

<p><strong>Estendere un volume logico</strong>
Quando si aumenta un volume logico, al contrario, si deve:</p>
<ol><li>estendere il volume logico</li>
<li>estendere il filesystem</li>
<li>fare un check del filesystem</li></ol>

<p><strong>Calcolare lo spazio allocabile</strong>
Un volume logico è composto da un <strong>insieme di extents</strong>, blocchi grandi di default 4 MiB, che sono la minima unità allocabile. Un volume logico è quindi <strong>sempre</strong> corrispondente ad un multiplo di 4 MiB, <em>n</em> extents di cui <em>n</em>-1 allocabili, il rimanente per i metadati. Ad es. un volume logico di 2 GiB è composta da 512 extents di cui <strong>511 allocabili</strong>.</p>

<p><strong>La potenza di due</strong>
Si deve tenere <strong>sempre</strong> presente che, nella matematica del calcolo dello spazio, si considerano le potenze di 2. Non di 10. Quindi un GiB equivale a 1024 MiB, non a 1000. Di conseguenza, se dividessi un GiB in due parti uguali avrei 2 blocchi da 512 MiB non da 500.</p>

<p><strong>Estensione e riduzione</strong>
Nelle istruzioni di estensione (<strong>lvextend</strong>) e riduzione (<strong>lvreduce</strong>) possiamo scegliere ciò che va specificato fra 4 modalità:</p>
<ol><li>il <strong>numero totale</strong> di extents</li>
<li>il <strong>delta</strong> in aggiunta o in diminuzione degli extents (a seconde che l’operazione sia rispettivamente di estensione o di riduzione)</li>
<li>la dimensione totale espressa in KiB-MiB-GiB-TiB</li>
<li>come prima, il delta in aggiunta o in diminuzione della dimensione espresso in KiB-MiB-GiB-TiB</li></ol>

<h2 id="2-scenario-1-estensione-e-riduzione-di-volumi-logici">2. Scenario 1: Estensione e riduzione di volumi logici</h2>

<p>Supponiamo di avere un disco da 2 GiB (2048 MiB) diviso in 3 volumi logici da <strong>550 MiB</strong>, <strong>350 MiB</strong> e <strong>1148 MiB</strong> di e di volerne ridurre due per ampliare il terzo.</p>

<p>Vogliamo ridurre il primo di <strong>150 MiB</strong>, il terzo di <strong>330 MiB</strong> e aumentare corrispondentemente il secondo volume di <strong>480 MiB</strong>.</p>

<p>Prepariamo il laboratorio col solito file appiccicato ad un loop device. Su quello definirò il volume group, il mio “paniere” di extents.</p>

<pre><code class="language-bash"># creazione device
fallocate -l 2GiB disk_1.img

# creazione device e volum group
vgcreate vg_lab $(losetup -Pf --show disk_1.img)

# creazione volumi logici
lvcreate -n lv_lab_1 vg_lab -L 550M
lvcreate -n lv_lab_2 vg_lab -L 350M
lvcreate -n lv_lab_3 vg_lab -l 100%FREE

# formattazione volumi logici
mkfs.ext4 /dev/vg_lab/lv_lab_1
mkfs.ext4 /dev/vg_lab/lv_lab_2
mkfs.ext4 /dev/vg_lab/lv_lab_3

# mount dei volumi
mkdir vol_1 vol_2 vol_3
mount -t ext4 -o defaults /dev/vg_lab/lv_lab_1 vol_1
mount -t ext4 -o defaults /dev/vg_lab/lv_lab_2 vol_2
mount -t ext4 -o defaults /dev/vg_lab/lv_lab_3 vol_3
</code></pre>

<h3 id="2-1-step-0-curiosità">2.1. Step 0: curiosità</h3>

<p>Prima di cominciare esaminiamo un po’ di dati, ad es. di quanti extents sono composti i nostri oggetti.</p>

<pre><code class="language-bash">pvdisplay /dev/loop9
  --- Physical volume ---
  PV Name               /dev/loop9
  VG Name               vg_lab
  PV Size               2,00 GiB / not usable 4,00 MiB
  Allocatable           yes (but full)
  PE Size               4,00 MiB
  Total PE              511
  Free PE               0
  Allocated PE          511
  PV UUID               YmLOru-bIdL-iqGb-vJfI-RsTk-yhv7-vSJhkX
</code></pre>

<p><code>pvdisplay</code> mi dà informazioni sul disco fisico che andrò ad aggiungere nel volume group. Fra queste:</p>
<ul><li><strong>PV Name</strong>: il nome del device, <strong>/dev/loop9</strong></li>
<li><strong>VG Name</strong>: è il nome del gruppo di volume, <strong>vg_lab</strong>, visibile solo perché abbiamo creato il gruppo di volume direttamente sul dispositivo invece che passare prima da <strong>pvcreate</strong>.</li>
<li><strong>PV Size</strong>: 2 GiB, la dimensione del nostro “disco”</li>
<li><strong>PE Size</strong>: dove <strong>PE</strong> sta <strong>P</strong>hysical <strong>E</strong>xtent, è di 4 MiB</li>
<li><strong>Total PE</strong> sono i PE totali e sono <strong>511</strong>, come previsto.</li></ul>

<pre><code class="language-bash">vgdisplay vg_lab
  --- Volume group ---
  VG Name               vg_lab
  System ID
  Format                lvm2
  Metadata Areas        1
  Metadata Sequence No  1
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                0
  Open LV               0
  Max PV                0
  Cur PV                1
  Act PV                1
  VG Size               &lt;2,00 GiB
  PE Size               4,00 MiB
  Total PE              511
  Alloc PE / Size       0 / 0
  Free  PE / Size       511 / &lt;2,00 GiB
  VG UUID               6D89ck-c2Ni-XlMN-5Was-rh5j-vi2t-5juCXt
</code></pre>

<p><code>vgdisplay</code> mi dà informazioni sul gruppo di volumi. Fra queste, disitnguiamo</p>
<ul><li><strong>VG Name</strong>: il nome del volume group, già visto in <code>pvdisplay</code>, <strong>vg_lab</strong></li>
<li><strong>VG Size</strong>: la dimensione del volume group, minore di 2 GiB perché ci sono i metadati da considerari</li>
<li><strong>PE Size</strong>: la dimensione di un extent, 4 MiB</li>
<li><strong>Total PE / Size</strong>: Il numero totale di extent allocabili, che conferma <strong>VG Size</strong>, pari a <strong>511</strong> invece che <strong>512</strong>.</li>
<li><strong>Alloc PE</strong>: il numero totale di extent allocati, momento della creazione del volume group è <strong>0</strong></li>
<li><strong>Free PE / Size</strong>: il numero totale di extent liberi, prima della creazione dei volumi logici è <strong>511</strong></li></ul>

<p>Cosa succede quando creerò i volumi logici? Che cambia il numero di PE liberi e allocati. Siccome userò tutti gli extent disponibili, i valori per <code>Alloc PE</code> e <code>Free PE</code> si invertiranno rispetto a prima.</p>

<p>Infatti dopo la creazione dei volumi logici, <code>vgdisplay</code> mi dirà:</p>

<pre><code class="language-bash">vgdisplay vg_lab
  --- Volume group ---
  VG Name               vg_lab
  ...
  Alloc PE / Size       511 / &lt;2,00 GiB
  Free  PE / Size       0 / 0
  ...  
</code></pre>

<p><strong>511 extents</strong> allocati come confermato dai dati desumibili dei 3 volumi logici</p>

<pre><code class="language-bash">lvdisplay vg_lab
 --- Logical volume ---
  LV Path                /dev/vg_lab/lv_lab_1
  LV Name                lv_lab_1
  VG Name                vg_lab
...
  LV Size                552,00 MiB
  Current LE             138
...
 --- Logical volume ---
  LV Path                /dev/vg_lab/lv_lab_2
  LV Name                lv_lab_2
  VG Name                vg_lab
...
  LV Size                352,00 MiB
  Current LE             88
...
 --- Logical volume ---
  LV Path                /dev/vg_lab/lv_lab_3
  LV Name                lv_lab_2
  VG Name                vg_lab
...
  LV Size                1,11 GiB
  Current LE             285
...
</code></pre>

<p>Per il primo, il secondo e il terzo volume logico abbiamo rispettivamente:</p>
<ul><li><strong>138, 88, 285 extents</strong> corrispondenti a</li>
<li><strong>552 MiB, 352 MiB e 1140 MiB (1,11 GiB)</strong></li>
<li>per un totale di <strong>2044 MiB</strong>, al netto dei metadati.</li></ul>

<p>Possiamo notare subito che le dimensioni non corrispondono a quanto indicato in <code>lvcreate</code>.</p>

<pre><code class="language-bash">lvcreate -n lv_lab_1 vg_lab -L 550M
lvcreate -n lv_lab_2 vg_lab -L 350M
lvcreate -n lv_lab_3 vg_lab -l 100%FREE
</code></pre>

<p>Questo succede perché vengono <strong>sempre</strong> approssimate all’extent più vicino. Ecco perché il primo e il secondo volume sono diventati di <strong>552</strong> (138 extents) e <strong>352 MiB</strong> (88 extents).</p>

<p>Sempre ricordando la particolarità dei multipli di 4 MiB legati a LVM, anche la riduzione di 150 MiB e di 330 MiB dei due volumi saranno approssimate sempre all’extent più vicino (<strong>152 MiB=38 extents</strong> e <strong>332=83 extents</strong>). Questo dettaglio si rivelerà fondamentale quando dovremo ridimensionare il filesystem.</p>

<p>Con questa rinnovata consapevolezza cominciamo a ridimensionare.</p>

<h3 id="2-2-step-1-smontare-i-dischi">2.2. Step 1: Smontare i dischi</h3>

<pre><code class="language-bash">umount /dev/vg_lab/lv_lab_1
umount /dev/vg_lab/lv_lab_2
umount /dev/vg_lab/lv_lab_3
</code></pre>

<h3 id="2-3-step-2-riduzione-del-filesystem">2.3. Step 2: Riduzione del filesystem</h3>

<p>Se dovessi ridimensionare solo il filesystem, sarebbe sufficiente considerare dimensioni che siano potenze di 2 e non di 10.</p>

<p>Ma sapendo che sotto c’è un LVM, sappiamo che per mantenere l’allineamento fra filesystem e volumi logici, oltre che potenze di due le dimensioni devono essere anche multipli di 4MiB.</p>

<p>Ecco perché <strong>anche</strong> nel resize reale del filesystem non dovrò levare <strong>150 MiB</strong> e <strong>330 MiB</strong> ma <strong>148 MiB (37 PE)</strong> e <strong>328 (82 PE)</strong> (è buona norma approssimare per difetto all’extent più vicino per maggior prudenza) per un totale effettivo di <strong>476 MiB (119 PE)</strong></p>

<p>Il filesystem del primo volume sarà dunque di <em>552 MiB – 148 MiB = 404 MiB</em>. Il filesystem del terzo volume sarà di <em>1140 MiB – 328 MiB = 812 MiB</em>.</p>

<pre><code class="language-bash"># check dei filesystem
e2fsck -f /dev/vg_lab/lv_lab_1
e2fsck -f /dev/vg_lab/lv_lab_2
e2fsck -f /dev/vg_lab/lv_lab_3

# Riduco il primo filesystem di 148 MiB
resize2fs /dev/vg_lab/lv_lab_1 404M

# Riduco il terzo filesystem di 328 MiB
resize2fs /dev/vg_lab/lv_lab_3 812M
</code></pre>

<h3 id="2-4-step-3-ridimensionare-i-volumi-logici">2.4. Step 3: Ridimensionare i volumi logici</h3>

<p>La riduzione del volume logico può essere fatta in 4 modi come sappiamo, ad es. sul primo volume:</p>

<pre><code class="language-bash"># il numero totale di extents, 138 PE - 37 PE = 101 PE
lvreduce -l 101 /dev/vg_lab/lv_lab_1 #oppure

# il numero di exrtents da sottrarre, 38 PE
lvreduce -l -37 /dev/vg_lab/lv_lab_1 #oppure

# la dimensione totale da ottenere, 404 MiB
lvreduce -L 404M /dev/vg_lab/lv_lab_1 #oppure

# il numero di MiB da sottrarre, 148 MiB
lvreduce -L -148M /dev/vg_lab/lv_lab_1 #oppure
</code></pre>

<p>Per maggior chiarezza userò il size assoluto in modo da farlo corrispondere a <code>resize2fs</code></p>

<pre><code class="language-bash"># Riduco il primo volume logico di 148 Mib
lvreduce -L 404M /dev/vg_lab/lv_lab_1

# Riduco il terzo volume logico di 328 Mib
lvreduce -L 812M /dev/vg_lab/lv_lab_3
</code></pre>

<p>Verifichiamo quanti siano i PE residui</p>

<pre><code class="language-bash">vgdisplay vg_lab | grep &#34;Free  PE&#34;
 Free  PE / Size       119 / 476,00 MiB
</code></pre>

<p>119 extents, come previsto.</p>

<h3 id="2-5-step-4-estendere-il-volume-logico">2.5. Step 4: Estendere il volume logico</h3>

<p>Dopo aver ridotto il primo e il terzo volume, non ci rimane che estendere il secondo in base alla scaletta indicata prima:</p>
<ol><li>si estende il secondo volume logico</li>
<li>si estende il filesystem</li>
<li>si esegue il check fnale del filesystem</li></ol>

<p>L’estensione del volume, come ormai ben sappiamo, non sarà di <strong>480 MiB</strong> ma di <strong>476 MiB (37 PE + 82 PE = 119 PE)</strong> per via degli arrotondamenti effettuati nella riduzione degli altri volumi logici.</p>

<pre><code class="language-bash"># specifico gli extent che so essere residui
lvextend -l +119 /dev/vg_lab/lv_lab_2
# o, equivalentemente
# lvextend -L +476M /dev/vg_lab/lv_lab_2

# estendo il filesystem
resize2fs /dev/vg_lab/lv_lab_2 828M

# check filesystem
e2fsck -f /dev/vg_lab/lv_lab_2
</code></pre>

<h3 id="2-6-step-5-bonus">2.6. Step 5: Bonus</h3>

<p>Come premio per essere arrivato in fondo, posso rivelare come fare in un colpo solo tutte le operazioni descritte sopra.</p>

<p>È vero che c&#39;è poco da considerare, giusto tenere a mente che su LVM ogni oggetto è multiplo di 4 MiB e che bisogna ridimensionare filesystem e volumi logici in ugual modo per non generare pericolose anomalie, ma tutte le operazioni che ho descritto nei passi 2-4 possono essere fatte con un unico comando che provvederà ad eseguire nell&#39;ordine corretto e con le giuste approssimazioni:</p>
<ul><li>il check del filesystem</li>
<li>il ridimensionamento del filesystem</li>
<li>il ridimensionamento dei volumi logici</li></ul>

<p>Dunque, tutto il pippone atomico precedente può essere condensato in un unico, solido comando:</p>

<pre><code class="language-bash"># Riduce il primo volume logico e il filesystem
lvreduce -r -L -150M /dev/vg_lab/lv_lab_1

# Riduce il terzo volume logico e il filesystem
lvreduce -r -L -330M /dev/vg_lab/lv_lab_3

# Estende il secondo volume logico e il filesystem
lvextend -r -l +119 /dev/vg_lab/lv_lab_2
</code></pre>

<p>Ora spieghiamo il perché soprattutto dell&#39;extend, che è interessante.</p>

<p>Diciamo che è tutto molto guidato e le eventuali correzioni da apportare, senza spaccarsi troppo il cervello, sono suggerite con estrema chiarezza, basta leggere.</p>

<pre><code class="language-bash">lvreduce -r -L -150M /dev/vg_lab/lv_lab_1
 Rounding size to boundary between physical extents: 148.00 MiB.
  File system ext4 found on vg_lab/lv_lab_1.
  File system size (552.00 MiB) is larger than the requested size (404.00 MiB).
  File system reduce is required using resize2fs.
...
  Size of logical volume vg_lab/lv_lab_1 changed from 552.00 MiB (138 extents) to 404.00 MiB (101 extents).
  Logical volume vg_lab/lv_lab_1 successfully resized.
</code></pre>

<p>Ci dice innanzitutto che:</p>
<ul><li>c&#39;è stato un arrotondamento a <strong>148 MiB (37 extents)</strong>;</li>
<li>il filesystem è più grande del volume richiesto pertanto va subito ridimensionato;</li>
<li>infine si ridimensiona il volume logico da <strong>552 MiB (138 extents)</strong> a <strong>404 MiB (101 extents)</strong>.</li></ul>

<p>Anche il secondo <code>lvreduce</code> ha un risultato analogo</p>

<pre><code class="language-bash">lvreduce -r -L -330M /dev/vg_lab/lv_lab_3
  Rounding size to boundary between physical extents: 328.00 MiB.
  File system ext4 found on vg_lab/lv_lab_3.
  File system size (1.11 GiB) is larger than the requested size (812.00 MiB).
  File system reduce is required using resize2fs.
...
  Size of logical volume vg_lab/lv_lab_3 changed from 1.11 GiB (285 extents) to 812.00 MiB (203 extents).
  Logical volume vg_lab/lv_lab_3 successfully resized.
</code></pre>
<ul><li>anche qui abbiamo un arrotondamento a <strong>328 MiB (82 extents)</strong>;</li>
<li>il filesystem è più grande del volume richiesto pertanto va subito ridimensionato;</li>
<li>infine si ridimensiona il volume logico da <strong>1140 MiB (285 extents)</strong> a <strong>812 MiB (203 extents)</strong>.</li></ul>

<p>È facilissimo desumere che la massima dimensione dell&#39;estensione sia <strong>148 MiB + 328 MiB = 476 MiB (119 extents)</strong>, basta fare una somma.</p>

<p>Ma supponiamo di essere particolarmente distratti e proviamo ad estendere considerando le quantità iniziali: 150 MiB + 330 MiB = <strong>480 MiB</strong></p>

<pre><code class="language-bash">lvextend -r -L +480M /dev/vg_lab/lv_lab_2
  File system ext4 found on vg_lab/lv_lab_2.
  File system fsck will be run before extend.
  Insufficient free space: 120 extents needed, but only 119 available
</code></pre>

<p>Nonostante la mia distrazione, come si può vedere, non si producono danni perché l&#39;ouput è categorico: “non faccio nulla. Se vuoi, puoi aumentare al max di 476 MiB (119 extents)”.
Non ci sono danni e anzi c&#39;è pure il suggerimento risolutivo.</p>

<p>Ed ecco spiegato il mio extend di prima.</p>

<h2 id="3-scenario-2-estensione-e-riduzione-di-gruppi-di-volume">3. Scenario 2: Estensione e riduzione di gruppi di volume</h2>

<p>Esaminiamo le possibilità di aggiungere o rimuovere dispositivi ad un volume group esistente.</p>

<p>Ricreiamo il laboratorio partendo da 3 dischi, poi aggiungeremo due nuovi dischi e ne rimuoveremo altrettanti, il tutto senza intaccare l&#39;integrità dei dati.</p>

<pre><code class="language-bash"># creazione di 5 device
for i in {1..9}: do fallocate -l 1GiB disk_${i}.img; done

# creazione del gruppo di volumi con 3 device
vgcreate vg_lab \
  $(losetup -Pf --show disk_1.img) \
  $(losetup -Pf --show disk_2.img) \
  $(losetup -Pf --show disk_3.img)

# crezione di 3 volumi logici
lvcreate -n lv_lab_1 vg_lab -l 300
lvcreate -n lv_lab_2 vg_lab -l 250
lvcreate -n lv_lab_3 vg_lab -l 100%FREE

# formattazione dei 3 dispositivi
mkfs.ext4 /dev/vg_lab/lv_lab_1
mkfs.ext4 /dev/vg_lab/lv_lab_2
mkfs.ext4 /dev/vg_lab/lv_lab_3
</code></pre>

<p>Ecco come sono distribuiti i volumi logici all&#39;interno dei dischi fisici</p>

<pre><code class="language-bash">lsblk -o NAME,FSTYPE,SIZE,TYPE
  NAME               FSTYPE        SIZE      TYPE
  loop9              LVM2_member     1G      loop
  └─vg_lab-lv_lab_1                1,2G      lvm
  loop10             LVM2_member     1G      loop
  ├─vg_lab-lv_lab_1                1,2G      lvm
  └─vg_lab-lv_lab_3                860M      lvm
  loop11             LVM2_member     1G      loop
  ├─vg_lab-lv_lab_2               1000M      lvm
  └─vg_lab-lv_lab_3                860M      lvm
</code></pre>

<p>Il gruppo di volumi è composto da 3 volumi fisici tutti attivi</p>

<pre><code class="language-bash">vgdisplay vg_lab |grep PV
  Max PV                0
  Cur PV                3
  Act PV                3
</code></pre>

<p>Andiamo ad estendere il nostro gurppo di volumi con altri due device</p>

<pre><code class="language-bash">vgextend vg_lab $(losetup -Pf --show disk_4.img) $(losetup -Pf --show disk_5.img)
</code></pre>

<p>I nuovi dischi sono visibili in fondo, come si può vedere anche da  <code>vgdisplay</code> che mostra i 5 dischi tutti attivi.</p>

<pre><code class="language-bash">lsblk -o NAME,FSTYPE,SIZE,TYPE
  NAME               FSTYPE        SIZE      TYPE
  loop9              LVM2_member     1G      loop
  └─vg_lab-lv_lab_1                1,2G      lvm
  loop10             LVM2_member     1G      loop
  ├─vg_lab-lv_lab_1                1,2G      lvm
  └─vg_lab-lv_lab_3                860M      lvm
  loop11             LVM2_member     1G      loop
  ├─vg_lab-lv_lab_2               1000M      lvm
  └─vg_lab-lv_lab_3                860M      lvmchan
  loop12             LVM2_member     1G      loop
  loop13             LVM2_member     1G      loop

vgdisplay vg_lab |grep PV
  Max PV                0
  Cur PV                5
  Act PV                5
</code></pre>

<p>Potremo usare i nuovi dischi per estendere i volumi logici esistenti ma li impiegheremo invece per rimpiazzare i primi due dischi.</p>

<p><code>pvmove</code> distribuisce tutti gli extents del disco fra tutti i volumi fisici che hanno spazio a sufficienza. Se non dovesse essercene, restituirà un messaggio d&#39;errore.</p>

<pre><code class="language-bash">pvmove /dev/loop9
  /dev/loop9: Moved: 3,14%
  /dev/loop9: Moved: 100,00%
</code></pre>

<p>Alla fine dell&#39;operazione il disco s&#39;è liberato di tutti i suoi extents e può essere rimosso</p>

<pre><code class="language-bash">lsblk -o NAME,FSTYPE,SIZE,TYPE
  NAME               FSTYPE        SIZE      TYPE
  loop9              LVM2_member     1G      loop
  loop10             LVM2_member     1G      loop
  ├─vg_lab-lv_lab_1                1,2G      lvm
  └─vg_lab-lv_lab_3                860M      lvm
  loop11             LVM2_member     1G      loop
  ├─vg_lab-lv_lab_2               1000M      lvm
  └─vg_lab-lv_lab_3                860M      lvm
  loop12             LVM2_member     1G      loop
  └─vg_lab-lv_lab_1                1,2G      lvm
  loop13             LVM2_member     1G      loop
</code></pre>

<p>Prima si estrae il volume fisico dal gruppo di volumi e poi si rimuove il volume fisico e così può essere scollegato.</p>

<pre><code class="language-bash">vgreduce vg_lab /dev/loop9
pvremove /dev/loop9
</code></pre>

<p>Verifichiamo che il volume fisico non sia più presente.</p>

<pre><code class="language-bash">vgdisplay vg_lab |grep PV
  Max PV                0
  Cur PV                4
  Act PV                4
</code></pre>

<p>Procediamo allo stesso modo col secondo disco.</p>

<pre><code class="language-bash">pvmove /dev/loop10
  /dev/loop10: Moved: 9,80%
  /dev/loop10: Moved: 17,65%
  /dev/loop10: Moved: 100,00%

vgreduce vg_lab /dev/loop10
  Removed &#34;/dev/loop10&#34; from volume group &#34;vg_lab&#34;

pvremove /dev/loop10
  Labels on physical volume &#34;/dev/loop10&#34; successfully wiped.
</code></pre>

<p>In conclusione possiamo vedere il gruppo di volumi con solo 3 dischi, gli altri due completamente disimpegnati col gruppo di volumi ricostituitosi attorno ai 3 dischi rimanenti. E tutto spostando semplicemente gli extents dove c&#39;era disponibilità in maniera totalmente trasparente per il filesystem.</p>

<pre><code class="language-bash">vgdisplay vg_lab |grep PV
  Max PV                0
  Cur PV                3
  Act PV                3


lsblk -o NAME,FSTYPE,SIZE,TYPE
  NAME               FSTYPE        SIZE      TYPE
  loop9                              1G      loop
  loop10                             1G      loop
  loop11             LVM2_member     1G      loop
  ├─vg_lab-lv_lab_2               1000M      lvm
  └─vg_lab-lv_lab_3                860M      lvm
  loop12             LVM2_member     1G      loop
  └─vg_lab-lv_lab_1                1,2G      lvm
  loop13             LVM2_member     1G      loop
  ├─vg_lab-lv_lab_1                1,2G      lvm
  └─vg_lab-lv_lab_3                860M      lvm
</code></pre>

<h2 id="4-conclusione">4. Conclusione</h2>

<p>Ho solo sfiorato la complessità e le capacità offerte da LVM.</p>

<p>L&#39;estensione e la riduzione di volumi logici e di gruppi di volumi sono scenari di base. Tuttavia sono sufficienti per mostrare come sia semplice, con i volumi logici, compiere operazioni che con un filesystem partizionato in maniera classica sarebbero complicatissime.</p>

<p><a href="/aytin/tag:lvm" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">lvm</span></a> <a href="/aytin/tag:volumegroup" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">volumegroup</span></a> <a href="/aytin/tag:logicalvolume" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">logicalvolume</span></a> <a href="/aytin/tag:filesystem" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">filesystem</span></a> <a href="/aytin/tag:devicemapper" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">devicemapper</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/ridimensionare-volumi-lvm</guid>
      <pubDate>Mon, 20 Apr 2026 21:13:18 +0000</pubDate>
    </item>
    <item>
      <title>Come aumentare il volume di una traccia audio</title>
      <link>https://noblogo.org/aytin/come-aumentare-il-volume-di-una-traccia-audio</link>
      <description>&lt;![CDATA[normalizzazione&#xA;Quando si deve aumentare il volume di una traccia audio, si deve ricorrere a ad un&#39;operazione di &#34;normalizzazione&#34;.&#xA;!--more--&#xA;&#xA;1. Cos’è la normalizzazione&#xA;2. Come misurare il &#34;picco&#34;?&#xA;3. Come leggere correttamente questa misura&#xA;   3.1. Perché usare il loudness invece di RMS?&#xA;4. Come ti normalizzo il file&#xA;  4.1. Peak normalization&#xA;  4.2. Loudness Normalization&#xA;     4.2.1. Loudness Normalization statica (ffmpeg)&#xA;     4.2.2. Loudness Normalization dinamica&#xA;     4.2.3. Loudness Normalization statica (rsgain)&#xA;&#xA;1. Cos&#39;è la normalizzazione&#xA;La normalizzazione è un&#39;operazione lineare che consiste nell&#39;analisi del file audio, nel calcolare la differenza (offset) fra il volume attuale ed un volume target, nell&#39;applicare una correzione di guadagno (Gain).&#xA;&#xA;La normalizzazione può essere distinta in base  al &#34;come&#34; e al &#34;dove&#34;.&#xA;&#xA;Il &#34;come&#34;&#xA;La normalizzazione classica si basa sui picchi. Cerca il punto più alto della forma d&#39;onda e lo porta a un valore massimo (es. 0 dB). Ignora la percezione umana; un brano con un singolo &#34;click&#34; molto forte risulterà comunque silenzioso perché quel picco blocca l&#39;aumento del volume.&#xA;&#xA;La normalizzazione più moderna si basa sui LUFS, ossia su come, mediamente, l&#39;audio viene effettivamente percepito dall&#39;orecchio umano (psicoacustica). Porta l&#39;intero brano a un livello di pressione sonora media costante, rendendo l&#39;ascolto uniforme tra diverse tracce.&#xA;&#xA;Il &#34;dove&#34;&#xA;Quando si normalizza una traccia audio si può scegliere di farla modificando ogni singolo sample della traccia audio oppure di agire sui metadati.&#xA;&#xA;Nel primo caso il file originale viene modificato (ricodifica quasi sempre lossy), nel secondo viene lasciato inalterato.&#xA;&#xA;Altro fattore di cui tenere conto è che una normalizzazione lossy funziona su ogni player, una normalizzazione che agisce sui metadati funziona solo se il player è in grado di leggerli.&#xA;&#xA;Possiamo fare quindi una prima distinzione:&#xA;&#xA;normalizzazione di picco (RMS) o iPeak Normalization/i: applicazione di un guadagno statico (RMS) in modalità lossy: non altera la dinamica del brano, richiede una ricodifica;&#xA;normalizzazione della sonorità (LUFS) o iLoudness Normalization/i:&#xA;   applicazione di un guadagno statico (LUFS) in modalità lossy: non altera la dinamica del brano, richiede una ricodifica;&#xA;   applicazione di un guadagno statico (LUFS) basato su tag: non altera la dinamica del brano, lascia il file inalterato (rsgain);&#xA;   agisce con un compressore / limiter in modalità lossy: altera la dinamica del brano, richiede una ricodifica.&#xA;&#xA;A questo punto la domanda diventa: quale scegliere?&#xA;&#xA;Per quel che mi riguarda, la salomonica risposta è: dipende.&#xA;&#xA;Come si può immaginare, non c&#39;è una risposta definitiva ma dipende dalla qualità della traccia, dal contesto ecc.&#xA;2. Come misurare il &#34;picco&#34;?&#xA;C&#39;è bisogno di un elemento misurabile che mi permetta di capire come agire con la normalizzazione.&#xA;&#xA;RMS (Root Mean Square): è un calcolo matematico asciutto su quanto sia potente elettricamente/digitalmente il segnale audio. È utile per capire l&#39;energia costante, ma non tiene conto del fatto che l&#39;orecchio umano è più sensibile ad alcune frequenze rispetto ad altre.&#xA;&#xA;LUFS (Loudness Units Full Scale): È lo standard moderno (EBU R128). Simula l&#39;udito umano applicando dei filtri che pesano maggiormente le frequenze medie.&#xA;&#xA;Per misurare il picco RMS posso ricorrere ad ffmpeg&#xA;ffmpeg -hidebanner -i &#34;audio.m4a&#34; -filter:a &#34;volumedetect&#34; -f null -&#xA;...&#xA;[...] nsamples: 18522112&#xA;[...] meanvolume: -20.3 dB&#xA;[...] maxvolume: -5.4 dB&#xA;[...] histogram5db: 40&#xA;[...] histogram6db: 1436&#xA;[...] histogram7db: 6443&#xA;[...] histogram8db: 18606&#xA;...&#xA;che mi mostrerà:&#xA;&#xA;il numero dei samples di cui si compone la traccia&#xA;il volume medio (meanvolume)&#xA;il picco (maxvolume)&#xA;&#xA;Il picco mi dice di quanto possa alzare il volume (fino al limite fisico di 0dB) staticamente senza causare distorsioni.&#xA;&#xA;La differenza fra volume medio e picco mi dà informazioni sulla dinamica del brano. Maggiore è la differenza, maggiore è la dinamica. Tipicamente:&#xA;&#xA;valori &lt; 5 sono tipici della musica dance, forte, uniforme, e molto compressa.&#xA;valori fra 5 e 15 sono tipici di brani pop-rock, ben bilanciati&#xA;valori   15 sono attribuibili a brani di musica classica, jazz, con una dinamica ricca.&#xA;&#xA;Per misurare il loudness, sempre con ffmpeg:&#xA;ffmpeg -hidebanner -i &#34;audio.m4a&#34; -filter:a &#34;ebur128=peak=true&#34; -f null - &#xA;...&#xA; Integrated loudness:&#xA;    I:         -18.1 LUFS&#xA;    Threshold: -28.4 LUFS&#xA;&#xA;  Loudness range:&#xA;    LRA:         4.1 LU&#xA;    Threshold: -38.3 LUFS&#xA;    LRA low:   -21.2 LUFS&#xA;    LRA high:  -17.1 LUFS&#xA;&#xA;  True peak:&#xA;    Peak:       -5.4 dBFS&#xA;La misurazione è più articolata rispetto alla precedente.&#xA;&#xA;FFmpeg innanzitutto mostra due sezioni: Integrated Loudness, rappresentante il volume medio complessivo del file e la Loudness Range che mi descrive la dinamica del brano come differenza di volume fra le parti più silenziose e quelle più rumorose.&#xA;&#xA;Sezione Integrated loudness:&#xA;   I: è il valore più importante. È il volume medio percepito dell&#39;intero brano (come si può vedere, diverso rispetto all&#39;RMS di prima. Il primo è pura potenza digitale, il secondo è volume percepito).&#xA;   Threshold: è la soglia usata per evitare che i silenzi abbassino artificialmente la media del volume. L&#39;algoritmo ignora tutto ciò che sta sotto questa soglia nel calcolo dell&#39;Integrated Loudness.&#xA;Sezione Loudness range:&#xA;   LRA: è un indice della variazione dinamica del brano. Più è basso, più il suono tende ad essere uniforme e probabilmente compresso&#xA;   Threshold: come prima, è la soglia oltre la quale i suoni vengono ignorati nel calcolo del range dinamico.&#xA;   LRA Low: indica il limite inferiore del loudness&#xA;   LRA High: indica il limite superiorebr&#xA;   quindi LRA = LRA High - LRA Low&#xA;Sezione True peak:&#xA;   Peak: Simile al max\volume dell&#39;RMS, indica il picco reale del brano in termini di sonorità.&#xA;&#xA;Un altro modo, forse meno pratico ma decisamente più scenografico, per analizzare un file audio è questo:&#xA;ffplay -f lavfi -i &#34;amovie=audio.m4a,ebur128=video=1:meter=18 out0&#34;&#xA;Disegna un grafico dell&#39;onda sonora in tempo reale.&#xA;3. Come leggere correttamente questa misura&#xA;L&#39;integrated loudness mi dice qual è il volume medio del brano.&#xA;True peak mi dice di quanto posso alzare prima di distorcere.&#xA;Queste sono le due informazioni cruciali sufficienti per applicare un guadagno statico senza fare danni.&#xA;&#xA;I valori High e Low del Loudness Range, che racchiudono asintoticamente il brano, tornano utili quando bisogna agire sulla dinamica.&#xA;&#xA;Notare che Integrated loudness è sempre compreso fra LRA Low e LRA High.&#xA;3.1. Perché usare il loudness invece di RMS?&#xA;L&#39;RMS è un calcolo puramente matematico che non tiene conto del fatto che l&#39;orecchio umano è molto più sensibile alle frequenze medie che non ai bassi estemi e agli acuti altissimi.&#xA;&#xA; A questo provvede il LUFS che è un&#39;evoluzione dell&#39;RMS perché include dei filtri di ponderazione che, prima di calcolare la media, esaltano le frequenze medie attenuando quelle basse.&#xA;&#xA;La conseguenza è che se agisco sul volume dei brani prendendo LUFS come riferimento, questi suoneranno tutti allo stesso volume. Se considerassi un adeguamento basato su RMS, i brani con più bassi sembreranno avere meno volume di quelli con frequenze medie più marcate. &#xA;4. Come ti normalizzo il file&#xA;La scelta fra una normalizzazione di picco e una di volume (loudness) è abbastanza semplice in realtà.&#xA;&#xA;A parte poche eccezioni in cui può avere senso avere RMS come riferimento, è sempre preferibile una normalizzazione della sonorità.&#xA;&#xA;Quest&#39;ultima può essere fatta modificando solo i metadati o agendo chirurgicamente sul file ricodificandolo.&#xA;4.1. Peak normalization&#xA;Una volta noti i dati di Max Volume e Mean Volume visti in precedenza, la normalizzazione è piuttosto semplice.&#xA;&#xA;Supponendo Max Volume = 6dB&#xA;ffmpeg -i audio.m4a -filter:a &#34;volume=6dB&#34; -c:a aac -b:a 192k audionormalized.m4a&#xA;Dovendo ricodificare, scelgo un bitrate piuttosto alto per limitare la perdita fisiologica di una ricodifica lossy.&#xA;&#xA;Come si può immaginare, è una aggiunta lineare secca a tutta la traccia a cui aumento solo la potenza digitale senza tenere conto della percezione sonora.&#xA;&#xA;Piccola nota: Conviene scegliere un valore che si avvicini, ma non equivalga, al limite di 0 dB perché altrimenti FFmpeg taglierà brutalmente le creste dell&#39;onda sonora che superano lo zero, creando quella tipica distorsione metallica grattata chiamata clipping.&#xA;&#xA;4.2. Loudness Normalization&#xA;La normalizzazione di volume, in base alla nostra scelta di alterare o meno la dinamica del brano, può essere fatta come detto applicando:&#xA;&#xA;un guadagno statico LUFS (lossy)&#xA;un guadagno statico LUFS sui metadati (non lossy)&#xA;compressore / limiter (sempre lossy) &#xA;&#xA;Il guadagno statico, quello con i metadati, avverrà con rsgain.&#xA;&#xA;La normalizzazione con perdita di qualità (lossy) avverrà con ffmpeg usando il filtro loudnorm che dispone di un compressore/limiter piuttosto efficace.&#xA;&#xA;Questo filtro è un processore dinamico (dual-pass o single-pass). Non si limita ad alzare il volume; se trova una parte troppo forte, può comprimere leggermente solo quella parte per permettere al resto della canzone di suonare più forte.&#xA;&#xA;loudnorm porta il loudness di default a -24 LUFS che è lo standard per il broadcast televisivo.&#xA;&#xA;I colossi dello streaming applicano automaticamente un loudness decisamente più marcato, salvo poche eccezioni, non si discostano da -14 LUFS. Ad es. Youtube, Amazon Music, Spotify, Soundcloud viaggiano mediamente su -14 LUFS, Deezer -15, Apple Music -16.&#xA;&#xA;Si può verificare facilmente, come sappiamo fare, come un audio presente su una di queste piattaforme, abbia uno dei loudness indicati.&#xA;&#xA;4.2.1. Loudness Normalization statica (ffmpeg)&#xA;Riprendiamo l&#39;esempio di prima.&#xA;ffmpeg -hidebanner -i &#34;audio.m4a&#34; -filter:a &#34;ebur128=peak=true&#34; -f null - &#xA;...&#xA; Integrated loudness:&#xA;    I:         -18.1 LUFS&#xA;    Threshold: -28.4 LUFS&#xA;&#xA;  Loudness range:&#xA;    LRA:         4.1 LU&#xA;    Threshold: -38.3 LUFS&#xA;    LRA low:   -21.2 LUFS&#xA;    LRA high:  -17.1 LUFS&#xA;&#xA;  True peak:&#xA;    Peak:       -5.4 dBFS&#xA;Con ffmpeg e loudnorm in modalità single-pass, posso applicare un guadagno statico 5.4 dBFS, con un true peak di -1 (Il default è -2), per arrivare, da -18.1 LUFS, a -13.0 LUFS senza distorsioni.&#xA;ffmpeg -i audio.m4a -filter:a &#34;loudnorm=I=-12.7:TP=-1.0&#34; -c:a aac -b:a 160k -vn audionorm.m4a&#xA;Verifichiamo:&#xA;ffmpeg -hidebanner -i &#34;audio.m4a&#34; -filter:a &#34;ebur128=peak=true&#34; -f null - &#xA;...&#xA;   Integrated loudness:&#xA;    I:         -12.5 LUFS&#xA;    Threshold: -22.6 LUFS&#xA;&#xA;  Loudness range:&#xA;    LRA:         4.0 LU&#xA;    Threshold: -32.6 LUFS&#xA;    LRA low:   -15.1 LUFS&#xA;    LRA high:  -11.1 LUFS&#xA;&#xA;  True peak:&#xA;    Peak:       -0.4 dBFS&#xA;...&#xA;Come si vede, sono arrivato al limite, forse un po&#39; troppo, del guadagno che potevo ottenere. Probabimente su dispositivi economici, l&#39;analogico di un brano così potrebbe gracchiare un po&#39;.&#xA;&#xA;Se avessi applicato il default  di  loudnorm, la sonorità sarebbe stata livellata sui -24 LUFS con una soglia true peak pari a -2 dBFS.&#xA;4.2.2. Loudness Normalization dinamica&#xA;Nei casi in cui:&#xA;&#xA;si vuole enfatizzare l&#39;audio di un podcast, di un parlato in generale;&#xA;la dinamica del brano è composta da picchi altissimi e una sonorità media molto bassa (un guadagno statico farebbe cambiare poco o nulla)&#xA;&#xA;con ffmpeg e loudnorm possiamo correggere ogni singolo sample del brano per rendere la dinamica più uniforme.&#xA;&#xA;Per ottenere un risultato ottimale, si deve procedere col dual-pass, in cui ffmpeg nel primo passaggio analizza il file e raccoglie i dati, nel secondo passaggio applica le correzioni puntualmente avendo già conoscenza della dinamica e dei picchi presenti nel file.&#xA;ffmpeg -i &#34;audio.m4a&#34; -filter:a &#34;loudnorm=I=-14:TP=-1.0:printformat=json&#34; -f null -&#xA;Ecco il json risultante dall&#39;analisi. I valori di input sono quelli che forniremo a ffmepg affinché possa impostare il loudness scelto da noi nel miglior modo possibile&#xA;{&#xA;&#x9;&#34;inputi&#34; : &#34;-18.17&#34;,&#xA;&#x9;&#34;inputtp&#34; : &#34;-5.41&#34;,&#xA;&#x9;&#34;inputlra&#34; : &#34;4.20&#34;,&#xA;&#x9;&#34;inputthresh&#34; : &#34;-28.47&#34;,&#xA;&#x9;&#34;outputi&#34; : &#34;-13.36&#34;,&#xA;&#x9;&#34;outputtp&#34; : &#34;-1.00&#34;,&#xA;&#x9;&#34;outputlra&#34; : &#34;4.30&#34;,&#xA;&#x9;&#34;outputthresh&#34; : &#34;-23.50&#34;,&#xA;&#x9;&#34;normalizationtype&#34; : &#34;dynamic&#34;,&#xA;&#x9;&#34;targetoffset&#34; : &#34;-0.64&#34;&#xA;}&#xA;Configurazione ffmpeg.&#xA;ffmpeg -i &#34;audio.m4a&#34; -filter:a &#34;loudnorm=I=-14:TP=-1.0:measuredI=-18.17:measuredTP=-5.41:measuredLRA=4.20:measuredthresh=-23.50:linear=true&#34; -c:a aac -b:a 160k -vn &#34;audionorm.m4a&#34;&#xA;Il compressore/limiter del filtro loudnorm è abbastanza intelligente da schiacciare i picchi affinche il guadagno di volume non produca clipping e alzerà le parti più &#34;deboli&#34;, livellando il suono e alterando la dinamica.&#xA;&#xA;4.2.3. Loudness Normalization statica (rsgain)&#xA;Rsgain permette di applicare un guadagno statico loseless, senza ricodifica, agendo sui metadati del brano con l&#39;applicazione dei tag.&#xA;&#xA;Se da un lato questo metodo ha l&#39;indubbio vantaggio di non alterare fisicamente il file, dall&#39;altro è necessario che il player che eseguirà il brano dovra essere capace di leggere e interpretare i tag. Nel caso precedente, la ricodifica rende il file disponibile per chiunque.&#xA;&#xA;Trattandosi di un guadagno statico, il campo d&#39;applicazione è quello visto per la Peak Normalization, cioè quando si vuole preservare la dinamica del brano, Ma nei casi particolari cui accennavo in precedenza, presenza di picchi altissimi e maggioranza sonorità medie molto basse, anche rsgain non è sufficiente.&#xA;&#xA;Come avevo detto all&#39;inizio, rsgain è una normalizzaziome della sonorità ottenuta agendo sui metadati del brano, applicando dei tag, che così non viene alternato in alcun modo.&#xA;&#xA;Rsgain è l&#39;evoluzione del vecchio mp3gain e come il suo predecessore ha due modalità di lavoro&#xA;&#xA;sul singolo brano (detta é custom)&#xA;su collezioni di brani (detta easy)&#xA;&#xA;La modalità custom è considerato un approccio legacy fatta per intervenire puntualmente sul brano con configurazioni ad-hoc ideali per lo scripting, quella easy, basata su presets, permette di normalizzare intere collezioni di brani che è lo scopo principale di rsgain.&#xA;&#xA;Analisi del file&#xA;rsgain custom -t audio.m4a&#xA;[✔] Scanning &#39;audio.m4a&#39;&#xA;[✔] Container: QuickTime / MOV [mov,mp4,m4a,3gp,3g2,mj2]&#xA;[✔] Stream #0: AAC (Advanced Audio Coding), 44.100 Hz, 2 ch&#xA; 100% [====================================================]&#xA;&#xA;Track: audio.m4a&#xA;  Loudness:   -18.12 LUFS&#xA;  Peak:     0.536630 (-5.41 dB)&#xA;  Gain:         0.12 dB&#xA;il flag -t individua il true peak&#xA;&#xA;Loudness: è la sonorità del brano in LUFS&#xA;Peak: è il true peak, esprime il guadagno che posso ottenere prima di distorcere&#xA;Gain: è il guadagno per arrivare allo standard LUFS di rsgain che è -18&#xA;&#xA;Nel nostro caso, Gain ci dice di diminuire di 0.12 LUFS mentre Peak ci dice che potrei aumentare di 5.41 LUFS&#xA;&#xA;Gain&#xA;rsgain custom -s i -l -13 -c p audio.m4a&#xA;Track: audio.m4a&#xA;  Loudness:   -18.12 LUFS&#xA;  Peak:     0.534149 (-5.45 dB)&#xA;  Gain:         5.12 dB&#xA;&#xA;-s i: scrive il tag&#xA;-l -13: imposta il loudness&#xA;-c p: protezione clipping&#xA;&#xA;Portando il loudness a -13 è come se avessi aumentato il volume di 5,12 dB mantenendo un cuscinetto di -0.33 dB (differenza fra peak e gain).&#xA;&#xA;Se provassi a spingere di più, il flag -c p impedisce al suono di distorcere.&#xA;rsgain custom -s i -l -10 -c p audio.m4a&#xA;Track: audio.m4a&#xA;  Loudness:   -18.12 LUFS&#xA;  Peak:     0.534149 (-5.45 dB)&#xA;  Gain:         5.45 dB  (adjusted to prevent clipping)&#xA;&#34;(adjusted to prevent clipping)&#34; è la conferma che la protezione anti-clipping è entrata in azione.&#xA;&#xA;Se non ci fosse stata:&#xA;rsgain custom -s i -l -10 audio.m4a&#xA;Track: audio.m4a&#xA;  Loudness:   -18.12 LUFS&#xA;  Peak:     0.534149 (-5.45 dB)&#xA;  Gain:         8.12 dB&#xA;La differenza fra peak e gain indica un&#39;evidente distorsione.&#xA;&#xA;Esempio di esecuzione del brano sfruttando il replaygain:&#xA;mpv --replaygain=track audio.m4a&#xA;Senza il flag --replaygain=track, il brano verrebbe letto normalmente.&#xA;&#xA;Cancellazione del tag&#xA;Basta cancellare il tag per riportare tutto alla normalità&#xA;verifico la presenza del tag prima&#xA;ffprobe -hidebanner -i &#34;audio.m4a&#34; 2  &amp;1 | grep -i &#34;replaygain&#34;&#xA;REPLAYGAINTRACKGAIN: 8.12 dB&#xA;REPLAYGAINTRACKPEAK: 0.534149&#xA;replaygain: track gain - 8.120000, track peak - 0.000012, album gain - unknown, album peak - unknown,&#xA;&#xA;cancello il tag&#xA;rsgain custom -s d audio.m4a&#xA;&#xA;verifico che il tag non si ci sia più&#xA;ffprobe -hidebanner -i &#34;audio.m4a&#34; 2  &amp;1 | grep -i &#34;replaygain&#34;&#xA;&#xA;Un altro modo più compatto per verificare la presenza del tag:&#xA;ffprobe -i &#34;audio.m4a&#34; -showentries formattags=REPLAYGAINTRACKGAIN -v quiet -of csv=&#34;p=0&#34;&#xA;Se c&#39;è il tag, mostra solo il gain.&#xA;&#xA;Easy mode&#xA;I flag impostati nella modalità custom nella modalitò easy sono affidati ad un file di configurazione.&#xA;&#xA;Su Gnu/Linux i file di default si trovano in /usr/share/rsgain/presets e sono 4&#xA;&#xA;default.ini&#xA;ebur128.ini&#xA;loudgain.ini&#xA;no\album.ini&#xA;&#xA;C&#39;è una sezione globla e delle sezioni specifiche per tipo di file.&#xA;&#xA;L&#39;override di queste configurazioni o la creazione di nuove, si fa in:&#xA;&#xA;~/.config/rsgain/presets&#xA;&#xA;e per la corrispondenza campi - flag custom vi rimando alla documentazione: https://github.com/complexlogic/rsgain?tab=readme-ov-file#scan-presets&#xA;&#xA;Una volta deciso il preset che fa per noi, basta chiamare rsgain su una directory in questo modo:&#xA;rsgain easy -s nomepreset pathalbum&#xA;rsgain farà la scansione e applicherà massivamente le configurazioni che potranno consistere per es.:&#xA;&#xA;nell&#39;applicazione di un loudness a tutti i brani per uniformare la sonorità;&#xA;nella cancellazione di tutti i tag;&#xA;nell&#39;analisi dei brani;&#xA;ecc.&#xA;&#xA;Esempio di file di configurazione per una scansione&#xA;[Global]&#xA;TagMode=s&#xA;Album=true&#xA;TargetLoudness=-18&#xA;ClipMode=p&#xA;MaxPeakLevel=-1.0&#xA;TruePeak=true&#xA;Lowercase=false&#xA;ID3v2Version=keep&#xA;OpusMode=d&#xA;PreserveMtimes=false&#xA;DualMono=false&#xA;In questo modo rsgain produrrà un&#39;analisi in modalità &#34;album&#34; per tutta la collezione, il gain da applicare all&#39;album e  una sintesi sulla media dei valori di picco ottenuti.&#xA;rsgain easy -p scan pathalbum &#xA;...&#xA;Track: pathalbum/track1&#xA;  Loudness:   -17.80 LUFS&#xA;  Peak:     0.743221 (-2.58 dB)&#xA;  Gain:        -0.20 dB&#xA;&#xA;Track: pathalbum/track2&#xA;  Loudness:   -17.81 LUFS&#xA;  Peak:     0.790007 (-2.05 dB)&#xA;  Gain:        -0.19 dB&#xA;&#xA;Track: pathalbum/track3&#xA;  Loudness:   -17.47 LUFS&#xA;  Peak:     0.834655 (-1.57 dB)&#xA;  Gain:        -0.53 dB&#xA;&#xA;...&#xA;&#xA;Album:&#xA;  Loudness:   -16.51 LUFS&#xA;  Peak:     0.991804 (-0.07 dB)&#xA;  Gain:        -1.49 dB&#xA;&#xA;Scanning Complete&#xA;Time Elapsed:      00:00:27&#xA;Files Scanned:     18&#xA;Clip Adjustments:  0 (0.0% of files)&#xA;Average Loudness:  -16.61 LUFS&#xA;Average Gain:      -1.39 dB&#xA;Average Peak:      0.823503 (-1.69 dB)&#xA;Negative Gains:    16 (88.9% of files)&#xA;Positive Gains:    2 (11.1% of files)&#xA;L&#39;ultima sezione, &#34;Album&#34;, mi dà le informazioni sul guadagno da applicare, in questo caso poco o nulla perché sono brani già normalizzati,.&#xA;&#xA;Con un altro presets, ad es. myGain.ini, posso normalizzare tutto l&#39;album in colpo solo.&#xA;&#xA;rsgain easy -p myGain pathalbum&#xA;In altre parole, tutto ciò che la modalità custom affida allo scripting, ora viene automatizzata dalla modalità easy.&#xA;&#xA;small Riferimenti:**&#xA;&#xA;https://ffmpeg.org/ffmpeg-filters.html#loudnorm&#xA;https://ffmpeg.org/ffmpeg-filters.html#toc-volumedetect&#xA;https://github.com/complexlogic/rsgain&#xA;/small&#xA;&#xA;#ffmpeg #rsgain #loudness #loudnorm]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/31410d826-759a86/dW3U92YRrKI4/EQCqOi56fpS0p9w4OdD2VsE3ZG4W8j3KZvbK0TWZ.jpg" alt="normalizzazione">
Quando si deve aumentare il volume di una traccia audio, si deve ricorrere a ad un&#39;operazione di “<strong>normalizzazione</strong>”.
</p>
<ul><li><a href="#1-cos-%C3%A8-la-normalizzazione" rel="nofollow">1. Cos’è la normalizzazione</a></li>
<li><a href="#2-come-misurare-il-picco" rel="nofollow">2. Come misurare il “picco”?</a></li>
<li><a href="#3-come-leggere-correttamente-questa-misura" rel="nofollow">3. Come leggere correttamente questa misura</a>
<ul><li><a href="#3-1-perch%C3%A9-usare-il-loudness-invece-di-rms" rel="nofollow">3.1. Perché usare il loudness invece di RMS?</a></li></ul></li>
<li><a href="#4-come-ti-normalizzo-il-file" rel="nofollow">4. Come ti normalizzo il file</a>
<ul><li><a href="#4-1-peak-normalization" rel="nofollow">4.1. Peak normalization</a></li>
<li><a href="#4-2-loudness-normalization" rel="nofollow">4.2. Loudness Normalization</a>
<ul><li><a href="#4-2-1-loudness-normalization-statica-ffmpeg" rel="nofollow">4.2.1. Loudness Normalization statica (ffmpeg)</a></li>
<li><a href="#4-2-2-loudness-normalization-dinamica" rel="nofollow">4.2.2. Loudness Normalization dinamica</a></li>
<li><a href="#4-2-3-loudness-normalization-statica-rsgain" rel="nofollow">4.2.3. Loudness Normalization statica (rsgain)</a></li></ul></li></ul></li></ul>

<h2 id="1-cos-è-la-normalizzazione">1. Cos&#39;è la normalizzazione</h2>

<p>La normalizzazione è un&#39;operazione lineare che consiste nell&#39;analisi del file audio, nel calcolare la differenza (offset) fra il volume attuale ed un volume target, nell&#39;applicare una correzione di guadagno (Gain).</p>

<p>La normalizzazione può essere distinta in base  al “come” e al “dove”.</p>

<p><strong>Il “come”</strong>
La normalizzazione classica si basa sui picchi. Cerca il punto più alto della forma d&#39;onda e lo porta a un valore massimo (es. 0 dB). Ignora la percezione umana; un brano con un singolo “click” molto forte risulterà comunque silenzioso perché quel picco blocca l&#39;aumento del volume.</p>

<p>La normalizzazione più moderna si basa sui <strong>LUFS</strong>, ossia su come, <strong>mediamente</strong>, l&#39;audio viene effettivamente percepito dall&#39;orecchio umano (psicoacustica). Porta l&#39;intero brano a un livello di pressione sonora media costante, rendendo l&#39;ascolto uniforme tra diverse tracce.</p>

<p><strong>Il “dove”</strong>
Quando si normalizza una traccia audio si può scegliere di farla modificando ogni singolo sample della traccia audio oppure di agire sui metadati.</p>

<p>Nel primo caso il file originale viene modificato (ricodifica quasi sempre lossy), nel secondo viene lasciato inalterato.</p>

<p>Altro fattore di cui tenere conto è che una normalizzazione lossy funziona su ogni player, una normalizzazione che agisce sui metadati funziona solo se il player è in grado di leggerli.</p>

<p>Possiamo fare quindi una prima distinzione:</p>
<ol><li>normalizzazione di picco (<strong>RMS</strong>) o <i>Peak Normalization</i>: applicazione di un <strong>guadagno statico</strong> (RMS) in modalità lossy: non altera la dinamica del brano, richiede una ricodifica;</li>
<li>normalizzazione della sonorità (<strong>LUFS</strong>) o <i>Loudness Normalization</i>:
<ol><li>applicazione di un <strong>guadagno statico</strong> (LUFS) in modalità lossy: non altera la dinamica del brano, richiede una ricodifica;</li>
<li>applicazione di un <strong>guadagno statico</strong> (LUFS) basato su tag: non altera la dinamica del brano, lascia il file inalterato (rsgain);</li>
<li>agisce con un compressore / limiter in modalità lossy: altera la dinamica del brano, richiede una ricodifica.</li></ol></li></ol>

<p>A questo punto la domanda diventa: quale scegliere?</p>

<p>Per quel che mi riguarda, la salomonica risposta è: dipende.</p>

<p>Come si può immaginare, non c&#39;è una risposta definitiva ma dipende dalla qualità della traccia, dal contesto ecc.</p>

<h2 id="2-come-misurare-il-picco">2. Come misurare il “picco”?</h2>

<p>C&#39;è bisogno di un elemento misurabile che mi permetta di capire come agire con la normalizzazione.</p>

<p><strong>RMS (Root Mean Square)</strong>: è un calcolo matematico asciutto su quanto sia potente elettricamente/digitalmente il segnale audio. È utile per capire l&#39;energia costante, ma non tiene conto del fatto che l&#39;orecchio umano è più sensibile ad alcune frequenze rispetto ad altre.</p>

<p><strong>LUFS (Loudness Units Full Scale)</strong>: È lo standard moderno (EBU R128). Simula l&#39;udito umano applicando dei filtri che pesano maggiormente le frequenze medie.</p>

<p>Per misurare il picco RMS posso ricorrere ad <strong>ffmpeg</strong></p>

<pre><code class="language-bash">ffmpeg -hide_banner -i &#34;audio.m4a&#34; -filter:a &#34;volumedetect&#34; -f null -
...
[...] n_samples: 18522112
[...] mean_volume: -20.3 dB
[...] max_volume: -5.4 dB
[...] histogram_5db: 40
[...] histogram_6db: 1436
[...] histogram_7db: 6443
[...] histogram_8db: 18606
...
</code></pre>

<p>che mi mostrerà:</p>
<ul><li>il numero dei samples di cui si compone la traccia</li>
<li>il volume medio (<em>mean_volume</em>)</li>
<li>il picco (<em>max_volume</em>)</li></ul>

<p>Il picco mi dice di quanto possa alzare il volume (fino al limite fisico di 0dB) staticamente senza causare distorsioni.</p>

<p>La differenza fra volume medio e picco mi dà informazioni sulla dinamica del brano. Maggiore è la differenza, maggiore è la dinamica. Tipicamente:</p>
<ul><li>valori &lt; 5 sono tipici della musica dance, forte, uniforme, e molto compressa.</li>
<li>valori fra 5 e 15 sono tipici di brani pop-rock, ben bilanciati</li>
<li>valori &gt; 15 sono attribuibili a brani di musica classica, jazz, con una dinamica ricca.</li></ul>

<p>Per misurare il loudness, sempre con ffmpeg:</p>

<pre><code class="language-bash">ffmpeg -hide_banner -i &#34;audio.m4a&#34; -filter:a &#34;ebur128=peak=true&#34; -f null - 
...
 Integrated loudness:
    I:         -18.1 LUFS
    Threshold: -28.4 LUFS

  Loudness range:
    LRA:         4.1 LU
    Threshold: -38.3 LUFS
    LRA low:   -21.2 LUFS
    LRA high:  -17.1 LUFS

  True peak:
    Peak:       -5.4 dBFS
</code></pre>

<p>La misurazione è più articolata rispetto alla precedente.</p>

<p>FFmpeg innanzitutto mostra due sezioni: <strong>Integrated Loudness</strong>, rappresentante il <strong>volume medio</strong> complessivo del file e la <strong>Loudness Range</strong> che mi descrive la dinamica del brano come differenza di volume fra le parti più silenziose e quelle più rumorose.</p>
<ol><li>Sezione <strong>Integrated loudness</strong>:
<ul><li><strong>I</strong>: è il valore più importante. È il volume medio percepito dell&#39;intero brano (come si può vedere, diverso rispetto all&#39;RMS di prima. Il primo è pura potenza digitale, il secondo è <strong>volume percepito</strong>).</li>
<li><strong>Threshold</strong>: è la soglia usata per evitare che i silenzi abbassino artificialmente la media del volume. L&#39;algoritmo ignora tutto ciò che sta sotto questa soglia nel calcolo dell&#39;Integrated Loudness.</li></ul></li>
<li>Sezione <strong>Loudness range</strong>:
<ul><li><strong>LRA</strong>: è un indice della variazione dinamica del brano. Più è basso, più il suono tende ad essere uniforme e probabilmente compresso</li>
<li><strong>Threshold</strong>: come prima, è la soglia oltre la quale i suoni vengono ignorati nel calcolo del range dinamico.</li>
<li><strong>LRA Low</strong>: indica il limite inferiore del loudness</li>
<li><strong>LRA High</strong>: indica il limite superiore<br>
quindi <em>LRA = LRA High – LRA Low</em></li></ul></li>
<li>Sezione <strong>True peak</strong>:
<ul><li><strong>Peak</strong>: Simile al <em>max_volume</em> dell&#39;RMS, indica il picco <strong>reale</strong> del brano in termini di sonorità.</li></ul></li></ol>

<p>Un altro modo, forse meno pratico ma decisamente più scenografico, per analizzare un file audio è questo:</p>

<pre><code class="language-bash">ffplay -f lavfi -i &#34;amovie=audio.m4a,ebur128=video=1:meter=18 [out0][out1]&#34;
</code></pre>

<p>Disegna un grafico dell&#39;onda sonora in tempo reale.</p>

<h2 id="3-come-leggere-correttamente-questa-misura">3. Come leggere correttamente questa misura</h2>

<p>L&#39;<strong>integrated loudness</strong> mi dice qual è il volume <strong>medio</strong> del brano.
<strong>True peak</strong> mi dice di quanto posso alzare prima di distorcere.
Queste sono le due informazioni cruciali sufficienti per applicare un <strong>guadagno statico</strong> senza fare danni.</p>

<p>I valori <strong>High</strong> e <strong>Low</strong> del <strong>Loudness Range</strong>, che racchiudono asintoticamente il brano, tornano utili quando bisogna agire sulla dinamica.</p>

<p>Notare che <strong>Integrated loudness</strong> è sempre compreso fra <strong>LRA Low</strong> e <strong>LRA High</strong>.</p>

<h3 id="3-1-perché-usare-il-loudness-invece-di-rms">3.1. Perché usare il loudness invece di RMS?</h3>

<p>L&#39;RMS è un calcolo puramente matematico che non tiene conto del fatto che l&#39;orecchio umano è molto più sensibile alle frequenze medie che non ai bassi estemi e agli acuti altissimi.</p>

<p> A questo provvede il LUFS che è un&#39;evoluzione dell&#39;RMS perché include dei <strong>filtri di ponderazione</strong> che, prima di calcolare la media, esaltano le frequenze medie attenuando quelle basse.</p>

<p>La conseguenza è che se agisco sul volume dei brani prendendo LUFS come riferimento, questi suoneranno tutti allo stesso volume. Se considerassi un adeguamento basato su RMS, i brani con più bassi sembreranno avere meno volume di quelli con frequenze medie più marcate.</p>

<h2 id="4-come-ti-normalizzo-il-file">4. Come ti normalizzo il file</h2>

<p>La scelta fra una normalizzazione di picco e una di volume (loudness) è abbastanza semplice in realtà.</p>

<p>A parte poche eccezioni in cui può avere senso avere RMS come riferimento, è sempre preferibile una normalizzazione della sonorità.</p>

<p>Quest&#39;ultima può essere fatta modificando solo i metadati o agendo chirurgicamente sul file ricodificandolo.</p>

<h3 id="4-1-peak-normalization">4.1. Peak normalization</h3>

<p>Una volta noti i dati di <em>Max Volume</em> e <em>Mean Volume</em> visti in precedenza, la normalizzazione è piuttosto semplice.</p>

<p>Supponendo <code>Max Volume = 6dB</code></p>

<pre><code class="language-bash">ffmpeg -i audio.m4a -filter:a &#34;volume=6dB&#34; -c:a aac -b:a 192k audio_normalized.m4a
</code></pre>

<p>Dovendo ricodificare, scelgo un bitrate piuttosto alto per limitare la perdita fisiologica di una ricodifica lossy.</p>

<p>Come si può immaginare, è una aggiunta lineare secca a tutta la traccia a cui aumento solo la potenza digitale senza tenere conto della percezione sonora.</p>

<p>Piccola nota: Conviene scegliere un valore che si avvicini, ma non equivalga, al limite di 0 dB perché altrimenti FFmpeg taglierà brutalmente le creste dell&#39;onda sonora che superano lo zero, creando quella tipica distorsione metallica grattata chiamata <strong>clipping</strong>.</p>

<h3 id="4-2-loudness-normalization">4.2. Loudness Normalization</h3>

<p>La normalizzazione di volume, in base alla nostra scelta di alterare o meno la dinamica del brano, può essere fatta come detto applicando:</p>
<ul><li>un guadagno statico LUFS (lossy)</li>
<li>un guadagno statico LUFS sui metadati (non lossy)</li>
<li>compressore / limiter (sempre lossy)</li></ul>

<p>Il guadagno statico, quello con i metadati, avverrà con <strong>rsgain</strong>.</p>

<p>La normalizzazione con perdita di qualità (lossy) avverrà con ffmpeg usando il filtro <strong>loudnorm</strong> che dispone di un compressore/limiter piuttosto efficace.</p>

<p>Questo filtro è un processore dinamico (dual-pass o single-pass). Non si limita ad alzare il volume; se trova una parte troppo forte, può comprimere leggermente solo quella parte per permettere al resto della canzone di suonare più forte.</p>

<p><code>loudnorm</code> porta il loudness di default a -24 LUFS che è lo standard per il broadcast televisivo.</p>

<p>I colossi dello streaming applicano automaticamente un loudness decisamente più marcato, salvo poche eccezioni, non si discostano da -14 LUFS. Ad es. Youtube, Amazon Music, Spotify, Soundcloud viaggiano mediamente su -14 LUFS, Deezer -15, Apple Music -16.</p>

<p>Si può verificare facilmente, come sappiamo fare, come un audio presente su una di queste piattaforme, abbia uno dei loudness indicati.</p>

<h4 id="4-2-1-loudness-normalization-statica-ffmpeg">4.2.1. Loudness Normalization statica (ffmpeg)</h4>

<p>Riprendiamo l&#39;esempio di prima.</p>

<pre><code class="language-bash">ffmpeg -hide_banner -i &#34;audio.m4a&#34; -filter:a &#34;ebur128=peak=true&#34; -f null - 
...
 Integrated loudness:
    I:         -18.1 LUFS
    Threshold: -28.4 LUFS

  Loudness range:
    LRA:         4.1 LU
    Threshold: -38.3 LUFS
    LRA low:   -21.2 LUFS
    LRA high:  -17.1 LUFS

  True peak:
    Peak:       -5.4 dBFS
</code></pre>

<p>Con <code>ffmpeg</code> e <code>loudnorm</code> in modalità <strong>single-pass</strong>, posso applicare un guadagno statico 5.4 dBFS, con un true peak di -1 (Il default è -2), per arrivare, da -18.1 LUFS, a -13.0 LUFS senza distorsioni.</p>

<pre><code class="language-bash">ffmpeg -i audio.m4a -filter:a &#34;loudnorm=I=-12.7:TP=-1.0&#34; -c:a aac -b:a 160k -vn audio_norm.m4a
</code></pre>

<p>Verifichiamo:</p>

<pre><code class="language-bash">ffmpeg -hide_banner -i &#34;audio.m4a&#34; -filter:a &#34;ebur128=peak=true&#34; -f null - 
...
   Integrated loudness:
    I:         -12.5 LUFS
    Threshold: -22.6 LUFS

  Loudness range:
    LRA:         4.0 LU
    Threshold: -32.6 LUFS
    LRA low:   -15.1 LUFS
    LRA high:  -11.1 LUFS

  True peak:
    Peak:       -0.4 dBFS
...
</code></pre>

<p>Come si vede, sono arrivato al limite, forse un po&#39; troppo, del guadagno che potevo ottenere. Probabimente su dispositivi economici, l&#39;analogico di un brano così potrebbe gracchiare un po&#39;.</p>

<p>Se avessi applicato il default  di  <code>loudnorm</code>, la sonorità sarebbe stata livellata sui -24 LUFS con una soglia true peak pari a -2 dBFS.</p>

<h4 id="4-2-2-loudness-normalization-dinamica">4.2.2. Loudness Normalization dinamica</h4>

<p>Nei casi in cui:</p>
<ul><li>si vuole enfatizzare l&#39;audio di un podcast, di un parlato in generale;</li>
<li>la dinamica del brano è composta da picchi altissimi e una sonorità media molto bassa (un guadagno statico farebbe cambiare poco o nulla)</li></ul>

<p>con <code>ffmpeg</code> e <code>loudnorm</code> possiamo correggere ogni singolo sample del brano per rendere la dinamica più uniforme.</p>

<p>Per ottenere un risultato ottimale, si deve procedere col <strong>dual-pass</strong>, in cui ffmpeg nel primo passaggio analizza il file e raccoglie i dati, nel secondo passaggio applica le correzioni puntualmente avendo già conoscenza della dinamica e dei picchi presenti nel file.</p>

<pre><code class="language-bash">ffmpeg -i &#34;audio.m4a&#34; -filter:a &#34;loudnorm=I=-14:TP=-1.0:print_format=json&#34; -f null -
</code></pre>

<p>Ecco il json risultante dall&#39;analisi. I valori di input sono quelli che forniremo a ffmepg affinché possa impostare il loudness scelto da noi nel miglior modo possibile</p>

<pre><code class="language-json">{
	&#34;input_i&#34; : &#34;-18.17&#34;,
	&#34;input_tp&#34; : &#34;-5.41&#34;,
	&#34;input_lra&#34; : &#34;4.20&#34;,
	&#34;input_thresh&#34; : &#34;-28.47&#34;,
	&#34;output_i&#34; : &#34;-13.36&#34;,
	&#34;output_tp&#34; : &#34;-1.00&#34;,
	&#34;output_lra&#34; : &#34;4.30&#34;,
	&#34;output_thresh&#34; : &#34;-23.50&#34;,
	&#34;normalization_type&#34; : &#34;dynamic&#34;,
	&#34;target_offset&#34; : &#34;-0.64&#34;
}
</code></pre>

<p>Configurazione ffmpeg.</p>

<pre><code class="language-bash">ffmpeg -i &#34;audio.m4a&#34; -filter:a &#34;loudnorm=I=-14:TP=-1.0:measured_I=-18.17:measured_TP=-5.41:measured_LRA=4.20:measured_thresh=-23.50:linear=true&#34; -c:a aac -b:a 160k -vn &#34;audio_norm.m4a&#34;
</code></pre>

<p>Il compressore/limiter del filtro loudnorm è abbastanza intelligente da schiacciare i picchi affinche il guadagno di volume non produca clipping e alzerà le parti più “deboli”, livellando il suono e alterando la dinamica.</p>

<h4 id="4-2-3-loudness-normalization-statica-rsgain">4.2.3. Loudness Normalization statica (rsgain)</h4>

<p>Rsgain permette di applicare un guadagno statico loseless, senza ricodifica, agendo sui metadati del brano con l&#39;applicazione dei tag.</p>

<p>Se da un lato questo metodo ha l&#39;indubbio vantaggio di non alterare fisicamente il file, dall&#39;altro è necessario che il player che eseguirà il brano dovra essere capace di leggere e interpretare i tag. Nel caso precedente, la ricodifica rende il file disponibile per chiunque.</p>

<p>Trattandosi di un guadagno statico, il campo d&#39;applicazione è quello visto per la Peak Normalization, cioè quando si vuole preservare la dinamica del brano, Ma nei casi particolari cui accennavo in precedenza, presenza di picchi altissimi e maggioranza sonorità medie molto basse, anche rsgain non è sufficiente.</p>

<p>Come avevo detto all&#39;inizio, rsgain è una normalizzaziome della sonorità ottenuta agendo sui metadati del brano, applicando dei tag, che così non viene alternato in alcun modo.</p>

<p>Rsgain è l&#39;evoluzione del vecchio mp3gain e come il suo predecessore ha due modalità di lavoro</p>
<ul><li>sul singolo brano (detta é <strong>custom</strong>)</li>
<li>su collezioni di brani (detta <strong>easy</strong>)</li></ul>

<p>La modalità <strong>custom</strong> è considerato un approccio legacy fatta per intervenire puntualmente sul brano con configurazioni ad-hoc ideali per lo scripting, quella <strong>easy</strong>, basata su presets, permette di normalizzare intere collezioni di brani che è lo scopo principale di rsgain.</p>

<p><strong>Analisi del file</strong></p>

<pre><code class="language-bash">rsgain custom -t audio.m4a
[✔] Scanning &#39;audio.m4a&#39;
[✔] Container: QuickTime / MOV [mov,mp4,m4a,3gp,3g2,mj2]
[✔] Stream #0: AAC (Advanced Audio Coding), 44.100 Hz, 2 ch
 100% [====================================================]

Track: audio.m4a
  Loudness:   -18.12 LUFS
  Peak:     0.536630 (-5.41 dB)
  Gain:         0.12 dB
</code></pre>

<p>il flag <code>-t</code> individua il true peak</p>
<ul><li><strong>Loudness</strong>: è la sonorità del brano in LUFS</li>
<li><strong>Peak</strong>: è il true peak, esprime il guadagno che posso ottenere prima di distorcere</li>
<li><strong>Gain</strong>: è il guadagno per arrivare allo standard LUFS di rsgain che è -18</li></ul>

<p>Nel nostro caso, Gain ci dice di diminuire di 0.12 LUFS mentre Peak ci dice che potrei aumentare di 5.41 LUFS</p>

<p><strong>Gain</strong></p>

<pre><code class="language-bash">rsgain custom -s i -l -13 -c p audio.m4a
Track: audio.m4a
  Loudness:   -18.12 LUFS
  Peak:     0.534149 (-5.45 dB)
  Gain:         5.12 dB
</code></pre>
<ul><li><code>-s i</code>: scrive il tag</li>
<li><code>-l -13</code>: imposta il loudness</li>
<li><code>-c p</code>: protezione clipping</li></ul>

<p>Portando il loudness a -13 è come se avessi aumentato il volume di 5,12 dB mantenendo un cuscinetto di -0.33 dB (differenza fra peak e gain).</p>

<p>Se provassi a spingere di più, il flag <code>-c p</code> impedisce al suono di distorcere.</p>

<pre><code class="language-bash">rsgain custom -s i -l -10 -c p audio.m4a
Track: audio.m4a
  Loudness:   -18.12 LUFS
  Peak:     0.534149 (-5.45 dB)
  Gain:         5.45 dB  (adjusted to prevent clipping)
</code></pre>

<p>“<em>(adjusted to prevent clipping)</em>” è la conferma che la protezione anti-clipping è entrata in azione.</p>

<p>Se non ci fosse stata:</p>

<pre><code class="language-bash">rsgain custom -s i -l -10 audio.m4a
Track: audio.m4a
  Loudness:   -18.12 LUFS
  Peak:     0.534149 (-5.45 dB)
  Gain:         8.12 dB
</code></pre>

<p>La differenza fra peak e gain indica un&#39;evidente distorsione.</p>

<p><strong>Esempio di esecuzione del brano sfruttando il replaygain</strong>:</p>

<pre><code class="language-bash">mpv --replaygain=track audio.m4a
</code></pre>

<p>Senza il flag <code>--replaygain=track</code>, il brano verrebbe letto normalmente.</p>

<p><strong>Cancellazione del tag</strong>
Basta cancellare il tag per riportare tutto alla normalità</p>

<pre><code class="language-bash"># verifico la presenza del tag prima
ffprobe -hide_banner -i &#34;audio.m4a&#34; 2&gt;&amp;1 | grep -i &#34;replaygain&#34;
REPLAYGAIN_TRACK_GAIN: 8.12 dB
REPLAYGAIN_TRACK_PEAK: 0.534149
replaygain: track gain - 8.120000, track peak - 0.000012, album gain - unknown, album peak - unknown,

# cancello il tag
rsgain custom -s d audio.m4a

# verifico che il tag non si ci sia più
ffprobe -hide_banner -i &#34;audio.m4a&#34; 2&gt;&amp;1 | grep -i &#34;replaygain&#34;
**
</code></pre>

<p>Un altro modo più compatto per verificare la presenza del tag:</p>

<pre><code>ffprobe -i &#34;audio.m4a&#34; -show_entries format_tags=REPLAYGAIN_TRACK_GAIN -v quiet -of csv=&#34;p=0&#34;
</code></pre>

<p>Se c&#39;è il tag, mostra solo il gain.</p>

<p><strong>Easy mode</strong>
I flag impostati nella modalità custom nella modalitò easy sono affidati ad un file di configurazione.</p>

<p>Su Gnu/Linux i file di default si trovano in <code>/usr/share/rsgain/presets</code> e sono 4</p>
<ul><li>default.ini</li>
<li>ebur128.ini</li>
<li>loudgain.ini</li>
<li>no_album.ini</li></ul>

<p>C&#39;è una sezione globla e delle sezioni specifiche per tipo di file.</p>

<p>L&#39;override di queste configurazioni o la creazione di nuove, si fa in:</p>

<p><code>~/.config/rsgain/presets</code></p>

<p>e per la corrispondenza campi – flag custom vi rimando alla documentazione: <a href="https://github.com/complexlogic/rsgain?tab=readme-ov-file#scan-presets" rel="nofollow">https://github.com/complexlogic/rsgain?tab=readme-ov-file#scan-presets</a></p>

<p>Una volta deciso il preset che fa per noi, basta chiamare rsgain su una directory in questo modo:</p>

<pre><code class="language-bash">rsgain easy -s &lt;nome_preset&gt; &lt;path_album&gt;
</code></pre>

<p>rsgain farà la scansione e applicherà massivamente le configurazioni che potranno consistere per es.:</p>
<ul><li>nell&#39;applicazione di un loudness a tutti i brani per uniformare la sonorità;</li>
<li>nella cancellazione di tutti i tag;</li>
<li>nell&#39;analisi dei brani;</li>
<li>ecc.</li></ul>

<p><strong>Esempio di file di configurazione per una scansione</strong></p>

<pre><code>[Global]
TagMode=s
Album=true
TargetLoudness=-18
ClipMode=p
MaxPeakLevel=-1.0
TruePeak=true
Lowercase=false
ID3v2Version=keep
OpusMode=d
PreserveMtimes=false
DualMono=false
</code></pre>

<p>In questo modo rsgain produrrà un&#39;analisi in modalità “<strong>album</strong>” per tutta la collezione, il gain da applicare all&#39;album e  una sintesi sulla media dei valori di picco ottenuti.</p>

<pre><code class="language-bash">rsgain easy -p scan &lt;path_album&gt; 
...
Track: &lt;path_album&gt;/track_1
  Loudness:   -17.80 LUFS
  Peak:     0.743221 (-2.58 dB)
  Gain:        -0.20 dB


Track: &lt;path_album&gt;/track_2
  Loudness:   -17.81 LUFS
  Peak:     0.790007 (-2.05 dB)
  Gain:        -0.19 dB


Track: &lt;path_album&gt;/track_3
  Loudness:   -17.47 LUFS
  Peak:     0.834655 (-1.57 dB)
  Gain:        -0.53 dB

...

Album:
  Loudness:   -16.51 LUFS
  Peak:     0.991804 (-0.07 dB)
  Gain:        -1.49 dB


Scanning Complete
Time Elapsed:      00:00:27
Files Scanned:     18
Clip Adjustments:  0 (0.0% of files)
Average Loudness:  -16.61 LUFS
Average Gain:      -1.39 dB
Average Peak:      0.823503 (-1.69 dB)
Negative Gains:    16 (88.9% of files)
Positive Gains:    2 (11.1% of files)
</code></pre>

<p>L&#39;ultima sezione, “<strong>Album</strong>”, mi dà le informazioni sul guadagno da applicare, in questo caso poco o nulla perché sono brani già normalizzati,.</p>

<p>Con un altro presets, ad es. <code>myGain.ini</code>, posso normalizzare tutto l&#39;album in colpo solo.</p>

<pre><code>rsgain easy -p myGain &lt;path_album&gt;
</code></pre>

<p>In altre parole, tutto ciò che la modalità <strong>custom</strong> affida allo scripting, ora viene automatizzata dalla modalità <strong>easy</strong>.</p>

<p><small> <strong>Riferimenti:</strong></p>
<ul><li><a href="https://ffmpeg.org/ffmpeg-filters.html#loudnorm" rel="nofollow">https://ffmpeg.org/ffmpeg-filters.html#loudnorm</a></li>
<li><a href="https://ffmpeg.org/ffmpeg-filters.html#toc-volumedetect" rel="nofollow">https://ffmpeg.org/ffmpeg-filters.html#toc-volumedetect</a></li>
<li><a href="https://github.com/complexlogic/rsgain" rel="nofollow">https://github.com/complexlogic/rsgain</a>
</small></li></ul>

<p><a href="/aytin/tag:ffmpeg" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">ffmpeg</span></a> <a href="/aytin/tag:rsgain" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">rsgain</span></a> <a href="/aytin/tag:loudness" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">loudness</span></a> <a href="/aytin/tag:loudnorm" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">loudnorm</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/come-aumentare-il-volume-di-una-traccia-audio</guid>
      <pubDate>Mon, 13 Apr 2026 15:03:39 +0000</pubDate>
    </item>
    <item>
      <title>Installazione di Cloudflare WARP su OSMC</title>
      <link>https://noblogo.org/aytin/installazione-di-cloudflare-warp-su-osmc</link>
      <description>&lt;![CDATA[cloudflare-warp&#xA;È noto come l&#39;uso dei resolver Cloudflare sia uno dei modi per anonimizzare il proprio IP all&#39;ISP.&#xA;&#xA;Cloudflare offre anche altre modalità di risoluzione ancora più efficaci:&#xA;&#xA;DNS over HTTPS (DoH)&#xA;DNS over TCP (DoT)&#xA;DNS over WARP (DoW)&#xA;&#xA;!--more--&#xA;I primi due sono relativi a richieste dns crittografate e incapsulate, in una richiesta https (porta 443) la prima, e in una connessione TLS (porta 853) la seconda.&#xA;&#xA;La terza modalità è una richiesta dns in chiaro ma all&#39;interno di un tunnel Wireguard o MASQUE (QUIC + HTTP/3 - rif. https://datatracker.ietf.org/meeting/interim-2021-masque-03/materials/slides-interim-2021-masque-03-sessa-masque-interim-2021-04-h3-dgram-00). Molto interessante ed è quella che approfondirò in seguito.&#xA;&#xA;Senza entrare nel merito, tutte le soluzioni anonimizzano le query dns. L&#39;ultima, quella che mi ha stutzzicato, è in realtà un tunnel vpn che crittografa TUTTO il traffico, non solo le richieste DNS.&#xA;&#xA;DoT è una cifratura TLS che lascia intatto il pacchetto UDP iniziale, è quindi più efficiente di DoH che converte una richieste DNS in una HTTP cifrata dal layer TLS.&#xA;&#xA;DoT di solito viene fatta a livello di dispositivo, DoH per singole applicazioni.&#xA;&#xA;DoT, basandosi su una porta specifica, 853, è facilmente identificabile (e bloccabile) come traffico DNS (benché cifrato), DoH è una richiesta HTTPS e si mescola col traffico che viaggia sulla porta 443 (difficilmente si invaliderà tutto quel tipo di traffico).&#xA;&#xA;DoT, DoH, DoW, mitigano notevolmente il cache poisoning dei resolver perché rendono quasi impossibilie per un attaccante alterare una richiesta che viene protetta per l&#39;intero percorso. Va detto che la soluzione ideale in questo contesto è la combinazione con DNSSEC, che fornisce autenticità e integrità alla riservatezza fornita da DoH/DoT.&#xA;&#xA;Anche se l&#39;obiettivo rimane l&#39;approfondimento di CLoudflare WARP, vale la pena di spendere due parole anche sulle altre modalità di risoluzione, DoT/DoH&#xA;Configurare risoluzioni DNS DoH&#xA;Configurare DoH è molto semplice perché è qualcosa legato all&#39;applicazione, il browser tipicamente. Se l&#39;applicazione lo supporta, di solito è poco di più di un flag da abilitare.&#xA;&#xA;Ad es. Firefox o Chrome permettono di attivare una sorte di &#34;protezione avanzata del DNS&#34; indicando semplicemente un resolver che la supporti (es. Cloudflare, NextDNS o Quad9).&#xA;Configurare risoluzioni DNS DoT&#xA;DoT, come detto, è una configurazione che avviene a livello di dispositivo, l&#39;anonimizzazione delle query DNS si ottiene quindi per ogni applicazione. Sul come farlo, dipende dal dispositivo.&#xA;&#xA;Ad es. su una linux box basta aggiungere due righe su systemd-resolved e riavviare il relativo servizio.&#xA;sudo vi /etc/systemd/resolved.conf&#xA;...&#xA;DNS=1.1.1.1&#xA;DNSOverTLS=yes&#xA;&#xA;dopo aver salvato il file&#xA;systemctl restart systemd-resolved&#xA;Un veloce test su https://1.1.1.1/help  (da qualunque browser) ci mostrerà qualcosa del tipo:&#xA;Connected to 1.1.1.1        Yes&#xA;Using DNS over HTTPS (DoH)  No&#xA;Using DNS over TLS (DoT)    Yes&#xA;Using DNS over WARP         No&#xA;AS Name                     Cloudflare, Inc.&#xA;AS Number                   13335&#xA;Cloudflare Data Center      MXP&#xA;indice che DoT è attivo e funzionante. Lo stesso test poteva essere fatto anche per DoH.&#xA;Cloudflare WARP&#xA;E poi c&#39;è DoW, che è qualcosa di ancora più estremo perché, all&#39;occorrenza, anonimizza non solo le richieste DNS ma tutto il nostro traffico (e infatti diversi servizi di streaming non lo consentono).&#xA;&#xA;Cloudflare Warp attiva diverse modalità di risoluzione dns fra cui DoH e DoT.&#xA;&#xA;Dal momento che Cloudflare Warp agisce su tutta la connessione, è il modo più semplice per avere risoluzione dns di tipo DoH o DoT, su qualunque dispositivo su cui è presente Cloudflare Warp senza gli sbattimenti di systemd o altro.&#xA;&#xA;Cloudflare Warp in modalità tunnel è un client che instaura un collegamento cifrato punto-punto (un tunnel) fra il nostro host e un endpoint Cloudflare. In questo modo ogni bit che esce dal nostro dispositivo viene cifrato prima della comunicazione, che diventa così totalmente schermata.&#xA;&#xA;La vpn di Coudflare si basa su wireguard o su MASQUE. Nel primo caso è una normale vpn con un setup roadwarrior, il secondo caso offre in più la possibilità di associare al tunnel anche le modalità DoH/DoT per le richieste dns.&#xA;Anonimato sì/no?&#xA;Cloudflare WARP è uno strumento incentrato sulla sicurezza, progettato per crittografare il traffico internet e proteggere la privacy dagli ISP, piuttosto che per garantire l&#39;anonimato completo o nascondere la posizione dell&#39;utente.&#xA;&#xA;Sostituisce l&#39;IP dell&#39;utente con un IP di Cloudflare che generalmente corrisponde alla sua reale area geografica, rendendolo inadatto a eludere le restrizioni basate sulla posizione.&#xA;&#xA;Non è una VPN tradizionale. WARP non maschera la nostra posizione ai siti web, che spesso possono visualizzare la tua posizione approssimativa.&#xA;&#xA;Per migliorare la privacy, si dovrebbe utilizzare il protocollo MASQUE, che offre anche una maggiore efficienza.&#xA;&#xA;In sintesi, WARP fornisce un &#34;tunnel sicuro&#34; per proteggere la privacy dei dati da amministratori di rete indiscreti, protegge il traffico perché eccelle nella crittografia del traffico su reti non sicure (ad esempio, Wi-Fi pubbliche), ma non offre le funzionalità di anonimato dei tradizionali servizi VPN incentrati sulla privacy.&#xA;&#xA;Fatta questa doverosa premessa, vediamo come può essere usato.&#xA;Configurare Cloudflare WARP&#xA;L&#39;installazione del client è molto semplice. Per Gnu/Linux c&#39;è la versione cli, per android un app, per altri sistemi, Win /MacOS, un installer.&#xA;La parte applicativa prima di tutto registra il dispositivo sulla rete Cloudflare generando degli ID e una chiave di licenza. In un secondo momento si generano le chiavi di cifratura.&#xA;&#xA;Per fissare le idee, una volta fatte le operazioni di inizializzazione, sulla linux box per tunnellizzare ogni nostra comunicazione con una risoluzione DoT, basta:&#xA;facoltativo&#xA;warp-cli mode warp+dot&#xA;&#xA;connessione&#xA;warp-cli connect&#xA;Per terminare:&#xA;warp-cli disconnect&#xA;Questo approccio torna molto comodo quando per es. vogliamo usare wifi pubbliche, in città o in aeroporto. A meno di non avere un&#39;installazione personale di una nostra vpn, questa è una soluzione immediata. Certo, bisogna fidarsi di Cloudflare ma è certamente meglio che fidarsi delle wifi free.&#xA;&#xA;E arriviamo al caso d&#39;uso che volevo approfondire riguardante l&#39;&#34;anonimizzazione&#34; di un mediacenter casalingo per il quale non vogliamo rendere noto il suo utilizzo.&#xA;&#xA;L&#39;esperienza che ho avuto al proposito è stata interessante, visto che uso da anni OSMC su una RasbPi 3 e ho deciso di metterla dietro Cloudflare.&#xA;&#xA;OSMC insieme a LibreELEC sono ottime soluzioni di mediacenter per SBC. La prima più &#34;general&#34;, essendo una debian customizzata per ospitare un mediacenter, la seconda invece meno elastica ma più essenziale ed efficiente.&#xA;&#xA;Nonostante la Raspberry Pi 3 sia dotata di un processore ARM64, la versione di OSMC che ho installato a suo tempo è a 32 bit e per quella non c&#39;è disponibilità per il client cloudflare (solo ARM64).&#xA;&#xA;Ho dovuto ricorrere ad un client &#34;unofficial&#34;, wgcf, che permette di registrare il dispositivo e di generare le chiavi ma solo per la modalità Wireguard, non MASQUE, quindi niente Warp+DoT/DoH (per inciso, wgcf rappresenta un&#39;ottima alternativa anche per chi non vuole usare il client Cloudflare su Gnu/Linux).&#xA;&#xA;A questo aggiungo che, sebbebe OSMC sia una Debian su cui posso installare e configurare tanta roba, l&#39;installazione di Wireguard, e penso di qualunque cosa che vada a toccare lo stack di rete, diventa qualcosa di estremamente complicato da fare, dal momento che OSMC si rifiuta categoricamente di eseguire operazione che metterebbero a rischio il suo essere un mediacenter, fondamentalmente.&#xA;&#xA;Tradotto in soldoni, il client wireguard si installa, sale su correttamente ma non c&#39;è verso di far funzionare la risoluzione. L&#39;unica via d&#39;usicta è stata configurare Wireguard attraverso il gestore di rete di OSMC che è connman.&#xA;&#xA;Una volta fatto questo, sono stati necessari solo un paio di piccoli accorgimenti per far si che, in seguito all&#39;avvio del mediacenter, la configurazione vpn venisse caricata automaticamente da connman, contestualmente alla connessione vpn.&#xA;Configurazione wgcf&#xA;Account cloudflare&#xA;curl -L https://github.com/ViRb3/wgcf/releases/latest/download/wgcf2.2.30linuxarmv7 -o /usr/local/bin/wgcf&#xA;chmod u+x /usr/local/bin/wgcf&#xA;wgcf register&#xA;wgcf generate&#xA;&#xA;status &amp; trace&#xA;wgcf status&#xA;curl https://www.cloudflare.com/cdn-cgi/trace&#xA;Configurazione connman&#xA;Su OSMC connman ha i suoi file di configurazione in /var/lib/connman e /var/lib/connman-vpn&#xA;&#xA;Nel file di configurazione, l&#39;host va indicato con l&#39;ip non con l&#39;fqdn (engage.cloudflareclients.com)&#xA;Configurazione wireguard cloudflare&#xA;La configurazione della vpn deve essere un file .config sotto /var/lib/connman-vpn&#xA;&#xA;vi /var/lib/connman-vpn/cloudflarewarp.config&#xA;[provider*]&#xA;Type = WireGuard&#xA;Name = CloudflareWARP&#xA;Host = 162.159.192.1&#xA;AutoConnect = true&#xA;WireGuard.Address = 172.16.0.2/24&#xA;WireGuard.ListenPort = 51280&#xA;WireGuard.PrivateKey = myprivatekey&#xA;WireGuard.PublicKey = cloudlarewgpublickey&#xA;WireGuard.DNS = 1.1.1.1, 1.0.0.1&#xA;WireGuard.AllowedIPs = 0.0.0.0/0&#xA;WireGuard.EndpointPort = 2408&#xA;WireGuard.PersistentKeepalive = 25&#xA;Dopo aver creato il file di configurazione, possiamo vedere il nuovo servizio pronto per essere richiamato da comman-vpnd&#xA;elenco servizi attivi&#xA;connmanctl services&#xA;AO SSID           wifiidmanagedpsk&#xA;R CloudflareWARP      vpn1621591921&#xA;Affinché la connessione alla vpn parta all&#39;avvio di OSMC, è necessario disporre di un servizio che:&#xA;&#xA;esegua common-vpnd per caricare il file di configurazione&#xA;effettui la connessione vpn&#xA;&#xA;Creazione nuovo servizio in /lib/systemd/system/connman-vpn.service&#xA;[Unit]&#xA;Description=ConnMan VPN service&#xA;After=network-online.target&#xA;Wants=network-online.target&#xA;&#xA;[Service]&#xA;Type=dbus&#xA;BusName=net.connman.vpn&#xA;ExecStart=/usr/sbin/connman-vpnd -n&#xA;ExecStop=/usr/local/bin/vpn-autoconnect.sh&#xA;StandardOutput=null&#xA;Restart=on-failure&#xA;&#xA;[Install]&#xA;WantedBy=multi-user.target&#xA;Script richiamato dal servizio per la connessione alla vpn:&#xA;connessione vpn&#xA;vi /usr/local/bin/vpn-autoconnect.sh&#xA;!/bin/bash&#xA;Attende che il demone VPN sia pronto&#xA;sleep 5&#xA;Tenta la connessione (usa il nome esatto che vedi in connmanctl services)&#xA;connmanctl connect vpn1621591921&#xA;Inifine si rende il file eseguibile e si avvia il servizio&#xA;chmod +x /usr/local/bin/vpn-autoconnect.sh&#xA;&#xA;avvio servizio&#xA;systemctl daemon-reload&#xA;systemctl enable connman-vpn.service&#xA;systemctl start connman-vpn.service&#xA;E il gioco è fatto.&#xA;&#xA;Da questo momento in poi, OSMC tunnellizza tutto il suo traffico verso Cloudflare.&#xA;&#xA;Come detto, in questo modo ho &#34;solo&#34; la configurazione di un tunnel wireguard verso l&#39;endpoint Cloudflare, non dispongo delle altre funzionalità che warp-cli offre.&#xA;&#xA;Tuttavia è un procedimento abbastanza trasparente che non prevede la convivenza con ulteriori servizi come nel caso di warp-cli e che può essere un&#39;alternativa anonimizzante valida anche su una linux box normale.&#xA;&#xA;#dns #doh #dot #warp #vpn #tunnel #cloudflare #wireguard #masque #osmc]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/31410d826-759a86/nDDNn0ObGm8H/bTjZEfazDrIzF1UqmzhRRGXWvH807nU98C2cdm16.jpg" alt="cloudflare-warp">
È noto come l&#39;uso dei resolver Cloudflare sia uno dei modi per anonimizzare il proprio IP all&#39;ISP.</p>

<p>Cloudflare offre anche altre modalità di risoluzione ancora più efficaci:</p>
<ol><li>DNS over HTTPS (<strong>DoH</strong>)</li>
<li>DNS over TCP (<strong>DoT</strong>)</li>
<li>DNS over WARP (<strong>DoW</strong>)</li></ol>



<p>I primi due sono relativi a richieste dns crittografate e incapsulate, in una richiesta https (porta 443) la prima, e in una connessione TLS (porta 853) la seconda.</p>

<p>La terza modalità è una richiesta dns <strong>in chiaro</strong> ma all&#39;interno di un tunnel <strong>Wireguard</strong> o <strong>MASQUE</strong> (<strong>QUIC</strong> + <strong>HTTP/3</strong> – rif. <a href="https://datatracker.ietf.org/meeting/interim-2021-masque-03/materials/slides-interim-2021-masque-03-sessa-masque-interim-2021-04-h3-dgram-00" rel="nofollow">https://datatracker.ietf.org/meeting/interim-2021-masque-03/materials/slides-interim-2021-masque-03-sessa-masque-interim-2021-04-h3-dgram-00</a>). Molto interessante ed è quella che approfondirò in seguito.</p>

<p>Senza entrare nel merito, tutte le soluzioni anonimizzano le query dns. L&#39;ultima, quella che mi ha stutzzicato, è in realtà un tunnel vpn che crittografa <strong>TUTTO</strong> il traffico, non solo le richieste DNS.</p>

<p><strong>DoT</strong> è una cifratura TLS che lascia intatto il pacchetto UDP iniziale, è quindi più efficiente di <strong>DoH</strong> che converte una richieste DNS in una HTTP cifrata dal layer TLS.</p>

<p><strong>DoT</strong> di solito viene fatta a livello di dispositivo, <strong>DoH</strong> per singole applicazioni.</p>

<p><strong>DoT</strong>, basandosi su una porta specifica, 853, è facilmente identificabile (e bloccabile) come traffico DNS (benché cifrato), <strong>DoH</strong> è una richiesta HTTPS e si mescola col traffico che viaggia sulla porta 443 (difficilmente si invaliderà tutto quel tipo di traffico).</p>

<p><strong>DoT</strong>, <strong>DoH</strong>, <strong>DoW</strong>, mitigano notevolmente il <strong>cache poisoning</strong> dei resolver perché rendono quasi impossibilie per un attaccante alterare una richiesta che viene protetta per l&#39;intero percorso. Va detto che la soluzione ideale in questo contesto è la combinazione con <strong>DNSSEC</strong>, che fornisce autenticità e integrità alla riservatezza fornita da DoH/DoT.</p>

<p>Anche se l&#39;obiettivo rimane l&#39;approfondimento di CLoudflare WARP, vale la pena di spendere due parole anche sulle altre modalità di risoluzione, DoT/DoH</p>

<h2 id="configurare-risoluzioni-dns-doh">Configurare risoluzioni DNS DoH</h2>

<p>Configurare <strong>DoH</strong> è molto semplice perché è qualcosa legato all&#39;applicazione, il browser tipicamente. Se l&#39;applicazione lo supporta, di solito è poco di più di un flag da abilitare.</p>

<p>Ad es. Firefox o Chrome permettono di attivare una sorte di “protezione avanzata del DNS” indicando semplicemente un resolver che la supporti (es. Cloudflare, NextDNS o Quad9).</p>

<h2 id="configurare-risoluzioni-dns-dot">Configurare risoluzioni DNS DoT</h2>

<p>DoT, come detto, è una configurazione che avviene a livello di dispositivo, l&#39;anonimizzazione delle query DNS si ottiene quindi per <strong>ogni</strong> applicazione. Sul come farlo, dipende dal dispositivo.</p>

<p>Ad es. su una linux box basta aggiungere due righe su <code>systemd-resolved</code> e riavviare il relativo servizio.</p>

<pre><code class="language-bash">sudo vi /etc/systemd/resolved.conf
...
DNS=1.1.1.1
DNSOverTLS=yes

# dopo aver salvato il file
systemctl restart systemd-resolved
</code></pre>

<p>Un veloce test su <a href="https://1.1.1.1/help" rel="nofollow">https://1.1.1.1/help</a>  (da qualunque browser) ci mostrerà qualcosa del tipo:</p>

<pre><code>Connected to 1.1.1.1        Yes
Using DNS over HTTPS (DoH)  No
Using DNS over TLS (DoT)    Yes
Using DNS over WARP         No
AS Name                     Cloudflare, Inc.
AS Number                   13335
Cloudflare Data Center      MXP
</code></pre>

<p>indice che DoT è attivo e funzionante. Lo stesso test poteva essere fatto anche per DoH.</p>

<h2 id="cloudflare-warp">Cloudflare WARP</h2>

<p>E poi c&#39;è <strong>DoW</strong>, che è qualcosa di ancora più estremo perché, all&#39;occorrenza, anonimizza non solo le richieste DNS ma tutto il <strong>nostro</strong> traffico (e infatti diversi servizi di streaming non lo consentono).</p>

<p><strong>Cloudflare Warp</strong> attiva diverse modalità di risoluzione dns fra cui DoH e DoT.</p>

<p>Dal momento che Cloudflare Warp agisce su tutta la connessione, è il modo più semplice per avere risoluzione dns di tipo DoH o DoT, su qualunque dispositivo su cui è presente Cloudflare Warp senza gli sbattimenti di systemd o altro.</p>

<p><strong>Cloudflare Warp</strong> in modalità tunnel è un client che instaura un collegamento cifrato punto-punto (un tunnel) fra il nostro host e un endpoint Cloudflare. In questo modo ogni bit che esce dal nostro dispositivo viene cifrato prima della comunicazione, che diventa così totalmente schermata.</p>

<p>La vpn di Coudflare si basa su wireguard o su MASQUE. Nel primo caso è una normale vpn con un setup roadwarrior, il secondo caso offre in più la possibilità di associare al tunnel anche le modalità DoH/DoT per le richieste dns.</p>

<h3 id="anonimato-sì-no">Anonimato sì/no?</h3>

<p>Cloudflare WARP è uno strumento incentrato sulla sicurezza, progettato per crittografare il traffico internet e proteggere la privacy dagli ISP, piuttosto che per garantire l&#39;anonimato completo o nascondere la posizione dell&#39;utente.</p>

<p>Sostituisce l&#39;IP dell&#39;utente con un IP di Cloudflare che generalmente corrisponde alla sua reale area geografica, rendendolo inadatto a eludere le restrizioni basate sulla posizione.</p>

<p>Non è una VPN tradizionale. WARP non maschera la nostra posizione ai siti web, che spesso possono visualizzare la tua posizione approssimativa.</p>

<p>Per migliorare la privacy, si dovrebbe utilizzare il protocollo MASQUE, che offre anche una maggiore efficienza.</p>

<p>In sintesi, WARP fornisce un “tunnel sicuro” per proteggere la privacy dei dati da amministratori di rete indiscreti, protegge il traffico perché eccelle nella crittografia del traffico su reti non sicure (ad esempio, Wi-Fi pubbliche), ma non offre le funzionalità di anonimato dei tradizionali servizi VPN incentrati sulla privacy.</p>

<p>Fatta questa doverosa premessa, vediamo come può essere usato.</p>

<h3 id="configurare-cloudflare-warp">Configurare Cloudflare WARP</h3>

<p>L&#39;installazione del client è molto semplice. Per Gnu/Linux c&#39;è la versione cli, per android un app, per altri sistemi, Win /MacOS, un installer.
La parte applicativa prima di tutto registra il dispositivo sulla rete Cloudflare generando degli ID e una chiave di licenza. In un secondo momento si generano le chiavi di cifratura.</p>

<p>Per fissare le idee, una volta fatte le operazioni di inizializzazione, sulla linux box per tunnellizzare ogni nostra comunicazione con una risoluzione DoT, basta:</p>

<pre><code class="language-bash"># facoltativo
warp-cli mode warp+dot

#connessione
warp-cli connect
</code></pre>

<p>Per terminare:</p>

<pre><code class="language-bash">warp-cli disconnect
</code></pre>

<p>Questo approccio torna molto comodo quando per es. vogliamo usare wifi pubbliche, in città o in aeroporto. A meno di non avere un&#39;installazione personale di una nostra vpn, questa è una soluzione immediata. Certo, bisogna fidarsi di Cloudflare ma è certamente meglio che fidarsi delle wifi free.</p>

<p>E arriviamo al caso d&#39;uso che volevo approfondire riguardante l&#39;“anonimizzazione” di un mediacenter casalingo per il quale non vogliamo rendere noto il suo utilizzo.</p>

<p>L&#39;esperienza che ho avuto al proposito è stata interessante, visto che uso da anni OSMC su una RasbPi 3 e ho deciso di metterla dietro Cloudflare.</p>

<p><strong>OSMC</strong> insieme a <strong>LibreELEC</strong> sono ottime soluzioni di mediacenter per SBC. La prima più “general”, essendo una debian customizzata per ospitare un mediacenter, la seconda invece meno elastica ma più essenziale ed efficiente.</p>

<p>Nonostante la Raspberry Pi 3 sia dotata di un processore ARM64, la versione di OSMC che ho installato a suo tempo è a 32 bit e per quella non c&#39;è disponibilità per il client cloudflare (solo ARM64).</p>

<p>Ho dovuto ricorrere ad un client “unofficial”, <strong>wgcf</strong>, che permette di registrare il dispositivo e di generare le chiavi ma solo per la modalità Wireguard, non MASQUE, quindi niente Warp+DoT/DoH (per inciso, wgcf rappresenta un&#39;ottima alternativa anche per chi non vuole usare il client Cloudflare su Gnu/Linux).</p>

<p>A questo aggiungo che, sebbebe OSMC sia una Debian su cui posso installare e configurare tanta roba, l&#39;installazione di Wireguard, e penso di qualunque cosa che vada a toccare lo stack di rete, diventa qualcosa di estremamente complicato da fare, dal momento che OSMC si rifiuta categoricamente di eseguire operazione che metterebbero a rischio il suo essere un mediacenter, fondamentalmente.</p>

<p>Tradotto in soldoni, il client wireguard si installa, sale su correttamente ma non c&#39;è verso di far funzionare la risoluzione. L&#39;unica via d&#39;usicta è stata configurare Wireguard attraverso il gestore di rete di OSMC che è <strong>connman</strong>.</p>

<p>Una volta fatto questo, sono stati necessari solo un paio di piccoli accorgimenti per far si che, in seguito all&#39;avvio del mediacenter, la configurazione vpn venisse caricata automaticamente da connman, contestualmente alla connessione vpn.</p>

<h3 id="configurazione-wgcf">Configurazione wgcf</h3>

<pre><code class="language-bash"># Account cloudflare
curl -L https://github.com/ViRb3/wgcf/releases/latest/download/wgcf_2.2.30_linux_armv7 -o /usr/local/bin/wgcf
chmod u+x /usr/local/bin/wgcf
wgcf register
wgcf generate

# status &amp; trace
wgcf status
curl https://www.cloudflare.com/cdn-cgi/trace
</code></pre>

<h3 id="configurazione-connman">Configurazione connman</h3>

<p>Su OSMC connman ha i suoi file di configurazione in <code>/var/lib/connman</code> e <code>/var/lib/connman-vpn</code></p>

<p>Nel file di configurazione, l&#39;host va indicato con l&#39;ip non con l&#39;fqdn (engage.cloudflareclients.com)</p>

<pre><code class="language-bash"># Configurazione wireguard cloudflare
# La configurazione della vpn deve essere un file .config sotto /var/lib/connman-vpn

vi /var/lib/connman-vpn/cloudflare_warp.config
[provider_*]
Type = WireGuard
Name = Cloudflare_WARP
Host = 162.159.192.1
AutoConnect = true
WireGuard.Address = 172.16.0.2/24
WireGuard.ListenPort = 51280
WireGuard.PrivateKey = &lt;my_private_key&gt;
WireGuard.PublicKey = &lt;cloudlare_wg_public_key&gt;
WireGuard.DNS = 1.1.1.1, 1.0.0.1
WireGuard.AllowedIPs = 0.0.0.0/0
WireGuard.EndpointPort = 2408
WireGuard.PersistentKeepalive = 25
</code></pre>

<p>Dopo aver creato il file di configurazione, possiamo vedere il nuovo servizio pronto per essere richiamato da <code>comman-vpnd</code></p>

<pre><code class="language-bash"># elenco servizi attivi
connmanctl services
* AO &lt;SSID&gt;           wifi_&lt;id&gt;_managed_psk
* R Cloudflare_WARP      vpn_162_159_192_1
</code></pre>

<p>Affinché la connessione alla vpn parta all&#39;avvio di OSMC, è necessario disporre di un servizio che:</p>
<ol><li>esegua <code>common-vpnd</code> per caricare il file di configurazione</li>
<li>effettui la connessione vpn</li></ol>

<pre><code class="language-bash"># Creazione nuovo servizio in /lib/systemd/system/connman-vpn.service
[Unit]
Description=ConnMan VPN service
After=network-online.target
Wants=network-online.target

[Service]
Type=dbus
BusName=net.connman.vpn
ExecStart=/usr/sbin/connman-vpnd -n
ExecStop=/usr/local/bin/vpn-autoconnect.sh
StandardOutput=null
Restart=on-failure

[Install]
WantedBy=multi-user.target
</code></pre>

<p>Script richiamato dal servizio per la connessione alla vpn:</p>

<pre><code class="language-bash"># connessione vpn
vi /usr/local/bin/vpn-autoconnect.sh
#!/bin/bash
# Attende che il demone VPN sia pronto
sleep 5
# Tenta la connessione (usa il nome esatto che vedi in connmanctl services)
connmanctl connect vpn_162_159_192_1
</code></pre>

<p>Inifine si rende il file eseguibile e si avvia il servizio</p>

<pre><code class="language-bash">chmod +x /usr/local/bin/vpn-autoconnect.sh

# avvio servizio
systemctl daemon-reload
systemctl enable connman-vpn.service
systemctl start connman-vpn.service
</code></pre>

<p>E il gioco è fatto.</p>

<p>Da questo momento in poi, OSMC tunnellizza tutto il suo traffico verso Cloudflare.</p>

<p>Come detto, in questo modo ho “solo” la configurazione di un tunnel wireguard verso l&#39;endpoint Cloudflare, non dispongo delle altre funzionalità che <code>warp-cli</code> offre.</p>

<p>Tuttavia è un procedimento abbastanza trasparente che non prevede la convivenza con ulteriori servizi come nel caso di <code>warp-cli</code> e che può essere un&#39;alternativa anonimizzante valida anche su una linux box normale.</p>

<p><a href="/aytin/tag:dns" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">dns</span></a> <a href="/aytin/tag:doh" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">doh</span></a> <a href="/aytin/tag:dot" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">dot</span></a> <a href="/aytin/tag:warp" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">warp</span></a> <a href="/aytin/tag:vpn" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">vpn</span></a> <a href="/aytin/tag:tunnel" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">tunnel</span></a> <a href="/aytin/tag:cloudflare" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">cloudflare</span></a> <a href="/aytin/tag:wireguard" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">wireguard</span></a> <a href="/aytin/tag:masque" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">masque</span></a> <a href="/aytin/tag:osmc" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">osmc</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/installazione-di-cloudflare-warp-su-osmc</guid>
      <pubDate>Fri, 03 Apr 2026 22:33:32 +0000</pubDate>
    </item>
    <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>Archiviare le password in sicurezza con KDF/password-hashing (Trilogia Della Password - 3 di 3)</title>
      <link>https://noblogo.org/aytin/archiviare-le-password-in-sicurezza-con-kdf-password-hashing-trilogia-della</link>
      <description>&lt;![CDATA[password hashing&#xA;&#xA;Dopo aver capito come creare password inviolabili anche avendo a disposizione tutta l&#39;energia termica dell&#39;universo, pensiamo al modo migliore per archiviarle.&#xA;&#xA;Pensare di lasciare la password raw in un database, rappresenta un grosso rischio in virtù di un possibile attacco offline.&#xA;!--more--&#xA;&#xA;Rainbow Table&#xA;Come ti blocco la Rainbow Table: Il “Salt” (sale)&#xA;Il livello successivo: Il Pepper&#xA;Final step: L’hashing&#xA;  PBKDF2&#xA;  Bcrypt&#xA;  Scrypt&#xA;  yescrypt&#xA;  Argon2&#xA;Un piccolo esempio: hashing di una password con Argon2&#xA;Gestione del pepper&#xA;HSM&#xA;Key / Algo Rotation&#xA;  Caso A: Algo rotation&#xA;  Caso B: Pepper rotation&#xA;&#xA;Una prima linea di difesa consiste nel memorizzare il digest della password, una stringa alfanumerica univoca generata da un apposito algoritmo, così da lasciare nelle mani dell&#39;attaccante degli oggetti che, per la loro non invertibilità, non permettono di risalire alle password.&#xA;&#xA;La scelta dell&#39;algoritmo di hashing diventa critica al fine di scongiurare altri tipi di attacchi. Ad es. SHA-256, pur essendo ottimo e molto efficiente per il digest e la firma anche di file di grandi dimensioni, mostra il fianco, proprio in virtù della sua velocità, nel caso di attacchi con:&#xA;&#xA;brute-force: si calcola l’hash di password casuali fino a trovare una corrispondenza,&#xA;dizionario: un&#39;alternativa intelligente alla forza bruta. Si punta alle password più comuni, si calcola l&#39;hash e si controlla se c&#39;è corrispondenza.&#xA;Rainbow Table: l&#39;attacco al dizionario più insidioso di tutti&#xA;&#xA;Oltre al fatto che, la funzione di hashing , essendo deterministica, permette di capire chi sono gli utenti che hanno la stessa password, dal momento che avranno lo stesso digest.&#xA;Rainbow Table&#xA;Una Rainbow Table è un enorme dizionario pre-calcolato che contiene:&#xA;&#xA;Milioni di password comuni.&#xA;Il relativo hash corrispondente.&#xA;&#xA;Invece di calcolare l’entropia di ogni tentativo, l’attaccante ruba il database degli hash e fa un semplice “Cerca e Trova”. Se l’hash della tua password è nella tabella, la tua password è violata in millisecondi, indipendentemente da quanto fosse alta la sua entropia teorica.&#xA;&#xA;smallOss.: Una password totalmente casuale, generata da un CSPRNG affidabile, con un&#39;alta entropia (  120), rimarrebbe comunque inviolabile anche dalla rainbow table perché la probabilità che quella password si trovi nel dizionario, sarebbe equivalente ad indovinarla./small&#xA;Come ti blocco la Rainbow Table: Il “Salt” (sale)&#xA;Per rendere inutili le Rainbow Table, i sistemi sicuri utilizzano il Salt. Il salt è una stringa di dati casuali (generati da una sorgente d’entropia affidabile ovviamente) che viene aggiunta alla password prima di calcolarne il digest.&#xA;&#xA;In questo modo le rainbow table vengono vanificate perché gli hash precalcolati sulle password raccolte, mancando il salt, non valgono più. Anche se due utenti avessero la stessa password, avrebbero degli hash completamente diversi.&#xA;&#xA;Anche per questo motivo non è un problema che il salt sia pubblico, perché il suo obiettivo non è nascondere quello che è un pezzetto di password a tutti gli effetti, ma di impedire economie di scala degli attacchi perché, pur potendo disporre offline di un database di decine di milioni di utenti, gli hash della mia Rainbow Table (che può arrivare a pesare anche decine di GB) andrebbero tutti ricalcolati per ogni utente, con un costo computazionale e di archiviazione inimmaginabile.&#xA;&#xA;Per riassumere, gli ingredienti di base sono:&#xA;&#xA;una buona sorgente d’entropia: una fonte di casualità certificata per generare un salt unico;&#xA;entropia della password: sempre buona norma, ove possibile, come sappiamo ormai fare (https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di). Evita attacchi brute-force o al dizionario in cui l’attaccante prova a indovinare;&#xA;salt: protegge la password dagli attacchi basati su database pre-calcolati (Rainbow Table).&#xA;&#xA;Il livello successivo: Il Pepper&#xA;È vero che col salt andiamo a complicare lo sfruttamento di un attacco offline ma possiamo fare di meglio.&#xA;&#xA;Il punto d&#39;attenzione è che il salt protegge le password di tutti gli utenti.&#xA;Ma un attaccante potrebbe non essere affatto interessato a violare ogni singolo utente (niente economia di scala) ma solo alcuni. E allora l&#39;attacco attraverso Ranbow Table potrebbe essere di nuovo praticabile.&#xA;&#xA;Ma gli informatici sono dei gran giocherelloni, si sa.&#xA;Visto che abbiamo già il &#34;sale&#34;, perché non finire aggiustando con un po’ di “pepe”? Detto, fatto!&#xA;&#xA;Il pepper, come il salt, è un&#39;altra password generata con gli stessi criteri del salt ma le analogie finiscono qua perché:&#xA;&#xA;a differenza del salt che si trova nel database, il pepper è separato da ques&#39;ultimo. L&#39;ideale sarebbe un HSM;&#xA;Il salt è visibile a tutti, attaccante compreso. Il pepper è segreto. Un eventuale data breach che permette all&#39;attaccante di disporre offline di tutto il database degli utenti, &#34;vedrà&#34; certamente gli eventuali salt ma sarà ignaro del fatto che gli mancherà sempre un pezzo di chiave;&#xA;il salt è diverso per ogni utente, il pepper, di solito, è unico;&#xA;il salt serve a rendere uniche la password degli utenti, il pepper protegge l&#39;intero database da attacchi offline.&#xA;&#xA;Il pepper è la chiave di un HMAC, o di un meccanismo di cifratura simmetrica, applicato al digest della password (che ricordo essere salt+password in realtà), che sarà ciò che verrà archiviato.&#xA;&#xA;Va detto che l&#39;uso del &#34;pepper&#34; complica ulteriormente lo scenario di archiviazione.&#xA;Nella stragrande maggioranza dei casi è sufficiente scegliere un buon algoritmo di password hashing (vedi paragrafo successivo) per scoraggiare gli attaccanti.&#xA;&#34;Pepare&#34; le password prevederebbe, come detto sopra, l&#39;uso di un HSM per es, e tutta una serie di riflessioni di contorno che evidenzierò più avanti.&#xA;Final step: L&#39;hashing&#xA;L&#39;ultimo punto da dettagliare è l&#39;hash della password.&#xA;&#xA;L&#39;hash crittografico, in uso in questi casi, deve soddisfare le seguenti proprietà:&#xA;&#xA;resistenza alla pre-immagine: dato un hash h, deve essere impossibile trovare una password p t.c. H(p) = h (non invertibilità della funzione hash)&#xA;resistenza alla pre-immagine secondaria: dato una password psub1/sub, deve essere impossibile trovare un&#39;altra password psub2/sub t.c. H(psub1/sub) = H(psub2/sub) (resistenza debole alle collisioni)&#xA;resistenza alle collisioni: è impossibile trovare due password diverse, psub1/sub e psub2/sub, t.c. H(psub1/sub) = H(psub2/sub) (resistenza forte alle collisioni)&#xA;effetto valanga: il cambio di un solo bit della password deve cambiare radicalmente l&#39;intero hash&#xA;&#xA;In un sistema moderno, l&#39;hash non può essere delegato a funzioni di tipo SHA perché nascono per altri compiti,&#xA;&#xA;SHA-2 e SHA-3 nascono per il digest veloce, per verificare l&#39;integrità di file anche molto grossi o firmare documenti. La loro eccellente velocità diventa il loro più grosso difetto quando si parla di password.&#xA;Negli scenari precedenti di attachi offline, l&#39;hacker che dispone di una grossa potenza di calcolo, può ricostituire velocemente le rainbow table per n utenti. Magari non di tutti ma di quelli attenzionati.&#xA;&#xA;Le funzioni di derivazione della chiave (KDF) come pbkdf2 e quelle ancora più estreme come B/Scrypt, Argon2, oltre che soddisfare tutti i punti precedentemente elencati tipici di funzioni di password hashing, sono progettate per essere computazionalmente pesantissime da calcolare perché il loro scopo non è il digest ma la protezione di un segreto contro il brute-force.&#xA;E mentre le vecchie KDF come pbdfk2 sono CPU bound, ma non GPU bound, le KDF più moderne come Bcrypt, Scrypt ma soprattutto Argon2, agiscono pesantemente su tempo, memoria e parallelismo e l&#39;attacco offline di cui sopra diventa impraticabile.&#xA;PBKDF2&#xA;È il decano delle KDF. Applica iterativamente una funzione pseudorandomica, come HMAC con uno SHA, con salt alla password.&#xA;Il conteggio delle iterazioni è un parametro configurabile.&#xA;&#xA;PBDKF2 è uno standard di lunga data ampiamente adottato. Se non ci sono necessità stringenti di sicurezza o requisiti legacy, è una buona scelta.&#xA;&#xA;Il fatto di essere solo CPU bound però non la rende la scelta ideale in scenari dove gli attaccanti possono attingere a risorse di calcolo considerevoli&#xA;Bcrypt&#xA;Basato su Blowfish, anche Bcrypt usa un hash crittografico sulla password con parametri il salt e un fattore di costo.&#xA;&#xA;Il fattore di costo aumenta esponenzialmente il numero di iterazioni per adattarsi all&#39;aumento di potenza di calcolo dell&#39;hardware.&#xA;&#xA;Bcrypt è stato progetto per essere lento e resistente a semplici attacchi di forzat bruta.&#xA;Tuttavia, il basso utilizzo di ram richiesto dal calcolo lo rendono poco resistente ad attacchi sferrati usando hardware specializzato.&#xA;&#xA;Bcrypt ha dalla sua una storia solidissima in ragione della quale da 20 anni a questa parte non sono state trovate vulnerabilità critiche nel suo design.&#xA;&#xA;Per questo motivo Bcrypt cifra le password di sistema di OpenBSD dal 1999, come pure ha cifrato quelle di tante distro Linux per anni, prima che passassero ad Argon2 o yescrypt (default di Fedora).&#xA;&#xA;Domina nei framework web (\[Python\] Django, \[Ruby\] Ruby on Rails, \[PHP\] Laravel), \[Java\] Spring, Node.js), nelle applicazioni (Ansible / Terraform, Docker), nel web (la cifratura in .htpasswd di Apache e Nginx) visto che la sua semplcitià di implementazione gli ha permesso di trovarsi praticamente in ogni linguaggio.&#xA;&#xA;È presente come alternativa anche nei password manager benché molti di essi abbiano spostato il default verso Argon2 o PBKDF2 per conformità agli standard FIPS.&#xA;&#xA;È molto semplice implementare e anche da usare perché bisogna agire solo sul fattore di costo (consigliato almeno 10-12, altrimenti diventa troppo vulnerabile ad attacchi sferrati attraverso la GPU)&#xA;Scrypt&#xA;Rilasciato nel 2009, Scrypt è stato il primo algoritmo a introdurre il concetto di Memory Hardness ed è stato progettato per rendere economicamente poco conveniente il ricorso ad hardware specializzato come gli ASIC o i FPGA e incidere pesantemente su CPU, ram e parallelismo.&#xA;&#xA;Il suo alveo principale sono state le cripto-valute, molte monete lo usano per il mining.&#xA;&#xA;Scrypt lo troviamo in quasi tutti i linguaggi di programmazione, in Tarsnap, servizio di baclup online creato dallo stesso autore di Scrypt, è stato usato da LastPass ed è presente come opzione in VeraCrypt per derivare la chiave dalla password.&#xA;Fino ad Android 9 era l&#39;algoritmo usato per la FDE del dispositvio (passato poi al FBE) .&#xA;Presente anche su FreeBSD come opzione per la cifratura delle password di sistema e come opzione su LUKS per la cifratura degli slot delle chiavi.&#xA;&#xA;Su Scrypt i parametri da configurare sono:&#xA;&#xA;Costro CPU/Memoria (N): un parametro che aumenta i costi computazionali di cpu e memoria&#xA;DImensione del blocco (R): influenza la larghezza di banda della memoria&#xA;Parallelizzazione (p): indica quanto deve incidere sul calcolo parallelo&#xA;&#xA;In questo modo riesce ad essere sia CPU bound che GPU bound che, a differenza di Bcrypt, lo rende resistente anche ad attacchi facenti uso di hardware specializzato..&#xA;&#xA;Di contro, in ambiente in cui siamo vincolati dalle risorse disponibili, la sua potenza diventa un fattore limitante.&#xA;Quasi paragonabile ad Argon2 in quanto a robustezza, il suo unico tallone d&#39;Achille è la permeabilità ad attacchi di tipo side-channel. &#xA;yescrypt&#xA;Piccola menzione per yescrypt, appartenente alla famiglia &#34;Scrypt&#34;, pensato per essere ancora più resistente di Scrypt agli attacchi GPU e FPGA ma con una gestione più intelligente delle risorse.&#xA;&#xA;Grazie alle sue peculiarità, di fatto, è diventato il successore spirituale di Bcrypt nei sistemi operativi gnu/linux dove, a cominciare da Fedora, passando per Debian, Ubuntu, Arch, Kali, è il default per la cifratura delle password di sistema in /etc/shadow.&#xA;&#xA;È talmente incardinato ormai nei sistemi operativi, che è la libreria libxcrypt di yescrypt a gestire la tipica funzione crypt() di C che è la base della crittografia su tutti i sistemi gnu/linux moderni.&#xA;&#xA;La sua robustezza unita alla gestione intelligente delle risorse lo rende un coltellino svizzero di riferimento utile per es. per versione custom di LUKS su sistemi embedded, che magari fanno uso di cpu meno recenti,  oppure come opzione per strumenti di backup specialistici&#xA;&#xA;Di fatto, sui sistemi operativi, yescrypt s&#39;è guadagnato un consenso amplissimo dovuto alla sua scalabilità, alla sua capacità di usare anche la ROM per rendere il cracking ancora più difficile e senza pesare sulla RAM e alla sua compatibilità potendosi inserire perfettamente nella storica funzione crypt() di C come detto prima.&#xA;&#xA;Se Argon2 è il vincitore accademico avendo vinto il Password Hashing Competition del 2015, yescrypt per la sua robustezza, efficienza e flessibilità si ritaglia un profilo di indispensabilità nei sistemi operativi,&#xA;Argon2&#xA;E veniamo al dominatore indiscusso di questa che non è una llista esaustiva di KDF.&#xA;&#xA;Argon2 è LO standard moderno per il password hashing raccomandato da OWASP e IETF.&#xA;&#xA;È il riferimento per praticamente ogni password manager: Bitwarden, KeppasXC, 1Password, a cui assegnanp la protezione della Master Password&#xA;&#xA;È la scelta principale per la cifratura degli hard disk anche con impostazioni molto aggressive, in ragione delle quali un ritardo di mezzo secondo (un tempo enorme se venisse scalato esponenzialmente) nell&#39;apertura di un HD è assolutamente accettabile.&#xA;È il default di LUKS2 (LUKS1 usava PBKDF2) e di VeraCrypt, con cui ha sostituito SHA-512.&#xA;&#xA;Come Bcrypt, è implementato estensivamente su praticamente ogni frameword web e backend, da PHP, Django (Python), Laravel fino a Node.js.&#xA;&#xA;Nei sistemi operativi, laddove yescrytpt domina nella gestione delle password utente, Argon2 è usato per compiti più critici.&#xA;Dal kernel Linux per gestire internamente le chiavi crittografiche o da macOS / iOS, dove algoritmi proprietari ispirati fortemente ad Argon2, proteggono i dati nel Secure Enclave.&#xA;&#xA;Argon2  setta 3 parametri principali per regolare la sua forza:&#xA;&#xA;t: iterazioni, quante volte vengono rimescolati i dati (default Bitwarden = 3)&#xA;m: memoria, quanta ram deve occupare il calcolo. Questa è la misura anti-GPU (default Bitwarden = 16 (64MB))&#xA;p: parallelismo, quanti core della cpu usare. Questa è la misura anti-CPU (default Bitwarden = 4)&#xA;&#xA;La variante id è anche resistente agli attacchi side-channel perché impediscono a un attaccante di capire la password osservando i tempi di accesso alla memoria.&#xA;&#xA;Un piccolo esempio: hashing di una password con Argon2&#xA;Il grosso vantaggio degli algoritmi di kdf è che sono naturalmente resilienti rispetto all&#39;evoluzione tecnologica che produce macchine con sempre maggiore potenza di calcolo.&#xA;Da pbkdf2 in poi, il salt implicito che invalida le rainbow table precalcolate e la possibilità di calibrare il key stretching in moda da agire intensivamente su ram e cpu, permettono all&#39;algoritmo di adeguarsi per conservare la sua robustezza.&#xA;&#xA;Mini-script per l&#39;hashing di una password fornita dall&#39;utente con argon2 settato al default di Bitwarden:&#xA;echo -n &#34;Password: &#34;; read -s PASSWORD&#xA;Genero un Salt casuale di 128 bit&#xA;SALT=$(openssl rand -base64 128)&#xA;PASSWORDHASH=$(echo &#34;${PASSWORD}&#34; | argon2 &#34;${SALT}&#34; -m 16 -t 3 -p 4 -id -e)&#xA;&#xA;PASSWORDHASH e SALT sono i dati che verranno archiviati e, poiché argon2 &#34;frulla&#34; la password con un salt, è praticamente impossibile risalire alla password originale.&#xA;&#xA;La verifica è tuttavia banale perché, avendo il salt e la password da verificare, si ricrea l&#39;hash con argon2 e si confronta con l&#39;hash memorizzato.&#xA;&#xA;Per maggior sicurezza salt e digest possono essere memorizzati in punti differenti. L&#39;importante è che possano essere recuperate a partire dall&#39;utente.&#xA;Gestione del pepper&#xA;Col pepper le cose cambiano un pochino perché:&#xA;&#xA;deve essere archiviato con tutte le paranoie possibili in un punto diverso dal database degli utenti&#xA;il key rotation del pepper non è banale&#xA;&#xA;Mini-script che mostra come applicare salt e pepper all&#39;hashing di una password:&#xA;L&#39;utente inserisce la password&#xA;echo -n &#34;Password: &#34;; read -s PASSWORD&#xA;&#xA;Genero un Salt casuale di 128 bit unico per ogni utente&#xA;SALT=$(openssl rand -base64 128)&#xA;&#xA;Anche PEPPER sarà qualcosa del tipo &#34;openssl rand -base64 128&#34;&#xA;e si troverà in un punto esterno al database degli utenti.&#xA;PEPPER=$(getpepperfromext)&#xA;&#xA;Digest della password+salt&#xA;PASSWORDHASH=$(echo &#34;${PASSWORD}&#34; | argon2 &#34;${SALT}&#34; -m 16 -t 3 -p 4 -id -e)&#xA;&#xA;HMAC del digest con PEPPER come chiave&#xA;PASSWORDPEPPER=$(echo &#34;${PASSWORDHASH}&#34; | openssl dgst -sha256 -hmac &#34;${PEPPER}&#34; -binary | base64)&#xA;HSM&#xA;Quella vista prima è una versione molto edulcorata di ciò che avviene nella realtà.&#xA;Il pepper, non può essere gestito con leggerezza visto che è un segreto che protegge non un singolo oggetto ma intere classi, come db di utenti.&#xA;&#xA;L&#39;apparato che gestisce chiavi di questo tipo e di questa importanza, deve essere robusto, praticamente inattaccabile, quasi completamente isolato dal resto dei sistemi a meno delle applicazioni, e solo di quelle, che hanno il permesso di richiedere una chiave,&#xA;&#xA;Apparati hardware specializzati che assolvono a tutte queste funzioni e anche di più, sono gli HSM (Hardware Security Module) che garantiscono il ciclo di vita delle chiavi, dalla generazione alla distruzione, includendo versionamento, rotazione e backup.&#xA;Sono concepiti per resistere anche a manipolazioni forzate che possono innescare un meccanismo di autodistruzione e, particolare rilevante, le operazioni crittografiche basate sulle chiavi protette vengono svolte dall&#39;hsm che consegna al client il risultato delle operazioni, non le chiavi. Nel nostro caso, l&#39;HSM dovrebbe restituirci l&#39;hmac del digest della password che gli inviamo.&#xA;Key / Algo Rotation&#xA;Cosa succede se cambio pepper o algoritmo (anche la sua configurazione)?&#xA;Non avendo disponibilità in alcun modo della password dovrò adottare una strategia ad-hoc.&#xA;Fra tutti gli scenari possibili, il miglior compromesso fra sicurezza e comodità secondo me, è quello basato sul wrapping.&#xA;&#xA;È necessario innanzitutto che vengano conservate le versioni delle chiavi per i servizi che le richiedono. E a questo dovrebbe pensarci l&#39;HSM, se ce n&#39;è uno o qualcosa di custom che abbia funzionalità analoghe.&#xA;Inoltre dovrebbero esserci dei flag che indichino quali sono gli utenti a cui sono state applicate le nuove configurazioni.&#xA;&#xA;Caso A: Algo rotation&#xA;Supponiamo che l&#39;algoritmo di hashing venga cambiato o vengano cambiate le sue configurazioni.&#xA;&#xA;Premessa:&#xA;Nel mio DB degli utenti, in corrispondenza di ogni utente, avrò:&#xA;&#xA;il digest della password &#34;pepato&#34;: HMAC ( pepper, HASH ( salt, password ) ) &#xA;il salt&#xA;&#xA;Il wrapping:&#xA;La strategia sarà quello di &#34;avvolgere&#34; la password di ogni utente col nuovo algoritmo, settare un qualche flag che mi indichi l&#39;operazione compiuta e archiviare il tutto.&#xA;&#xA;Imponiamo il nuovo algoritmo a tutti gli utenti &#34;imbustando&#34; il digest attuale (in questo caso &#39;HMAC in realtà, visto che abbiamo a che fare anche col pepper) con il nuovo digest HASH\NEW:&#xA;HASH\NEW ( salt\new, HMAC ( pepper, HASH ( salt, password ) ) ).&#xA;Per ogni utente averemo dunque:&#xA;&#x9;il nuovo digest al posto di quello vecchio,&#xA;&#x9;il nuovo salt &#xA;&#x9;il vecchio salt&#xA;Settiamo il flag del cambio algoritmo a true (o quello che è)&#xA;Quando l&#39;utente effettuerà il login con successo e il flag sarà a &#34;true&#34;, abbiamo la password che ci permetterà di eliminare il vecchio &#34;involucro&#34; e ripristinare l&#39;HMAC del nuovo digest: HMAC ( pepper, HASH\NEW ( salt\new, password ) ) e il flag ritornerà a &#34;false&#34;&#xA;&#xA;Considerazioni:&#xA;&#xA;La sicurezza non viene compromessa perché il digest di un digest, con KDF configurate a dovere, non comporta alcun rischio.&#xA;La fase di verifica è quella che si complica di più perché in base al valore del flag, dovrà essere effettuata in maniera differente.&#xA;   Se il flag è &#34;true&#34; (nella nostra convenzione), dopo il login devo avere gli elementi per calcolare il digest in questo modo: HASH\NEW ( salt\new, HMAC ( pepper, HASH ( salt, password ) ) ).&#xA;   Se il flag è a false, calcolerò al solito: HMAC ( pepper, HASH\NEW ( salt\new, password ) )&#xA;&#xA;Caso B: Pepper rotation&#xA;Supponiamo che a ruotare sia il pepper.&#xA;Procediamo sempre con il wrapping massivo su tutti gli utenti incapsulando il digest :&#xA;&#xA;HMAC ( pepper, HASH ( salt, password ) )&#xA;&#xA;con quello nuovo:&#xA;&#xA;HMAC ( pepper\new, HMAC ( pepper, HASH ( salt, password ) ) )&#xA;&#xA;mettendo il flag a &#34;true&#34;.&#xA;&#xA;Come prima, una volta che gli utenti cominceranno a fare il login, se il flag è &#34;true&#34; innanzitutto verificherò che:&#xA;&#xA;HMAC ( pepper\new, HMAC ( pepper, HASH ( salt, password ) ) ) &#xA;&#xA;sia uguale a ciò che è stato archiviato.&#xA;Se così fosse, ora che sono di nuovo in possesso della password, ripristinerò l&#39;HMAC con:&#xA;&#xA;HMAC ( pepper\new, HASH ( salt, password ) )_&#xA;&#xA;memorizzandolo al posto di quello vecchio e rimettendo il flag a false.&#xA;&#xA;Considerazioni:&#xA;La modifica massiva delle password degli utenti, stavolta passa dall&#39;HSM e potrebbe essere un problema perché un HSM è progettato per scoraggiare flooding di richieste.&#xA;&#xA;È vero che il pepper è sempre lo stesso per tutti gli utenti ma, come ricordavo prima, di solito un HSM non fornisce i suoi segreti ma solo i risultati crittografici delle loro applicazioni.&#xA;&#xA;#kdf #pbkdf2 #bcrypt #scrypt #yescrypt #argon2 #luks #cryptography #aes #sha #digest #RainbowTable #BruteForce #salt #pepper #entropy #hsm #hmac #hash]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/ffe7c43a6-a8b5f2/dnumO91UA8rS/L0t7UvdH6Z7pYPEvBDVb3aulMdNhW1WPBRIRKHMF.jpg" alt="password hashing"></p>

<p>Dopo aver capito come creare password inviolabili anche avendo a disposizione tutta l&#39;energia termica dell&#39;universo, pensiamo al modo migliore per archiviarle.</p>

<p>Pensare di lasciare la password raw in un database, rappresenta un grosso rischio in virtù di un possibile attacco offline.
</p>
<ul><li><a href="#rainbow-table" rel="nofollow">Rainbow Table</a></li>
<li><a href="#come-ti-blocco-la-rainbow-table-il-salt-sale" rel="nofollow">Come ti blocco la Rainbow Table: Il “Salt” (sale)</a></li>
<li><a href="#il-livello-successivo-il-pepper" rel="nofollow">Il livello successivo: Il Pepper</a></li>
<li><a href="#final-step-l-hashing" rel="nofollow">Final step: L’hashing</a>
<ul><li><a href="#pbkdf2" rel="nofollow">PBKDF2</a></li>
<li><a href="#bcrypt" rel="nofollow">Bcrypt</a></li>
<li><a href="#scrypt" rel="nofollow">Scrypt</a></li>
<li><a href="#yescrypt" rel="nofollow">yescrypt</a></li>
<li><a href="#argon2" rel="nofollow">Argon2</a></li></ul></li>
<li><a href="#un-piccolo-esempio-hashing-di-una-password-con-argon2" rel="nofollow">Un piccolo esempio: hashing di una password con Argon2</a></li>
<li><a href="#gestione-del-pepper" rel="nofollow">Gestione del pepper</a></li>
<li><a href="#hsm" rel="nofollow">HSM</a></li>
<li><a href="#key-algo-rotation" rel="nofollow">Key / Algo Rotation</a>
<ul><li><a href="#caso-a-algo-rotation" rel="nofollow">Caso A: Algo rotation</a></li>
<li><a href="#caso-b-pepper-rotation" rel="nofollow">Caso B: Pepper rotation</a></li></ul></li></ul>

<p>Una prima linea di difesa consiste nel memorizzare il <strong>digest della password</strong>, una stringa alfanumerica univoca generata da un apposito algoritmo, così da lasciare nelle mani dell&#39;attaccante degli oggetti che, per la loro non invertibilità, non permettono di risalire alle password.</p>

<p>La <strong>scelta</strong> dell&#39;algoritmo di hashing diventa critica al fine di scongiurare altri tipi di attacchi. Ad es. SHA-256, pur essendo ottimo e molto efficiente per il digest e la firma anche di file di grandi dimensioni, mostra il fianco, proprio in virtù della sua velocità, nel caso di attacchi con:</p>
<ul><li><strong>brute-force:</strong> si calcola l’hash di password casuali fino a trovare una corrispondenza,</li>
<li><strong>dizionario:</strong> un&#39;alternativa intelligente alla forza bruta. Si punta alle password più comuni, si calcola l&#39;hash e si controlla se c&#39;è corrispondenza.</li>
<li><strong>Rainbow Table:</strong> l&#39;attacco al dizionario più insidioso di tutti</li></ul>

<p>Oltre al fatto che, la funzione di hashing , essendo deterministica, permette di capire chi sono gli utenti che hanno la stessa password, dal momento che avranno lo stesso digest.</p>

<h2 id="rainbow-table">Rainbow Table</h2>

<p>Una <strong>Rainbow Table</strong> è un enorme dizionario pre-calcolato che contiene:</p>
<ul><li>Milioni di password comuni.</li>
<li>Il relativo hash corrispondente.</li></ul>

<p>Invece di calcolare l’entropia di ogni tentativo, l’attaccante ruba il database degli hash e fa un semplice “Cerca e Trova”. Se l’hash della tua password è nella tabella, la tua password è violata in millisecondi, indipendentemente da quanto fosse alta la sua entropia teorica.</p>

<p><small><strong>Oss.:</strong> Una password totalmente casuale, generata da un CSPRNG affidabile, con un&#39;alta entropia (&gt;120), rimarrebbe comunque inviolabile anche dalla rainbow table perché la probabilità che quella password si trovi nel dizionario, sarebbe equivalente ad indovinarla.</small></p>

<h2 id="come-ti-blocco-la-rainbow-table-il-salt-sale">Come ti blocco la Rainbow Table: Il “Salt” (sale)</h2>

<p>Per rendere inutili le Rainbow Table, i sistemi sicuri utilizzano il <strong>Salt</strong>. Il salt è una stringa di dati casuali (generati da una sorgente d’entropia affidabile ovviamente) che viene aggiunta alla password prima di calcolarne il digest.</p>

<p>In questo modo le rainbow table vengono vanificate perché gli hash precalcolati sulle password raccolte, mancando il salt, non valgono più. Anche se due utenti avessero la stessa password, avrebbero degli hash completamente diversi.</p>

<p>Anche per questo motivo non è un problema che il salt sia pubblico, perché il suo obiettivo non è nascondere quello che è un pezzetto di password a tutti gli effetti, ma di impedire <strong>economie di scala</strong> degli attacchi perché, pur potendo disporre offline di un database di decine di milioni di utenti, gli hash della mia Rainbow Table (che può arrivare a pesare anche decine di GB) <strong>andrebbero tutti ricalcolati per ogni utente</strong>, con un costo computazionale e di archiviazione inimmaginabile.</p>

<p>Per riassumere, gli ingredienti di base sono:</p>
<ol><li><strong>una buona sorgente d’entropia:</strong> una fonte di casualità certificata per generare un salt unico;</li>
<li><strong>entropia della password:</strong> sempre buona norma, ove possibile, come sappiamo ormai fare (<a href="https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di" rel="nofollow">https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di</a>). Evita attacchi brute-force o al dizionario in cui l’attaccante prova a indovinare;</li>
<li><strong>salt:</strong> protegge la password dagli attacchi basati su database pre-calcolati (Rainbow Table).</li></ol>

<h2 id="il-livello-successivo-il-pepper">Il livello successivo: Il Pepper</h2>

<p>È vero che col salt andiamo a complicare lo sfruttamento di un attacco offline ma possiamo fare di meglio.</p>

<p>Il punto d&#39;attenzione è che il salt protegge le password di <strong>tutti gli utenti</strong>.
Ma un attaccante potrebbe non essere affatto interessato a violare <strong>ogni singolo utente</strong> (niente economia di scala) ma solo alcuni. E allora l&#39;attacco attraverso Ranbow Table potrebbe essere di nuovo praticabile.</p>

<p>Ma gli informatici sono dei gran giocherelloni, si sa.
Visto che abbiamo già il “sale”, perché non finire aggiustando con un po’ di “pepe”? Detto, fatto!</p>

<p>Il <strong>pepper</strong>, come il salt, è un&#39;altra password generata con gli stessi criteri del salt ma le analogie finiscono qua perché:</p>
<ul><li>a differenza del <strong>salt</strong> che si trova nel database, il <strong>pepper</strong> è separato da ques&#39;ultimo. L&#39;ideale sarebbe un <strong>HSM</strong>;</li>
<li>Il <strong>salt</strong> è visibile a tutti, attaccante compreso. Il <strong>pepper</strong> è segreto. Un eventuale data breach che permette all&#39;attaccante di disporre offline di tutto il database degli utenti, “vedrà” certamente gli eventuali salt ma sarà ignaro del fatto che gli mancherà sempre un pezzo di chiave;</li>
<li>il <strong>salt</strong> è diverso per ogni utente, il <strong>pepper</strong>, di solito, è unico;</li>
<li>il <strong>salt</strong> serve a rendere uniche la password degli utenti, il <strong>pepper</strong> protegge l&#39;intero database da attacchi offline.</li></ul>

<p><strong>Il pepper è la chiave di un HMAC, o di un meccanismo di cifratura simmetrica, applicato al digest della password</strong> (che ricordo essere salt+password in realtà), che sarà ciò che verrà archiviato.</p>

<p>Va detto che l&#39;uso del “pepper” complica ulteriormente lo scenario di archiviazione.
Nella stragrande maggioranza dei casi è sufficiente scegliere un buon algoritmo di password hashing (vedi paragrafo successivo) per scoraggiare gli attaccanti.
“Pepare” le password prevederebbe, come detto sopra, l&#39;uso di un HSM per es, e tutta una serie di riflessioni di contorno che evidenzierò più avanti.</p>

<h2 id="final-step-l-hashing">Final step: L&#39;hashing</h2>

<p>L&#39;ultimo punto da dettagliare è l&#39;hash della password.</p>

<p>L&#39;<strong>hash crittografico</strong>, in uso in questi casi, deve soddisfare le seguenti proprietà:</p>
<ol><li><strong>resistenza alla pre-immagine:</strong> dato un hash <em>h</em>, deve essere impossibile trovare una password <em>p</em> t.c. <em>H(p) = h</em> (non invertibilità della funzione hash)</li>
<li><strong>resistenza alla pre-immagine secondaria:</strong> dato una password <em>p<sub>1</sub></em>, deve essere impossibile trovare un&#39;altra password <em>p<sub>2</sub></em> t.c. <em>H(p<sub>1</sub>) = H(p<sub>2</sub>)</em> (resistenza debole alle collisioni)</li>
<li><strong>resistenza alle collisioni:</strong> è impossibile trovare due password diverse, <em>p<sub>1</sub></em> e <em>p<sub>2</sub></em>, t.c. <em>H(p<sub>1</sub>) = H(p<sub>2</sub>)</em> (resistenza forte alle collisioni)</li>
<li><strong>effetto valanga:</strong> il cambio di un solo bit della password deve cambiare radicalmente l&#39;intero hash</li></ol>

<p>In un sistema moderno, l&#39;hash non può essere delegato a funzioni di tipo SHA perché nascono per altri compiti,</p>

<p><strong>SHA-2</strong> e <strong>SHA-3</strong> nascono per il digest veloce, per verificare l&#39;integrità di file anche molto grossi o firmare documenti. La loro eccellente velocità diventa il loro più grosso difetto quando si parla di password.
Negli scenari precedenti di attachi offline, l&#39;hacker che dispone di una grossa potenza di calcolo, può ricostituire velocemente le rainbow table per <em>n</em> utenti. Magari non di tutti ma di quelli attenzionati.</p>

<p>Le funzioni di derivazione della chiave (<strong>KDF</strong>) come <strong>pbkdf2</strong> e quelle ancora più estreme come <strong>B/Scrypt</strong>, <strong>Argon2</strong>, oltre che soddisfare tutti i punti precedentemente elencati tipici di funzioni di password hashing, sono progettate per essere computazionalmente pesantissime da calcolare perché il loro scopo non è il digest ma la protezione di un segreto contro il brute-force.
E mentre le vecchie KDF come <strong>pbdfk2</strong> sono CPU bound, ma non GPU bound, le KDF più moderne come <strong>Bcrypt</strong>, <strong>Scrypt</strong> ma soprattutto <strong>Argon2</strong>, agiscono pesantemente su tempo, memoria e parallelismo e l&#39;attacco offline di cui sopra diventa impraticabile.</p>

<h3 id="pbkdf2">PBKDF2</h3>

<p>È il decano delle KDF. Applica iterativamente una funzione pseudorandomica, come HMAC con uno SHA, con salt alla password.
Il conteggio delle iterazioni è un parametro configurabile.</p>

<p>PBDKF2 è uno standard di lunga data ampiamente adottato. Se non ci sono necessità stringenti di sicurezza o requisiti legacy, è una buona scelta.</p>

<p>Il fatto di essere solo CPU bound però non la rende la scelta ideale in scenari dove gli attaccanti possono attingere a risorse di calcolo considerevoli</p>

<h3 id="bcrypt">Bcrypt</h3>

<p>Basato su Blowfish, anche Bcrypt usa un hash crittografico sulla password con parametri il salt e un fattore di costo.</p>

<p>Il fattore di costo aumenta esponenzialmente il numero di iterazioni per adattarsi all&#39;aumento di potenza di calcolo dell&#39;hardware.</p>

<p>Bcrypt è stato progetto per essere lento e resistente a semplici attacchi di forzat bruta.
Tuttavia, il basso utilizzo di ram richiesto dal calcolo lo rendono poco resistente ad attacchi sferrati usando hardware specializzato.</p>

<p>Bcrypt ha dalla sua una storia solidissima in ragione della quale da 20 anni a questa parte non sono state trovate vulnerabilità critiche nel suo design.</p>

<p>Per questo motivo Bcrypt cifra le password di sistema di OpenBSD dal 1999, come pure ha cifrato quelle di tante distro Linux per anni, prima che passassero ad Argon2 o <strong>yescrypt</strong> (default di Fedora).</p>

<p>Domina nei framework web ([Python] Django, [Ruby] Ruby on Rails, [PHP] Laravel), [Java] Spring, Node.js), nelle applicazioni (Ansible / Terraform, Docker), nel web (la cifratura in .htpasswd di Apache e Nginx) visto che la sua semplcitià di implementazione gli ha permesso di trovarsi praticamente in ogni linguaggio.</p>

<p>È presente come alternativa anche nei password manager benché molti di essi abbiano spostato il default verso Argon2 o PBKDF2 per conformità agli standard FIPS.</p>

<p>È molto semplice implementare e anche da usare perché bisogna agire solo sul <strong>fattore di costo</strong> (consigliato almeno 10-12, altrimenti diventa troppo vulnerabile ad attacchi sferrati attraverso la GPU)</p>

<h3 id="scrypt">Scrypt</h3>

<p>Rilasciato nel 2009, Scrypt è stato il primo algoritmo a introdurre il concetto di <strong>Memory Hardness</strong> ed è stato progettato per rendere economicamente poco conveniente il ricorso ad hardware specializzato come gli ASIC o i FPGA e incidere pesantemente su CPU, ram e parallelismo.</p>

<p>Il suo alveo principale sono state le cripto-valute, molte monete lo usano per il mining.</p>

<p>Scrypt lo troviamo in quasi tutti i linguaggi di programmazione, in <strong>Tarsnap</strong>, servizio di baclup online creato dallo stesso autore di Scrypt, è stato usato da <strong>LastPass</strong> ed è presente come opzione in <strong>VeraCrypt</strong> per derivare la chiave dalla password.
Fino ad Android 9 era l&#39;algoritmo usato per la <strong>FDE</strong> del dispositvio (passato poi al <strong>FBE</strong>) .
Presente anche su FreeBSD come opzione per la cifratura delle password di sistema e come opzione su <strong>LUKS</strong> per la cifratura degli slot delle chiavi.</p>

<p>Su Scrypt i parametri da configurare sono:</p>
<ul><li><strong>Costro CPU/Memoria <em>(N)</em>:</strong> un parametro che aumenta i costi computazionali di cpu e memoria</li>
<li><strong>DImensione del blocco <em>®</em>:</strong> influenza la larghezza di banda della memoria</li>
<li><strong>Parallelizzazione <em>(p)</em>:</strong> indica quanto deve incidere sul calcolo parallelo</li></ul>

<p>In questo modo riesce ad essere sia CPU bound che GPU bound che, a differenza di Bcrypt, lo rende resistente anche ad attacchi facenti uso di hardware specializzato..</p>

<p>Di contro, in ambiente in cui siamo vincolati dalle risorse disponibili, la sua potenza diventa un fattore limitante.
Quasi paragonabile ad Argon2 in quanto a robustezza, il suo unico tallone d&#39;Achille è la permeabilità ad attacchi di tipo <strong>side-channel</strong>.</p>

<h3 id="yescrypt">yescrypt</h3>

<p>Piccola menzione per <strong>yescrypt</strong>, appartenente alla famiglia “Scrypt”, pensato per essere ancora più resistente di Scrypt agli attacchi GPU e FPGA ma con una gestione più intelligente delle risorse.</p>

<p>Grazie alle sue peculiarità, di fatto, è diventato il successore spirituale di Bcrypt nei sistemi operativi gnu/linux dove, a cominciare da Fedora, passando per Debian, Ubuntu, Arch, Kali, è il default per la cifratura delle password di sistema in <code>/etc/shadow</code>.</p>

<p>È talmente incardinato ormai nei sistemi operativi, che è la libreria <code>libxcrypt</code> di <strong>yescrypt</strong> a gestire la tipica funzione <code>crypt()</code> di C che è la base della crittografia su tutti i sistemi gnu/linux moderni.</p>

<p>La sua robustezza unita alla gestione intelligente delle risorse lo rende un coltellino svizzero di riferimento utile per es. per versione custom di LUKS su sistemi embedded, che magari fanno uso di cpu meno recenti,  oppure come opzione per strumenti di backup specialistici</p>

<p>Di fatto, sui sistemi operativi, <strong>yescrypt</strong> s&#39;è guadagnato un consenso amplissimo dovuto alla sua scalabilità, alla sua capacità di usare anche la ROM per rendere il cracking ancora più difficile e senza pesare sulla RAM e alla sua compatibilità potendosi inserire perfettamente nella storica funzione <code>crypt()</code> di C come detto prima.</p>

<p>Se Argon2 è il vincitore accademico avendo vinto il Password Hashing Competition del 2015, <strong>yescrypt</strong> per la sua robustezza, efficienza e flessibilità si ritaglia un profilo di indispensabilità nei sistemi operativi,</p>

<h3 id="argon2">Argon2</h3>

<p>E veniamo al dominatore indiscusso di questa che non è una llista esaustiva di KDF.</p>

<p>Argon2 è LO standard moderno per il password hashing raccomandato da OWASP e IETF.</p>

<p>È il riferimento per praticamente ogni password manager: <strong>Bitwarden</strong>, <strong>KeppasXC</strong>, <strong>1Password</strong>, a cui assegnanp la protezione della <strong>Master Password</strong></p>

<p>È la scelta principale per la cifratura degli hard disk anche con impostazioni molto aggressive, in ragione delle quali un ritardo di mezzo secondo (un tempo enorme se venisse scalato esponenzialmente) nell&#39;apertura di un HD è assolutamente accettabile.
È il default di <strong>LUKS2</strong> (LUKS1 usava PBKDF2) e di <strong>VeraCrypt</strong>, con cui ha sostituito SHA-512.</p>

<p>Come Bcrypt, è implementato estensivamente su praticamente ogni frameword web e backend, da PHP, Django (Python), Laravel fino a Node.js.</p>

<p>Nei sistemi operativi, laddove <strong>yescrytpt</strong> domina nella gestione delle password utente, <strong>Argon2</strong> è usato per compiti più critici.
Dal kernel Linux per gestire internamente le chiavi crittografiche o da macOS / iOS, dove algoritmi proprietari ispirati fortemente ad Argon2, proteggono i dati nel Secure Enclave.</p>

<p>Argon2  setta 3 parametri principali per regolare la sua forza:</p>
<ul><li><strong>t: iterazioni</strong>, quante volte vengono rimescolati i dati <em>(default Bitwarden = 3)</em></li>
<li><strong>m: memoria</strong>, quanta ram deve occupare il calcolo. Questa è la misura anti-GPU <em>(default Bitwarden = 16 (64MB))</em></li>
<li><strong>p: parallelismo</strong>, quanti core della cpu usare. Questa è la misura anti-CPU <em>(default Bitwarden = 4)</em></li></ul>

<p>La variante <em>id</em> è anche resistente agli <strong>attacchi side-channel</strong> perché impediscono a un attaccante di capire la password osservando i tempi di accesso alla memoria.</p>

<h2 id="un-piccolo-esempio-hashing-di-una-password-con-argon2">Un piccolo esempio: hashing di una password con Argon2</h2>

<p>Il grosso vantaggio degli algoritmi di kdf è che sono naturalmente resilienti rispetto all&#39;evoluzione tecnologica che produce macchine con sempre maggiore potenza di calcolo.
Da pbkdf2 in poi, il salt implicito che invalida le rainbow table precalcolate e la possibilità di calibrare il key stretching in moda da agire intensivamente su ram e cpu, permettono all&#39;algoritmo di adeguarsi per conservare la sua robustezza.</p>

<p>Mini-script per l&#39;hashing di una password fornita dall&#39;utente con argon2 settato al default di Bitwarden:</p>

<pre><code class="language-bash">echo -n &#34;Password: &#34;; read -s PASSWORD
# Genero un Salt casuale di 128 bit
SALT=$(openssl rand -base64 128)
PASSWORD_HASH=$(echo &#34;${PASSWORD}&#34; | argon2 &#34;${SALT}&#34; -m 16 -t 3 -p 4 -id -e)
</code></pre>

<p><code>PASSWORD_HASH</code> e <code>SALT</code> sono i dati che verranno archiviati e, poiché argon2 “frulla” la password con un salt, è praticamente impossibile risalire alla password originale.</p>

<p>La verifica è tuttavia banale perché, avendo il salt e la password da verificare, si ricrea l&#39;hash con argon2 e si confronta con l&#39;hash memorizzato.</p>

<p>Per maggior sicurezza salt e digest possono essere memorizzati in punti differenti. L&#39;importante è che possano essere recuperate a partire dall&#39;utente.</p>

<h2 id="gestione-del-pepper">Gestione del pepper</h2>

<p>Col pepper le cose cambiano un pochino perché:</p>
<ul><li>deve essere archiviato con tutte le paranoie possibili in un punto diverso dal database degli utenti</li>
<li>il key rotation del pepper non è banale</li></ul>

<p>Mini-script che mostra come applicare salt e pepper all&#39;hashing di una password:</p>

<pre><code class="language-bash"># L&#39;utente inserisce la password
echo -n &#34;Password: &#34;; read -s PASSWORD

# Genero un Salt casuale di 128 bit unico per ogni utente
SALT=$(openssl rand -base64 128)

# Anche PEPPER sarà qualcosa del tipo &#34;openssl rand -base64 128&#34;
# e si troverà in un punto esterno al database degli utenti.
PEPPER=$(get_pepper_from_ext)

# Digest della password+salt
PASSWORD_HASH=$(echo &#34;${PASSWORD}&#34; | argon2 &#34;${SALT}&#34; -m 16 -t 3 -p 4 -id -e)

# HMAC del digest con PEPPER come chiave
PASSWORD_PEPPER=$(echo &#34;${PASSWORD_HASH}&#34; | openssl dgst -sha256 -hmac &#34;${PEPPER}&#34; -binary | base64)
</code></pre>

<h2 id="hsm">HSM</h2>

<p>Quella vista prima è una versione molto edulcorata di ciò che avviene nella realtà.
Il pepper, non può essere gestito con leggerezza visto che è un segreto che protegge non un singolo oggetto ma intere classi, come db di utenti.</p>

<p>L&#39;apparato che gestisce chiavi di questo tipo e di questa importanza, deve essere robusto, praticamente inattaccabile, quasi completamente isolato dal resto dei sistemi a meno delle applicazioni, e solo di quelle, che hanno il permesso di richiedere una chiave,</p>

<p>Apparati hardware specializzati che assolvono a tutte queste funzioni e anche di più, sono gli <strong>HSM</strong> (<strong>H</strong>ardware <strong>S</strong>ecurity <strong>M</strong>odule) che garantiscono il ciclo di vita delle chiavi, dalla generazione alla distruzione, includendo versionamento, rotazione e backup.
Sono concepiti per resistere anche a manipolazioni forzate che possono innescare un meccanismo di autodistruzione e, particolare rilevante, <strong>le operazioni crittografiche basate sulle chiavi protette vengono svolte dall&#39;hsm che consegna al client il risultato delle operazioni, non le chiavi</strong>. Nel nostro caso, l&#39;HSM dovrebbe restituirci l&#39;hmac del digest della password che gli inviamo.</p>

<h2 id="key-algo-rotation">Key / Algo Rotation</h2>

<p>Cosa succede se cambio pepper o algoritmo (anche la sua configurazione)?
Non avendo disponibilità in alcun modo della password dovrò adottare una strategia ad-hoc.
Fra tutti gli scenari possibili, il miglior compromesso fra sicurezza e comodità secondo me, è quello basato sul wrapping.</p>

<p>È necessario innanzitutto che vengano conservate le versioni delle chiavi per i servizi che le richiedono. E a questo dovrebbe pensarci l&#39;HSM, se ce n&#39;è uno o qualcosa di custom che abbia funzionalità analoghe.
Inoltre dovrebbero esserci dei flag che indichino quali sono gli utenti a cui sono state applicate le nuove configurazioni.</p>

<h3 id="caso-a-algo-rotation">Caso A: Algo rotation</h3>

<p>Supponiamo che <strong>l&#39;algoritmo di hashing venga cambiato</strong> o vengano cambiate le sue configurazioni.</p>

<p><strong>Premessa:</strong>
Nel mio DB degli utenti, in corrispondenza di ogni utente, avrò:</p>
<ol><li>il digest della password “pepato”: <em>HMAC ( pepper, HASH ( salt, password ) )</em></li>
<li>il salt</li></ol>

<p><strong>Il wrapping:</strong>
La strategia sarà quello di “avvolgere” la password di ogni utente col nuovo algoritmo, settare un qualche flag che mi indichi l&#39;operazione compiuta e archiviare il tutto.</p>
<ol><li>Imponiamo il nuovo algoritmo a tutti gli utenti “imbustando” il digest attuale (in questo caso &#39;HMAC in realtà, visto che abbiamo a che fare anche col pepper) con il nuovo digest <em><strong>HASH_NEW</strong></em>:
<em><strong>HASH_NEW</strong> ( <strong>salt_new</strong>, HMAC ( pepper, HASH ( salt, password ) ) )</em>.</li>
<li>Per ogni utente averemo dunque:
<ol><li>il nuovo digest al posto di quello vecchio,</li>
<li>il nuovo salt</li>
<li>il vecchio salt</li></ol></li>
<li>Settiamo il flag del cambio algoritmo a <em>true</em> (o quello che è)</li>
<li>Quando l&#39;utente effettuerà il login con successo e il flag sarà a “<em>true</em>”, abbiamo la password che ci permetterà di eliminare il vecchio “involucro” e ripristinare l&#39;HMAC del nuovo digest: <em>HMAC ( pepper, <strong>HASH_NEW</strong> ( <strong>salt_new</strong>, password ) )</em> e il flag ritornerà a “<em>false</em>“</li></ol>

<p><strong>Considerazioni:</strong></p>
<ul><li>La sicurezza non viene compromessa perché il digest di un digest, con KDF configurate a dovere, non comporta alcun rischio.</li>
<li>La fase di verifica è quella che si complica di più perché in base al valore del flag, dovrà essere effettuata in maniera differente.
<ul><li>Se il flag è “<em>true</em>” (nella nostra convenzione), dopo il login devo avere gli elementi per calcolare il digest in questo modo: <em><strong>HASH_NEW</strong> ( <strong>salt_new</strong>, HMAC ( pepper, HASH ( salt, password ) ) )</em>.</li>
<li>Se il flag è a <em>false</em>, calcolerò al solito: <em>HMAC ( pepper, <strong>HASH_NEW</strong> ( <strong>salt_new</strong>, password ) )</em></li></ul></li></ul>

<h3 id="caso-b-pepper-rotation">Caso B: Pepper rotation</h3>

<p>Supponiamo che a ruotare sia il pepper.
Procediamo sempre con il wrapping massivo su tutti gli utenti incapsulando il digest :</p>

<p><em>HMAC ( pepper, HASH ( salt, password ) )</em></p>

<p>con quello nuovo:</p>

<p><em>HMAC ( <strong>pepper_new</strong>, HMAC ( pepper, HASH ( salt, password ) ) )</em></p>

<p>mettendo il flag a “<em>true</em>”.</p>

<p>Come prima, una volta che gli utenti cominceranno a fare il login, se il flag è “<em>true</em>” innanzitutto verificherò che:</p>

<p><em>HMAC ( <strong>pepper_new</strong>, HMAC ( pepper, HASH ( salt, password ) ) )</em></p>

<p>sia uguale a ciò che è stato archiviato.
Se così fosse, ora che sono di nuovo in possesso della password, ripristinerò l&#39;HMAC con:</p>

<p><em>HMAC ( <strong>pepper_new</strong>, HASH ( salt, password ) )</em></p>

<p>memorizzandolo al posto di quello vecchio e rimettendo il flag a false.</p>

<p><strong>Considerazioni:</strong>
La modifica massiva delle password degli utenti, stavolta passa dall&#39;HSM e potrebbe essere un problema perché un HSM è progettato per scoraggiare flooding di richieste.</p>

<p>È vero che il pepper è sempre lo stesso per tutti gli utenti ma, come ricordavo prima, di solito un HSM non fornisce i suoi segreti ma solo <strong>i risultati crittografici delle loro applicazioni.</strong></p>

<p><a href="/aytin/tag:kdf" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">kdf</span></a> <a href="/aytin/tag:pbkdf2" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">pbkdf2</span></a> <a href="/aytin/tag:bcrypt" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">bcrypt</span></a> <a href="/aytin/tag:scrypt" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">scrypt</span></a> <a href="/aytin/tag:yescrypt" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">yescrypt</span></a> <a href="/aytin/tag:argon2" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">argon2</span></a> <a href="/aytin/tag:luks" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">luks</span></a> <a href="/aytin/tag:cryptography" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">cryptography</span></a> <a href="/aytin/tag:aes" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">aes</span></a> <a href="/aytin/tag:sha" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">sha</span></a> <a href="/aytin/tag:digest" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">digest</span></a> <a href="/aytin/tag:RainbowTable" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">RainbowTable</span></a> <a href="/aytin/tag:BruteForce" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">BruteForce</span></a> <a href="/aytin/tag:salt" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">salt</span></a> <a href="/aytin/tag:pepper" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">pepper</span></a> <a href="/aytin/tag:entropy" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">entropy</span></a> <a href="/aytin/tag:hsm" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">hsm</span></a> <a href="/aytin/tag:hmac" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">hmac</span></a> <a href="/aytin/tag:hash" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">hash</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/archiviare-le-password-in-sicurezza-con-kdf-password-hashing-trilogia-della</guid>
      <pubDate>Thu, 29 Jan 2026 17:49:50 +0000</pubDate>
    </item>
    <item>
      <title>Come valutare la resistenza di una password (Trilogia Della Password - 2 di 3)</title>
      <link>https://noblogo.org/aytin/come-valutare-la-resistenza-di-una-password-trilogia-della-password-2-di-3</link>
      <description>&lt;![CDATA[ent,zxcvb,diceware&#xA;&#xA;In &#34;Come generare una password o un keyfile sicuri&#34; abbiamo visto come generare password e keyfile che si basassero su dati il più possibile casuali.&#xA;La verifica matematica di una password si basa sulla determinazione del numero di tentativi necessari a un attaccante per indovinarla.&#xA;!--more--&#xA;Esistono due approcci: quello teorico (brute force) e quello realistico (pattern matching).&#xA;&#xA;Calcolo teorico (Entropia di Shannon)&#xA;  Spiegazione dell’entropia di Shannon&#xA;  Esempi d’uso&#xA;Calcolo realistico (pattern matching)&#xA;  Ent&#xA;  zxcvbn&#xA;  Riassumendo&#xA;Metodo Diceware&#xA;&#xA;Calcolo teorico (Entropia di Shannon)&#xA;Un primo strumento per la valutazione di una password è dato dall&#39;entropia di Shannon, che chiunque abbia usato un password manager certamente conoscerà.&#xA;&#xA;Questo calcolo assume che l&#39;attaccante non sappia nulla della nostra password e debba provare ogni possibile combinazione (forza bruta).&#xA;&#xA;Dato un alfabeto di R simboli e una password di lunghezza L, l&#39;entropia E sarà pari a: &#xA;&#xA;E = logsub2/sub ( RsupL/sup ) = L  \ logsub2/sub ( R )&#xA;&#xA;L&#39;entropia è un valore numerico espresso in bit (gli &#34;Shannon&#34;) che rappresenta una misura, non tanto della robustezza, quanto della &#34;densità&#34; della password, ossia di quanto lavoro richieda ad un calcolatore per essere indovinata. Più è alta, meglio è.&#xA;Spiegazione dell&#39;entropia di Shannon&#xA;Innanzitutto notiamo che RsupL/sup è la dimensione dello spazio di possibilità in cui esiste la mia password e, per R e L sufficientemente grandi, è un numero talmente enorme da essere difficilmente comprensibile.&#xA;&#xA;L&#39;equivalente E, che non è altro che l&#39;esponente della potenza di 2 tale per cui 2supE/sup = RsupL/sup, risulta invece molto più gestibile e confrontabile.&#xA;&#xA;Semplificando, se alla mia password lunga L corrisponde quindi un&#39;analoga chiave in bit lunga E, un attaccante che voglia scoprire la mia password, invece che indovinare gli L simboli da un alfabeto R, compirà lo stesso sforzo rispondendo correttamente ad un numero di domande binarie (SI / NO) pari a E, per ricostruire la giusta sequenza binaria.&#xA;&#xA;Quanto costa ricostruire la sequenza?&#xA;O, in altre parole, qual è lo sforzo computazionale richiesto?&#xA;&#xA;Si parla di  caso medio ottimale corrispondente ad una ricerca binaria in cui ogni domanda dimezza lo spazio di possibilità fino ad azzerarlo completamente.&#xA;&#xA;E = L \ logsub2/sub ( R ), è quel numero di bit che mi dice quant&#39;è profondo l&#39;albero delle decisioni che il calcolatore deve percorrere, albero in cui il numero dei possibili cammini radice-foglia (equivalenti a tutte le possibili password) è 2supE/sup = RsupL/sup.&#xA; &#xA;Nel caso migliore, rispondo correttamente a tutte le E domande al primo tentativo (trovo subito il mio cammino sull&#39;albero).&#xA;Nel caso peggiore, mi occorreranno 2supE/sup risposte (percorro tutti i cammini dell&#39;albero) equivalente proprio a RsupL/sup.&#xA;&#xA;Possiamo allora definire formalmente l&#39;entropia come quella quantità minima di informazione necessaria ad azzerare l&#39;incertezza legata all&#39;identificazione della password. Per questo motivo è espressa in bit.&#xA;&#xA;Una misurazione di questo tipo ha senso solo se ipotizziamo che i simboli siano tutti equiprobabili.&#xA;&#xA;La formula di Shannon misura, sì, l&#39;entropia, ma al suo massimo potenziale, quando la distribuzione dei simboli nella sequenza è omogenea e assolutamente casuale.&#xA;Esempi d&#39;uso&#xA;Facciamo l&#39;esempio di una password lunga 20, costruita su un alfabeto di 66 simboli (alfanumerico con maiuscole e minuscole più 4 simboli speciali).&#xA;La dimensione di questo spazio di possibilità è pari a:&#xA;&#xA;Ssubp/sub = RsupL/sup = 66sup20/sup = 2,46 \ 10sup36/sup&#xA;&#xA;Tentare un attacco di forza bruta su un oggetto del genere è semplicemente impensabile.&#xA;Faccio un esempio.&#xA;&#xA;Per forzare la nostra password, supponiamo di avere a disposizione il più potente supercomputer del mondo, El Capitan ad oggi, dotato di una potenza di calcolo spaventosa, in media 2.000 exaFLOPS con picchi di 2.746 exaFLOPS, dove 1 exaFLOPS è un quintilione (10sup18/sup) di operazioni al secondo.&#xA;&#xA;Il calcolo di una password si misura in Hash al secondo, H/s per usare una notazione compatta, che è più dispendiosa della singola operazione.&#xA;&#xA;Approssimando per eccesso con molto ottimismo e nell&#39;ipotesi di usare algoritmi estrememente deboli e poco costosi dal punto di vista computazionale come NTLM o MD5, possiamo pensare che il nostro sistema possa arrivare a calcolare, in queste condizioni, circa 1,5 quintilioni  ( 1,5 \ 10sup18/sup ) H/s.&#xA;Per algoritmi come bcrypt o argon2, progettati per essere molto dispendiosi, tale potenza si riduce drasticamente di molti ordini di grandezza. Da 10sup18/sup a 10sup9/sup - 10sup6/sup. Ma consideriamo il caso più favorevole perché sembra appunto una potenza enorme.&#xA;&#xA;Ma anche questa tremenda esibizione di potenza annichilisce di fronte al numero di calcoli da compiere nel nosro spazio di possibilità.&#xA;Dato Ssubp/sub lo spazio di possibilità (il numero di possibili combinazioni), il tempo T espresso in secondi necessario ad eseguire tutte le operazioni sarà:&#xA;&#xA;Ssubp/sub = 66sup20/sup = 2,46 \ 10sup36/sup&#xA;&#xA;T = 2,46 \ sup36/sup / 1,5 \ 10sup18/sup = 1,64 \ 10sup18/sup&#xA;&#xA;Che equivale a circa 52 miliardi di anni.&#xA;&#xA;Per avere un&#39;idea di questa grandezza cosmica, si pensi che l&#39;età del nostro universo è di circa 13,8 miliardi di anni. Quindi il calcolo della nostra password potrebbe richiedere un tempo che è grossomodo 3,8 volte l&#39;età dell&#39;universo.&#xA;&#xA;I 120 bit di entropia, sono dunque la misura di questo sforzo potenziale, interpretabile equivalentemente in due modi differenti:&#xA;&#xA;la probabilità di riuscire a trovare la password tirando a indovinare, probabilità che è 1 su 2sup120/sup&#xA;&#xA;oppure&#xA;&#xA;la capacità di rispondere correttamente e consecutivamente a 120 domande di tipo (SI / NO) (ricerca del giusto cammino in un albero decisionale binario profondo 120 livelli)&#xA;&#xA;Allungando la nostra password di altri due caratteri, l&#39;entropia arriva a circa 133 e il calcolo delle possibili combinazioni, posto che fosse possibile ignorando le leggi della termodinamica, richiederebbe circa 16.500 di volte l&#39;età dell&#39;universo.&#xA;&#xA;Considerazione a margine: è la lunghezza della password ad incidere più che la complessità dell&#39;alfabeto. E lo vediamo dalla formula dell&#39;entropia, perché, in una funzione di elevamento a potenza RsupL/sup, aumentare l&#39;esponente L fa crescere molto più rapidamente la funzione che non aumentando la base R.&#xA;Calcolo realistico (pattern matching)&#xA;L&#39;entropia di Shannon fornisce un riscontro utilizzabile solo ipotizzando che:&#xA;&#xA;le scelte siano indipendenti &#xA;la distribuzione sia uniforme&#xA;&#xA;e in uno scenario di questo tipo, l&#39;attacco di forza bruta non è una via percorribile.&#xA;&#xA;Allo stesso tempo, se non vengono rispettati questi vincoli, l&#39;entropia dà una falsa sicurezza perché la formula di Shannon &#34;standard&#34; non tiene conto della ridondanza:&#xA;&#xA;Consideriamo questa password: Password12345678&#xA;&#xA;teoria: la formula E = L  log2R direbbe che la sua entropia sia 95, ottima.&#xA;realtà: poiché è una sequenza ovvia, l&#39;attaccante la proverà per prima. La sua entropia reale sarà vicina a 0 bit.&#xA;&#xA;L&#39;entropia quindi misura la &#34;densità&#34; della password, la sua imprevedibilità potenziale ma non dà nessuna informazione sulla presenza di schemi ripetuti e sul pattern matching.&#xA;&#xA;Ent&#xA;L&#39;essere umano come generatore di entropia fa schifo.&#xA;Ecco perché, per un attaccante, prima ancora di provare tutte le possibili combinazioni di caratteri, un attacco a dizionario può far risparmiare un sacco di tempo.&#xA;Infatti sempre Shannon ci dice che nelle parole dei linguaggi naturali alcune lettere ricorrono più di altre, non serve lo stesso numero di domanda ma molto meno e così l&#39;entropia media diminuisce.&#xA;Per prevenire questi effetti collaterali, il nostro metodo di generazione e quindi ciò che viene generato, deve essere testato con qualcos&#39;altro che non sia la semplice entropia.&#xA;&#xA;ent è un tool a linea di comando che fa 4 valutazioni differenti:&#xA;&#xA;entropia&#xA;Chi-quadrato&#xA;Media aritmetica&#xA;Monte Carlo Pi&#xA;&#xA;N.B. ent non è adatto alla valutazione della singola password perché ha bisogno di migliaia di dati (almeno 1K). Una singola password di 24 caratteri per es. (24 byte) non ha materiale casuale sufficiente affinché ent converga verso un giudizio oggettivo.&#xA;&#xA;Entropia&#xA;L&#39;entropia misura la densità di informazione. In ent, viene calcolata in bit per carattere (byte).&#xA;&#xA;Il valore: Si analizza il file byte per byte, il valore massimo è 8.0 (ogni byte è totalmente imprevedibile).&#xA;Interpretazione: Più il valore è vicino a 8, più la casualità è &#34;densa&#34; e difficile da indovinare tramite attacchi basati su dizionario. Se il valore è basso (es. 2.0 o 3.0), significa che ci sono molte ripetizioni o uno schema prevedibile.&#xA;Compressione: ent ti dice anche quanto il file potrebbe essere compresso. Un&#39;entropia di 8.0 significa che il file è già &#34;puro caos&#34; e non può essere compresso ulteriormente.&#xA;&#xA;Chi-quadrato&#xA;Il test del chi-quadrato prova a capire se il disordine presente nel file sia veramente equo o se si preferiscono certi caratteri ad altri. Esamina la distribuzione dei caratteri e la confronta con una distribuzione uniforme teorica. Il risultato viene presentato come percentuale con questi scaglioni:&#xA;&#xA;10% \ chi&lt;sup2/sup \&lt; 90%: La sequenza è considerata casuale. Il 50% è il valore &#34;perfetto&#34;.&#xA;chisup2/sup \ 1% o chi&lt;sup2/sup \  99%: È quasi certamente non casuale.&#xA;&#x9;chisup2/sup = 99.99%: i dati sono sospettosamente regolari;&#xA;&#x9;chisup2/sup = 0.01%: i dati sono &#34;troppo&#34; casuali per essere naturali (sospetta manipolazione)&#xA;&#xA;Media aritmetica&#xA;Per capire se la distribuzione è sufficientemente omogenea, si fa la somma dei valori dei byte del file e si fa una media.&#xA;&#xA;Poiché i byte vanno da 0 a 255, il valore ideale della media sarebbe 127,5.&#xA;Se è troppo lontano dalla media avvcinandosi ad uno dei due estremi (ad es. 50 o 190), vuol dire che si sta usando solo un piccola parte dei caratteri a disposizione e questo, a suo modo di vedere, rende le password più prevedibili.&#xA;&#xA;Monte Carlo Pi&#xA;È il metodo più fantasioso di tutti.&#xA;I dati casuali vengono trasformati in una serie di &#34;dardi&#34; virtuali che vanno a colpire un bersaglio. L&#39;obiettivo non è quello di colpire un ipotico centro ma di verificare che i &#34;dardi&#34; si distribuiscano uniformemente nel bersaglio.&#xA;&#xA;Tutto ciò si realizza immaginando di avere un quadrato 1x1 e 1/4 di cerchio al suo interno di raggio 1 e area π/4&#xA;I dati della sequenza casuale vengono prelevati a gruppi di n byte e supponiamo n = 3 per ora.&#xA;Ogni gruppo di 3 byte sarà un numero compreso tra 0 e 2sup24/sup-1.&#xA;Se normalizziamo questo numero dividendolo per  2sup24/sup, otteniamo un numero compreso fra 0 e 1.&#xA;Calcolando le coordinate in questo modo, col teorema di Pitagora possiamo verificare se la coordinata (X,Y) &#34;cada&#34; nel quarto di cerchio oppure no e ciò succede se:&#xA;&#xA;Xsup2/sup + Ysup2/sup ≤ 1&#xA;&#xA;Lanciando un migliaio di queste &#34;frecce&#34;, accumuliamo dati sufficiente per fare una stima.&#xA;&#xA;Se indichiamo con In il numero di &#34;lanci&#34; con successo e con Total il numero totale di lanci effettuati:&#xA;&#xA;4 \ (ln/Total) si avvicinerà a π solo se la distribuzione dei caratteri sarà uniforme (indice di una casualità omogenea), altrimenti divergerà in maniera significativa (indice della presenza di pattern o di ripetizioni).&#xA;&#xA;zxcvbn&#xA;ent fa un&#39;analisi statistica della distribuzione dei bit in un generatore di casualità.&#xA;&#xA;zxcvbn invece fa un&#39;analisi di tipo euristico, è verticale sulla verifica delle password in particolare nel rilevare se vi sono schemi o ripetizioni di caratteri che renderebbero le password violabili.&#xA;&#xA;Il suo algoritmo scompone le password in pezzi dei quali cerca corrispondenze in dizionari o schemi come:&#xA;&#xA;dizionari: controlla la presenza di parole di uso comune&#xA;sequenze: controlla la presenza di serie di caratteri prevedibili come &#34;123456&#34;, &#34;abcde&#34;&#xA;pattern spaziali: controlla la presenza di percorsi sulla tastiera come &#34;qwerty&#34;, &#34;asdfg&#34;, &#34;zcvbn&#34; o sequenze diagonali&#xA;ripetizioni: ripetizione di caratteri come &#34;kkkkkkkkkk&#34; o &#34;12121212&#34;&#xA;l33t: una parola come &#34;p4$$w0rd&#34; viene subito riconosciuta come &#34;password&#34;&#xA;date: riconosce giorni, mesi, anni, anche composti come &#34;15062026&#34;&#xA;&#xA;Il suo uso è molto semplice.&#xA;Le si dà in pasto la password e zxcvbn restituisce diverse informazioni utili:&#xA;&#xA;uno score da &#34;0&#34; (terribile) a &#34;4 (ottima);&#xA;la stima di quanto tempo impiegherebbe un hacker a violarla in base a vari scenari di attacco;&#xA;suggerimenti su come migliorare eventualmente la password.&#xA;&#xA;zxcvbn era una libreria javascript orginariamente sviluppata da Dropbox e ora disponibile in tante forme: go, python, c++.&#xA;&#xA;L&#39;originale Dropbox in javascript, non più manutenuto, può essere trovata qui: https://github.com/dropbox/zxcvbn.&#xA;&#xA;Benché esistano diversi porting in python, se c&#39;è l&#39;esigenza di usare la versione legacy, gli stessi sviluppatori dell&#39;originale zxcvbn consigliano questa versione: https://github.com/dwolfhub/zxcvbn-python, che può essere installata con pip.&#xA;&#xA;In realtà la versione migliore è un fork in typescript, zxcvbn-ts che offre modularità (a differenza della versione python che è monolitica), maggior sicurezza, risoluzione di bug, aggiornamento continuo dizionari compresi.&#xA;&#xA;Per capirci, mentre ent usa l&#39;entropia di Shannon per valutare la probabilità statistica dei byte, zxcvbn cerca di calcolare una stima dei tempi necessari per indovinare la password.&#xA;&#xA;Una passphrase su ent avrebbe un punteggio risibile perché le entropie di parole comuni sono molto basse. Su zxcvbn invece avrebbe un punteggio molto alto perché l&#39;entropia di una parola viene calcolata sulla posizione del dizionario che la contiene per cui un hacker dovrebbe provare milioni di combinazioni prima di trovarla.&#xA;&#xA;Allo stesso modo, password che per ent sarebbero ottime, per zxcvbn sarebbero da evitare perché legate a pattern o a ripetizioni.&#xA;&#xA;Riassumendo&#xA;Se si deve testare una password / passphrase, sicuramente zxcvbn.&#xA;Se si deve testare un generatore di casualità o un keyfile di almeno 2k, sicuramente ent.&#xA;&#xA;Metodo Diceware&#xA;Visto che nell&#39;ultima parte abbiamo evidenziato l&#39;anomalia che sorge nel momento in cui si valuta un oggetto casuale o dal punto di vista puramente statistico o dal punto di vista euristico, vale la pena di spendere due parole sulla modalità di creazione delle passphrase usando il metodo Diceware.&#xA;&#xA;Usando come password parole estratte dal linguaggio naturale bisogna fare i conti col problema della prevedibilità.&#xA;Shannon ha dimostrato che la lingua italiana (o inglese) ha un&#39;entropia molto bassa (circa 1-1.5 bit per lettera) perché dopo una &#34;q&#34; ci si aspetta quasi sempre una &#34;u&#34;, e dopo un soggetto ci si aspetta un verbo. E così via.&#xA;Ecco perché, piuttosto che valutare l&#39;entropia nel suo complesso e provare ogni possibile combinazione, un moderno calcolatore inzia col far ricorso a &#34;pattern&#34; umani per violare password in pochi minuti invece che millenni.&#xA;&#xA;Per unire la sicurezza del calcolo casuale alla comodità di una password menmonica, si ricorre al metodo Diceware che consiste nel far uso di un dizionario di migliaia di parole.&#xA;&#xA;Quello classico, di 7776 parole inglesi, curato dall EFF si può trovare qui:&#xA;curl -L https://www.eff.org/files/2016/07/18/efflargewordlist.txt   dicdiceware.txt&#xA;Altrimenti Tarin Gamberini espone il suo dizionario diceware , aggiornato al 2019, qui: https://www.taringamberini.com/downloads/dicewareitIT/lista-di-parole-diceware-in-italiano/4/wordlistdicewareit-IT-4.txt.&#xA;&#xA;Questo dizionario contiene 6sup5/sup parole numerate da 11111 a 66666.&#xA;La passphrase è composta da n di queste parole il cui indice è ricavato lanciando un dado (o un analogo virtuale) per 5 volte.&#xA;In questo modo le parole non sono correlate fra di loro come si potrebbero trovare in una frase, vanificando ogni possibile speculazione sulla sua composizione.&#xA;&#xA;Volendo fare un calcolo dell&#39;entropia, supponendo di costruire una passphrase di 6 parole:&#xA;&#xA;E = L \ logsub2/sub R = 6 \ logsub2/sub 7776 ~ 77,6 &#xA;&#xA;Nella password classiche basate su un alfabeto di R simboli, il mattoncino è rappresentato dal singolo carattere che ha una probabilità 1/R di essere estratto.&#xA;&#xA;Con Diceware, il mattoncino è la parola che ha una probabilità su 7776 di essere estratta. Ogni parola in più, aggiunge una quantità enorme di incertezza.&#xA;&#xA;Ecco perché con sole 6 parole abbiamo già una passphrase molto robusta e con 10 parole siamo di fronte ad una passphrase inattacabile, almeno dal punto di vista dell&#39;analisi statistica (E   129_) e imperforabile anche ricorrendo ad analisi euristiche.&#xA;&#xA;Regola aurea: la scelta delle parole deve essere realmente casuale e non seguire regole grammaticali o preferenze personali. Altrimenti sarà un gioco da ragazzi violarla con un approccio a-là zxcvbn.&#xA;&#xA;#entropy #shannon #bruteforce #ent #zxcvbn #diceware #passphrase #PatternMatching]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/ffe7c43a6-a8b5f2/dgaPhFXQtnxH/E2m9YHqhOVs4GDAjNBVqJmqOE2yoFdq8S1IjuD96.jpg" alt="ent,zxcvb,diceware"></p>

<p>In <a href="https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di" rel="nofollow">“Come generare una password o un keyfile sicuri”</a> abbiamo visto come generare password e keyfile che si basassero su dati il più possibile casuali.
La verifica matematica di una password si basa sulla determinazione del numero di tentativi necessari a un attaccante per indovinarla.

Esistono due approcci: quello teorico (<strong>brute force</strong>) e quello realistico (<strong>pattern matching</strong>).</p>
<ul><li><a href="#calcolo-teorico-entropia-di-shannon" rel="nofollow">Calcolo teorico (Entropia di Shannon)</a>
<ul><li><a href="#spiegazione-dell-entropia-di-shannon" rel="nofollow">Spiegazione dell’entropia di Shannon</a></li>
<li><a href="#esempi-d-uso" rel="nofollow">Esempi d’uso</a></li></ul></li>
<li><a href="#calcolo-realistico-pattern-matching" rel="nofollow">Calcolo realistico (pattern matching)</a>
<ul><li><a href="#ent" rel="nofollow">Ent</a></li>
<li><a href="#zxcvbn" rel="nofollow">zxcvbn</a></li>
<li><a href="#riassumendo" rel="nofollow">Riassumendo</a></li></ul></li>
<li><a href="#metodo-diceware" rel="nofollow">Metodo Diceware</a></li></ul>

<h2 id="calcolo-teorico-entropia-di-shannon">Calcolo teorico (Entropia di Shannon)</h2>

<p>Un primo strumento per la valutazione di una password è dato dall&#39;<strong>entropia di Shannon</strong>, che chiunque abbia usato un password manager certamente conoscerà.</p>

<p>Questo calcolo assume che l&#39;attaccante non sappia nulla della nostra password e debba provare ogni possibile combinazione (forza bruta).</p>

<p>Dato un alfabeto di <em>R</em> simboli e una password di lunghezza <em>L</em>, l&#39;entropia <em>E</em> sarà pari a:</p>

<p><em>E = log<sub>2</sub></em> ( <em>R<sup>L</sup></em> ) <em>= L  * log<sub>2</sub></em> ( <em>R</em> )</p>

<p>L&#39;entropia è un valore numerico espresso in bit (gli “Shannon”) che <strong>rappresenta una misura, non tanto della robustezza, quanto della “densità” della password</strong>, ossia di quanto lavoro richieda ad un calcolatore per essere indovinata. Più è alta, meglio è.</p>

<h3 id="spiegazione-dell-entropia-di-shannon">Spiegazione dell&#39;entropia di Shannon</h3>

<p>Innanzitutto notiamo che <em>R</em><sup>L</sup> è la <strong>dimensione dello spazio di possibilità in cui esiste la mia password</strong> e, per <em>R</em> e <em>L</em> sufficientemente grandi, è un numero talmente enorme da essere difficilmente comprensibile.</p>

<p>L&#39;equivalente <em>E</em>, che non è altro che l&#39;esponente della potenza di 2 tale per cui <em>2<sup>E</sup> = R<sup>L</sup></em>, risulta invece molto più gestibile e confrontabile.</p>

<p>Semplificando, se alla mia password lunga <em>L</em> corrisponde quindi un&#39;analoga chiave in bit lunga <em>E</em>, un attaccante che voglia scoprire la mia password, invece che indovinare gli <em>L</em> simboli da un alfabeto <em>R</em>, compirà lo stesso sforzo rispondendo correttamente ad un numero di <strong>domande binarie (SI / NO)</strong> pari a <em>E</em>, per ricostruire la giusta sequenza binaria.</p>

<p>Quanto costa ricostruire la sequenza?
O, in altre parole, qual è lo sforzo computazionale richiesto?</p>

<p>Si parla di  <strong>caso medio ottimale</strong> corrispondente ad una ricerca binaria in cui <strong>ogni domanda dimezza</strong> lo spazio di possibilità fino ad azzerarlo completamente.</p>

<p><em>E = L * log<sub>2</sub></em> ( <em>R</em> ), è quel numero di bit che mi dice <strong>quant&#39;è profondo</strong> l&#39;albero delle decisioni che il calcolatore deve percorrere, albero in cui il numero dei possibili cammini radice-foglia (equivalenti a tutte le possibili password) è <em>2<sup>E</sup> = R<sup>L</sup></em>.</p>
<ul><li>Nel <strong>caso migliore</strong>, rispondo correttamente a <strong>tutte le <em>E</em> domande</strong> al primo tentativo (trovo subito il mio cammino sull&#39;albero).</li>
<li>Nel <strong>caso peggiore</strong>, mi occorreranno <em>2<sup>E</sup></em> risposte (percorro tutti i cammini dell&#39;albero) equivalente proprio a <em>R<sup>L</sup></em>.</li></ul>

<p>Possiamo allora definire formalmente l&#39;entropia come <strong>quella quantità minima di informazione necessaria ad azzerare l&#39;incertezza legata all&#39;identificazione della password</strong>. Per questo motivo è espressa in bit.</p>

<p>Una misurazione di questo tipo <strong>ha senso solo se ipotizziamo che i simboli siano tutti equiprobabili</strong>.</p>

<p>La formula di Shannon misura, sì, l&#39;entropia, ma <strong>al suo massimo potenziale</strong>, quando la distribuzione dei simboli nella sequenza è omogenea e assolutamente casuale.</p>

<h3 id="esempi-d-uso">Esempi d&#39;uso</h3>

<p>Facciamo l&#39;esempio di una password lunga 20, costruita su un alfabeto di 66 simboli (alfanumerico con maiuscole e minuscole più 4 simboli speciali).
La dimensione di questo spazio di possibilità è pari a:</p>

<p><em>S<sub>p</sub> = R<sup>L</sup> = 66<sup>20</sup> = 2,46 * 10<sup>36</sup></em></p>

<p>Tentare un attacco di forza bruta su un oggetto del genere è semplicemente impensabile.
Faccio un esempio.</p>

<p>Per forzare la nostra password, supponiamo di avere a disposizione il più potente supercomputer del mondo, <strong>El Capitan</strong> ad oggi, dotato di una potenza di calcolo spaventosa, in media 2.000 exaFLOPS con picchi di 2.746 exaFLOPS, dove 1 exaFLOPS è <strong>un quintilione (10<sup>18</sup>) di operazioni al secondo</strong>.</p>

<p>Il calcolo di una password si misura in <strong>Hash al secondo</strong>, H/s per usare una notazione compatta, che è più dispendiosa della singola operazione.</p>

<p>Approssimando per eccesso con molto ottimismo e nell&#39;ipotesi di usare algoritmi estrememente deboli e poco costosi dal punto di vista computazionale come <strong>NTLM</strong> o <strong>MD5</strong>, possiamo pensare che il nostro sistema possa arrivare a calcolare, in queste condizioni, circa <strong>1,5 quintilioni</strong>  ( 1,5 * 10<sup>18</sup> ) <strong>H/s</strong>.
Per algoritmi come <strong>bcrypt</strong> o <strong>argon2</strong>, progettati per essere molto dispendiosi, tale potenza si riduce drasticamente di molti ordini di grandezza. Da 10<sup>18</sup> a 10<sup>9</sup> – 10<sup>6</sup>. Ma consideriamo il caso più favorevole perché sembra appunto una potenza enorme.</p>

<p>Ma anche questa tremenda esibizione di potenza annichilisce di fronte al numero di calcoli da compiere nel nosro spazio di possibilità.
Dato <em>S<sub>p</sub></em> lo spazio di possibilità (il numero di possibili combinazioni), il tempo <em>T</em> espresso in secondi necessario ad eseguire tutte le operazioni sarà:</p>

<p><em>S<sub>p</sub> = 66<sup>20</sup> = 2,46 * 10<sup>36</sup></em></p>

<p><em>T = 2,46 * <sup>36</sup> / 1,5 * 10<sup>18</sup> = 1,64 * 10<sup>18</sup></em></p>

<p>Che equivale a circa <strong>52 miliardi di anni</strong>.</p>

<p>Per avere un&#39;idea di questa grandezza cosmica, si pensi che l&#39;età del nostro universo è di circa <strong>13,8 miliardi di anni.</strong> Quindi il calcolo della nostra password potrebbe richiedere un tempo che è grossomodo <strong>3,8 volte l&#39;età dell&#39;universo</strong>.</p>

<p>I 120 bit di entropia, sono dunque <strong>la misura di questo sforzo potenziale</strong>, interpretabile equivalentemente in due modi differenti:</p>
<ul><li>la <strong>probabilità</strong> di riuscire a trovare la password tirando a indovinare, probabilità che è 1 su 2<sup>120</sup></li></ul>

<p>oppure</p>
<ul><li>la <strong>capacità</strong> di rispondere <strong>correttamente e consecutivamente</strong> a 120 domande di tipo (SI / NO) (ricerca del giusto cammino in un albero decisionale binario profondo <strong>120 livelli</strong>)</li></ul>

<p>Allungando la nostra password di altri due caratteri, l&#39;entropia arriva a circa 133 e il calcolo delle possibili combinazioni, posto che fosse possibile ignorando le leggi della termodinamica, richiederebbe circa <strong>16.500 di volte l&#39;età dell&#39;universo</strong>.</p>

<p><strong>Considerazione a margine:</strong> è la lunghezza della password ad incidere più che la complessità dell&#39;alfabeto. E lo vediamo dalla formula dell&#39;entropia, perché, in una funzione di elevamento a potenza <em>R<sup>L</sup></em>, aumentare l&#39;esponente <em>L</em> fa crescere molto più rapidamente la funzione che non aumentando la base <em>R</em>.</p>

<h2 id="calcolo-realistico-pattern-matching">Calcolo realistico (pattern matching)</h2>

<p>L&#39;entropia di Shannon fornisce un riscontro utilizzabile solo ipotizzando che:</p>
<ul><li>le scelte siano indipendenti</li>
<li>la distribuzione sia uniforme</li></ul>

<p>e in uno scenario di questo tipo, l&#39;attacco di forza bruta non è una via percorribile.</p>

<p>Allo stesso tempo, se non vengono rispettati questi vincoli, l&#39;entropia dà una falsa sicurezza perché la formula di Shannon “standard” non tiene conto della ridondanza:</p>

<p>Consideriamo questa password: <code>Password12345678</code></p>
<ul><li><strong>teoria</strong>: la formula <em>E = L * log2R</em> direbbe che la sua entropia sia 95, ottima.</li>
<li><strong>realtà</strong>: poiché è una sequenza ovvia, l&#39;attaccante la proverà per prima. La sua entropia reale sarà vicina a <strong>0 bit</strong>.</li></ul>

<p>L&#39;entropia quindi misura la “densità” della password, la sua imprevedibilità potenziale ma non dà nessuna informazione sulla presenza di schemi ripetuti e sul <strong>pattern matching</strong>.</p>

<h3 id="ent">Ent</h3>

<p>L&#39;essere umano come generatore di entropia fa schifo.
Ecco perché, per un attaccante, prima ancora di provare tutte le possibili combinazioni di caratteri, un attacco a dizionario può far risparmiare un sacco di tempo.
Infatti sempre Shannon ci dice che nelle parole dei linguaggi naturali alcune lettere ricorrono più di altre, non serve lo stesso numero di domanda ma molto meno e così l&#39;entropia media diminuisce.
Per prevenire questi effetti collaterali, il nostro metodo di generazione e quindi ciò che viene generato, deve essere testato con qualcos&#39;altro che non sia la semplice entropia.</p>

<p><code>ent</code> è un tool a linea di comando che fa 4 valutazioni differenti:</p>
<ul><li>entropia</li>
<li>Chi-quadrato</li>
<li>Media aritmetica</li>
<li>Monte Carlo Pi</li></ul>

<p><strong>N.B.</strong> <code>ent</code> non è adatto alla valutazione della singola password perché ha bisogno di migliaia di dati (almeno 1K). Una singola password di 24 caratteri per es. (24 byte) non ha materiale casuale sufficiente affinché <code>ent</code> converga verso un giudizio oggettivo.</p>

<p><strong>Entropia</strong>
L&#39;entropia misura la densità di informazione. In ent, viene calcolata in bit per carattere (byte).</p>
<ul><li><strong>Il valore</strong>: Si analizza il file byte per byte, il valore massimo è 8.0 (ogni byte è totalmente imprevedibile).</li>
<li><strong>Interpretazione</strong>: Più il valore è vicino a 8, più la casualità è “densa” e difficile da indovinare tramite attacchi basati su dizionario. Se il valore è basso (es. 2.0 o 3.0), significa che ci sono molte ripetizioni o uno schema prevedibile.</li>
<li><strong>Compressione</strong>: ent ti dice anche quanto il file potrebbe essere compresso. Un&#39;entropia di 8.0 significa che il file è già “puro caos” e non può essere compresso ulteriormente.</li></ul>

<p><strong>Chi-quadrato</strong>
Il test del chi-quadrato prova a capire se il disordine presente nel file sia veramente equo o se si preferiscono certi caratteri ad altri. Esamina la distribuzione dei caratteri e la confronta con una distribuzione uniforme teorica. Il risultato viene presentato come percentuale con questi scaglioni:</p>
<ul><li><strong>10% &lt; chi<sup>2</sup> &lt; 90%</strong>: La sequenza è considerata casuale. Il 50% è il valore “perfetto”.</li>
<li><strong>chi<sup>2</sup> &lt; 1% o chi<sup>2</sup> &gt; 99%</strong>: È quasi certamente non casuale.
<ul><li><strong>chi<sup>2</sup> = 99.99%</strong>: i dati sono sospettosamente regolari;</li>
<li><strong>chi<sup>2</sup> = 0.01%</strong>: i dati sono “troppo” casuali per essere naturali (sospetta manipolazione)</li></ul></li></ul>

<p><strong>Media aritmetica</strong>
Per capire se la distribuzione è sufficientemente omogenea, si fa la somma dei valori dei byte del file e si fa una media.</p>

<p>Poiché i byte vanno da 0 a 255, il valore ideale della media sarebbe 127,5.
Se è troppo lontano dalla media avvcinandosi ad uno dei due estremi (ad es. 50 o 190), vuol dire che si sta usando solo un piccola parte dei caratteri a disposizione e questo, a suo modo di vedere, rende le password più prevedibili.</p>

<p><strong>Monte Carlo Pi</strong>
È il metodo più fantasioso di tutti.
I dati casuali vengono trasformati in una serie di “dardi” virtuali che vanno a colpire un bersaglio. L&#39;obiettivo non è quello di colpire un ipotico centro ma di verificare che i “dardi” si distribuiscano uniformemente nel bersaglio.</p>

<p>Tutto ciò si realizza immaginando di avere un quadrato <em>1x1</em> e ¼ di cerchio al suo interno di raggio 1 e area π/4
I dati della sequenza casuale vengono prelevati a gruppi di <em>n</em> byte e supponiamo <em>n = 3</em> per ora.
Ogni gruppo di 3 byte sarà un numero compreso tra <em>0 e 2<sup>24</sup>-1</em>.
Se normalizziamo questo numero dividendolo per  <em>2<sup>24</sup></em>, otteniamo un numero compreso fra 0 e 1.
Calcolando le coordinate in questo modo, col teorema di Pitagora possiamo verificare se la coordinata (X,Y) “cada” nel quarto di cerchio oppure no e ciò succede se:</p>

<p><em>X<sup>2</sup> + Y<sup>2</sup> ≤ 1</em></p>

<p>Lanciando un migliaio di queste “frecce”, accumuliamo dati sufficiente per fare una stima.</p>

<p>Se indichiamo con <em>In</em> il numero di “lanci” con successo e con <em>Total</em> il numero totale di lanci effettuati:</p>

<p><em>4 * (ln/Total)</em> si avvicinerà a π solo se la distribuzione dei caratteri sarà uniforme (indice di una casualità omogenea), altrimenti divergerà in maniera significativa (indice della presenza di pattern o di ripetizioni).</p>

<h3 id="zxcvbn">zxcvbn</h3>

<p><code>ent</code> fa un&#39;analisi statistica della distribuzione dei bit in un generatore di casualità.</p>

<p><code>zxcvbn</code> invece fa un&#39;analisi di tipo euristico, è verticale sulla verifica delle password in particolare nel rilevare se vi sono schemi o ripetizioni di caratteri che renderebbero le password violabili.</p>

<p>Il suo algoritmo scompone le password in pezzi dei quali cerca corrispondenze in dizionari o schemi come:</p>
<ul><li><strong>dizionari</strong>: controlla la presenza di parole di uso comune</li>
<li><strong>sequenze</strong>: controlla la presenza di serie di caratteri prevedibili come “123456”, “abcde”</li>
<li><strong>pattern spaziali</strong>: controlla la presenza di percorsi sulla tastiera come “qwerty”, “asdfg”, “zcvbn” o sequenze diagonali</li>
<li><strong>ripetizioni</strong>: ripetizione di caratteri come “kkkkkkkkkk” o “12121212”</li>
<li><strong>l33t</strong>: una parola come “p4$$w0rd” viene subito riconosciuta come “password”</li>
<li><strong>date</strong>: riconosce giorni, mesi, anni, anche composti come “15062026”</li></ul>

<p>Il suo uso è molto semplice.
Le si dà in pasto la password e <code>zxcvbn</code> restituisce diverse informazioni utili:</p>
<ul><li>uno score da “0” (terribile) a “4 (ottima);</li>
<li>la stima di quanto tempo impiegherebbe un hacker a violarla in base a vari scenari di attacco;</li>
<li>suggerimenti su come migliorare eventualmente la password.</li></ul>

<p><code>zxcvbn</code> era una libreria javascript orginariamente sviluppata da Dropbox e ora disponibile in tante forme: go, python, c++.</p>

<p>L&#39;originale Dropbox in javascript, non più manutenuto, può essere trovata qui: <a href="https://github.com/dropbox/zxcvbn" rel="nofollow">https://github.com/dropbox/zxcvbn</a>.</p>

<p>Benché esistano diversi porting in python, se c&#39;è l&#39;esigenza di usare la versione legacy, gli stessi sviluppatori dell&#39;originale <code>zxcvbn</code> consigliano questa versione: <a href="https://github.com/dwolfhub/zxcvbn-python" rel="nofollow">https://github.com/dwolfhub/zxcvbn-python</a>, che può essere installata con <code>pip</code>.</p>

<p>In realtà la versione migliore è un fork in typescript, <strong>zxcvbn-ts</strong> che offre modularità (a differenza della versione python che è monolitica), maggior sicurezza, risoluzione di bug, aggiornamento continuo dizionari compresi.</p>

<p>Per capirci, mentre <code>ent</code> usa l&#39;entropia di Shannon per valutare la probabilità statistica dei byte, <code>zxcvbn</code> cerca di calcolare una stima dei tempi necessari per indovinare la password.</p>

<p>Una passphrase su ent avrebbe un punteggio risibile perché le entropie di parole comuni sono molto basse. Su <code>zxcvbn</code> invece avrebbe un punteggio molto alto perché l&#39;entropia di una parola viene calcolata sulla posizione del dizionario che la contiene per cui un hacker dovrebbe provare milioni di combinazioni prima di trovarla.</p>

<p>Allo stesso modo, password che per <code>ent</code> sarebbero ottime, per <code>zxcvbn</code> sarebbero da evitare perché legate a pattern o a ripetizioni.</p>

<h3 id="riassumendo">Riassumendo</h3>

<p>Se si deve testare una password / passphrase, sicuramente <code>zxcvbn</code>.
Se si deve testare un generatore di casualità o un keyfile di almeno 2k, sicuramente <code>ent</code>.</p>

<h2 id="metodo-diceware">Metodo Diceware</h2>

<p>Visto che nell&#39;ultima parte abbiamo evidenziato l&#39;anomalia che sorge nel momento in cui si valuta un oggetto casuale o dal punto di vista puramente statistico o dal punto di vista euristico, vale la pena di spendere due parole sulla modalità di creazione delle passphrase usando il <strong>metodo Diceware</strong>.</p>

<p>Usando come password parole estratte dal linguaggio naturale bisogna fare i conti col problema della <strong>prevedibilità</strong>.
Shannon ha dimostrato che la lingua italiana (o inglese) ha un&#39;entropia molto bassa (circa 1-1.5 bit per lettera) perché dopo una “q” ci si aspetta quasi sempre una “u”, e dopo un soggetto ci si aspetta un verbo. E così via.
Ecco perché, piuttosto che valutare l&#39;entropia nel suo complesso e provare ogni possibile combinazione, un moderno calcolatore inzia col far ricorso a “pattern” umani per violare password in pochi minuti invece che millenni.</p>

<p>Per unire la sicurezza del calcolo casuale alla comodità di una password menmonica, si ricorre al <strong>metodo Diceware</strong> che consiste nel far uso di un dizionario di migliaia di parole.</p>

<p>Quello classico, di 7776 parole inglesi, curato dall EFF si può trovare qui:</p>

<pre><code class="language-bash">curl -L https://www.eff.org/files/2016/07/18/eff_large_wordlist.txt &gt; dic_diceware.txt
</code></pre>

<p>Altrimenti Tarin Gamberini espone il suo dizionario diceware , aggiornato al 2019, qui: <a href="https://www.taringamberini.com/downloads/diceware_it_IT/lista-di-parole-diceware-in-italiano/4/word_list_diceware_it-IT-4.txt" rel="nofollow">https://www.taringamberini.com/downloads/diceware_it_IT/lista-di-parole-diceware-in-italiano/4/word_list_diceware_it-IT-4.txt</a>.</p>

<p>Questo dizionario contiene 6<sup>5</sup> parole numerate da 11111 a 66666.
La passphrase è composta da <em>n</em> di queste parole il cui indice è ricavato lanciando un dado (o un analogo virtuale) per 5 volte.
In questo modo le parole non sono correlate fra di loro come si potrebbero trovare in una frase, vanificando ogni possibile speculazione sulla sua composizione.</p>

<p>Volendo fare un calcolo dell&#39;entropia, supponendo di costruire una passphrase di 6 parole:</p>

<p><em>E = L * log<sub>2</sub> R = 6 * log<sub>2</sub> 7776 ~ 77,6</em></p>

<p>Nella password classiche basate su un alfabeto di <em>R</em> simboli, il mattoncino è rappresentato dal <strong>singolo carattere</strong> che ha una probabilità <em>1/R</em> di essere estratto.</p>

<p>Con Diceware, il mattoncino è <strong>la parola</strong> che ha <strong>una probabilità su 7776</strong> di essere estratta. Ogni parola in più, aggiunge una quantità enorme di incertezza.</p>

<p>Ecco perché con sole 6 parole abbiamo già una passphrase molto robusta e con 10 parole siamo di fronte ad una passphrase inattacabile, almeno dal punto di vista dell&#39;analisi statistica (<em>E &gt; 129</em>) e imperforabile anche ricorrendo ad analisi euristiche.</p>

<p><strong>Regola aurea</strong>: la scelta delle parole deve essere <strong>realmente</strong> casuale e non seguire regole grammaticali o preferenze personali. Altrimenti sarà un gioco da ragazzi violarla con un approccio a-là <code>zxcvbn</code>.</p>

<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:bruteforce" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">bruteforce</span></a> <a href="/aytin/tag:ent" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">ent</span></a> <a href="/aytin/tag:zxcvbn" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">zxcvbn</span></a> <a href="/aytin/tag:diceware" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">diceware</span></a> <a href="/aytin/tag:passphrase" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">passphrase</span></a> <a href="/aytin/tag:PatternMatching" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">PatternMatching</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/come-valutare-la-resistenza-di-una-password-trilogia-della-password-2-di-3</guid>
      <pubDate>Thu, 22 Jan 2026 19:04:39 +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>Cifrare directory con gocryptfs</title>
      <link>https://noblogo.org/aytin/come-cifrare-file-e-directory-con-gocryptfs</link>
      <description>&lt;![CDATA[gocryptfs&#xA;&#xA;Encfs è stata per tanto tempo la mia soluzione preferita per conservare velocemente i dati che volevo tenere riservati su uno storage esterno o su un cloud storage.&#xA;&#xA;Almeno fino al 2014 quando encfs è risultato estremamente fragile. Alcuni buchi sono stati coperti ma altri no, con la promessa che l&#39;eventuale 2.0 avrebbe risolto tutti i problemi.&#xA;!--more--&#xA;&#34;Eventuale&#34; perché lo sviluppo s&#39;è fermato e lo stesso manteiner consiglia di ricorrere ad altre soluzioni più valide.&#xA;Come gocryptfs (https://github.com/vgough/encfs?tab=readme-ov-file#status), appunto.&#xA;&#xA;Come EncFS e i suoi omologhi (cryfs, eCryptfs), gocryptfs è uno &#34;stackable filesystem&#34;.&#xA;&#xA;Ma cos&#39;è uno stackable filesystem?&#xA; &#xA;Analogamente a device mapper, il framework che fornisce funzionalità aggiuntive (cifratura, volumi logici, raid) ai dispositivi a blocchi a livello del kernel, gli stackable filesystem sono file system &#34;impilati&#34; (e non poteva essere altrimenti) sopra un altro file system per fornire funzionalità aggiuntive (cifratura, viste in lettura e/o scrittura) a livello di file/directory nello spazio utente grazie a FUSE.&#xA;&#xA;Essendo complementari, device mapper e stackable filesystem possono dunque cooperare.&#xA;&#xA;Ecco perché posso avere:&#xA;&#xA;due dischi fisici (block device)&#xA;che divido in volumi logici (device mapper),&#xA;ognuno dei quali formattato in ext4 (il file system)&#xA;a cui aggiungo funzionalità di cifratura con gocryptfs (stackable filesystem)&#xA;&#xA;Un altro celebre stackable filesystem è quello di tipo &#34;unionale&#34; nelle sue varie declinazioni come unionfs prima, aufs poi, per finire a overlayfs, lo standard in ambito container per la manipolazione delle immagini.&#xA;&#xA;Gocryptfs:&#xA;&#xA;è facile da usare&#xA;è in pieno sviluppo&#xA;non ha i problemi stringenti di sicurezza del suo &#34;collega&#34;&#xA;è tuttavia suscettibile ad attacchi statistici e di watermarking strutturale (effettuato sui metadati, come la dimensione dei file e la struttura delle directory) by design&#xA;&#xA;Su una cifratura file-based, raggiungere la triangolazione perfetta fra performance, full-privacy e ottimizzazione dello spazio, è quasi impossibile.&#xA;&#xA;Gocryptfs non è l&#39;optimum ma costituisce una valida alternativa ad EncFS, avendo dalla sua la stessa facilità d&#39;uso, maggior robustezza (l&#39;uso di AES-GCM impedisce di rompere matematicamente la cifratura dei dati, come invece succedeva su EncFS) e, come EncFS, ha ottime performance.&#xA;&#xA;Anche Gocryptfs prevede due modalità distinte di funzionamento: forward mode e reverse mode&#xA;&#xA;Nella prima, si battezza la directory che conterrà tutto ciò che vorrò cifrare. Localmente avrò un punto di montaggio su cui depositare i file in chiaro che verranno cifrati e memorizzati on-fly.&#xA;&#xA;Nel secondo caso, ribalto i termini della cifratura. Battezzerò una directory in chiaro il cui punto di montaggio sarà una directory che fornirà al volo i file cifrati.&#xA;&#xA;La prima modalità è comoda per la sincronizzazione su storage esterni o su cloud storage.&#xA;La seconda, dal momento che può fornire una vista cifrata di qualunque cartella, è utile quando si vuole effettuare velocemente un backup cifrato dei propri file&#xA;&#xA;!!! Attenzione !!!&#xA;Come tutte le crittografie file-based suscettibili di attacchi di tipo statistico e watermarking strutturale, nel caso del reverse mode, il watermarking diventa ancora più insidioso perché, dovendo funzionare presumibilmente con strumenti tipo rsync per il backup, il reverse mode di gocryptfs fa uso di un algoritmo, AES-SIV, deterministico per design cosi che lo stesso file, cifrato due volte, possa produrre lo stesso, identico risultato. Comodo per rsync ma un paradiso per il watermarking.&#xA;Tuttavia, anche così risulta più robusto di EncFS perché è una vulnerabilità che, a differenza del primo, non rompe matematicamente la cifratura esponendo il testo in chiaro pur consentendo attacchi di watermarking passivo per la rilevabilità dei file.&#xA;&#xA;Prove sul campo&#xA;Gocryptfs, nella fase di inizializzazione, crea il file gocryptfs.conf contenente la password cifrata ed altri elementi di configurazione.&#xA;&#xA;In Forward Mode, tale file è situato nella root della directory cifrata, quella che presumibilmente finirà nello storage esterno/cloud.&#xA;&#xA;Forward mode classico&#xA;1. Inizializzazione:&#xA;creazione della directory cifrata e della directory in chiaro&#xA;mkdir $HOME/{cipherdir,plaindir}&#xA;&#xA;inizializzazione della cartella cifrata&#xA;gocryptfs -init $HOME/cipherdir&#xA;&#xA;Choose a password for protecting your files.&#xA;Password: &#xA;Repeat: &#xA;&#xA;Your master key is:&#xA;&#xA;    93499318-58f766af-6a172304-114cab2c-&#xA;    7e9d6a6e-48f38c7a-b00a8e04-3b2e0583&#xA;&#xA;If the gocryptfs.conf file becomes corrupted or you ever forget your password, there is only one hope for recovery: The master key. Print it to a piece of paper and store it in a drawer. This message is only printed once.&#xA;The gocryptfs filesystem has been created successfully.&#xA;You can now mount it using: gocryptfs cipherdir MOUNTPOINT&#xA;Nella fase di inizializzazione viene generata una master key cifrata con una password che verrà chiesta durante la fase di init e che finirà nel file di configurazione gocryptfs.conf situato di default nella cartella cifrata.&#xA;&#xA;small&#xA;N.B. È bene conservare la master key in un luogo sicuro perché, in caso di malfunzionamenti, potrebbe essere l&#39;unico modo di recuperare la visibilità della cartella cifrata&#xA;/small&#xA;&#xA;2. Mount:&#xA;gocryptfs cipherdir plaindir&#xA;Nella fase di mount, viene chiesta la password, gocryptfs legge il file di configurazione e decripta la master key che servirà per la cifratura dei file presenti nel mountpoint in chiaro e che verranno cifrati al volo e scritti nella cartella cifrata.&#xA;&#xA;3. Unmount:&#xA;fusermount -u plaindir&#xA;Nella fase di unmount si &#34;libera&#34; il mountpoint lasciando la sola cartella cifrata.&#xA;&#xA;small&#xA;&#x9;&#xA;Note:&#xA;&#xA;Occorre prestare attenzione al file gocryptfs.conf. Visto che contiene la master key cifrata, senza questo file la decifratura sarebbe impossibile.&#xA;Come suggerito durante la fase di inizializzazione, è bene conservare la master key così che, nel caso si perda o si corrompa il file gocryptfs.conf, sia possibile rigenerarlo con la master key.&#xA;&#xA;/small&#xA;&#xA;Forward Mode su cloud storage (es. Dropbox)&#xA;In questo caso, sia il file di configurazione contenente la master key cifrata che la password di decifratura, saranno allocate esternamente alla directory cifrata su Dropbox.&#xA;In questo modo, anche guadagnando l&#39;accesso al clud storage, ci sarebbero solo dei file cifrati senza avere nemmeno la possibilità di tentare attacchi di forza bruta sulla master key cifrata.&#xA;&#xA;Visto che la password sarà scritta su un file, e non avrò bisogno di ricordarla a memoria, verrà generata ricorrendo al generatore di pseudo-casualità del kernel /dev/urandom e sarà lunga il massimo consentito, 2048 bytes.&#xA;&#xA;1. Inizializzazione&#xA;creazione della directory cifrata e della directory in chiaro&#xA;mkdir $HOME/Dropbox/.cipherdir $HOME/plaindir&#xA;&#xA;creazione di un keyfile di 2k (la massima lunghezza possibile)&#xA;umask 077 &amp;&amp; tr -dc &#39;[:graph:]&#39;  /dev/urandom | head -c 2048  /run/media/$USER/pendrive/mykey.txt&#xA; &#xA;inizializzazione della cartella cifrata&#xA;gocryptfs \&#xA;  -passfile /run/media/$USER/pendrive/mykey.txt \&#xA;  -config /run/media/$USER/pendrive/gocryptfs.conf \&#xA;  -init $HOME/Dropbox/.cipherdir&#xA;Using config file at custom location /run/media/$USER/pendrive/gocryptfs.conf&#xA;Choose a password for protecting your files.&#xA;passfile: reading from file &#34;/run/media/$USER/pendrive/mykey.txt&#34;&#xA;&#xA;Your master key is:&#xA;&#xA;    dcceb426-75724350-f53566f6-2991cfa9-&#xA;    7a091a4f-397eab55-170c3363-a16b0ab3&#xA;&#xA;If the gocryptfs.conf file becomes corrupted or you ever forget your password,&#xA;there is only one hope for recovery: The master key. Print it to a piece of&#xA;paper and store it in a drawer. This message is only printed once.&#xA;The gocryptfs filesystem has been created successfully.&#xA;You can now mount it using: gocryptfs cipherdir MOUNTPOINT&#xA;2. Mount&#xA;gocryptfs \&#xA;  -config /run/media/$USER/pendrive/gocryptfs.conf \&#xA;  -passfile /run/media/$USER/pendrive/mykey.txt &#xA;  $HOME/Dropbox/.cipherdir $HOME/plaindir&#xA;3. Unmount&#xA;fusermount -u $HOME/plaindir&#xA;Reverse mode&#xA;Questa modalità torna utile quando si vuole offrire al volo una vista cifrata di una determinata directory, ad es. quando vogliamo fare un backup cifrato.&#xA;&#xA;Supponiamo di volere effettuare un backup cifrato della directory &#34;myDocuments&#34;&#xA;&#xA;1. Inizializzazione&#xA;gocryptfs -init -reverse $HOME/myDocuments&#xA;Choose a password for protecting your files.&#xA;Password:&#xA;Repeat:&#xA;&#xA;Your master key is:&#xA;&#xA;    cda5cac4-5435e8e8-68d6d038-451a6955-&#xA;    c269c57c-d8b5fe5e-4d5ca589-4eb5e7ac&#xA;&#xA;If the gocryptfs.conf file becomes corrupted or you ever forget your password,&#xA;there is only one hope for recovery: The master key. Print it to a piece of&#xA;paper and store it in a drawer. This message is only printed once.&#xA;The gocryptfs-reverse filesystem has been created successfully.&#xA;You can now mount it using: gocryptfs -reverse plaindir MOUNTPOINT&#xA;Nella directory &#34;myDocuments&#34; sarà presente il file di configurazione, di default .gocryptfs.reverse.conf&#xA;&#xA;2. Mount&#xA;mkdir $HOME/cipherdirreverse&#xA;gocryptfs -reverse $HOME/myDocuments $HOME/cipherdirreverse&#xA;Dopo il mount, il file .gocryptfs.reverse.conf verrà &#34;copiato&#34; nel punto di montaggio come gocryptfs.conf in modo che il backup possa essere montato direttamente in forward mode.&#xA;&#xA;3. Unmont&#xA;fusermount -u $HOME/cipherdirreverse&#xA;&#xA;Nulla vieta che anche nel reverse mode si possa ricorrere a password e file di configurazione &#34;detachable&#34;.&#xA;gocryptfs \&#xA;  -passfile /run/media/$USER/pendrive/mykey.txt \&#xA;  -config /run/media/$USER/pendrive/gocryptfs.reverse.conf \&#xA;  -init -reverse $HOME/myDocuments&#xA;smallN.B. In questo caso anche il backup avrà bisogno del file di configurazione e della password per essere montato./small&#xA;Varie ed eventuali&#xA;Cambio password&#xA;Supponiamo di voler cambiare la password (keyfile) della nostra directory cifrata su Dropbox&#xA;gocryptfs \&#xA;  -config /run/media/$USER/pendrive/gocryptfs.conf &#xA;  -passfile /run/media/$USER/pendrive/mykey.txt&#xA;  -passwd $HOME/Dropbox/.cipherdir&#xA;Using config file at custom location /run/media/$USER/pendrive/gocryptfs.conf&#xA;Password:&#xA;Decrypting master key&#xA;Please enter your new password.&#xA;Password:&#xA;Repeat:&#xA;smallN.B. Non è possibile specificare un keyfile come nuova password (possibile solo durante l&#39;init).&#xA;Il keyfile in questo caso servirà solo a decriptare la master key che verrà cifrata con la nuova password./small&#xA;Mount automatico&#xA;Nel caso di forward mode, può tornare comodo il mount automatico della directory cifrata.&#xA;È sufficiente definire un piccolo script che esegua il montaggio e che parta in esecuzione automatica dopo il login.&#xA;&#xA;Due osservazioni:&#xA;&#xA;Conviene che la password sia stoccata nel keyring (di Gnome nel mio caso) così da rendere la password inaccessibile senza il login. &#xA;il file di configurazione può continuare a rimanere al di fuori della directory cifrata (soprattutto nel caso cloud storage) purché sia accessibile dopo il login.&#xA;&#xA;1. Generazione password&#xA;suppongo che la password sia stata generata come in forward&#xA;mode e che stia in un file di testo che ora memorizzerò nel&#xA;keyring con secret-tool&#xA;cat mykey.txt | secret-tool store --label=&#34;gocryptfs&#34; myCipherDir myPassword&#xA;2. Creazione script&#xA;cat   $HOME/mountgocryptfs.sh &lt;&lt; EOF&#xA;!/bin/bash&#xA;gocryptfs \&#xA;  -config $HOME/gocryptfs.conf \&#xA;  -extpass=&#34;secret-tool lookup myCipherDir myPassword&#34; \&#xA;  $HOME/Dropbox/.cipherdir $HOME/plaindir&#xA;EOF&#xA;chmod 700 $HOME/mountgocryptfs.sh&#xA;3. Creazione del launcher&#xA;cat   $HOME/.config/autostart/mountGocryptfs.desktop &lt;&lt; EOF&#xA;[Desktop Entry]&#xA;Name=mountgocryptfs&#xA;GenericName=mountgocryptfs&#xA;Comment=Monta la cartella cifrata con gocryptfs&#xA;Exec=/home/user/mountgocryptfs.sh&#xA;Terminal=false&#xA;Type=Application&#xA;X-GNOME-Autostart-enabled=true&#xA;Comment[itIT]=&#xA;EOF&#xA;In questo modo, dopo il login, verrà eseguito lo script (grazie a $HOME/.config/autostart/) che recupererà la password via secret-tool dal keyring.&#xA;Rigenerazione del file gocryptfs.conf&#xA;Ma se smarrissi il file gocryptfs.conf, o mi si corrompe il supporto esterno che lo contiene?&#xA;O se dimenticassi / perdessi la password?&#xA;&#xA;È un grosso guaio. La directory cifrata non sarà più accessibile.&#xA;O meglio.&#xA;Lo sarà solo avendo la master key. E con questa possiamo, non solo montare la directory cifrata, ma anche ricostruire il file di configurazione.&#xA;&#xA;Innanzitutto verifichiamo se l&#39;accesso diretto con la master key funzioni:&#xA;&#xA;Accesso con la master key&#xA;gocryptfs \&#xA;  -masterkey dcceb426-75724350-f53566f6-2991cfa9-7a091a4f-397eab55-170c3363-a16b0ab3 \&#xA;  $HOME/Dropbox/.cipherdir $HOME/plaindir&#xA;Using explicit master key.&#xA;THE MASTER KEY IS VISIBLE VIA &#34;ps ax&#34; AND MAY BE STORED IN YOUR SHELL HISTORY!&#xA;ONLY USE THIS MODE FOR EMERGENCIES&#xA;Filesystem mounted and ready.&#xA;Per evitare il warning, si può ricorrere al flag stdin che obbliga all&#39;inserimento manuale da tastiera della master key:&#xA;gocryptfs -masterkey stdin $HOME/Dropbox/.cipherdir $HOME/plaindir&#xA;Masterkey:&#xA;Using explicit master key.&#xA;Filesystem mounted and ready.&#xA;Caso 1: Smarrimento password&#xA;Se è solo la password, basterà accedere alla directory cifrata con la master key usando lo stesso file di configurazone e inserire una nuova password:&#xA;Cambio password&#xA;gocryptfs \Inserimento&#xA;  -masterkey dcceb426-75724350-f53566f6-2991cfa9-7a091a4f-397eab55-170c3363-a16b0ab3 \&#xA;  -config /run/media/$USER/pendrive/gocryptfs.conf \&#xA;  -passwd&#xA;  $HOME/Dropbox/.cipherdir&#xA;Using config file at custom location /run/media/$USER/pendrive/gocryptfs.conf&#xA;Using explicit master key.&#xA;THE MASTER KEY IS VISIBLE VIA &#34;ps ax&#34; AND MAY BE STORED IN YOUR SHELL HISTORY!&#xA;ONLY USE THIS MODE FOR EMERGENCIES&#xA;Please enter your new password.&#xA;Password:&#xA;Repeat:&#xA;A copy of the old config file has been created at &#34;/run/media/$USER/pendrive/gocryptfs.conf.bak&#34;.&#xA;Delete it after you have verified that you can access your files with the new password.&#xA;Password changed.&#xA;smallN.B. Siccome il file di configurazione verrà modificato con un nuovo salt e una nuova password, del file di configurazione verrà fatta una copia di backup precauzionale,/small&#xA;&#xA;Caso 2: Ricostruzione file di configurazione&#xA;È praticamente lo stesso procedimentod di prima solo che in questo caso occorre ricostruire il file di configurazione.&#xA;&#xA;Si ricrea un file di configurazione con -init avente cura di replicare le stesse impostazioni di quello compromesso (nel mio caso è semplice, tutto default) su una directory cifrata temporanea&#xA;il file di configurazione così ottenuto, si sposta nella directory cifrata effettiva e si imposta la nuova password&#xA;&#xA;inizializzo una directory cifrata temporanea&#xA;gocryptfs -init $HOME/ciphertemp&#xA;&#xA;Sposto il nuovo file di configurazione dalla directory&#xA;temporanea cifrata al punto in cui si trovava in precedenza &#xA;(la nostra nuova pendrive)&#xA;mv $HOME/ciphertemp/gocryptfs.conf /run/media/$USER/nuovapendrive/gocryptfs.conf&#xA;&#xA;Inserimento password&#xA;gocryptfs \&#xA;  -masterkey dcceb426-75724350-f53566f6-2991cfa9-7a091a4f-397eab55-170c3363-a16b0ab3 \&#xA;  -config /run/media/$USER/nuovapendrive/gocryptfs.conf \&#xA;  -passwd&#xA;  $HOME/Dropbox/.cipherdir&#xA;Using config file at custom location /run/media/$USER/nuovapendrive/gocryptfs.conf&#xA;Using explicit master key.&#xA;THE MASTER KEY IS VISIBLE VIA &#34;ps ax&#34; AND MAY BE STORED IN YOUR SHELL HISTORY!&#xA;ONLY USE THIS MODE FOR EMERGENCIES&#xA;Please enter your new password.&#xA;Password:&#xA;Repeat:&#xA;A copy of the old config file has been created at &#34;/run/media/$USER/nuovapendrive/gocryptfs.conf.bak&#34;.&#xA;Delete it after you have verified that you can access your files with the new password.&#xA;Password changed.&#xA;E ora il volume può essere montato nuovamente.&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/ffe7c43a6-a8b5f2/9Td73xxaBl69/Eupr4WKOZNWAcM6Bz2cB82bMjBVesdvMs9HyMFNV.jpg" alt="gocryptfs"></p>

<p><strong>Encfs</strong> è stata per tanto tempo la mia soluzione preferita per conservare velocemente i dati che volevo tenere riservati su uno storage esterno o su un cloud storage.</p>

<p>Almeno fino al 2014 quando encfs è risultato estremamente fragile. Alcuni buchi sono stati coperti ma altri no, con la promessa che l&#39;eventuale 2.0 avrebbe risolto tutti i problemi.

“Eventuale” perché lo sviluppo s&#39;è fermato e lo stesso manteiner consiglia di ricorrere ad altre soluzioni più valide.
Come gocryptfs (<a href="https://github.com/vgough/encfs?tab=readme-ov-file#status" rel="nofollow">https://github.com/vgough/encfs?tab=readme-ov-file#status</a>), appunto.</p>

<p>Come <strong>EncFS</strong> e i suoi omologhi (<strong>cryfs</strong>, <strong>eCryptfs</strong>), <strong>gocryptfs</strong> è uno “<strong>stackable filesystem</strong>”.</p>

<p>Ma cos&#39;è uno <strong>stackable filesystem</strong>?</p>

<p>Analogamente a <strong>device mapper</strong>, il framework che fornisce funzionalità aggiuntive (cifratura, volumi logici, raid) ai <strong>dispositivi a blocchi</strong> a livello del kernel, gli stackable filesystem sono file system “impilati” (e non poteva essere altrimenti) sopra un altro file system per fornire funzionalità aggiuntive (cifratura, viste in lettura e/o scrittura) <strong>a livello di file/directory</strong> nello spazio utente grazie a FUSE.</p>

<p>Essendo complementari, device mapper e stackable filesystem possono dunque cooperare.</p>

<p>Ecco perché posso avere:</p>
<ul><li>due dischi fisici (<strong>block device</strong>)</li>
<li>che divido in volumi logici (<strong>device mapper</strong>),</li>
<li>ognuno dei quali formattato in ext4 (il <strong>file system</strong>)</li>
<li>a cui aggiungo funzionalità di cifratura con <strong>gocryptfs</strong> (<strong>stackable filesystem</strong>)</li></ul>

<p>Un altro celebre stackable filesystem è quello di tipo “unionale” nelle sue varie declinazioni come <strong>unionfs</strong> prima, <strong>aufs</strong> poi, per finire a <strong>overlayfs</strong>, lo standard in ambito container per la manipolazione delle immagini.</p>

<p>Gocryptfs:</p>
<ul><li>è facile da usare</li>
<li>è in pieno sviluppo</li>
<li>non ha i problemi stringenti di sicurezza del suo “collega”</li>
<li>è tuttavia suscettibile ad attacchi statistici e di watermarking strutturale (effettuato sui metadati, come la dimensione dei file e la struttura delle directory) by design</li></ul>

<p>Su una cifratura file-based, raggiungere la triangolazione perfetta fra performance, full-privacy e ottimizzazione dello spazio, è quasi impossibile.</p>

<p>Gocryptfs non è l&#39;optimum ma costituisce una valida alternativa ad EncFS, avendo dalla sua la stessa facilità d&#39;uso, maggior robustezza (l&#39;uso di <strong>AES-GCM</strong> impedisce di rompere matematicamente la cifratura dei dati, come invece succedeva su EncFS) e, come EncFS, ha ottime performance.</p>

<p>Anche Gocryptfs prevede due modalità distinte di funzionamento: <strong>forward mode</strong> e <strong>reverse mode</strong></p>

<p>Nella prima, si battezza la directory che conterrà tutto ciò che vorrò cifrare. Localmente avrò un punto di montaggio su cui depositare i file in chiaro che verranno cifrati e memorizzati on-fly.</p>

<p>Nel secondo caso, ribalto i termini della cifratura. Battezzerò una directory in chiaro il cui punto di montaggio sarà una directory che fornirà al volo i file cifrati.</p>

<p>La prima modalità è comoda per la sincronizzazione su storage esterni o su cloud storage.
La seconda, dal momento che può fornire una vista cifrata di qualunque cartella, è utile quando si vuole effettuare velocemente un backup cifrato dei propri file</p>

<p><strong>!!! Attenzione !!!</strong>
Come tutte le crittografie file-based suscettibili di attacchi di tipo statistico e watermarking strutturale, nel caso del reverse mode, il watermarking diventa ancora più insidioso perché, dovendo funzionare presumibilmente con strumenti tipo <strong>rsync</strong> per il backup, il reverse mode di gocryptfs fa uso di un algoritmo, <strong>AES-SIV</strong>, deterministico per design cosi che lo stesso file, cifrato due volte, possa produrre lo stesso, identico risultato. Comodo per rsync ma un paradiso per il watermarking.
Tuttavia, anche così risulta più robusto di EncFS perché è una vulnerabilità che, a differenza del primo, non rompe matematicamente la cifratura esponendo il testo in chiaro pur consentendo attacchi di watermarking passivo per la rilevabilità dei file.</p>

<h2 id="prove-sul-campo">Prove sul campo</h2>

<p>Gocryptfs, nella fase di inizializzazione, crea il file <code>gocryptfs.conf</code> contenente la password cifrata ed altri elementi di configurazione.</p>

<p>In <strong>Forward Mode</strong>, tale file è situato nella root della directory cifrata, quella che presumibilmente finirà nello storage esterno/cloud.</p>

<h3 id="forward-mode-classico">Forward mode classico</h3>

<p><strong>1. Inizializzazione:</strong></p>

<pre><code class="language-bash"># creazione della directory cifrata e della directory in chiaro
mkdir $HOME/{cipherdir,plaindir}

# inizializzazione della cartella cifrata
gocryptfs -init $HOME/cipherdir

Choose a password for protecting your files.
Password: 
Repeat: 

Your master key is:

    93499318-58f766af-6a172304-114cab2c-
    7e9d6a6e-48f38c7a-b00a8e04-3b2e0583

If the gocryptfs.conf file becomes corrupted or you ever forget your password, there is only one hope for recovery: The master key. Print it to a piece of paper and store it in a drawer. This message is only printed once.
The gocryptfs filesystem has been created successfully.
You can now mount it using: gocryptfs cipherdir MOUNTPOINT
</code></pre>

<p>Nella fase di inizializzazione viene generata una <strong>master key</strong> cifrata con una password che verrà chiesta durante la fase di init e che finirà nel file di configurazione <code>gocryptfs.conf</code> situato di default nella cartella cifrata.</p>

<p><small>
<strong>N.B.</strong> È bene conservare la master key in un luogo sicuro perché, in caso di malfunzionamenti, potrebbe essere l&#39;unico modo di recuperare la visibilità della cartella cifrata
</small></p>

<p><strong>2. Mount:</strong></p>

<pre><code class="language-bash">gocryptfs cipherdir plaindir
</code></pre>

<p>Nella fase di mount, viene chiesta la password, gocryptfs legge il file di configurazione e decripta la master key che servirà per la cifratura dei file presenti nel mountpoint in chiaro e che verranno cifrati al volo e scritti nella cartella cifrata.</p>

<p><strong>3. Unmount:</strong></p>

<pre><code class="language-bash">fusermount -u plaindir
</code></pre>

<p>Nella fase di unmount si “libera” il mountpoint lasciando la sola cartella cifrata.</p>

<p><small></p>

<p><strong>Note:</strong></p>
<ol><li>Occorre prestare attenzione al file <strong>gocryptfs.conf</strong>. Visto che contiene la master key cifrata, senza questo file la decifratura sarebbe impossibile.</li>
<li>Come suggerito durante la fase di inizializzazione, è bene conservare la master key così che, nel caso si perda o si corrompa il file gocryptfs.conf, sia possibile rigenerarlo con la master key.</li></ol>

<p></small></p>

<h3 id="forward-mode-su-cloud-storage-es-dropbox">Forward Mode su cloud storage (es. Dropbox)</h3>

<p>In questo caso, sia il file di configurazione contenente la master key cifrata che la password di decifratura, saranno allocate esternamente alla directory cifrata su Dropbox.
In questo modo, anche guadagnando l&#39;accesso al clud storage, ci sarebbero solo dei file cifrati senza avere nemmeno la possibilità di tentare attacchi di forza bruta sulla master key cifrata.</p>

<p>Visto che la password sarà scritta su un file, e non avrò bisogno di ricordarla a memoria, verrà generata ricorrendo al generatore di pseudo-casualità del kernel <code>/dev/urandom</code> e sarà lunga il massimo consentito, 2048 bytes.</p>

<p><strong>1. Inizializzazione</strong></p>

<pre><code class="language-bash"># creazione della directory cifrata e della directory in chiaro
mkdir $HOME/Dropbox/.cipherdir $HOME/plaindir

# creazione di un keyfile di 2k (la massima lunghezza possibile)
umask 077 &amp;&amp; tr -dc &#39;[:graph:]&#39; &lt; /dev/urandom | head -c 2048 &gt; /run/media/$USER/&lt;pendrive&gt;/mykey.txt
 
# inizializzazione della cartella cifrata
gocryptfs \
  -passfile /run/media/$USER/&lt;pendrive&gt;/mykey.txt \
  -config /run/media/$USER/&lt;pendrive&gt;/gocryptfs.conf \
  -init $HOME/Dropbox/.cipherdir
Using config file at custom location /run/media/$USER/&lt;pendrive&gt;/gocryptfs.conf
Choose a password for protecting your files.
passfile: reading from file &#34;/run/media/$USER/&lt;pendrive&gt;/mykey.txt&#34;

Your master key is:

    dcceb426-75724350-f53566f6-2991cfa9-
    7a091a4f-397eab55-170c3363-a16b0ab3

If the gocryptfs.conf file becomes corrupted or you ever forget your password,
there is only one hope for recovery: The master key. Print it to a piece of
paper and store it in a drawer. This message is only printed once.
The gocryptfs filesystem has been created successfully.
You can now mount it using: gocryptfs cipherdir MOUNTPOINT
</code></pre>

<p><strong>2. Mount</strong></p>

<pre><code class="language-bash">gocryptfs \
  -config /run/media/$USER/&lt;pendrive&gt;/gocryptfs.conf \
  -passfile /run/media/$USER/&lt;pendrive&gt;/mykey.txt 
  $HOME/Dropbox/.cipherdir $HOME/plaindir
</code></pre>

<p><strong>3. Unmount</strong></p>

<pre><code class="language-bash">fusermount -u $HOME/plaindir
</code></pre>

<h3 id="reverse-mode">Reverse mode</h3>

<p>Questa modalità torna utile quando si vuole offrire al volo una vista cifrata di una determinata directory, ad es. quando vogliamo fare un backup cifrato.</p>

<p>Supponiamo di volere effettuare un backup cifrato della directory “myDocuments”</p>

<p><strong>1. Inizializzazione</strong></p>

<pre><code class="language-bash">gocryptfs -init -reverse $HOME/myDocuments
Choose a password for protecting your files.
Password:
Repeat:

Your master key is:

    cda5cac4-5435e8e8-68d6d038-451a6955-
    c269c57c-d8b5fe5e-4d5ca589-4eb5e7ac

If the gocryptfs.conf file becomes corrupted or you ever forget your password,
there is only one hope for recovery: The master key. Print it to a piece of
paper and store it in a drawer. This message is only printed once.
The gocryptfs-reverse filesystem has been created successfully.
You can now mount it using: gocryptfs -reverse plaindir MOUNTPOINT
</code></pre>

<p>Nella directory “myDocuments” sarà presente il file di configurazione, di default <code>.gocryptfs.reverse.conf</code></p>

<p><strong>2. Mount</strong></p>

<pre><code class="language-bash">mkdir $HOME/cipherdir_reverse
gocryptfs -reverse $HOME/myDocuments $HOME/cipherdir_reverse
</code></pre>

<p>Dopo il mount, il file <code>.gocryptfs.reverse.conf</code> verrà “copiato” nel punto di montaggio come <code>gocryptfs.conf</code> in modo che il backup possa essere montato direttamente in forward mode.</p>

<p><strong>3. Unmont</strong></p>

<pre><code class="language-bash">fusermount -u $HOME/cipherdir_reverse
</code></pre>

<p>Nulla vieta che anche nel reverse mode si possa ricorrere a password e file di configurazione “detachable”.</p>

<pre><code class="language-bash">gocryptfs \
  -passfile /run/media/$USER/&lt;pendrive&gt;/mykey.txt \
  -config /run/media/$USER/&lt;pendrive&gt;/gocryptfs.reverse.conf \
  -init -reverse $HOME/myDocuments
</code></pre>

<p><small><strong>N.B.</strong> In questo caso anche il backup avrà bisogno del file di configurazione e della password per essere montato.</small></p>

<h2 id="varie-ed-eventuali">Varie ed eventuali</h2>

<h3 id="cambio-password">Cambio password</h3>

<p>Supponiamo di voler cambiare la password (keyfile) della nostra directory cifrata su Dropbox</p>

<pre><code class="language-bash">gocryptfs \
  -config /run/media/$USER/&lt;pendrive&gt;/gocryptfs.conf 
  -passfile /run/media/$USER/&lt;pendrive&gt;/mykey.txt
  -passwd $HOME/Dropbox/.cipherdir
Using config file at custom location /run/media/$USER/&lt;pendrive&gt;/gocryptfs.conf
Password:
Decrypting master key
Please enter your new password.
Password:
Repeat:
</code></pre>

<p><small><strong>N.B.</strong> Non è possibile specificare un keyfile come nuova password (possibile solo durante l&#39;init).
Il keyfile in questo caso servirà solo a decriptare la master key che verrà cifrata con la nuova password.</small></p>

<h3 id="mount-automatico">Mount automatico</h3>

<p>Nel caso di forward mode, può tornare comodo il mount automatico della directory cifrata.
È sufficiente definire un piccolo script che esegua il montaggio e che parta in esecuzione automatica dopo il login.</p>

<p>Due osservazioni:</p>
<ol><li>Conviene che la password sia stoccata nel keyring (di Gnome nel mio caso) così da rendere la password inaccessibile senza il login.</li>
<li>il file di configurazione può continuare a rimanere al di fuori della directory cifrata (soprattutto nel caso cloud storage) purché sia accessibile dopo il login.</li></ol>

<p><strong>1. Generazione password</strong></p>

<pre><code class="language-bash"># suppongo che la password sia stata generata come in forward
# mode e che stia in un file di testo che ora memorizzerò nel
# keyring con secret-tool
cat mykey.txt | secret-tool store --label=&#34;gocryptfs&#34; myCipherDir myPassword
</code></pre>

<p><strong>2. Creazione script</strong></p>

<pre><code class="language-bash">cat &gt; $HOME/mount_gocryptfs.sh &lt;&lt; EOF
#!/bin/bash
gocryptfs \
  -config $HOME/gocryptfs.conf \
  -extpass=&#34;secret-tool lookup myCipherDir myPassword&#34; \
  $HOME/Dropbox/.cipherdir $HOME/plaindir
EOF
chmod 700 $HOME/mount_gocryptfs.sh
</code></pre>

<p><strong>3. Creazione del launcher</strong></p>

<pre><code>cat &gt; $HOME/.config/autostart/mountGocryptfs.desktop &lt;&lt; EOF
[Desktop Entry]
Name=mount_gocryptfs
GenericName=mount_gocryptfs
Comment=Monta la cartella cifrata con gocryptfs
Exec=/home/&lt;user&gt;/mount_gocryptfs.sh
Terminal=false
Type=Application
X-GNOME-Autostart-enabled=true
Comment[it_IT]=
EOF
</code></pre>

<p>In questo modo, dopo il login, verrà eseguito lo script (grazie a <code>$HOME/.config/autostart/</code>) che recupererà la password via <code>secret-tool</code> dal keyring.</p>

<h3 id="rigenerazione-del-file-gocryptfs-conf">Rigenerazione del file gocryptfs.conf</h3>

<p>Ma se smarrissi il file <code>gocryptfs.conf</code>, o mi si corrompe il supporto esterno che lo contiene?
O se dimenticassi / perdessi la password?</p>

<p>È un grosso guaio. La directory cifrata non sarà più accessibile.
O meglio.
Lo sarà solo avendo la master key. E con questa possiamo, non solo montare la directory cifrata, ma anche ricostruire il file di configurazione.</p>

<p>Innanzitutto verifichiamo se l&#39;accesso diretto con la master key funzioni:</p>

<p><strong>Accesso con la master key</strong></p>

<pre><code class="language-bash">gocryptfs \
  -masterkey dcceb426-75724350-f53566f6-2991cfa9-7a091a4f-397eab55-170c3363-a16b0ab3 \
  $HOME/Dropbox/.cipherdir $HOME/plaindir
Using explicit master key.
THE MASTER KEY IS VISIBLE VIA &#34;ps ax&#34; AND MAY BE STORED IN YOUR SHELL HISTORY!
ONLY USE THIS MODE FOR EMERGENCIES
Filesystem mounted and ready.
</code></pre>

<p>Per evitare il warning, si può ricorrere al flag <code>stdin</code> che obbliga all&#39;inserimento manuale da tastiera della master key:</p>

<pre><code class="language-bash">gocryptfs -masterkey stdin $HOME/Dropbox/.cipherdir $HOME/plaindir
Masterkey:
Using explicit master key.
Filesystem mounted and ready.
</code></pre>

<p><strong>Caso 1: Smarrimento password</strong>
Se è solo la password, basterà accedere alla directory cifrata con la master key usando lo stesso file di configurazone e inserire una nuova password:</p>

<pre><code class="language-bash"># Cambio password
gocryptfs \Inserimento
  -masterkey dcceb426-75724350-f53566f6-2991cfa9-7a091a4f-397eab55-170c3363-a16b0ab3 \
  -config /run/media/$USER/&lt;pendrive&gt;/gocryptfs.conf \
  -passwd
  $HOME/Dropbox/.cipherdir
Using config file at custom location /run/media/$USER/&lt;pendrive&gt;/gocryptfs.conf
Using explicit master key.
THE MASTER KEY IS VISIBLE VIA &#34;ps ax&#34; AND MAY BE STORED IN YOUR SHELL HISTORY!
ONLY USE THIS MODE FOR EMERGENCIES
Please enter your new password.
Password:
Repeat:
A copy of the old config file has been created at &#34;/run/media/$USER/&lt;pendrive&gt;/gocryptfs.conf.bak&#34;.
Delete it after you have verified that you can access your files with the new password.
Password changed.
</code></pre>

<p><small><strong>N.B.</strong> Siccome il file di configurazione verrà modificato con un nuovo salt e una nuova password, del file di configurazione verrà fatta una copia di backup precauzionale,</small></p>

<p><strong>Caso 2: Ricostruzione file di configurazione</strong>
È praticamente lo stesso procedimentod di prima solo che in questo caso occorre ricostruire il file di configurazione.</p>
<ol><li>Si ricrea un file di configurazione con <code>-init</code> avente cura di replicare <strong>le stesse impostazioni</strong> di quello compromesso (nel mio caso è semplice, tutto default) su una directory cifrata temporanea</li>
<li>il file di configurazione così ottenuto, si sposta nella directory cifrata effettiva e si imposta la nuova password</li></ol>

<pre><code class="language-bash"># inizializzo una directory cifrata temporanea
gocryptfs -init $HOME/cipher_temp

# Sposto il nuovo file di configurazione dalla directory
# temporanea cifrata al punto in cui si trovava in precedenza 
# (la nostra nuova pendrive)
mv $HOME/cipher_temp/gocryptfs.conf /run/media/$USER/&lt;nuova_pendrive&gt;/gocryptfs.conf

# Inserimento password
gocryptfs \
  -masterkey dcceb426-75724350-f53566f6-2991cfa9-7a091a4f-397eab55-170c3363-a16b0ab3 \
  -config /run/media/$USER/&lt;nuova_pendrive&gt;/gocryptfs.conf \
  -passwd
  $HOME/Dropbox/.cipherdir
Using config file at custom location /run/media/$USER/&lt;nuova_pendrive&gt;/gocryptfs.conf
Using explicit master key.
THE MASTER KEY IS VISIBLE VIA &#34;ps ax&#34; AND MAY BE STORED IN YOUR SHELL HISTORY!
ONLY USE THIS MODE FOR EMERGENCIES
Please enter your new password.
Password:
Repeat:
A copy of the old config file has been created at &#34;/run/media/$USER/&lt;nuova_pendrive&gt;/gocryptfs.conf.bak&#34;.
Delete it after you have verified that you can access your files with the new password.
Password changed.
</code></pre>

<p>E ora il volume può essere montato nuovamente.</p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/come-cifrare-file-e-directory-con-gocryptfs</guid>
      <pubDate>Mon, 05 Jan 2026 15:30:07 +0000</pubDate>
    </item>
    <item>
      <title>Audit per client e server ssh</title>
      <link>https://noblogo.org/aytin/audit-per-client-e-server-ssh</link>
      <description>&lt;![CDATA[ssh-audit&#xA;&#xA;ssh-audit è un un comodo tool per l&#39;audit di sicurezza del server e del client SSH (banner, scambio di chiavi, crittografia, mac, compressione, compatibilità, sicurezza, ecc.)&#xA;&#xA;Il sito di riferimento: https://www.ssh-audit.com/ da cui si può effettuare una scansione sia del proprio client che di un server.&#xA;!--more--&#xA;Questa sezione https://www.ssh-audit.com/hardeningguides.html invece fornisce una serie di configurazioni rapide e sicure per la pletora di client e server più noti. &#xA;&#xA;ssh-audit permette di eseguire delle scansioni generiche client e/o server o di controllare una specifica compliance (ne parlerò più avanti) in base al sistema in uso&#xA;&#xA;Installare ssh-audit&#xA;&#xA;Trattandosi di una utility via CLI, la installerò con pipx che mi garantisce il necessario isolamento e un link all&#39;eseguibile che sia &#34;globale&#34; per l&#39;utente.&#xA;&#xA;pipx install ssh-audit&#xA;o pipx install ssh-audit --python pythonversione&#xA;se si vuole una versione di python specifica&#xA;&#xA;Se non dovesse essere presente pipx, nella nostra home:&#xA;aggiornamento e installazione pip, pipx&#xA;pip install --user -U pip pipx&#xA;&#xA;ssh-audit può essere usato per il check e la configurazione di un server ssh o del client.&#xA;&#xA;Scansione server&#xA;Semplice.&#xA;&#xA;ssh-audit -p porta ssh ip / server ssh&#xA;&#xA;effettua la scansione di un server ssh. Il risultato consisterà in una serie di informazioni sulle direttive riguardanti cipher, klex, mac ecc. che saranno:&#xA;&#xA;[info] di colore verde o bianco corrispondenti a configurazioni corrette&#xA;[warning] di colore giallo, corrispondenti a configurazioni da attenzionare&#xA;[fail] di colore rosso, corrispondenti a configurazioni palesemente critiche e da correggere urgentemente.&#xA;&#xA;Ecco un es. di scansione sul default ssh server di una debian 13 (RaspBI 2):&#xA;&#xA;general&#xA;(gen) banner: SSH-2.0-OpenSSH10.0p2 Raspbian-7&#xA;(gen) software: OpenSSH 10.0p2&#xA;(gen) compatibility: OpenSSH 9.9+, Dropbear SSH 2020.79+&#xA;(gen) compression: enabled (zlib@openssh.com)&#xA;&#xA;key exchange algorithms&#xA;(kex) mlkem768x25519-sha256               -- [info] available since OpenSSH 9.9&#xA;                                          `- [info] hybrid key exchange based on post-quantum resistant algorithm and proven conventional X25519 algorithm&#xA;(kex) sntrup761x25519-sha512              -- [info] available since OpenSSH 9.9&#xA;                                          `- [info] default key exchange since OpenSSH 9.9&#xA;                                          `- [info] hybrid key exchange based on post-quantum resistant algorithm and proven conventional X25519 algorithm&#xA;(kex) sntrup761x25519-sha512@openssh.com  -- [info] available since OpenSSH 8.5&#xA;                                          `- [info] default key exchange from OpenSSH 9.0 to 9.8&#xA;                                          `- [info] hybrid key exchange based on post-quantum resistant algorithm and proven conventional X25519 algorithm&#xA;(kex) curve25519-sha256                   -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76&#xA;                                          `- [info] default key exchange from OpenSSH 7.4 to 8.9&#xA;(kex) curve25519-sha256@libssh.org        -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62&#xA;                                          `- [info] default key exchange from OpenSSH 6.5 to 7.3&#xA;(kex) ecdh-sha2-nistp256                  -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency&#xA;                                          `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62&#xA;(kex) ecdh-sha2-nistp384                  -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency&#xA;                                          `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62&#xA;(kex) ecdh-sha2-nistp521                  -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency&#xA;                                          `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62&#xA;(kex) ext-info-s                          -- [info] available since OpenSSH 9.6&#xA;                                          `- [info] pseudo-algorithm that denotes the peer supports RFC8308 extensions&#xA;(kex) kex-strict-s-v00@openssh.com        -- [info] pseudo-algorithm that denotes the peer supports a stricter key exchange method as a counter-measure to the Terrapin attack (CVE-2023-48795)&#xA;&#xA;host-key algorithms&#xA;(key) rsa-sha2-512 (3072-bit)             -- [info] available since OpenSSH 7.2&#xA;(key) rsa-sha2-256 (3072-bit)             -- [info] available since OpenSSH 7.2, Dropbear SSH 2020.79&#xA;(key) ecdsa-sha2-nistp256                 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency&#xA;                                          `- [warn] using weak random number generator could reveal the key&#xA;                                          `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62&#xA;(key) ssh-ed25519                         -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79&#xA;&#xA;encryption algorithms (ciphers)&#xA;(enc) chacha20-poly1305@openssh.com       -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79&#xA;                                          `- [info] default cipher since OpenSSH 6.9&#xA;(enc) aes128-gcm@openssh.com              -- [info] available since OpenSSH 6.2&#xA;(enc) aes256-gcm@openssh.com              -- [info] available since OpenSSH 6.2&#xA;(enc) aes128-ctr                          -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52&#xA;(enc) aes192-ctr                          -- [info] available since OpenSSH 3.7&#xA;(enc) aes256-ctr                          -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52&#xA;&#xA;message authentication code algorithms&#xA;(mac) umac-64-etm@openssh.com             -- [warn] using small 64-bit tag size&#xA;                                          `- [info] available since OpenSSH 6.2&#xA;(mac) umac-128-etm@openssh.com            -- [info] available since OpenSSH 6.2&#xA;(mac) hmac-sha2-256-etm@openssh.com       -- [info] available since OpenSSH 6.2&#xA;(mac) hmac-sha2-512-etm@openssh.com       -- [info] available since OpenSSH 6.2&#xA;(mac) hmac-sha1-etm@openssh.com           -- [fail] using broken SHA-1 hash algorithm&#xA;                                          `- [info] available since OpenSSH 6.2&#xA;(mac) umac-64@openssh.com                 -- [warn] using encrypt-and-MAC mode&#xA;                                          `- [warn] using small 64-bit tag size&#xA;                                          `- [info] available since OpenSSH 4.7&#xA;(mac) umac-128@openssh.com                -- [warn] using encrypt-and-MAC mode&#xA;                                          `- [info] available since OpenSSH 6.2&#xA;(mac) hmac-sha2-256                       -- [warn] using encrypt-and-MAC mode&#xA;                                          `- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56&#xA;(mac) hmac-sha2-512                       -- [warn] using encrypt-and-MAC mode&#xA;                                          `- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56&#xA;(mac) hmac-sha1                           -- [fail] using broken SHA-1 hash algorithm&#xA;                                          `- [warn] using encrypt-and-MAC mode&#xA;                                          `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28&#xA;&#xA;fingerprints&#xA;(fin) ssh-ed25519: SHA256:MQLZsXQca6z39VMYmL3a+BkZCbBSQywXlwUQ7t/SJJc&#xA;(fin) ssh-rsa: SHA256:rSR43CCF4H6QSMPR+TudpYEMuH0xQ/61iE4ktcidw2c&#xA;&#xA;additional info&#xA;(nfo) Be aware that, while this target properly supports the strict key exchange method (via the kex-strict-?-v00@openssh.com marker) needed to protect against the Terrapin vulnerability (CVE-2023-48795), all peers must also support this feature as well, otherwise the vulnerability will still be present.  The following algorithms would allow an unpatched peer to create vulnerable SSH channels with this target: chacha20-poly1305@openssh.com.  If any CBC ciphers are in this list, you may remove them while leaving the -etm@openssh.com MACs in place; these MACs are fine while paired with non-CBC cipher types.&#xA;&#xA;Per la scansione del server ssh basta:&#xA;&#xA;ssh-audit serverssh &#xA;se la porta è di default, se no occorre specificarla.&#xA;&#xA;Altrimenti se si vuole verificare la compliance con un target specifico, si può usare il flag -P&#xA;Ad es. per verificare la configurazione ottimale rispetto ad una debian 12 di riferimento.&#xA;&#xA;ssh-audit -P &#34;Hardened Debian 12 (version 2)&#34; serverssh&#xA;&#xA;e l&#39;argomento di P è dato da una delle policies della seguente lista:&#xA;&#xA;ssh-audit -L &#xA;&#xA;La versione attuale di ssh-audit è la 3.3.0 che supporta al max. OpenSSH 9.9, Debian 12, Ubuntu 24 ecc.&#xA;&#xA;Con la 3.4.0, ci sarà il supporto a OpenSSH 10, Debian 13, si rimuoverà sshv1 ecc. (per maggiori info https://github.com/jtesta/ssh-audit)&#xA;&#xA;Se avessi più server da verificare?&#xA;&#xA;ssh-audit -t host.txt&#xA;&#xA;dove host.txt è un file contente una lista host, uno per linea, dal formato: HOST[:PORT]&#xA;&#xA;Scansione client&#xA;Prima si fa partire un server ssh-audit sulla porta 2222 (default, altrimenti si può cambiare con -p) &#xA;&#xA;ssh-audit -c&#xA;&#xA;e poi si prova la connessione ssh sulla porta 2222 (o su quella impostata su localhost)&#xA;&#xA;ssh -p2222 127.0.0.1&#xA;&#xA;Come per il server, il risultato con una configurazione di default, di solito, non è molto incoraggiante:&#xA;&#xA;Connection closed by 127.0.0.1 port 2222&#xA;general&#xA;(gen) client IP: 127.0.0.1&#xA;(gen) banner: SSH-2.0-OpenSSH10.0&#xA;(gen) software: OpenSSH 10.0&#xA;(gen) compression: enabled (zlib@openssh.com)&#xA;&#xA;key exchange algorithms&#xA;(kex) mlkem768x25519-sha256                        -- [info] available since OpenSSH 9.9&#xA;                                                   `- [info] hybrid key exchange based on post-quantum resistant algorithm and proven conventional X25519 algorithm&#xA;(kex) curve25519-sha256                            -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76&#xA;                                                   `- [info] default key exchange from OpenSSH 7.4 to 8.9&#xA;(kex) curve25519-sha256@libssh.org                 -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62&#xA;                                                   `- [info] default key exchange from OpenSSH 6.5 to 7.3&#xA;(kex) ecdh-sha2-nistp256                           -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency&#xA;                                                   `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62&#xA;(kex) ecdh-sha2-nistp384                           -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency&#xA;                                                   `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62&#xA;(kex) ecdh-sha2-nistp521                           -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency&#xA;                                                   `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62&#xA;(kex) diffie-hellman-group-exchange-sha256         -- [info] available since OpenSSH 4.4&#xA;(kex) diffie-hellman-group14-sha256                -- [warn] 2048-bit modulus only provides 112-bits of symmetric strength&#xA;                                                   `- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73&#xA;(kex) diffie-hellman-group16-sha512                -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73&#xA;(kex) diffie-hellman-group18-sha512                -- [info] available since OpenSSH 7.3&#xA;(kex) ext-info-c                                   -- [info] available since OpenSSH 7.2&#xA;                                                   `- [info] pseudo-algorithm that denotes the peer supports RFC8308 extensions&#xA;(kex) kex-strict-c-v00@openssh.com                 -- [info] pseudo-algorithm that denotes the peer supports a stricter key exchange method as a counter-measure to the Terrapin attack (CVE-2023-48795)&#xA;&#xA;host-key algorithms&#xA;(key) ssh-ed25519-cert-v01@openssh.com             -- [info] available since OpenSSH 6.5&#xA;(key) ecdsa-sha2-nistp256-cert-v01@openssh.com     -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency&#xA;                                                   `- [warn] using weak random number generator could reveal the key&#xA;                                                   `- [info] available since OpenSSH 5.7&#xA;(key) ecdsa-sha2-nistp384-cert-v01@openssh.com     -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency&#xA;                                                   `- [warn] using weak random number generator could reveal the key&#xA;                                                   `- [info] available since OpenSSH 5.7&#xA;(key) ecdsa-sha2-nistp521-cert-v01@openssh.com     -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency&#xA;                                                   `- [warn] using weak random number generator could reveal the key&#xA;                                                   `- [info] available since OpenSSH 5.7&#xA;(key) sk-ssh-ed25519-cert-v01@openssh.com          -- [info] available since OpenSSH 8.2&#xA;(key) sk-ecdsa-sha2-nistp256-cert-v01@openssh.com  -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency&#xA;                                                   `- [warn] using weak random number generator could reveal the key&#xA;                                                   `- [info] available since OpenSSH 8.2&#xA;(key) rsa-sha2-512-cert-v01@openssh.com            -- [info] available since OpenSSH 7.8&#xA;(key) rsa-sha2-256-cert-v01@openssh.com            -- [info] available since OpenSSH 7.8&#xA;(key) ssh-ed25519                                  -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79&#xA;(key) ecdsa-sha2-nistp256                          -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency&#xA;                                                   `- [warn] using weak random number generator could reveal the key&#xA;                                                   `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62&#xA;(key) ecdsa-sha2-nistp384                          -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency&#xA;                                                   `- [warn] using weak random number generator could reveal the key&#xA;                                                   `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62&#xA;(key) ecdsa-sha2-nistp521                          -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency&#xA;                                                   `- [warn] using weak random number generator could reveal the key&#xA;                                                   `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62&#xA;(key) sk-ssh-ed25519@openssh.com                   -- [info] available since OpenSSH 8.2&#xA;(key) sk-ecdsa-sha2-nistp256@openssh.com           -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency&#xA;                                                   `- [warn] using weak random number generator could reveal the key&#xA;                                                   `- [info] available since OpenSSH 8.2&#xA;(key) rsa-sha2-512                                 -- [info] available since OpenSSH 7.2&#xA;(key) rsa-sha2-256                                 -- [info] available since OpenSSH 7.2, Dropbear SSH 2020.79&#xA;&#xA;encryption algorithms (ciphers)&#xA;(enc) aes256-gcm@openssh.com                       -- [info] available since OpenSSH 6.2&#xA;(enc) chacha20-poly1305@openssh.com                -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79&#xA;                                                   `- [info] default cipher since OpenSSH 6.9&#xA;(enc) aes256-ctr                                   -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52&#xA;(enc) aes128-gcm@openssh.com                       -- [info] available since OpenSSH 6.2&#xA;(enc) aes128-ctr                                   -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52&#xA;&#xA;message authentication code algorithms&#xA;(mac) hmac-sha2-256-etm@openssh.com                -- [info] available since OpenSSH 6.2&#xA;(mac) hmac-sha1-etm@openssh.com                    -- [fail] using broken SHA-1 hash algorithm&#xA;                                                   `- [info] available since OpenSSH 6.2&#xA;(mac) umac-128-etm@openssh.com                     -- [info] available since OpenSSH 6.2&#xA;(mac) hmac-sha2-512-etm@openssh.com                -- [info] available since OpenSSH 6.2&#xA;(mac) hmac-sha2-256                                -- [warn] using encrypt-and-MAC mode&#xA;                                                   `- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56&#xA;(mac) hmac-sha1                                    -- [fail] using broken SHA-1 hash algorithm&#xA;                                                   `- [warn] using encrypt-and-MAC mode&#xA;                                                   `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28&#xA;(mac) umac-128@openssh.com                         -- [warn] using encrypt-and-MAC mode&#xA;                                                   `- [info] available since OpenSSH 6.2&#xA;(mac) hmac-sha2-512                                -- [warn] using encrypt-and-MAC mode&#xA;                                                   `- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56&#xA;&#xA;additional info&#xA;(nfo) Be aware that, while this target properly supports the strict key exchange method (via the kex-strict-?-v00@openssh.com marker) needed to protect against the Terrapin vulnerability (CVE-2023-48795), all peers must also support this feature as well, otherwise the vulnerability will still be present.  The following algorithms would allow an unpatched peer to create vulnerable SSH channels with this target: chacha20-poly1305@openssh.com.  If any CBC ciphers are in this list, you may remove them while leaving the -etm@openssh.com MACs in place; these MACs are fine while paired with non-CBC cipher types.&#xA;&#xA;Hardening&#xA;&#xA;Le scansioni dei client e dei server contengono numerosi suggerimenti per il miglioramento delle configurazioni.&#xA;&#xA;La conoscenza a grandi linee degli algoritmi usati da openssh per contrattare una connessione (e su questo può venire in aiuto, benché datato, il sito a cui ssh-audit.com si ispira: https://blog.stribik.technology/2015/01/04/secure-secure-shell.html) aiuterebbe.&#xA;&#xA;Oppure si può ricorrere o alle configurazioni &#34;precotte&#34; che potete trovare qui e magari partendo da quelle, limarle in base alle nostre esigenze.&#xA;&#xA;Come regola generale, in sintesi, ricordarsi di evitare in prima battuta:&#xA;&#xA;chiavi rsa &lt; 3072 bit&#xA;dsa&#xA;le curve nist&#xA;qualunque algoritmo che usi sha1&#xA;&#xA;Per il resto, basterebbe eliminare tutti gli algoritmi che risultano fail e warning dalla scansione e includere, in ordine decrescente, gli algoritmi più robusti che scaturiscono dalle liste degli algoritmi supportati dalla versione ssh in uso disponibili con ssh -Q:&#xA;&#xA;key exchange&#xA;ssh -Q kex&#xA;&#xA;cifratura simmetrica e simmetrica-autenticata&#xA;ssh -Q [ cipher | cipher-auth ]&#xA;&#xA;key types, CA signatures, certificate key types, tutti&#xA;ssh -Q [ key | key-ca-sign | key-cert | key-sig ]&#xA;&#xA;algoritmi di firma&#xA;ssh-Q sig&#xA;&#xA;L&#39;hardenizzazione di un servizio come ssh passa anche da altro. Esigerebbe una stretta sui metodi di autenticazione (la sola public key), restrizioi a utenti o gruppi di utenti ecc. (accennavo qualcosa qui)&#xA;&#xA;Ad ogni modo, una volta effettuato l&#39;hardening del server, ecco come si può presentare la scansione:&#xA;&#xA;general&#xA;(gen) banner: SSH-2.0-OpenSSH10.0p2 Raspbian-7&#xA;(gen) software: OpenSSH 10.0p2&#xA;(gen) compatibility: OpenSSH 9.6+, Dropbear SSH 2020.79+&#xA;(gen) compression: enabled (zlib@openssh.com)&#xA;&#xA;key exchange algorithms&#xA;(kex) sntrup761x25519-sha512@openssh.com    -- [info] available since OpenSSH 8.5&#xA;                                            `- [info] default key exchange from OpenSSH 9.0 to 9.8&#xA;                                            `- [info] hybrid key exchange based on post-quantum resistant algorithm and proven conventional X25519 algorithm&#xA;(kex) curve25519-sha256                     -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76&#xA;                                            `- [info] default key exchange from OpenSSH 7.4 to 8.9&#xA;(kex) curve25519-sha256@libssh.org          -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62&#xA;                                            `- [info] default key exchange from OpenSSH 6.5 to 7.3&#xA;(kex) diffie-hellman-group16-sha512         -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73&#xA;(kex) diffie-hellman-group18-sha512         -- [info] available since OpenSSH 7.3&#xA;(kex) diffie-hellman-group-exchange-sha256 (3072-bit) -- [info] available since OpenSSH 4.4&#xA;                                                      `- [info] OpenSSH&#39;s GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 3072. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V94/dh.c#L477).&#xA;(kex) ext-info-s                            -- [info] available since OpenSSH 9.6&#xA;                                            `- [info] pseudo-algorithm that denotes the peer supports RFC8308 extensions&#xA;(kex) kex-strict-s-v00@openssh.com          -- [info] pseudo-algorithm that denotes the peer supports a stricter key exchange method as a counter-measure to the Terrapin attack (CVE-2023-48795)&#xA;&#xA;host-key algorithms&#xA;(key) ssh-ed25519                           -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79&#xA;&#xA;encryption algorithms (ciphers)&#xA;(enc) aes256-gcm@openssh.com                -- [info] available since OpenSSH 6.2&#xA;(enc) aes256-ctr                            -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52&#xA;(enc) aes192-ctr                            -- [info] available since OpenSSH 3.7&#xA;(enc) aes128-gcm@openssh.com                -- [info] available since OpenSSH 6.2&#xA;(enc) aes128-ctr                            -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52&#xA;&#xA;message authentication code algorithms&#xA;(mac) hmac-sha2-256-etm@openssh.com         -- [info] available since OpenSSH 6.2&#xA;(mac) hmac-sha2-512-etm@openssh.com         -- [info] available since OpenSSH 6.2&#xA;(mac) umac-128-etm@openssh.com              -- [info] available since OpenSSH 6.2&#xA;&#xA;fingerprints&#xA;(fin) ssh-ed25519: SHA256:MQLZsXQca6z39VMYmL3a+BkZCbBSQywXlwUQ7t/SJJc&#xA;&#xA;Tutto molto verde, molto più rassicurante&#xA;&#xA;Idem dicasi per il client:&#xA;&#xA;general&#xA;(gen) client IP: 127.0.0.1&#xA;(gen) banner: SSH-2.0-OpenSSH_10.0&#xA;(gen) software: OpenSSH 10.0&#xA;(gen) compression: enabled (zlib@openssh.com)&#xA;&#xA;key exchange algorithms&#xA;(kex) sntrup761x25519-sha512@openssh.com    -- [info] available since OpenSSH 8.5&#xA;                                            `- [info] default key exchange from OpenSSH 9.0 to 9.8&#xA;                                            `- [info] hybrid key exchange based on post-quantum resistant algorithm and proven conventional X25519 algorithm&#xA;(kex) curve25519-sha256                     -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76&#xA;                                            `- [info] default key exchange from OpenSSH 7.4 to 8.9&#xA;(kex) curve25519-sha256@libssh.org          -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62&#xA;                                            `- [info] default key exchange from OpenSSH 6.5 to 7.3&#xA;(kex) diffie-hellman-group16-sha512         -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73&#xA;(kex) diffie-hellman-group18-sha512         -- [info] available since OpenSSH 7.3&#xA;(kex) diffie-hellman-group-exchange-sha256  -- [info] available since OpenSSH 4.4&#xA;(kex) ext-info-c                            -- [info] available since OpenSSH 7.2&#xA;                                            `- [info] pseudo-algorithm that denotes the peer supports RFC8308 extensions&#xA;(kex) kex-strict-c-v00@openssh.com          -- [info] pseudo-algorithm that denotes the peer supports a stricter key exchange method as a counter-measure to the Terrapin attack (CVE-2023-48795)&#xA;&#xA;host-key algorithms&#xA;(key) sk-ssh-ed25519-cert-v01@openssh.com   -- [info] available since OpenSSH 8.2&#xA;(key) ssh-ed25519-cert-v01@openssh.com      -- [info] available since OpenSSH 6.5&#xA;(key) rsa-sha2-512-cert-v01@openssh.com     -- [info] available since OpenSSH 7.8&#xA;(key) rsa-sha2-256-cert-v01@openssh.com     -- [info] available since OpenSSH 7.8&#xA;(key) sk-ssh-ed25519@openssh.com            -- [info] available since OpenSSH 8.2&#xA;(key) ssh-ed25519                           -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79&#xA;(key) rsa-sha2-512                          -- [info] available since OpenSSH 7.2&#xA;(key) rsa-sha2-256                          -- [info] available since OpenSSH 7.2, Dropbear SSH 2020.79&#xA;&#xA;encryption algorithms (ciphers)&#xA;(enc) aes256-gcm@openssh.com                -- [info] available since OpenSSH 6.2&#xA;(enc) aes256-ctr                            -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52&#xA;(enc) aes192-ctr                            -- [info] available since OpenSSH 3.7&#xA;(enc) aes128-gcm@openssh.com                -- [info] available since OpenSSH 6.2&#xA;(enc) aes128-ctr                            -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52&#xA;&#xA;message authentication code algorithms&#xA;(mac) hmac-sha2-256-etm@openssh.com         -- [info] available since OpenSSH 6.2&#xA;(mac) hmac-sha2-512-etm@openssh.com         -- [info] available since OpenSSH 6.2&#xA;(mac) umac-128-etm@openssh.com              -- [info] available since OpenSSH 6.2&#xA;Connection closed by 127.0.0.1 port 2222&#xA;Giusto per completezza, anche se la scansione generica può essere positiva, non è detto che lo sia l&#39;aderenza ad una specifica compliance.&#xA;&#xA;Una scansione di questo tipo infatti tiene conto di tutti gli algoritmi che devono essere presenti. E nell&#39;ordine stabilito.]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/c19ce1b25-2f8843/r0tEnEU2zL4y/WhbF4H8D4mnRULqFV8Cz9IYKBYu36Ahl5OeonsxT.jpg" alt="ssh-audit"></p>

<p><code>ssh-audit</code> è un un comodo tool per l&#39;audit di sicurezza del server e del client SSH (banner, scambio di chiavi, crittografia, mac, compressione, compatibilità, sicurezza, ecc.)</p>

<p>Il sito di riferimento: <a href="https://www.ssh-audit.com/" rel="nofollow">https://www.ssh-audit.com/</a> da cui si può effettuare una scansione sia del proprio client che di un server.

Questa sezione <a href="https://www.ssh-audit.com/hardening_guides.html" rel="nofollow">https://www.ssh-audit.com/hardening_guides.html</a> invece fornisce una serie di configurazioni rapide e sicure per la pletora di client e server più noti.</p>

<p>ssh-audit permette di eseguire delle scansioni generiche client e/o server o di controllare una specifica compliance (ne parlerò più avanti) in base al sistema in uso</p>

<h2 id="installare-ssh-audit">Installare ssh-audit</h2>

<p>Trattandosi di una utility via CLI, la installerò con <code>pipx</code> che mi garantisce il necessario isolamento e un link all&#39;eseguibile che sia “globale” per l&#39;utente.</p>

<pre><code class="language-bash">pipx install ssh-audit
# o pipx install ssh-audit --python python&lt;versione&gt;
# se si vuole una versione di python specifica
</code></pre>

<p>Se non dovesse essere presente pipx, nella nostra home:</p>

<pre><code class="language-bash"># aggiornamento e installazione pip, pipx
pip install --user -U pip pipx
</code></pre>

<p><code>ssh-audit</code> può essere usato per il check e la configurazione di un server ssh o del client.</p>

<h2 id="scansione-server">Scansione server</h2>

<p>Semplice.</p>

<pre><code class="language-bash">ssh-audit -p &lt;porta ssh&gt; &lt;ip / server ssh&gt;
</code></pre>

<p>effettua la scansione di un server ssh. Il risultato consisterà in una serie di informazioni sulle direttive riguardanti cipher, klex, mac ecc. che saranno:</p>
<ul><li><strong>[info]</strong> di colore verde o bianco corrispondenti a configurazioni corrette</li>
<li><strong>[warning]</strong> di colore giallo, corrispondenti a configurazioni da attenzionare</li>
<li><strong>[fail]</strong> di colore rosso, corrispondenti a configurazioni palesemente critiche e da correggere urgentemente.</li></ul>

<p>Ecco un es. di scansione sul default ssh server di una debian 13 (RaspBI 2):</p>

<pre><code># general
(gen) banner: SSH-2.0-OpenSSH_10.0p2 Raspbian-7
(gen) software: OpenSSH 10.0p2
(gen) compatibility: OpenSSH 9.9+, Dropbear SSH 2020.79+
(gen) compression: enabled (zlib@openssh.com)

# key exchange algorithms
(kex) mlkem768x25519-sha256               -- [info] available since OpenSSH 9.9
                                          `- [info] hybrid key exchange based on post-quantum resistant algorithm and proven conventional X25519 algorithm
(kex) sntrup761x25519-sha512              -- [info] available since OpenSSH 9.9
                                          `- [info] default key exchange since OpenSSH 9.9
                                          `- [info] hybrid key exchange based on post-quantum resistant algorithm and proven conventional X25519 algorithm
(kex) sntrup761x25519-sha512@openssh.com  -- [info] available since OpenSSH 8.5
                                          `- [info] default key exchange from OpenSSH 9.0 to 9.8
                                          `- [info] hybrid key exchange based on post-quantum resistant algorithm and proven conventional X25519 algorithm
(kex) curve25519-sha256                   -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
                                          `- [info] default key exchange from OpenSSH 7.4 to 8.9
(kex) curve25519-sha256@libssh.org        -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
                                          `- [info] default key exchange from OpenSSH 6.5 to 7.3
(kex) ecdh-sha2-nistp256                  -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
                                          `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) ecdh-sha2-nistp384                  -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
                                          `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) ecdh-sha2-nistp521                  -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
                                          `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) ext-info-s                          -- [info] available since OpenSSH 9.6
                                          `- [info] pseudo-algorithm that denotes the peer supports RFC8308 extensions
(kex) kex-strict-s-v00@openssh.com        -- [info] pseudo-algorithm that denotes the peer supports a stricter key exchange method as a counter-measure to the Terrapin attack (CVE-2023-48795)

# host-key algorithms
(key) rsa-sha2-512 (3072-bit)             -- [info] available since OpenSSH 7.2
(key) rsa-sha2-256 (3072-bit)             -- [info] available since OpenSSH 7.2, Dropbear SSH 2020.79
(key) ecdsa-sha2-nistp256                 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
                                          `- [warn] using weak random number generator could reveal the key
                                          `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(key) ssh-ed25519                         -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79

# encryption algorithms (ciphers)
(enc) chacha20-poly1305@openssh.com       -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79
                                          `- [info] default cipher since OpenSSH 6.9
(enc) aes128-gcm@openssh.com              -- [info] available since OpenSSH 6.2
(enc) aes256-gcm@openssh.com              -- [info] available since OpenSSH 6.2
(enc) aes128-ctr                          -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) aes192-ctr                          -- [info] available since OpenSSH 3.7
(enc) aes256-ctr                          -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52

# message authentication code algorithms
(mac) umac-64-etm@openssh.com             -- [warn] using small 64-bit tag size
                                          `- [info] available since OpenSSH 6.2
(mac) umac-128-etm@openssh.com            -- [info] available since OpenSSH 6.2
(mac) hmac-sha2-256-etm@openssh.com       -- [info] available since OpenSSH 6.2
(mac) hmac-sha2-512-etm@openssh.com       -- [info] available since OpenSSH 6.2
(mac) hmac-sha1-etm@openssh.com           -- [fail] using broken SHA-1 hash algorithm
                                          `- [info] available since OpenSSH 6.2
(mac) umac-64@openssh.com                 -- [warn] using encrypt-and-MAC mode
                                          `- [warn] using small 64-bit tag size
                                          `- [info] available since OpenSSH 4.7
(mac) umac-128@openssh.com                -- [warn] using encrypt-and-MAC mode
                                          `- [info] available since OpenSSH 6.2
(mac) hmac-sha2-256                       -- [warn] using encrypt-and-MAC mode
                                          `- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56
(mac) hmac-sha2-512                       -- [warn] using encrypt-and-MAC mode
                                          `- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56
(mac) hmac-sha1                           -- [fail] using broken SHA-1 hash algorithm
                                          `- [warn] using encrypt-and-MAC mode
                                          `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28

# fingerprints
(fin) ssh-ed25519: SHA256:MQLZsXQca6z39VMYmL3a+BkZCbBSQywXlwUQ7t/SJJc
(fin) ssh-rsa: SHA256:rSR43CCF4H6QSMPR+TudpYEMuH0xQ/61iE4ktcidw2c

# additional info
(nfo) Be aware that, while this target properly supports the strict key exchange method (via the kex-strict-?-v00@openssh.com marker) needed to protect against the Terrapin vulnerability (CVE-2023-48795), all peers must also support this feature as well, otherwise the vulnerability will still be present.  The following algorithms would allow an unpatched peer to create vulnerable SSH channels with this target: chacha20-poly1305@openssh.com.  If any CBC ciphers are in this list, you may remove them while leaving the *-etm@openssh.com MACs in place; these MACs are fine while paired with non-CBC cipher types.
</code></pre>

<p>Per la scansione del server ssh basta:</p>

<pre><code class="language-bash">ssh-audit server_ssh 
# se la porta è di default, se no occorre specificarla.
</code></pre>

<p>Altrimenti se si vuole verificare la compliance con un target specifico, si può usare il flag <code>-P</code>
Ad es. per verificare la configurazione ottimale rispetto ad una debian 12 di riferimento.</p>

<pre><code class="language-bash">ssh-audit -P &#34;Hardened Debian 12 (version 2)&#34; &lt;server_ssh&gt;
</code></pre>

<p>e l&#39;argomento di <code>P</code> è dato da una delle policies della seguente lista:</p>

<pre><code class="language-bash">ssh-audit -L 
</code></pre>

<p>La versione attuale di ssh-audit è la <strong>3.3.0</strong> che supporta al max. <strong>OpenSSH 9.9</strong>, <strong>Debian 12</strong>, <strong>Ubuntu 24</strong> ecc.</p>

<p>Con la 3.4.0, ci sarà il supporto a <strong>OpenSSH 10</strong>, <strong>Debian 13</strong>, si rimuoverà sshv1 ecc. (per maggiori info <a href="https://github.com/jtesta/ssh-audit" rel="nofollow">https://github.com/jtesta/ssh-audit</a>)</p>

<p>Se avessi più server da verificare?</p>

<pre><code class="language-bash">ssh-audit -t host.txt
</code></pre>

<p>dove <code>host.txt</code> è un file contente una lista host, uno per linea, dal formato: <code>HOST[:PORT]</code></p>

<h2 id="scansione-client">Scansione client</h2>

<p>Prima si fa partire un server ssh-audit sulla porta 2222 (default, altrimenti si può cambiare con <code>-p</code>)</p>

<pre><code class="language-bash">ssh-audit -c
</code></pre>

<p>e poi si prova la connessione ssh sulla porta 2222 (o su quella impostata su localhost)</p>

<pre><code class="language-bash">ssh -p2222 127.0.0.1
</code></pre>

<p>Come per il server, il risultato con una configurazione di default, di solito, non è molto incoraggiante:</p>

<pre><code class="language-bash">Connection closed by 127.0.0.1 port 2222
# general
(gen) client IP: 127.0.0.1
(gen) banner: SSH-2.0-OpenSSH_10.0
(gen) software: OpenSSH 10.0
(gen) compression: enabled (zlib@openssh.com)

# key exchange algorithms
(kex) mlkem768x25519-sha256                        -- [info] available since OpenSSH 9.9
                                                   `- [info] hybrid key exchange based on post-quantum resistant algorithm and proven conventional X25519 algorithm
(kex) curve25519-sha256                            -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
                                                   `- [info] default key exchange from OpenSSH 7.4 to 8.9
(kex) curve25519-sha256@libssh.org                 -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
                                                   `- [info] default key exchange from OpenSSH 6.5 to 7.3
(kex) ecdh-sha2-nistp256                           -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
                                                   `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) ecdh-sha2-nistp384                           -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
                                                   `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) ecdh-sha2-nistp521                           -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
                                                   `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) diffie-hellman-group-exchange-sha256         -- [info] available since OpenSSH 4.4
(kex) diffie-hellman-group14-sha256                -- [warn] 2048-bit modulus only provides 112-bits of symmetric strength
                                                   `- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
(kex) diffie-hellman-group16-sha512                -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
(kex) diffie-hellman-group18-sha512                -- [info] available since OpenSSH 7.3
(kex) ext-info-c                                   -- [info] available since OpenSSH 7.2
                                                   `- [info] pseudo-algorithm that denotes the peer supports RFC8308 extensions
(kex) kex-strict-c-v00@openssh.com                 -- [info] pseudo-algorithm that denotes the peer supports a stricter key exchange method as a counter-measure to the Terrapin attack (CVE-2023-48795)

# host-key algorithms
(key) ssh-ed25519-cert-v01@openssh.com             -- [info] available since OpenSSH 6.5
(key) ecdsa-sha2-nistp256-cert-v01@openssh.com     -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
                                                   `- [warn] using weak random number generator could reveal the key
                                                   `- [info] available since OpenSSH 5.7
(key) ecdsa-sha2-nistp384-cert-v01@openssh.com     -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
                                                   `- [warn] using weak random number generator could reveal the key
                                                   `- [info] available since OpenSSH 5.7
(key) ecdsa-sha2-nistp521-cert-v01@openssh.com     -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
                                                   `- [warn] using weak random number generator could reveal the key
                                                   `- [info] available since OpenSSH 5.7
(key) sk-ssh-ed25519-cert-v01@openssh.com          -- [info] available since OpenSSH 8.2
(key) sk-ecdsa-sha2-nistp256-cert-v01@openssh.com  -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
                                                   `- [warn] using weak random number generator could reveal the key
                                                   `- [info] available since OpenSSH 8.2
(key) rsa-sha2-512-cert-v01@openssh.com            -- [info] available since OpenSSH 7.8
(key) rsa-sha2-256-cert-v01@openssh.com            -- [info] available since OpenSSH 7.8
(key) ssh-ed25519                                  -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79
(key) ecdsa-sha2-nistp256                          -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
                                                   `- [warn] using weak random number generator could reveal the key
                                                   `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(key) ecdsa-sha2-nistp384                          -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
                                                   `- [warn] using weak random number generator could reveal the key
                                                   `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(key) ecdsa-sha2-nistp521                          -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
                                                   `- [warn] using weak random number generator could reveal the key
                                                   `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(key) sk-ssh-ed25519@openssh.com                   -- [info] available since OpenSSH 8.2
(key) sk-ecdsa-sha2-nistp256@openssh.com           -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
                                                   `- [warn] using weak random number generator could reveal the key
                                                   `- [info] available since OpenSSH 8.2
(key) rsa-sha2-512                                 -- [info] available since OpenSSH 7.2
(key) rsa-sha2-256                                 -- [info] available since OpenSSH 7.2, Dropbear SSH 2020.79

# encryption algorithms (ciphers)
(enc) aes256-gcm@openssh.com                       -- [info] available since OpenSSH 6.2
(enc) chacha20-poly1305@openssh.com                -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79
                                                   `- [info] default cipher since OpenSSH 6.9
(enc) aes256-ctr                                   -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) aes128-gcm@openssh.com                       -- [info] available since OpenSSH 6.2
(enc) aes128-ctr                                   -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52

# message authentication code algorithms
(mac) hmac-sha2-256-etm@openssh.com                -- [info] available since OpenSSH 6.2
(mac) hmac-sha1-etm@openssh.com                    -- [fail] using broken SHA-1 hash algorithm
                                                   `- [info] available since OpenSSH 6.2
(mac) umac-128-etm@openssh.com                     -- [info] available since OpenSSH 6.2
(mac) hmac-sha2-512-etm@openssh.com                -- [info] available since OpenSSH 6.2
(mac) hmac-sha2-256                                -- [warn] using encrypt-and-MAC mode
                                                   `- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56
(mac) hmac-sha1                                    -- [fail] using broken SHA-1 hash algorithm
                                                   `- [warn] using encrypt-and-MAC mode
                                                   `- [info] available since OpenSSH 2.1.0, Dropbear SSH 0.28
(mac) umac-128@openssh.com                         -- [warn] using encrypt-and-MAC mode
                                                   `- [info] available since OpenSSH 6.2
(mac) hmac-sha2-512                                -- [warn] using encrypt-and-MAC mode
                                                   `- [info] available since OpenSSH 5.9, Dropbear SSH 2013.56

# additional info
(nfo) Be aware that, while this target properly supports the strict key exchange method (via the kex-strict-?-v00@openssh.com marker) needed to protect against the Terrapin vulnerability (CVE-2023-48795), all peers must also support this feature as well, otherwise the vulnerability will still be present.  The following algorithms would allow an unpatched peer to create vulnerable SSH channels with this target: chacha20-poly1305@openssh.com.  If any CBC ciphers are in this list, you may remove them while leaving the *-etm@openssh.com MACs in place; these MACs are fine while paired with non-CBC cipher types.
</code></pre>

<h2 id="hardening">Hardening</h2>

<p>Le scansioni dei client e dei server contengono numerosi suggerimenti per il miglioramento delle configurazioni.</p>

<p>La conoscenza a grandi linee degli algoritmi usati da openssh per contrattare una connessione (e su questo può venire in aiuto, benché datato, il sito a cui ssh-audit.com si ispira: <a href="https://blog.stribik.technology/2015/01/04/secure-secure-shell.html" rel="nofollow">https://blog.stribik.technology/2015/01/04/secure-secure-shell.html</a>) aiuterebbe.</p>

<p>Oppure si può ricorrere o alle configurazioni “precotte” che potete trovare <a href="https://www.ssh-audit.com/hardening_guides.html" rel="nofollow">qui</a> e magari partendo da quelle, limarle in base alle nostre esigenze.</p>

<p>Come regola generale, in sintesi, ricordarsi di evitare in prima battuta:</p>
<ul><li>chiavi rsa &lt; 3072 bit</li>
<li>dsa</li>
<li>le curve nist</li>
<li>qualunque algoritmo che usi sha1</li></ul>

<p>Per il resto, basterebbe eliminare tutti gli algoritmi che risultano fail e warning dalla scansione e includere, in ordine decrescente, gli algoritmi più robusti che scaturiscono dalle liste degli algoritmi supportati dalla versione ssh in uso disponibili con <code>ssh -Q</code>:</p>

<pre><code class="language-bash"># key exchange
ssh -Q kex

# cifratura simmetrica e simmetrica-autenticata
ssh -Q [ cipher | cipher-auth ]

# key types, CA signatures, certificate key types, tutti
ssh -Q [ key | key-ca-sign | key-cert | key-sig ]

# algoritmi di firma
ssh-Q sig
</code></pre>

<p>L&#39;hardenizzazione di un servizio come ssh passa anche da altro. Esigerebbe una stretta sui metodi di autenticazione (la sola public key), restrizioi a utenti o gruppi di utenti ecc. (accennavo qualcosa qui)</p>

<p>Ad ogni modo, una volta effettuato l&#39;hardening del server, ecco come si può presentare la scansione:</p>

<pre><code># general
(gen) banner: SSH-2.0-OpenSSH_10.0p2 Raspbian-7
(gen) software: OpenSSH 10.0p2
(gen) compatibility: OpenSSH 9.6+, Dropbear SSH 2020.79+
(gen) compression: enabled (zlib@openssh.com)

# key exchange algorithms
(kex) sntrup761x25519-sha512@openssh.com    -- [info] available since OpenSSH 8.5
                                            `- [info] default key exchange from OpenSSH 9.0 to 9.8
                                            `- [info] hybrid key exchange based on post-quantum resistant algorithm and proven conventional X25519 algorithm
(kex) curve25519-sha256                     -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
                                            `- [info] default key exchange from OpenSSH 7.4 to 8.9
(kex) curve25519-sha256@libssh.org          -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
                                            `- [info] default key exchange from OpenSSH 6.5 to 7.3
(kex) diffie-hellman-group16-sha512         -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
(kex) diffie-hellman-group18-sha512         -- [info] available since OpenSSH 7.3
(kex) diffie-hellman-group-exchange-sha256 (3072-bit) -- [info] available since OpenSSH 4.4
                                                      `- [info] OpenSSH&#39;s GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 3072. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).
(kex) ext-info-s                            -- [info] available since OpenSSH 9.6
                                            `- [info] pseudo-algorithm that denotes the peer supports RFC8308 extensions
(kex) kex-strict-s-v00@openssh.com          -- [info] pseudo-algorithm that denotes the peer supports a stricter key exchange method as a counter-measure to the Terrapin attack (CVE-2023-48795)

# host-key algorithms
(key) ssh-ed25519                           -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79

# encryption algorithms (ciphers)
(enc) aes256-gcm@openssh.com                -- [info] available since OpenSSH 6.2
(enc) aes256-ctr                            -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) aes192-ctr                            -- [info] available since OpenSSH 3.7
(enc) aes128-gcm@openssh.com                -- [info] available since OpenSSH 6.2
(enc) aes128-ctr                            -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52

# message authentication code algorithms
(mac) hmac-sha2-256-etm@openssh.com         -- [info] available since OpenSSH 6.2
(mac) hmac-sha2-512-etm@openssh.com         -- [info] available since OpenSSH 6.2
(mac) umac-128-etm@openssh.com              -- [info] available since OpenSSH 6.2

# fingerprints
(fin) ssh-ed25519: SHA256:MQLZsXQca6z39VMYmL3a+BkZCbBSQywXlwUQ7t/SJJc
</code></pre>

<p>Tutto molto verde, molto più rassicurante</p>

<p>Idem dicasi per il client:</p>

<pre><code># general
(gen) client IP: 127.0.0.1
(gen) banner: SSH-2.0-OpenSSH_10.0
(gen) software: OpenSSH 10.0
(gen) compression: enabled (zlib@openssh.com)

# key exchange algorithms
(kex) sntrup761x25519-sha512@openssh.com    -- [info] available since OpenSSH 8.5
                                            `- [info] default key exchange from OpenSSH 9.0 to 9.8
                                            `- [info] hybrid key exchange based on post-quantum resistant algorithm and proven conventional X25519 algorithm
(kex) curve25519-sha256                     -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
                                            `- [info] default key exchange from OpenSSH 7.4 to 8.9
(kex) curve25519-sha256@libssh.org          -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
                                            `- [info] default key exchange from OpenSSH 6.5 to 7.3
(kex) diffie-hellman-group16-sha512         -- [info] available since OpenSSH 7.3, Dropbear SSH 2016.73
(kex) diffie-hellman-group18-sha512         -- [info] available since OpenSSH 7.3
(kex) diffie-hellman-group-exchange-sha256  -- [info] available since OpenSSH 4.4
(kex) ext-info-c                            -- [info] available since OpenSSH 7.2
                                            `- [info] pseudo-algorithm that denotes the peer supports RFC8308 extensions
(kex) kex-strict-c-v00@openssh.com          -- [info] pseudo-algorithm that denotes the peer supports a stricter key exchange method as a counter-measure to the Terrapin attack (CVE-2023-48795)

# host-key algorithms
(key) sk-ssh-ed25519-cert-v01@openssh.com   -- [info] available since OpenSSH 8.2
(key) ssh-ed25519-cert-v01@openssh.com      -- [info] available since OpenSSH 6.5
(key) rsa-sha2-512-cert-v01@openssh.com     -- [info] available since OpenSSH 7.8
(key) rsa-sha2-256-cert-v01@openssh.com     -- [info] available since OpenSSH 7.8
(key) sk-ssh-ed25519@openssh.com            -- [info] available since OpenSSH 8.2
(key) ssh-ed25519                           -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79
(key) rsa-sha2-512                          -- [info] available since OpenSSH 7.2
(key) rsa-sha2-256                          -- [info] available since OpenSSH 7.2, Dropbear SSH 2020.79

# encryption algorithms (ciphers)
(enc) aes256-gcm@openssh.com                -- [info] available since OpenSSH 6.2
(enc) aes256-ctr                            -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) aes192-ctr                            -- [info] available since OpenSSH 3.7
(enc) aes128-gcm@openssh.com                -- [info] available since OpenSSH 6.2
(enc) aes128-ctr                            -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52

# message authentication code algorithms
(mac) hmac-sha2-256-etm@openssh.com         -- [info] available since OpenSSH 6.2
(mac) hmac-sha2-512-etm@openssh.com         -- [info] available since OpenSSH 6.2
(mac) umac-128-etm@openssh.com              -- [info] available since OpenSSH 6.2
Connection closed by 127.0.0.1 port 2222
</code></pre>

<p>Giusto per completezza, anche se la scansione generica può essere positiva, non è detto che lo sia l&#39;aderenza ad una specifica compliance.</p>

<p>Una scansione di questo tipo infatti tiene conto di <strong>tutti</strong> gli algoritmi che devono essere presenti. E nell&#39;ordine stabilito.</p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/audit-per-client-e-server-ssh</guid>
      <pubDate>Sat, 13 Dec 2025 11:08:44 +0000</pubDate>
    </item>
    <item>
      <title>La risposta alla vita, l&#39;universo e a tutto quanto: Fedora 42</title>
      <link>https://noblogo.org/aytin/la-risposta-alla-vita-luniverso-e-a-tutto-quanto-fedora-42</link>
      <description>&lt;![CDATA[Fedora 42&#xA;smallida: a href=&#34;https://fedoramagazine.org/whats-new-fedora-workstation-42&#34;fedoramagazine.org/a/i/small&#xA;&#xA;L&#39;aggiornamento a fedora 42 scorre abbastanza tranquillamente con dnf-plugin-system-upgrade nel mio solito modo, ormai consolidato dal passaggio di 7 major release.&#xA;&#xA;Sempre sul filo del rasoio, con poco spazio (dovrò decidermi a ridimensionare un po&#39; di volumi) ma i (più di) 6 giga di aggiornamento vanno via lisci.&#xA;!--more--&#xA;Dopo l&#39;aggiornamento non noto particolari problemi. Un po&#39; di estensioni saltate per aria (fisiologico), qualche repository ancora non aggiornato, Niente di tragico.&#xA;&#xA;dnf repo list --disabled mi dà le indicazioni dei repo disabilitati.&#xA;&#xA;Fra i tanti (sono di tipo “test” e “source” al 99%) ne spiccano due che non godono ancora della visibilità a fedora 42. Sono quelli relativi a vagrant e virtualbox. I binari di fedora 41 sono ancora compatibili con fedora 42 per cui, per non lasciare disabilitati questi repo o per non vedere gli irritanti errori 404 durante l&#39;update, compio un&#39;azione un po&#39; indiscriminata:&#xA;&#xA;riabilito i repo (e fin qui…)&#xA;&#xA;dnf config-manager setopt hashicorp.enabled=1&#xA;dnf config-manager setopt virtualbox.enabled=1&#xA;modifico brutalmente il baseurl scolpendo il numero di versione:&#xA;&#xA;dnf config-manager setopt hashicorp.baseurl=https://rpm.releases.hashicorp.com/fedora/41/x8664/stable&#xA;dnf config-manager setopt virtualbox.baseurl=&#34;http://download.virtualbox.org/virtualbox/rpm/fedora/41/x8664&#34;&#xA;smallNota a margine: quest&#39;operazione mi ha dato modo di approfondire un po&#39; la conoscenza di dnf5. La vecchia cartella /etc/yum/repos.d per le configurazioni dei repo viene mantenuta ancora per legacy. Le modifiche fatte attraverso dnf config-manager vengono mantenute in un file, solitamente 99-configmanager.repo posizionato in /etc/dnf/repos.override.d./small&#xA;&#xA;Sistemati i repository volevo rimettere a posto l&#39;estensione per le notifiche delle app nella tray, visto che AppIndicator and KStatusNotifierItem Support si è rotta dopo l&#39;aggiornamento.&#xA;&#xA;La installo dal repository e semplicemente creo un link simbolico in ~/.local/share&#xA;ln -s /usr/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com ~/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com&#xA;&#xA;Così funziona. Mah…&#xA;&#xA;Tutto il resto sembra ok. Mi ritrovo con i profili per il risparmio energetico finalmente funzionanti senza ricorrere a strani sotterfugi (prima per passare da un profilo all&#39;altro dovevo staccare l&#39;alimentazione, se no gli rimbalzava. Ora funziona), un nuovo font, il monitoraggio per il consumo, nuove notifiche ecc. (rif. https://fedoramagazine.org/whats-new-fedora-workstation-42/)&#xA;&#xA;Insomma la solita Fedora, aggiornata e soddisfacentemente stabile.&#xA;&#xA;#fedora42 #fedora #upgrade]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/6ac28a0f2-92b4f8/nwbVk6diJ53Q/uABeL2j67WPABmsuMviqa7IF8i3VLLnRi79vZyhv.jpg" alt="Fedora 42">
<small><i>da: <a href="https://fedoramagazine.org/whats-new-fedora-workstation-42" rel="nofollow">fedoramagazine.org</a></i></small></p>

<p>L&#39;aggiornamento a fedora 42 scorre abbastanza tranquillamente con <code>dnf-plugin-system-upgrade</code> nel <a href="/aytin/aggiornando-fedora-37/" rel="nofollow">mio solito modo</a>, ormai consolidato dal passaggio di 7 major release.</p>

<p>Sempre sul filo del rasoio, con poco spazio (dovrò decidermi a ridimensionare un po&#39; di volumi) ma i (più di) 6 giga di aggiornamento vanno via lisci.

Dopo l&#39;aggiornamento non noto particolari problemi. Un po&#39; di estensioni saltate per aria (fisiologico), qualche repository ancora non aggiornato, Niente di tragico.</p>

<p><code>dnf repo list --disabled</code> mi dà le indicazioni dei repo disabilitati.</p>

<p>Fra i tanti (sono di tipo “test” e “source” al 99%) ne spiccano due che non godono ancora della visibilità a fedora 42. Sono quelli relativi a vagrant e virtualbox. I binari di fedora 41 sono ancora compatibili con fedora 42 per cui, per non lasciare disabilitati questi repo o per non vedere gli irritanti errori 404 durante l&#39;update, compio un&#39;azione un po&#39; indiscriminata:</p>
<ul><li>riabilito i repo (e fin qui…)</li></ul>

<pre><code class="language-bash">dnf config-manager setopt hashicorp.enabled=1
dnf config-manager setopt virtualbox.enabled=1
</code></pre>
<ul><li>modifico brutalmente il baseurl scolpendo il numero di versione:</li></ul>

<pre><code class="language-bash">dnf config-manager setopt hashicorp.baseurl=https://rpm.releases.hashicorp.com/fedora/41/x86_64/stable
dnf config-manager setopt virtualbox.baseurl=&#34;http://download.virtualbox.org/virtualbox/rpm/fedora/41/x86_64&#34;
</code></pre>

<p><small><strong>Nota a margine:</strong> quest&#39;operazione mi ha dato modo di approfondire un po&#39; la conoscenza di <code>dnf5</code>. La vecchia cartella <code>/etc/yum/repos.d</code> per le configurazioni dei repo viene mantenuta ancora per legacy. Le modifiche fatte attraverso <code>dnf config-manager</code> vengono mantenute in un file, solitamente <code>99-config_manager.repo</code> posizionato in <code>/etc/dnf/repos.override.d</code>.</small></p>

<p>Sistemati i repository volevo rimettere a posto l&#39;estensione per le notifiche delle app nella tray, visto che <strong>AppIndicator and KStatusNotifierItem Support</strong> si è rotta dopo l&#39;aggiornamento.</p>

<p>La installo dal repository e semplicemente creo un link simbolico in ~/.local/share</p>

<pre><code class="language-bash">ln -s /usr/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com ~/.local/share/gnome-shell/extensions/appindicatorsupport@rgcjonas.gmail.com
</code></pre>

<p>Così funziona. Mah…</p>

<p>Tutto il resto sembra ok. Mi ritrovo con i profili per il risparmio energetico finalmente funzionanti senza ricorrere a strani sotterfugi (prima per passare da un profilo all&#39;altro dovevo staccare l&#39;alimentazione, se no gli rimbalzava. Ora funziona), un nuovo font, il monitoraggio per il consumo, nuove notifiche ecc. (rif. <a href="https://fedoramagazine.org/whats-new-fedora-workstation-42/" rel="nofollow">https://fedoramagazine.org/whats-new-fedora-workstation-42/</a>)</p>

<p>Insomma la solita Fedora, aggiornata e soddisfacentemente stabile.</p>

<p><a href="/aytin/tag:fedora42" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">fedora42</span></a> <a href="/aytin/tag:fedora" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">fedora</span></a> <a href="/aytin/tag:upgrade" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">upgrade</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/la-risposta-alla-vita-luniverso-e-a-tutto-quanto-fedora-42</guid>
      <pubDate>Tue, 22 Apr 2025 11:46:23 +0000</pubDate>
    </item>
  </channel>
</rss>