La criptografia te com objectiu la integritat, la confidencialitat i el no repudi de les dades.

Introducció

La criptografia és un tema molt estens, però tens sort ja que només cal entendre algunes parts concretes de la criptografia per poder fer-la servir.

La criptografia en general té tres objectius:

  • Integritat. Demostrar que el missatge no ha estat modificat, ni accidentalment ni deliberadament.
  • Confidencialitat. Fer que el missatge sigui il·legible per a ningú, excepte el destinatari previst.
  • No repudi. Poder demostrar que el missatge prové del remitent declarat.

Les diferents eines de criptografia admeten diferents aspectes d'aquests objectius.

Funcions hash

Una funció hash és com una caixa negra que pren una sola entrada i dóna una única sortida.

flowchart LR
   data["very long data"] 
   hash["2d..e4"]
   data --> hash

Una funció hash pren una entrada de longitud arbitrària (un fitxer, un missatge, un vídeo, etc.) i produeix una sortida de longitud fixa (per exemple, 256 bits per a SHA-256).

Una funció hash pren com a entrada qualsevol seqüència de bytes que vulguis i produeix una seqüènica única de pocs bytes com a resultat.

Per exemple la funció SHA-256 sempre torna 32 bytes com a resultat, dona igual que la seqüència d’entrada sigui de 1000 bytes com de 2 Terabytes.

La seqüència de bytes por ser qualsevol cosa, un fitxer de video, audio, etc. perquè a la fi tots son bytes.

I el que és més important, donada la mateixa entrada, la funció hash sempre produeix la mateixa seqüència de bytes.

A un fitxer li pots canviar el nom, però sempre tindrà el mateix hash a no ser que el modifiquis.

Per això el hash pot identificar de manera unívoca un fitxer i el nom del fitxer no

Per qué serveix una funció hash?

Ves a la pàgina web Ubuntu 22.04 LTS (Jammy Jellyfish) daily.

Desde la pàgina web em puc descarregar una ova, i com que és de la pàgina oficial d’Ubuntu puc suposar que no està manipulada.

$ wget https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.ova
...[============================================================>] 601.11M  23.1MB/s    in 30s     
2024-06-13 16:42:02 (19.7 MB/s) - ‘jammy-server-cloudimg-amd64.ova’ saved [630312960/630312960]

De totes maneres, i encara que gairebé ningú ho fa, en aquesta pàgina a més de baixar-te una ISO d’Ubuntu et pots baixar el hash de la ISO per confirmar que la còpia que et baixaràs d’un dels llocs de distribució d’Ubuntu no està manipulada:

Si mires el contingut del fitxer SHA256SUMS pots veure que té un hash de la iso.

$ wget -q https://cloud-images.ubuntu.com/jammy/current/SHA256SUMS
$ more SHA256SUMS | grep ova
6b1a026eb2b881158abc8baf2d6f0a1f8e64656b740b7a133bbe42ed52f8cb69 *jammy-server-cloudimg-amd64.ova

El hash és de 32 bytes encara que l'ova sigui de 620MB!

openssl és una aplicació que està instal.lada a tots els Linux, que entre altres coses em permet computar resums.

Per confirmar que tinc una còpia autèntica vaig a computar el hash de l’ova amb l’algorisme SHA-256:

$ openssl dgst -sha256 jammy-server-cloudimg-amd64.ova 
SHA2-256(jammy-server-cloudimg-amd64.ova)= 6b1a026eb2b881158abc8baf2d6f0a1f8e64656b740b7a133bbe42ed52f8cb69
$ more SHA256SUMS | grep ova
6b1a026eb2b881158abc8baf2d6f0a1f8e64656b740b7a133bbe42ed52f8cb69 *jammy-server-cloudimg-amd64.ova

Els resums coincideixen!

Encara que canviï el nom del fitxer, el hash del fitxer continua sent el mateix:

$ mv jammy-server-cloudimg-amd64.ova ubuntu-jammy.ova
$ openssl dgst -sha256 ubuntu-jammy.ova 
SHA2-256(ubuntu-jammy.ova)= 6b1a026eb2b881158abc8baf2d6f0a1f8e64656b740b7a133bbe42ed52f8cb69
$ cat SHA256SUMS | grep ova
6b1a026eb2b881158abc8baf2d6f0a1f8e64656b740b7a133bbe42ed52f8cb69 *jammy-server-cloudimg-amd64.ova

De moment només farem servir -sha256 encara que hi ha altres funcions hash implementades:

$ openssl dgst -list
Supported digests:
-blake2b512                -blake2s256                -md4                      
-md5                       -md5-sha1                  -ripemd                   
-ripemd160                 -rmd160                    -sha1                     
-sha224                    -sha256                    -sha3-224                 
-sha3-256                  -sha3-384                  -sha3-512                 
-sha384                    -sha512                    -sha512-224               
-sha512-256                -shake128                  -shake256                 
-sm3                       -ssl3-md5                  -ssl3-sha1

Propietats de la funció hash

Treballar amb ovas, isos, videos, audios, etc. està bé, excepte que són molt grans i requereixen bastant ample de banda.

Per aquest motiu baixarem el llibre Moby Dick; Or, The Whale i computar el hash del llibre:

$ wget -q https://www.gutenberg.org/cache/epub/2701/pg2701.txt -O moby-dick.txt
$ ls -l moby-dick.txt 
-rw-r--r-- 1 david david 1276290 Jun  2 10:37 moby-dick.txt
$ openssl dgst -sha256 moby-dick.txt 
SHA2-256(moby-dick.txt)= 15e0f2c564e3293775707c22d443c38d869caff7a9d2302293751c244712d81a

Per què serveix aquest hash que hem computat?

Ens proporciona integritat i autenticitat.

Si algú baixa la La Ilíada amb el nom de moby-dick.txt, jo puc saber que han canviat el llibre sense necessitat d’obrir-lo si si quin és el hash de "Moby Dick":

$ wget -q https://www.gutenberg.org/cache/epub/6130/pg6130.txt -O moby-dick.txt
$ openssl dgst -sha256 moby-dick.txt 
SHA2-256(moby-dick.txt)= c333e6b96f5dad450a61007db0ec19836b5942f6a5a1efa7e1f3dd6804b19463

Pots veure que el hash c333.. no coincideix amb el hash 15e0.. de l'autèntic moby-dick.txt.

Recupero el llibre original i problema soluctionat ...

$ wget -q https://www.gutenberg.org/cache/epub/2701/pg2701.txt -O moby-dick.txt

a no ser que algú modifiqui la meva còpia sense que jo ho sapiga.

Si guardo el tamany del fitxer puc saber que ha estat manipulat si aquesta canvia ...

$ ls -l moby-dick.txt 
-rw-r--r-- 1 david david 1161405 Jun  3 13:23 moby-dick.txt

Estás segur?

$ sed -i 's/Moby/Toby/g' moby-dick.txt 
$ ls -l moby-dick.txt 
-rw-r--r-- 1 david david 1161405 Jun 13 17:03 moby-dick.txt

El tamany del fitxer és el mateix, però ara on deia Moby diu Toby !

$ grep -o -i Moby moby-dick.txt | wc -l
3
$ grep -o -i Toby moby-dick.txt | wc -l
86

Algún TOBY s'ha escapat, en concret 3.

Queda clar que l’identificador del llibre ‘Moby Dick’ és 61d5ab6a3910fab66eabc9d2fc708b68b756199cb754fd5ff51751dbe5f766cd.

Inclús en el Windows és el mateix:

> curl.exe -s https://www.gutenberg.org/cache/epub/2701/pg2701.txt -o moby-dick.txt
> Get-FileHash .\moby-dick.txt
Algorithm       Hash                                                                   Path
---------       ----                                                                   ----
SHA256          15E0F2C564E3293775707C22D443C38D869CAFF7A9D2302293751C244712D81A       C:\Users\david\moby-dick.txt

Hem utilitzat la funció hash SHA-256 per transformar l'entrada (el fitxer descarregat) en un identificador únic.

Resistència a la segona preimatge

Un hash pot garantir la integritat i l'autenticitat d’un fitxer si es gairebé imposible manipular un altre fitxer perquè computi el mateix hash, i així poder suplantar el fitxer original.

Les funcion hash segures tenen una propietat anomenada resistència a la segona preimatge.

Això vol dir que a partir del hash 362f76079b45e8d8b6c3380f0cec2dae4a12385bf06f200082b74f00fee2ed44 és gairebé impossible trobar o manipular un fitxer que computi el hash 362f76079b45e8d8b6c3380f0cec2dae4a12385bf06f200082b74f00fee2ed44.

El hash sempre té la mateixa mida

Si apliquem la funció hash a la mateixa entrada sempre obtenim el mateix resum.

En el nostre exemple, SHA-256 sempre proporciona una sortida de 256 bits (32 bytes), que es codifiquen com 64 caràcters alfanumèrics en hexadecimal.

$ echo -n "Hello" | openssl dgst -sha256
SHA2-256(stdin)= 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
$ echo -n "Hello" | openssl dgst -sha256
SHA2-256(stdin)= 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
$ echo -n "Hello" | openssl dgst -sha256
SHA2-256(stdin)= 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
$ echo -n "Hello" | openssl dgst -sha256
SHA2-256(stdin)= 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969

Si vols ho podem provar 50 vegades si encara no estas convençut:

$ for i in {0..50}; do echo -c "Hello World!" | openssl dgst -sha256; done
SHA2-256(stdin)= 6e1f91f8c5fc22c805a65c1dc0969e02e02d55b9ede1ca28865f7d22425a9eaf
SHA2-256(stdin)= 6e1f91f8c5fc22c805a65c1dc0969e02e02d55b9ede1ca28865f7d22425a9eaf
SHA2-256(stdin)= 6e1f91f8c5fc22c805a65c1dc0969e02e02d55b9ede1ca28865f7d22425a9eaf
...

Notació hexadecimal

Per representar el resum o hash, openssl fa servir notació hexadecimal.

Si contes la quantitat de caràcters que té la seqüència 362f76079b45e8d8b6c3380f0cec2dae4a12385bf06f200082b74f00fee2ed44 pots verificar que la longitut és de 64 caràcters.

Cada caràcter representa 4 bits, per tant la seqüencia és de (64 *4 ) = 256 bits (o 32 bytes). (256bits/8=32 bytes)

8 bits = 1 byte 🙄

Per aixó l’algoritme s’anomena SHA-256.

Un petit canvi a l'entrada canvia completament la sortida:

$ echo -n "Hello" | openssl dgst -sha256
SHA2-256(stdin)= 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
$ echo -n "hello" | openssl dgst -sha256
SHA2-256(stdin)= 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
$ echo -n "Hello!" | openssl dgst -sha256
SHA2-256(stdin)= 334d016f755cd6dc58c53a86e183882f8ec14f52fb05345887c8a5edd42c87b7
$ echo -n "Hllo" | openssl dgst -sha256
SHA2-256(stdin)= 93c25d951f707030399c6a5573f9a4ed61529cb39ba5d4e7934ba6104811d358

La sortida de SHA-256 és sempre de la mateixa mida, independentment de la mida de l'entrada ...

256 bits! 🧐
$ echo -n "" | openssl dgst -sha256
SHA2-256(stdin)= e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
$ echo -n "Hello" | openssl dgst -sha256
SHA2-256(stdin)= 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
$ echo -n "Hello World!" | openssl dgst -sha256
SHA2-256(stdin)= 7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069
$ echo -n "Hola, Bonjour, こんにちは, 你好" | openssl dgst -sha256
SHA2-256(stdin)= 4dfcaeacecfd67597e9e783e4da58d601745446a443ab7e8517d59695e2d81af

Funció unidireccional

Una de les propietats principals d'una funció hash és que no es pot revertir l'algorisme.

A partir d’un hash és impossible recuperar l’arxiu original.

Si esborres un video sense voler, però tens els seu hash f76f035ceef4e6f816ab4adf5f859a28f9fb248602af36aebf820661a172f3d0, ¿creus que podries recuperar aquest video a partir d’aquests 32 bytes 🤔 ?

És impossible 😲!

Creus que podries escriure Don Quijote a partir d'aquesta frase:

"En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha mucho tiempo que vivía un hidalgo de los de lanza en astillero, adarga antigua, rocín flaco y galgo corredor."

Funcions hash estandaritzades

Fins ara només hem utilitzat la funció SHA-256, que és una de les més utilitzades, però n’hi ha moltes altres.

Una funció hash dedica molt de temps a moure bits amunt i avall, barrejar-los, etc. tal com pots veure en aquest recurs web: https://sha256algorithm.com.

Precisament una de les característiques principals d’un bon algorisme hash és que sigui el més ràpid possible com veurem a continuació.

Funcions de detecció d’errors

No totes les funcions hash són criptogràfiques.

Per exemple, funcions com CRC32, són funcions de codi de detecció d'errors.

gzip fa servir crc32 en els últims 8 bytes per detectar si hi ha hagut un error en la compressió:

$ echo -n "Hello" | gzip -1 -c | tail -c8 | hexdump -n4 -e '"%u\n"'
4157704578

How to calculate crc32 checksum from a string on linux bash

gzip uses crc32 in the last 8 bytes and the -c option causes it to output to standard output and tail strips out the last 8 bytes. ( so we don't waste time actually doing the compression).

hexdump parse the gzip crc32 as a single 32-bit number:

  • -n4 takes only the relevant first 4 bytes of the gzip footer.
  • '"%u"' is your standard fprintf format string that formats the bytes as a single unsigned 32-bit integer. Notice that there are double quotes nested within single quotes here.

If you want a hexadecimal checksum you can change the format string to '"%08x"' (or '"%08X"' for upper case hex) which will format the checksum as 8 character (0 padded) hexadecimal.

Aquestes funcions, tot i que detecten de manera útil alguns errors senzills, no proporcionen cap de les propietats de seguretat esmentades anteriorment i no s'han de confondre amb les funcions hash de les quals estem parlant (tot i que de vegades poden compartir el nom).

La seva sortida s'anomena normalment cheksum.

També pots instal.lar l’eina crc32:

$ sudo apt install -y libarchive-zip-perl
$ crc32 <(echo "Moby Dick")
2096f510
$ crc32 <(echo "Moby Dick")
2096f510

Funcions hash criptogràfiques insegures

En la dècada de 1990 les funcions MD5 i SHA-1 eren les més utilitzades, però avui en dia es consideren que ja no són segures.

El 2004 es va demostrar que MD5 no era segur quan es van publicar col·lisions per diferents equips de recerca.

El 2016 va passar el mateix amb SHA1.

Aquests atacs van tenir èxit en part a causa dels avenços en la informàtica, però sobretot perquè es van trobar defectes en la manera com es van dissenyar les funcions hash.

Una col.lisió es produeix quan dos fitxers diferents tenen el mateix hash, i normalment no passa de manera accidental.

Ves a https://gitlab.com/xtec/security/-/tree/main/crypto i observa com les imatges de allan.jpg i james.jpg són diferents.

Descarrega les imatges allan.jpg i james.png i verifica que tenen el mateix hash md5:

$ wget -q https://gitlab.com/xtec/smx-6/-/raw/main/crypto/allan.jpg
$ openssl dgst -md5 allan.jpg 
MD5(allan.jpg)= e06723d4961a0a3f950e7786f3766338

$ wget -q https://gitlab.com/xtec/smx-6/-/raw/main/crypto/james.jpg
$ openssl dgst -md5 james.jpg 
MD5(james.jpg)= e06723d4961a0a3f950e7786f3766338

En canvi amb sha-256 no hi ha col.lisió:

$ openssl dgst -sha256 allan.jpg 
SHA2-256(allan.jpg)= 1a072a5b8f988a4088a6ed42fac3011532a3d62fa85d0d0c76281a5a1fae2056
$ openssl dgst -sha256 james.jpg 
SHA2-256(james.jpg)= 808e8a228d54cb6e43e9b22cf14d745db617622ec3d8e45fa8a1be68fbfe9ef4

Tenen el mateix hash perquè la imatge de James ha estat manipulada (s’han retocat alguns bits) perquè doni el mateix hash md5 que la imatge d’Allan.

Hi ha una col.lisió: el hash de md5 no identifica de manera unívoca una sól fitxer.

Recordes que el primer que hem fet en aquesta activitat era baixar una ova i verificar amb el hash que no havia estat manipulada?

Quan instal.les software amb apt penses que no verifica de forma automàtica amb un hash el que està instal.lant?

I per quin motiu seguim parlant d’aquestes funcions 😒?

Entre altres motius perquè encara es fan servir i les pots trobar perquè són resistents a la preimatge (encara que no a la col.lisió).

SHA-2

És la funció hash més utilitzada i és la que hem estat fent servir fins ara.

Va ser desenvolupada per la NSA i estandarditzada pel NIST l'any 2001.

SHA-2 ofereix 4 versions diferents en funció del tamnay de la sortida: 224, 256, 384 o 512 bits.

El seus noms són: SHA-224, SHA-256, SHA-384 i SHA-512.

Normalment es fa servir el SHA-256 que proporciona els 128 bits de seguretat mínims necessaris avui en dia.

Encara que les aplicacions més paranoiaques fan servir SHA-512.

Pots veure a continuació com per la mateixa entrada produeixen un hash de tamany diferent (el que li pertoca):

$ echo -n "Hello" | openssl dgst -sha224
SHA2-224(stdin)= 4149da18aa8bfc2b1e382c6c26556d01a92c261b6436dad5e3be3fcc
$ echo -n "Hello" | openssl dgst -sha256
SHA2-256(stdin)= 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
$ echo -n "Hello" | openssl dgst -sha384
SHA2-384(stdin)= 3519fe5ad2c596efe3e276a6f351b8fc0b03db861782490d45f7598ebd0ab5fd5520ed102f38c4a5ec834e98668035fc
$ echo -n "Hello" | openssl dgst -sha512
SHA2-512(stdin)= 3615f80c9d293ed7402687f94b22d58e529b8cc7916f8fac7fddf7fbd5af4cf777d3d795a7a00a16bf7e7f3fb9561ee9baae480da9fe7a18769e71886b03f315

Com hem explicat abans, una funció hash consumeix molt de temps.

La funció SHA-512 és més ràpida que la SHA-256:

$ TIMEFORMAT=%R

$ time openssl dgst -sha256 ubuntu-jammy.ova 
SHA2-256(ubuntu-jammy.ova)= 6b1a026eb2b881158abc8baf2d6f0a1f8e64656b740b7a133bbe42ed52f8cb69
1.809

$ time openssl dgst -sha512 ubuntu-jammy.ova 
SHA2-512(ubuntu-jammy.ova)= 9ac849ff42d4b7a3a069650b858037fb0db70f576a06d22a59fea5a0bbd4df3dfc18e6a5956a8b0e6ebf05f73173e60e4afc9ed1bbb66ee07ae26f0efa78d89c
1.378

Això passa perqè fem servir un processador de 64 bits.

Ara són molt habituals les CPUs de 64 bits, però a l’any 2001 la majoria de CPUs eren de 32 bits.

SHA-3

Un hash secret et permet fer un hash ràpidament d’un text sense exposar el text, el hash generat i l'algorisme utilitzat.

SHA-2 no es adequat per hash secrets degut a un problema de la construcció Merkle-Damgård, que fa que SHA-2 sigui vulnerable a un atac (anomenat atac d'extensió de longitud) si s'utilitza per hash secrets.

Aquí tens un video amb un exemple:

L'any 2007 el NIST va promoure un nou estàndard, i l’any 2015 l’algorisme SHA-3 es va estandarditzar a la Publicació FIPS 202.

SHA-3 és tant segur com SHA-2 i no és vulnerable als atacs d'extensió de longitud.

Per tant és pot utilitzar per hash secrets.

Ofereix les mateixes variants que SHA-2, però hem d’indicar que es tracta de SHA-3:

p$ echo -n "Hello" | openssl dgst -sha3-224
SHA3-224(stdin)= 4cf679344af02c2b89e4a902f939f4608bcac0fbf81511da13d7d9b9
$ echo -n "Hello" | openssl dgst -sha3-256
SHA3-256(stdin)= 8ca66ee6b2fe4bb928a8e3cd2f508de4119c0895f22e011117e22cf9b13de7ef
$ echo -n "Hello" | openssl dgst -sha3-384
SHA3-384(stdin)= df7e26e3d067579481501057c43aea61035c8ffdf12d9ae427ef4038ad7c13266a11c0a3896adef37ad1bc85a2b5bdac
$ echo -n "Hello" | openssl dgst -sha3-512
SHA3-512(stdin)= 0b8a44ac991e2b263e8623cfbeefc1cffe8c1c0de57b3e2bf1673b4f35e660e89abd18afb7ac93cf215eba36dd1af67698d6c9ca3fdaaf734ffc4bd5a8e34627

Però només es fa servir en casos molts concrets perquè és molt més lent que SHA-2:

$ time openssl dgst -sha512 ubuntu-jammy.ova 
SHA2-512(ubuntu-jammy.ova)= 9ac849ff42d4b7a3a069650b858037fb0db70f576a06d22a59fea5a0bbd4df3dfc18e6a5956a8b0e6ebf05f73173e60e4afc9ed1bbb66ee07ae26f0efa78d89c
1.280

$ time openssl dgst -sha3-512 ubuntu-jammy.ova 
SHA3-512(ubuntu-jammy.ova)= 1930b1ef5144b333b88f4409626a4516691a6670d8e455f0cac7789ad5c8aff9eb0723ec455890d50f922ed8ff390ac9689714d056bdade0e31a6bf180cefb9b
4.024

Funcions hash no estandaritzades

El 2013, després de les revelacions d'Edward Snowden, es va descobrir que la NSA havia impulsat deliberadament i amb èxit la inclusió d'algoritmes de “backdoor” (porta del darrere) als estàndards (vegeu "Dual EC: A Standardized Back Door" de Bernstein et al.)

Aquests portes del darrere es poden considerar contrasenyes màgiques que permeten al govern (i només a ell, suposadament) subvertir el vostre xifratge.

Arran d'això, la comunitat criptogràfica va perdre molta confiança en els estàndards i els suggeriments procedents dels organismes governamentals.

Blake 2

BLAKE2 és una funció hash criptogràfica més ràpida que MD5, SHA-1, SHA-2 i SHA-3, i almenys tan segura com SHA-3.

BLAKE2 ha sigut adoptat per molts projectes per la seva alta velocitat, seguretat i senzillesa tal com pots veure en aquest enllaç: Blake2 - Users

Important! BLAKE2 es l’estandard de "facto", però en àmbits públic com administracions públiques potser has de fer servir els estàndards oficials per obligació legal.

$ openssl dgst -blake2s256 ubuntu-jammy.ova 
BLAKE2S-256(ubuntu-jammy.ova)= cbd6b7dd49001005fde431eb987aa0017050b05d851368091a6f111cbe3ade61
$ openssl dgst -blake2b512 ubuntu-jammy.ova 
BLAKE2B-512(ubuntu-jammy.ova)= b91cae689df79bb61f8449771b27d73e7d740e945d34d2fa87b39e38a18fbc6f723a3df06f9f4799dcacbc577a30fe964249ddd5fd6315715e49dfe98869a949

A continuació anem a verificar la velocitat de cada funcio hash:

$ time openssl dgst -md5 ubuntu-jammy.ova 
MD5(ubuntu-jammy.ova)= a0914ee0cc3344277adf3027993fc019
1.170
$ time openssl dgst -sha1 ubuntu-jammy.ova 
SHA1(ubuntu-jammy.ova)= fc09b6d6ce06ea0a92ab396c1814d47cd649b29e
0.876
$ time openssl dgst -sha-512 ubuntu-jammy.ova 
SHA2-512(ubuntu-jammy.ova)= 9ac849ff42d4b7a3a069650b858037fb0db70f576a06d22a59fea5a0bbd4df3dfc18e6a5956a8b0e6ebf05f73173e60e4afc9ed1bbb66ee07ae26f0efa78d89c
1.241
$ time openssl dgst -sha3-512 ubuntu-jammy.ova 
SHA3-512(ubuntu-jammy.ova)= 1930b1ef5144b333b88f4409626a4516691a6670d8e455f0cac7789ad5c8aff9eb0723ec455890d50f922ed8ff390ac9689714d056bdade0e31a6bf180cefb9b
3.839
$ time openssl dgst -blake2b-512 ubuntu-jammy.ova 
BLAKE2B-512(ubuntu-jammy.ova)= b91cae689df79bb61f8449771b27d73e7d740e945d34d2fa87b39e38a18fbc6f723a3df06f9f4799dcacbc577a30fe964249ddd5fd6315715e49dfe98869a949
1.039

SHA3-512 és la funció hash més lenta, i BLAKE2B-512 és la segona més ràpida i tan segura com SHA3-512.

Ja pots intuïr perquè blake2 es la funció hash criptogràfica preferida si pots escollir.

Propietats d'una funció hash segura

Aquestes són les propietats que ha de tenir una funció hash perquè sigui criptogràficament segura.

Farem servir aquest dades d'exemple:

$ echo -n "Hello World!" | openssl dgst -blake2b512
BLAKE2B-512(stdin)= 54b113f499799d2f3c0711da174e3bc724737ad18f63feb286184f0597e1466436705d6c8e8c7d3d3b88f5a22e83496e0043c44a3c2b1700e0e02259f8ac468e

Recorda! És un exemple i el text d'entrada és molt petit.

Resistència prèvia a la imatge

Per genera el digest fem servir una funció hash aplicada a l'input:

flowchart LR
   data["Hello Wordl!"] 
   hash["54b113f..."]
   data -- Hash function--> hash   

Però si només tens el digest no pots reconstruir l'input que es va fer servir per genera el digest.

flowchart LR
   data["?"] 
   hash["54b113f..."]
   hash -- Magic function--> data   

Per exemple, encara que et mostri el hash tardarás uns quants dies en poder saber que estava escrit en el que havia on estan els ?:

$ echo -n "????????????????????????????????????????????" | openssl dgst -blake2b512
BLAKE2B-512(stdin)= 8b88ac87f7bda6f5e75e1ad15ca46b1749e048e3c9dd69f3afc55f797873ffe8cdd41c80d7eeed7b61bc7a52f56dcf3d24dc50a7d6a6fdaaf854d3ba975eb360

Resistència prèvia a la segona imatge

Encara que tinguis linput i el digest :

flowchart LR
   data["Hello World!"] 
   hash["54b113f..."]
   data -- Hash function--> hash   

No podrás trobar un altre input que generi el mateix digest:

flowchart LR
   data["?"] 
   hash[""54b113f...""]
   data -- Hash function--> hash   

No et servei de res tenir la seqüènica original per produïr una altre seqüència que tingui el mateix hash:

$ echo -n "A cada ocellet li agrada el seu niuet" | openssl dgst -blake2b512
BLAKE2B-512(stdin)= 76a432e02eadc7865a14385e617c4dbf884e6943edf1e8c629bcb6c680c401bfdfe20cb038aae35c701bbf903ea7e293fd661492850f33642346218f4476c9ea
$ echo -n "A cada ocell li agrada el seu niuet" | openssl dgst -blake2b512
BLAKE2B-512(stdin)= 9fc88211fc47b692dac2f26694463ac9ece42e1f9b205871ccd50d307316dbb259aaf6a4468d1ed7bacee497ba0a794b1c10d2c4d36dff8a066b9ed35c7a2eb8

Resistència a la col·lisió

Ningú poc crear expressament una seqüència de bytes que produeixi el mateix hash que una altra seqüència de bytes.

Això no pot passar:

flowchart LR
   data1["Hello World!"]
   data2["Hello Barcelona!"]  
   hash["54b113f..."]
   data1 -- Hash function--> hash
   data2 -- Hash function--> hash    

Ja vam veure que això no és cert en MD5, per això desde fa anys ja no és una fucnió hash segura.

Xifratge simètric

El xifratge "simètric" és el xifratge tradicional que existeix desde fa més de 4000 anys.

Precisament, l’origen de la paraula criptografia el trobem en el grec antic: krypto, «ocult», i graphos, «escriure»; es a dir, escritura oculta.

Funcionament

Un algorisme de xifratge (també anomenat xifrat) transforma una seqüència de bytes en quelcom que sembla aleatori.

L’algorisme de xifratge necessita:

  • Una clau secreta (key) que es farà servir per xifrar el text
  • Un text en clar (plaintext) que es que vos xifrar.
flowchart LR
   plaintext["plaintext 'Hello'"]
   key["key 0x8866..."]  
   encrypt["Encrypt"]
   ciphertext["Ciphertext 0x6e0e..."]
   
   plaintext --> encrypt
   key --> encrypt
   encrypt --> ciphertext    

Aquest procés de xifratge produeix text xifrat (chipertext)

El text xifrat sembla aleatori per a qualsevol persona que no coneix la clau secreta i no revela cap informació sobre el text original.

Pots utilitzar un algorisme de desxifrat per revertir el text xifrat al text pla original.

L’algorisme necessita:

  • La mateixa clau secreta (key) que es va fer servir per crear el text xifrat.
  • El text xifrat (chipertext) amb la clau secreta.
flowchart LR
   plaintext["plaintext 'Hello'"]
   key["key 0x8866..."]  
   decrypt["Decrypt"]
   ciphertext["Ciphertext 0x6e0e..."]
   
   ciphertext --> decrypt
   key --> decrypt
   decrypt --> plaintext    

El resultat és el text pla original (plaintext).

AES

Un dels algorismes més utilitzats per xifrar és l’AES (estàndard de xifratge avançat).

Va ser publicat com estàndar pel NIST l’any 2001.

AES ofereix tres versions diferents:

  • AES-128 pren una clau de 128 bits (16 bytes)
  • AES-192 pren una clau de 192 bits (24 bytes)
  • AES-256 pren una clau de 256 bits (32 bytes).

La longitud de la clau determina el nivell de seguretat: com més gran, més fort.

No obstant això, la majoria de les aplicacions fan servir AES-128 ja que proporciona prou seguretat (128 bits de seguretat).

Xifra el text

Podem xifrar un text amb openssl tal com es mostra a continuació:

$ echo -n "Hello Wordl!" | openssl enc -e -base64 -aes-256-cbc -pbkdf2 -pass pass:very-secret
U2FsdGVkX19oc9l8D8va99zJEsT5kQTUWK8UEhVdDak=

$ echo "U2FsdGVkX19oc9l8D8va99zJEsT5kQTUWK8UEhVdDak=" | openssl enc -d -base64 -aes-256-cbc -pbkdf2 -pass pass:very-secret
Hello Wordl!

L'opció -base64 indica a openssl que el resultat del xifratge es mostri en Base64.

D’aquesta manera tenim una seqüència de caràcters ASCII que es poden imprimir a la pantalla. Si no fem servir aquesta opció el resultat és una seqüència de bytes que no es poden mostrar per pantalla:

$ echo -n "Hello Wordl!" | openssl enc -e -aes-256-cbc -pbkdf2 -pass pass:very-secret
Salted__j:�&]���<��-�M��2��

L’opció -pbkdf2 es per utilitzar un mètode de derivació de clau concret.

Si no t'en recordes openssl ja t'avisa!

`$ echo -n "Hello Wordl!" | openssl enc -e -base64 -aes-256-cbc -pbkdf2 -pass pass:very-secret
U2FsdGVkX19IC6/ldMNq1yA3i5BUS96Y2FecqTfIxjk=
$ echo -n "Hello Wordl!" | openssl enc -e -base64 -aes-256-cbc -pass pass:very-secret
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
U2FsdGVkX1/vdI65EMgqCGZVQcrSgzXFJt2sTIVdTBs=

A més de l'avís pots veure que el hash comença igual però acaba diferent.

Xifrar un fitxer

Normalment el que volem es xifrar un fitxer.

Crear un fitxer data.txt i encripta el fitxer:

$ echo "Name: John Smith, Credit Card: 2332..33" > data.txt
$ openssl enc -e -aes-256-cbc -pbkdf2 -pass pass:"very-secret" -in data.txt -out data.txt.enc
$ cat data.txt.enc 
Salted__sVA\[��I�F�rd'+�^3�O�k)/[d�@��,{���v"3�����]&�m

Per desencriptar el fitxer has de fer servir la mateixa clau:

$ rm data.txt
$ openssl enc -d -aes-256-cbc -pbkdf2 -pass pass:"very-secret" -in data.txt.enc -out data.txt
$ cat data.txt
Name: John Smith, Credit Card: 2332..33

Ús d'un fitxer de claus

Les persones fem servir claus de xifratge curtes i fàcils de recordar.

Si volem xifrar una seqüència de bytes de manera segura és millor fer servir una bona clau de xifratge per si el "ciphertext" es interceptat d’alguna manera.

La forma de fer-ho és generar un fitxer que té la clau de xifratge i guardar aquest fitxer de manera segura.

$ openssl rand 256 > very-secret.key
$ cat very-secret.key 
$���<��Z��a�fN$�VmX]����d�~�Tr���}�Cg�"V�#�+��0�+�����e��8��y�����R
��
  �J��F
��}/iv�1'-=�-�"wi��<޻��sg��9-�:
        r�5�#d*ޒ4ˬ������;"F1�&�(�ǁRyįԟU����$�t�#��%փ��ˑMBWw�i�ĉ�~ӡp9���s�Q�.���t"��ݪ�~�AJ,�7���:���
^�e4pU�
$ openssl enc -e -aes-256-cbc -pbkdf2 -k very-secret.key -in data.txt -out data.txt.enc

Per desxifrar el text el procés és el mateix:

$ rm data.txt
$ openssl enc -d -aes-256-cbc -pbkdf2 -k very-secret.key -in data.txt.enc -out data.txt
$ cat data.txt
Name: John Smith, Credit Card: 2332..33

ChaCha20

AES és l'estàndard oficial, però ChaCha20 és més ràpid.

ChaCha és una família d’algorismes de xifrats creat per Daniel J. Bernstein per ser ràpid quan s'utilitza en programari, al contrari de l'AES, que és lent quan el suport de maquinari no està disponible.

Avui en dia, és àmpliament adoptat per protocols d'Internet com Transport Layer Security i Wireguard.

L'únic que canvia a efecte pràctic es que enlloc de -aes-256-cbc hem de posar -chacha20:

$ openssl enc -e -chacha20 -pbkdf2 -k very-secret.key -in data.txt -out data.txt.enc 
$ rm data.txt
$ openssl enc -d -chacha20 -pbkdf2 -k very-secret.key -in data.txt.enc -out data.txt
$ cat data.txt
Name: John Smith, Credit Card: 2332..33

Velocitat

Anem a veure quin dels dos és més ràpid!

$ TIMEFORMAT=%R
$ time openssl enc -e -aes-256-cbc -pbkdf2 -k very-secret.key -in ubuntu-jammy.ova -out ubuntu-jammy.ova.enc 
2.370
$ time openssl enc -e -chacha20 -pbkdf2 -k very-secret.key -in ubuntu-jammy.ova -out ubuntu-jammy.ova.enc 
1.521

Xifratge asimètric

El xifratge asimètric es va inventar a finals de 1970 (RSA) i ha permés que les comunicacions per Internet siguin xifrades.

Factorització d'enters 🐣 🐤 🐥 🦅

🦄
  • El xifratge simètrica (la clàssica) utilitza una única clau per xifrar i desxifrar.

  • El xifratge asimètric:

    • Utilitza dues claus: una per xifrar i l'altre per desxifrar.

    • Una és pública (la puc compartir amb qui vulgui) i l’altre és privada (la guardo per mi).

I la pública és per xifrar o desxifrar 😐?

Per les dos coses 😳.

A la "Uni" és un rotllo matemàtic de bastantes hores de classe que es diu Factorització d'enters.

Per tant, presta un moment d'atenció!

👍

Claus

Primer haig de generar la clau privada:

$ openssl genpkey -algorithm RSA -out private.pem
$ cat private.pem 
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCmqAxS4TZkITcR
...
NqJthDb9w5BZAQbw0+DK+BQ=
-----END PRIVATE KEY-----

Aquesta clau és la privada perquè ha de ser secreta, no la puc compartir.

Per quin motiu ha de ser secreta?

Perquè la segona clau, la "publica" la genero a partir d'aquesta clau!

$ openssl rsa -pubout -in private.pem -out public.pem 
writing RSA key
$ cat public.pem 
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApqgMUuE2ZCE3EXBdpm1w
...
KQIDAQAB
-----END PUBLIC KEY-----

Puc generar la clau privada a partir de la pública?

$ openssl rsa -pubout -in public.pem -out private.pem 
Could not read private key from public.pem
4097EBB95A7F0000:error:1608010C:STORE routines:ossl_store_handle_load_result:unsupported:../crypto/store/store_result.c:151:
4097EBB95A7F0000:error:1608010C:STORE routines:ossl_store_handle_load_result:unsupported:../crypto/store/store_result.c:151:

🦄

La clau privada genera la clau pública, però la clau pública no pot generar la privada.

🌈

Xifrar dades

Si la Laura em vol enviar un missatge secret pot utilitzar la meva clau pública que tinc accessible a tothom.

$ echo "Quedem dimarts a les 12 al Zurich de Plaça Catalunya" > message.txt
$ openssl pkeyutl -encrypt -inkey public.pem -pubin -in message.txt -out message.txt.enc
$ rm message.txt
$ cat message.txt.enc 

Important! Recorda de borrar el fitxer message.txt.enc si existeix perquè openssl per precaució no sobreesciurà el fitxer.

Només qui té la clau privada, se suposa que només jo 🙄, pot desencriptar aquest missatge:

$ openssl pkeyutl -decrypt -inkey private.pem -in message.txt.enc -out message.txt
$ cat message.txt
Quedem dimarts a les 12 al Zurich de Plaça Catalunya

Una de les coses sorprenents del xifratge asimètric és que cada cop que xifro el mateix missatge el missatge xifrat és diferent:

$ rm message.txt.enc 
$ openssl pkeyutl -encrypt -inkey public.pem -pubin -in message.txt -out message.txt.enc
$ openssl dgst -blake2s256 message.txt.enc 
BLAKE2S-256(message.txt.enc)= 8a837220d83c323768be0e7fc7174845663a82acfdaab5cc3984608287d89e23
$ openssl pkeyutl -decrypt -inkey private.pem -in message.txt.enc 
Quedem dimarts a les 12 al Zurich de Plaça Catalunya
 
$ rm message.txt.enc 
$ openssl pkeyutl -encrypt -inkey public.pem -pubin -in message.txt -out message.txt.enc
$ openssl dgst -blake2s256 message.txt.enc 
BLAKE2S-256(message.txt.enc)= 44f3b9559fae4ee970dac8f19deea99eeb06a8a9139c72fe81f16da7cdd9abb5
$ openssl pkeyutl -decrypt -inkey private.pem -in message.txt.enc 
Quedem dimarts a les 12 al Zurich de Plaça Catalunya

$ rm message.txt.enc 
$ openssl pkeyutl -encrypt -inkey public.pem -pubin -in message.txt -out message.txt.enc
$ openssl dgst -blake2s256 message.txt.enc 
BLAKE2S-256(message.txt.enc)= e8e334a3e466f057768500411cf022da36c45975f746a7ef957b92b1b8ef663f
$ openssl pkeyutl -decrypt -inkey private.pem -in message.txt.enc 
Quedem dimarts a les 12 al Zurich de Plaça Catalunya

Això és molt important perquè puc escriure el mateix missatge encriptat tantes vegades com vulgui i ningú pot saber que és el mateix missatge.

Missatges petits

La criptografía asimètrica (o de clau pública) és molt poc eficient en temps de computació.

Necessita milers de vegades més potència de càlcul per xifrar, desxifrar i validar que els algorismes simètrics.

I openssl es nega a fer-ho si l’arxiu és una mica gran:

$ openssl pkeyutl -encrypt -inkey public.pem -pubin -in moby-dick.txt -out moby-dick.txt.enc
Public Key operation error
40376248027F0000:error:0200006E:rsa routines:ossl_rsa_padding_add_PKCS1_type_2_ex:data too large for key size:../crypto/rsa/rsa_pk1.c:133:

openssl diu que no! Motiu: data too large for key size.

El problema és que una clau RSA pot ser de de 1024, 2048 o 4096 bits (per defecte és de 2048 bits).

I té uns limits molt petits respecte el tamany del missatge que pot encriptar: (TODO simplificar)

  • Una clau RSA de 1024-bit fent servir padding OAEP pot encriptar com a màxim (1024/8) – 42 = 128 – 42 = 86 bytes.

  • Una clau RSA de 2048-bit pot encriptar com a màxim (2048/8) – 42 = 256 – 42 = 214 bytes.

Per això la criptografia pública només es pot fer servir per encriptar:

  1. Hash
  2. Claus simètriques
  3. Missatges molt curts

Compartir una clau secreta

Si per exemple la Laura em vol enviar "Moby Dick" encriptat el que ha de fer és:

  1. Crear una clau simètrica temporal (AES o ChaCha20)
  2. Encriptar ‘Moby Dick’ amb la clau simètrica temporal
  3. Publicar ‘Moby Dick’ encriptat.
$ openssl rand 128 > moby.key
$ openssl enc -e -chacha20 -pbkdf2 -k moby.key -in moby-dick.txt -out moby-dick.txt.enc
$ curl -T moby-dick.txt.enc https://oshi.at

https://oshi.at/a/3f4760c1873e254c4b5ab8786781cd4b60b06ba0 [Admin]
https://oshi.at/ibYw [Download]
http://5ety7tpkim5me6eszuwcje7bmy25pbtrjtue7zkqqgziljwqy3rrikqd.onion/ibYw [Tor download]

Pots veure que tothom que tingui l'enllaç pot tenir el fitxer encriptat, però no pots saber que hi ha en aquest fitxer.

El problema es que per desencriptar necessito la clau moby.key 😆!

Ara el problema és com la Laura em pot enviar la clau moby.key de manera segura.

Com que la clau és petita la Laura pot utilitzar la criptografia asimètrica:

  1. Encripta moby.key amb la meva clau pública
  2. Publica la clau simètrica encriptada
$ openssl pkeyutl -encrypt -inkey public.pem -pubin -in moby.key -out moby.key.enc
$ curl -T moby.key.enc https://oshi.at

https://oshi.at/a/85fd211456f9cb44a0c2e84094cc0499547a7cfe [Admin]
https://oshi.at/RhAC [Download]
http://5ety7tpkim5me6eszuwcje7bmy25pbtrjtue7zkqqgziljwqy3rrikqd.onion/RhAC [Tor download]

Borra tots els fitxers "moby":

$ rm moby*

Windows

Obre una sessió de Powershell en un Windos o inicia sessió en una altre màquina (per exemple, a Isard).

El que haig de fer a continuació per recuperar "Moby Dick" és:

  1. Baixar els dos fitxers
  2. Desencriptar moby.key.enc amb la clau privada private.pem que has creat
  3. Desencriptar el fitxer moby-dick.text.enc amb la clau simètrica moby.key.
# (1) Baixo els dos fitxers
$ curl -s https://oshi.at/ibYw -o moby-dick.txt.enc
$ curl -s https://oshi.at/RhAC -o moby.key.enc

# (2) Desencripto la clau simètrica (AES)
$ openssl pkeyutl -decrypt -inkey private.pem -in moby.key.enc -out moby.key

# (3) Desencripto el llibre amb la clau simètrica (AES)
$ openssl enc -d -chacha20 -pbkdf2 -k moby.key -in moby-dick.txt.enc -out moby-dick.txt

# (4) Ja tinc accés al llibre
$ cat moby-dick.txt | head -2
The Project Gutenberg eBook of Moby Dick; Or, The Whale
    

Resum

🦄

Pots veure que per enviar qualsevol fitxer encriptat a alguna persona només necessito que ell em doni una clau pública RSA.

Puc enviar el que vulgui a aquella persona que només ell podrà desencriptar el fitxer encara que tothom pugui tenir una còpia del fitxer encriptat.

A l'activitat GPG veurem com l'eina gpg ens permete fer tot això i molt més de manera molt senzilla (si saps el que estas fent, per això fem aquesta activitat).

Signatura

En l’activitat anterior la Laura m’ha enviat un missatge i un llibre.

Però com puc estar segur que me l’ha enviat la Laura?

La criptografia asimètrica de clau pública també s’ocupa de solucionar el problema de l’autenticitat.

Primer fem que la Laura generi les seves claus:

$ openssl genpkey -quiet -algorithm RSA -out laura_private.pem
$ openssl rsa -pubout -in laura_private.pem -out laura_public.pem 
writing RSA key

Si la laura em vol enviar un missatge que només jo pugui llegir i que jo pugui confirmar que l’ha escrit la Laura:

  1. La Laura ha de generar un hash del missatge i encriptar el hash del missatge amb la seva clau privada (això es coneix com firmar un missatge).

  2. Ha de tonar a encriptar el missatge amb la meva clau pública.

El primer que ha de fer és firmar el missatge:

$ echo "Quedem dilluns a les 10 a la cafeteria de l'Institut" > message.txt
$ openssl dgst -sha256 -sign laura_private.pem -out message.txt.signed message.txt

$ openssl base64 -in message.txt.signed 
rurwwPWSFiEebwlEwMXldyP6DfCcBg/pePyqBsofLPpclo785jmJkTW1Zo8Ki76C
73e36KRR0OW18OSCqLA4ol2iA+Nh38q1o97YZIwQ9B3CYBkxNqZxY/ccMga9pvxp
30y/Cyf+NkP+cXFqdiR9IG+RZKtTsO3Rc+FlKLap1bTV/xtjnrG1q+fCFUnKJLJ5
1ihQJQPd1EdzVdS7IAlydlZgEik8xDUtuT+EDozPI9fKBdotwIldWOzqZDJEjkaT
ea6/UbgtAtEvxJowcrEMbiXzS3WBOVxzZZKyZKNG2p3n5B1qAtifT/O9E6kQfRCk
8+rkAO477QT/OHh4YnX4bg==

El contingut del missatge és el hash SHA256 del fitxer message.txt codificat amb la clau privada laura_private.pem:

$ openssl dgst -sha256 message.txt
SHA2-256(message.txt)= b455f09698edff582b4102065734dc87326d59949c6ebabe6ac6abbeb704cf92

Puc verificar que la Laura ha firmat el missatge perquè la clau pública de la Laura, i només la Laura, pot decodificar el contingut del fitxer message.txt.signed i que el resultat sigui el hash de message.txt:

$ openssl dgst -verify laura_public.pem -signature message.txt.signed  message.txt
Verified OK

Si per exemple provo amb la meva clau pública dona error:

$ openssl dgst -verify public.pem -signature message.txt.signed  message.txt
Verification failure
40E7936B1F7F0000:error:02000084:rsa routines:rsa_ossl_public_decrypt:data too large for modulus:../crypto/rsa/rsa_ossl.c:661:
40E7936B1F7F0000:error:1C880004:Provider routines:rsa_verify:RSA lib:../providers/implementations/signature/rsa_sig.c:774:

Que és una signatura?

🦄

És un hash d'un fitxer encriptat amb la clau privada d'alguna persona.

Com que només la clau publica d'aquesta persona pot "desencriptar" el hash, sabem que aquella signatura pertany a aquella persona.

Altre cosa és qui té accés a aquella clau privada ... no està ben guardada, la tenim vàries persones, etc.

Però això ja no són coses d'informàtica.

🙄

Windows

Fes el mateix amb el Windows.

Consulta tot el que vulguis a Internet, excepte les solucions que tens en aquest document.

Baixa els dos fitxers:

> curl.exe -s https://oshi.at/ibYw -o moby-dick.txt.enc
> curl.exe -s https://oshi.at/RhAC -o moby.key.enc
> Get-ChildItem -Filter moby*


    Directory: C:\Users\david\tmp


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        15/06/2024     10:20        1161421 moby-dick.txt.enc
-a----        15/06/2024     10:20            256 moby.key.enc

Si intento obrir el fitxer moby-dick.txt.enc ...

Necessito la clau simètrica per desencriptar el fitxer.

Però el fitxer moby.key.enc també està encriptat.

Necessito la clau privada que ha encriptat moby.key.enc i només qui tingui aquesta clau podrà accedir.

Doncs ja pots passar la clau private.pem del Linux al Windows, i no preguntis al professor com fer-ho que ja t'has de poder espabilar per tu mateix.

> $rsa = New-Object -TypeName System.Security.Cryptography.RSACryptoServiceProvider

(todo)

> [byte[]]$str = Get-Content "moby.key.enc" -Encoding Byte
> $DecryptedStr = $rsa.Decrypt($str, $false);  
> Write-Host "File content : " $DecryptedStr

TODO RSA Encrypt Text In PowerShell

Python

Per treballar amb Python farem servir la llibreia pycryptdome.

Instal.la la llibreria amb pip:

$ pip install pycryptodome

RSA

Primer generem les claus RSA (1024 bits) i les imprimim a la consola (com a números hexadecimals i en el format PKCS#8 PEM ASN.1).

Crea un nou fitxer crypto.py:

from Crypto.PublicKey import RSA

keyPair = RSA.generate(1024)

pubKey = keyPair.publickey()
print(f"Public key:  (n={hex(pubKey.n)}, e={hex(pubKey.e)})", end="\n\n")
pubKeyPEM = pubKey.exportKey()
print(pubKeyPEM.decode("ascii"), end="\n\n")

print(f"Private key: (n={hex(pubKey.n)}, d={hex(keyPair.d)})", end="\n\n")
privKeyPEM = keyPair.exportKey()
print(privKeyPEM.decode("ascii"))

Executa el codi:

$ python3 crypto.py 
Public key:  (n=0x9846e53267677f0d6e913c6ea274fd6ea5394a800ce688548e95295517b2298341081bb9badaf9bc778dc2b8f503cb444db1c7bd8a675c02947bf69872ed80e8f50961f27737012ea231fecafdeb4bec826258e71ce2f24a3bbe9e8b0df5bf13e2ce41428dfc2eab329b3aced399432d907702defd3ed15189a25aa7c71dcaeb, e=0x10001)

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCYRuUyZ2d/DW6RPG6idP1upTlK
gAzmiFSOlSlVF7Ipg0EIG7m62vm8d43CuPUDy0RNsce9imdcApR79phy7YDo9Qlh
8nc3AS6iMf7K/etL7IJiWOcc4vJKO76eiw31vxPizkFCjfwuqzKbOs7TmUMtkHcC
3v0+0VGJolqnxx3K6wIDAQAB
-----END PUBLIC KEY-----

Private key: (n=0x9846e53267677f0d6e913c6ea274fd6ea5394a800ce688548e95295517b2298341081bb9badaf9bc778dc2b8f503cb444db1c7bd8a675c02947bf69872ed80e8f50961f27737012ea231fecafdeb4bec826258e71ce2f24a3bbe9e8b0df5bf13e2ce41428dfc2eab329b3aced399432d907702defd3ed15189a25aa7c71dcaeb, d=0x803f0a68c38da158bea0b2df651302735d28e85afa826d44499120ee4eb6a31fad20170efa6a7c49adfbf0ddb4a72d59fe7feba8f0c226a0f04ce15ccdee18d22229229e29aa36ae95db74431c5cf4827d4556bf341958643a6c4e7d0242e8b1abdd3b8c71d0782ede1a2ecd0b0698776b50ee3357e01a3ebd9455c9a599319)

-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCYRuUyZ2d/DW6RPG6idP1upTlKgAzmiFSOlSlVF7Ipg0EIG7m6
2vm8d43CuPUDy0RNsce9imdcApR79phy7YDo9Qlh8nc3AS6iMf7K/etL7IJiWOcc
4vJKO76eiw31vxPizkFCjfwuqzKbOs7TmUMtkHcC3v0+0VGJolqnxx3K6wIDAQAB
AoGACAPwpow42hWL6gst9lEwJzXSjoWvqCbURJkSDuTrajH60gFw76anxJrfvw3b
SnLVn+f+uo8MImoPBM4VzN7hjSIikinimqNq6V23RDHFz0gn1FVr80GVhkOmxOfQ
JC6LGr3TuMcdB4Lt4aLs0LBph3a1DuM1fgGj69lFXJpZkxkCQQC8/QFtogF6ZXaA
4Z78CL0irPTnussJK1SJbmevaT4LXU6cuVx+p1+1qqApalAlYhd0OAkAgo+IBiAs
ROFh1hDHAkEAzkV/Ij/ot6yXUvf5ff0Yn7Log2IMB2IYQ++NK6nDpgM3fEaGMVV0
ZrJ2DGMVKNyE8BoMrIH3T0lF5n9o9jlYvQJBAIpVW41HL3PK/wH5pGjxcJgIJ7/T
T7jneZqbMNQJ4ftpkhhP6e9fTkRon5GRGxcyBN7yAUzZRHyZl0UwKhV2HpMCQQCw
HPAOOwikAcz1vtkas8SZXXRd8JGaoCtdnaMnm3t7O5XdGo2qg26t3EMkEljXmWg7
Y9JcW17fKA1xXmksiQv1AkB+EcEGK4TcD/6jIc/8wV3CdlBprWwsIXDAvQO8QsU9
Pcf/JLN72xtbk8PeWwy759OOFdCVrJ/DYPcX5Toe43KM
-----END RSA PRIVATE KEY-----

Pots veure que el tamany de la clau és bastant llarg encara que sigui de 1024 bits.

Peró en un ús real tindries que utilitzar una clau RSA de 3072 o 4096 bits.

Factorització d'enters

Però el més important és que pots veure el contingut real de les claus:

  1. La clau pública es composa de 2 números: n i e.
  2. La clau privada es composa de 2 números: n i d.

Quan fem les activitats de SSH, Transport Layer Security, etc. veurás molts cops les claus en format ASCII.

Però ara pots veure que es tracta de números, no de lletres, i que la criptografia asimètrica es basa en fer servir números molts grans que són especials per fer uns càlculs senzills mijantçant Factorització d'enters.

Per conduïr un cotxe no cal ser un enginyer, només tenir uns conceptes bàsics de com funciona un cotxe.

Per cert, el número que s'ha de mantenir secret és el d 🤐.

A continuació, xifra el missatge mitjançant l'esquema de xifratge RSA-OAEP (RSA amb padding PKCS#1 OAEP) amb la clau pública RSA:

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import binascii

keyPair = RSA.generate(1024)
pubKey = keyPair.publickey()

msg = b'A message for encryption'
encryptor = PKCS1_OAEP.new(pubKey)
encrypted = encryptor.encrypt(msg)
print("Encrypted:", binascii.hexlify(encrypted))

Executa l'script crypto.py:

$ python3 crypto.py
Encrypted: b'93440b3838d91e1f7d3980d2dd2c14b17f4e8c322dab1ed325cb83f49b10866ddaac7d35de1788a5232cfd0cb25d8cf8f2b4221bf3ba3554bc37269fd7dcc1aca356ddea35a1e0afe0b9b1b764b74ae3d37ac68b37399480caacb0d0ffca46444380abc2de3e73ccd3b671dc3c0e6f4bbcb3fadecc1754fcd34063fa30a65b0b'

A continuació desxifra el missatge fent servir RSA-OAEP amb la clau privada RSA:

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import binascii

keyPair = RSA.generate(1024)
pubKey = keyPair.publickey()

msg = b'A message for encryption'
encryptor = PKCS1_OAEP.new(pubKey)
encrypted = encryptor.encrypt(msg)
print("Encrypted:", binascii.hexlify(encrypted))

decryptor = PKCS1_OAEP.new(keyPair)
decrypted = decryptor.decrypt(encrypted)
print('Decrypted:', decrypted)

Pots veure que el missatge es desxifra sense problemes:

$ python3 crypto.py 
Encrypted: b'320626aa408f39908e7734f5dfc5ae515ca1b2a149d01c02eca2f74c8a2011e2c9a59fe60cbbbd4be9af0122340092bdce348b0ca9835a1346365877f937b4a142c1e0640295964522c5e52f448f7cc99c5e31877b96485c11e631da8eb0cf164b8e5b2ed097b6f24d389f9eb0cbf46822cc41036b2d852d1b163c8a86441c52'
Decrypted: b'A message for encryption'

Per saber més

[TODO] Article s’ha d’adaptar (versió 0.03 pycoin problema import) https://cryptobook.nakov.com/digital-signatures/ecdsa-sign-verify-examples

Activitats

1.- Has aconseguit obtenir una clau que et permet desxifrar un missatge molt secret que utilitza ChaCha20, però et falta l'últim digit: very-secret-

El missatge és U2FsdGVkX1+c11lZXqn7akxqW+3Z8RjqGvGF16/RSeReLnDC

Quin és el contingut del missatge?

$ echo "U2FsdGVkX1+c11lZXqn7akxqW+3Z8RjqGvGF16/RSeReLnDC" | openssl enc -d -base64 -chacha20 -pbkdf2 -pass pass:very-secret-8
Missatge molt secret

2.- Descarrega el llibre A Tail of Two Cities en format text UTF-8 i computa el hash blake2b512.

$ wget -q https://www.gutenberg.org/files/98/98-0.txt -O book.txt
$ wc -l book.txt
16285 book.txt
$ openssl dgst -blake2b512 book.txt > book.txt.hash
$ cat book.txt.hash 
BLAKE2B-512(book.txt)= 1a8ac18fde710ecc452770fcd52a2c4945d40c71467b2cd4c64a7b5308261078201cefdb6ddc682a67511aa60992324c5ff87e29192adfd8f113a1e6030b0459

Encripta el llibre amb AES i ChaCha

$ openssl enc -e -aes-256-cbc -pbkdf2 -pass pass:very-secret -in book.txt -out book.txt.enc_aes
$ openssl enc -e -chacha20 -pbkdf2 -pass pass:very-secret -in book.txt -out book.txt.enc_chacha
$ ls -l book.txt*
-rw-r--r-- 1 david david 807231 Mar 27  2021 book.txt
-rw-r--r-- 1 david david 807248 Jun 14 18:58 book.txt.enc_aes
-rw-r--r-- 1 david david 807247 Jun 14 18:58 book.txt.enc_chacha
-rw-r--r-- 1 david david    152 Jun 14 18:54 book.txt.hash

Pots veure que el fitxer encriptat i els encriptats tenen gairebé el mateix tamany!

Elimina el llibre original, recupera els llibres encriptats i verifica que les còpies desencriptades són el mateix que l’original.

$ cat book.txt.hash 
BLAKE2B-512(book.txt)= 1a8ac18fde710ecc452770fcd52a2c4945d40c71467b2cd4c64a7b5308261078201cefdb6ddc682a67511aa60992324c5ff87e29192adfd8f113a1e6030b0459

$ rm book.txt
$ openssl enc -d -aes-256-cbc -pbkdf2 -pass pass:very-secret -in book.txt.enc_aes -out book.txt
$ openssl dgst -blake2b512 book.txt
BLAKE2B-512(book.txt)= 1a8ac18fde710ecc452770fcd52a2c4945d40c71467b2cd4c64a7b5308261078201cefdb6ddc682a67511aa60992324c5ff87e29192adfd8f113a1e6030b0459

$ rm book.txt
$ openssl enc -d -chacha20 -pbkdf2 -pass pass:very-secret -in book.txt.enc_chacha -out book.txt
$ openssl dgst -blake2b512 book.txt
BLAKE2B-512(book.txt)= 1a8ac18fde710ecc452770fcd52a2c4945d40c71467b2cd4c64a7b5308261078201cefdb6ddc682a67511aa60992324c5ff87e29192adfd8f113a1e6030b0459