paint-brush
Kryptering: Ciphers, Digests, Salt og IV - Hvad du behøver at videved@gliimlang
Ny historie

Kryptering: Ciphers, Digests, Salt og IV - Hvad du behøver at vide

ved Gliimly14m2025/01/04
Read on Terminal Reader

For langt; At læse

Kryptering er en metode til at omdanne data til en ubrugelig form, der kun kan gøres nyttig ved hjælp af dekryptering. Her lærer du, hvordan du krypterer og dekrypterer data ved hjælp af en adgangskode.
featured image - Kryptering: Ciphers, Digests, Salt og IV - Hvad du behøver at vide
Gliimly HackerNoon profile picture

Hvad er kryptering?

Kryptering er en metode til at omdanne data til en ubrugelig form, der kun kan gøres nyttig ved hjælp af dekryptering. Formålet er udelukkende at gøre data tilgængelige for dem, der kan dekryptere dem (dvs. gøre dem brugbare). Typisk skal data krypteres for at sikre, at de ikke kan fås i tilfælde af uautoriseret adgang. Det er den sidste forsvarslinje, efter at en angriber har formået at bryde igennem autorisationssystemer og adgangskontrol.

Det betyder ikke, at alle data skal krypteres, for ofte kan autorisations- og adgangssystemer være nok, og derudover er der en ydeevnestraf for at kryptere og dekryptere data. Hvis og hvornår dataene bliver krypteret, er et spørgsmål om applikationsplanlægning og risikovurdering, og nogle gange er det også et lovkrav, såsom med HIPAA eller GDPR.

Data kan krypteres i hvile, f.eks. på disk, eller under transport, f.eks. mellem to parter, der kommunikerer over internettet.

Her lærer du, hvordan du krypterer og dekrypterer data ved hjælp af en adgangskode, også kendt som symmetrisk kryptering. Denne adgangskode skal være kendt af begge parter, der udveksler oplysninger.

Cipher, Digest, Salt, Iterations, IV

For korrekt og sikkert at bruge kryptering er der et par begreber, der skal forklares.


En chiffer er den algoritme, der bruges til kryptering. For eksempel er AES256 en chiffer. Ideen med en chiffer er, hvad de fleste mennesker vil tænke på, når det kommer til kryptering.


En digest er dybest set en hash-funktion, der bruges til at kryptere og forlænge adgangskoden (dvs. krypteringsnøglen), før den bruges af chifferen. Hvorfor gøres dette? For det første skaber det en vel-randomiseret hash af ensartet længde af en nøgle, der fungerer bedre til kryptering. Den er også meget velegnet til at "salte", som er den næste at tale om.


"Saltet" er en metode til at besejre såkaldte "regnbue"-borde. En angriber ved, at to hash-værdier stadig vil se nøjagtig ens ud, hvis originalerne var. Men hvis du tilføjer saltværdien til hashing, så gør de det ikke. Det kaldes "salt", fordi det på en måde er blandet med nøglen til at producere noget anderledes.


Nu vil en regnbuetabel forsøge at matche kendte hash-værdier med forudberegnet data i et forsøg på at gætte en adgangskode.


Normalt genereres salt tilfældigt for hver nøgle og opbevares med den. For at matche kendte hashes, ville angriberen skulle forudberegne regnbuetabeller for en lang række tilfældige værdier, hvilket generelt ikke er muligt.

Du vil ofte høre om "iterationer" i kryptering. En iteration er en enkelt cyklus, hvor en nøgle og salt blandes på en sådan måde, at det bliver sværere at gætte nøglen. Dette gøres mange gange for at gøre det beregningsmæssigt vanskeligt for en angriber at omvendt gætte nøglen, derfor "iterationer" (flertal). Typisk er det mindst nødvendige antal iterationer 1000, men det kan være anderledes end det. Hvis du starter med en rigtig stærk adgangskode, har du generelt brug for mindre.

IV (eller "initialiseringsvektor") er typisk en tilfældig værdi, der bruges til kryptering af hver besked. Nu bruges salt til at producere en nøgle baseret på et kodeord. Og IV bruges, når du allerede har en nøgle og nu krypterer beskeder. Formålet med IV er at få de samme beskeder til at se anderledes ud, når de er krypteret. Nogle gange har IV også en sekventiel komponent, så den er lavet af en tilfældig streng plus en sekvens, der konstant øges.


Dette gør "genafspilning" angreb vanskelige, hvilket er hvor angriberen ikke behøver at dekryptere en besked; snarere blev en krypteret besked "sniffet" (dvs. opsnappet mellem afsender og modtager) og derefter afspillet igen i håb om at gentage den allerede udførte handling. Selvom de fleste protokoller på højt niveau i virkeligheden allerede har en sekvens på plads, hvor hver meddelelse som en del af den har et stigende pakkenummer, så i de fleste tilfælde har IV ikke brug for det.

Forudsætninger

Dette eksempel bruger Gliimly -rammen. Installer det først.

Eksempel på kryptering

For at køre eksemplerne her skal du oprette en applikation "enc" i en egen mappe (se mgrg for mere om Gliimlys program manager):

 mkdir enc_example cd enc_example gg -k enc

Brug encrypt-data statement for at kryptere data. Den enkleste form er at kryptere en null-termineret streng. Opret en fil "encrypt.gliim" og kopier denne:

 begin-handler /encrypt public set-string str = "This contains a secret code, which is Open Sesame!" // Encrypt encrypt-data str to enc_str password "my_password" p-out enc_str @ // Decrypt decrypt-data enc_str password "my_password" to dec_str p-out dec_str @ end-handler

Du kan se den grundlæggende brug af kryptere-data og dekryptere-data . Du leverer data (original eller krypteret) og adgangskoden, og så er du afsted. Dataene krypteres og dekrypteres derefter, hvilket giver originalen.

I kildekoden vil en strengvariabel "enc_str" (som er oprettet som en "char *") indeholde den krypterede version af "Dette indeholder en hemmelig kode, som er Open Sesame!" og "dec_str" vil være de dekrypterede data, som skal være nøjagtig det samme.

For at køre denne kode fra kommandolinjen, lav applikationen først:

 gg -q

Lad derefter Gliimly producere bash-koden for at køre den - anmodningsstien er "/encrypt", som i vores tilfælde håndteres af funktionen "void encrypt()" defineret i kildefilen "encrypt.gliim". I Gliimly matcher disse navne altid, hvilket gør det nemt at skrive, læse og udføre kode. Brug muligheden "-r" i gg for at angive anmodningsstien og få den kode, du skal bruge for at køre programmet:

 gg -r --req="/encrypt" --silent-header --exec


Du får et svar som dette:

 72ddd44c10e9693be6ac77caabc64e05f809290a109df7cfc57400948cb888cd23c7e98e15bcf21b25ab1337ddc6d02094232111aa20a2d548c08f230b6d56e9 This contains a secret code, which is Open Sesame!


Det, du har her, er de krypterede data, og så dekrypteres disse krypterede data med samme adgangskode. Ikke overraskende matcher resultatet den streng, du krypterede i første omgang.

Bemærk, at kryptering-data som standard producerer krypteret værdi i en menneskelig læsbar hexadecimal form, hvilket betyder bestående af hexadecimale tegn "0" til "9" og "a" til "f". På denne måde kan du gemme de krypterede data i en almindelig streng. For eksempel kan det gå til et JSON-dokument, ind i en VARCHAR-kolonne i en database eller stort set andre steder. Du kan dog også producere binært krypterede data. Mere om det om lidt.

Krypter data til et binært resultat

I det foregående eksempel er de resulterende krypterede data i en menneskelig læsbar hexadecimal form. Du kan også oprette binært krypterede data, som ikke er en menneskelig læsbar streng og også er kortere. For at gøre det, brug den "binære" klausul. Erstat koden i "encrypt.gliim" med:

 begin-handler /encrypt public set-string str = "This contains a secret code, which is Open Sesame!" // Encrypt encrypt-data str to enc_str password "my_password" binary // Save the encrypted data to a file write-file "encrypted_data" from enc_str get-app directory to app_dir @Encrypted data written to file <<p-out app_dir>>/encrypted_data // Decrypt data decrypt-data enc_str password "my_password" binary to dec_str p-out dec_str @ end-handler

Når du ønsker at få binært krypterede data, bør du også få dets længde i bytes, ellers ved du ikke, hvor det ender, da det kan indeholde null bytes. Brug klausulen "output-længde" til det formål. I denne kode er de krypterede data i variablen "enc_str" skrevet til filen "encrypted_data", og længden skrevet er "outlen" bytes.


Når en fil er skrevet uden en sti, skrives den altid i programmets hjemmemappe (se mapper ), så du ville bruge get-app til at hente den mappe.

Når du dekrypterer data, skal du bemærke brugen af "input-længde"-klausulen. Den siger, hvor mange bytes de krypterede data har. Det kan du naturligvis få fra "outlen"-variablen, hvor krypteringsdata gemmer længden af krypterede data. Når kryptering og dekryptering er afkoblet, dvs. kører i separate programmer, sørger du for, at denne længde er tilgængelig.

Bemærk også, at når data er krypteret som "binært" (hvilket betyder at producere et binært output), skal dekrypteringen bruge det samme.

Lav ansøgningen:

 gg -q


Kør det på samme måde som før:

 gg -r --req="/encrypt" --silent-header --exec


Resultatet er:

 Encrypted data written to file /var/lib/gg/enc/app/encrypted_data This contains a secret code, which is Open Sesame!


De dekrypterede data er nøjagtig de samme som originalen.

Du kan se de faktiske krypterede data skrevet til filen ved at bruge "oktal dump" ("od") Linux-værktøjet:

 od -c /var/lib/gg/enc/app/encrypted_data


med resultatet som:

 $ od -c /var/lib/gg/enc/app/encrypted_data 0000000 r 335 324 L 020 351 i ; 346 254 w 312 253 306 N 005 0000020 370 \t ) \n 020 235 367 317 305 t \0 224 214 270 210 315 0000040 # 307 351 216 025 274 362 033 % 253 023 7 335 306 320 0000060 224 # ! 021 252 242 325 H 300 217 # \vm V 351 0000100

Der har du det. Du vil bemærke, at dataene er binære, og de faktisk indeholder null-byten(e).

Krypter binære data

Dataene, der skal krypteres i disse eksempler, er en streng, dvs. nul-separeret. Du kan kryptere binære data lige så nemt ved at specificere det hele (da Gliimly holder styr på hvor mange bytes der er!) eller specificere dets længde i "input-length" klausulen, kopier for eksempel dette til "encrypt.gliim":

 begin-handler /encrypt public set-string str = "This c\000ontains a secret code, which is Open Sesame!" // Encrypt encrypt-data str to enc_str password "my_password" input-length 12 p-out enc_str @ // Decrypt decrypt-data enc_str password "my_password" to dec_str // Output binary data; present null byte as octal \000 string-length dec_str to res_len start-loop repeat res_len use i start-with 0 if-true dec_str[i] equal 0 p-out "\\000" else-if pf-out "%c", dec_str[i] end-if end-loop @ end-handler

Dette vil kryptere 12 bytes på hukommelsesplaceringen "enc_str" uanset eventuelle null-bytes. I dette tilfælde er det "This c" efterfulgt af en null-byte efterfulgt af en "ontain"-streng, men det kan være enhver form for binære data, for eksempel indholdet af en JPG-fil.

På dekrypteringssiden vil du få antallet af bytes dekrypteret i "output-længde"-klausulen. Endelig er de dekrypterede data vist at være nøjagtigt de originale, og null-byten præsenteres i en typisk oktal repræsentation.

Lav ansøgningen:

 gg -q


Kør det på samme måde som før:

 gg -r --req="/encrypt" --silent-header --exec


Resultatet er:

 6bea45c2f901c0913c87fccb9b347d0a This c\000ontai


Den krypterede værdi er kortere, fordi dataene også i dette tilfælde er kortere, og resultatet matcher nøjagtigt originalen.

Brug enhver chiffer eller digest

Krypteringen, der som standard bruges, er AES256 og SHA256 hashing fra standard OpenSSL -biblioteket, som begge er meget brugt i kryptografi. Du kan dog bruge enhver tilgængelig cipher og digest (dvs. hash), der understøttes af OpenSSL (selv de brugerdefinerede, du leverer).

For at se, hvilke algoritmer der er tilgængelige, skal du gøre dette på kommandolinjen:

 #get list of cipher providers openssl list -cipher-algorithms #get list of digest providers openssl list -digest-algorithms


Disse to vil give en liste over cipher og digest (hash) algoritmer. Nogle af dem kan være svagere end de standard, der er valgt af Gliimly, og andre kan være der kun for bagudkompatibilitet med ældre systemer. Alligevel kan andre være helt nye og ikke havde tid nok til at blive valideret i det omfang, du måske ønsker, at de skal være.


Så vær forsigtig, når du vælger disse algoritmer, og sørg for at vide, hvorfor du ændrer standardalgoritmerne. Når det er sagt, er her et eksempel på brug af Camellia-256 (dvs. "CAMELLIA-256-CFB1") kryptering med "SHA3-512" digest. Erstat koden i "encrypt.gliim" med:

 begin-handler /encrypt public set-string str = "This contains a secret code, which is Open Sesame!" // Encrypt data encrypt-data str to enc_str password "my_password" \ cipher "CAMELLIA-256-CFB1" digest "SHA3-512" p-out enc_str @ // Decrypt data decrypt-data enc_str password "my_password" to dec_str \ cipher "CAMELLIA-256-CFB1" digest "SHA3-512" p-out dec_str @ end-handler


Lav ansøgningen:

 gg -q


Kør det:

 gg -r --req="/encrypt" --silent-header --exec


I dette tilfælde er resultatet:

 f4d64d920756f7220516567727cef2c47443973de03449915d50a1d2e5e8558e7e06914532a0b0bf13842f67f0a268c98da6 This contains a secret code, which is Open Sesame!

Igen får du de originale data. Bemærk, du skal bruge den samme cipher og digest i både krypter-data og dekrypter-data!

Du kan selvfølgelig producere den binære krypterede værdi ligesom før ved at bruge "binære" og "output-længde" klausuler.

Hvis du har eksterne systemer, der krypterer data, og du ved, hvilken cipher og digest de bruger, kan du matche dem og gøre din kode interoperabel. Gliimly bruger standard OpenSSL-bibliotek, så chancerne er, at anden software også kan.

Brug af salt

For at tilføje salt til krypteringen skal du bruge "salt"-sætningen. Du kan generere tilfældigt salt ved at bruge random-string- sætningen (eller random-crypto, hvis der er et behov). Her er koden til "encrypt.gliim":

 begin-handler /encrypt public set-string str = "This contains a secret code, which is Open Sesame!" // Get salt random-string to rs length 16 // Encrypt data encrypt-data str to enc_str password "my_password" salt rs @Salt used is <<p-out rs>>, and the encrypted string is <<p-out enc_str>> // Decrypt data decrypt-data enc_str password "my_password" salt rs to dec_str p-out dec_str @ end-handler


Lav ansøgningen:

 gg -q


Kør det et par gange:

 gg -r --req="/encrypt" --silent-header --exec gg -r --req="/encrypt" --silent-header --exec gg -r --req="/encrypt" --silent-header --exec


Resultatet:

 Salt used is VA9agPKxL9hf3bMd, and the encrypted string is 3272aa49c9b10cb2edf5d8a5e23803a5aa153c1b124296d318e3b3ad22bc911d1c0889d195d800c2bd92153ef7688e8d1cd368dbca3c5250d456f05c81ce0fdd This contains a secret code, which is Open Sesame! Salt used is FeWcGkBO5hQ1uo1A, and the encrypted string is 48b97314c1bc88952c798dfde7a416180dda6b00361217ea25278791c43b34f9c2e31cab6d9f4f28eea59baa70aadb4e8f1ed0709db81dff19f24cb7677c7371 This contains a secret code, which is Open Sesame! Salt used is nCQClR0NMjdetTEf, and the encrypted string is f19cdd9c1ddec487157ac727b2c8d0cdeb728a4ecaf838ca8585e279447bcdce83f7f95fa53b054775be1bb2de3b95f2e66a8b26b216ea18aa8b47f3d177e917 This contains a secret code, which is Open Sesame!

Som du kan se, genereres en tilfældig saltværdi (16 bytes lang i dette tilfælde) for hver kryptering, og den krypterede værdi er forskellig hver gang, selvom de data, der blev krypteret, var de samme! Dette gør det svært at knække kryptering som denne.

For at dekryptere skal du selvfølgelig optage saltet og bruge det nøjagtigt, som du gjorde ved kryptering. I koden her indeholder variablen "rs" saltet. Hvis du gemmer de krypterede værdier i databasen, vil du sandsynligvis gemme saltet lige ved siden af.

Initialiseringsvektor

I praksis ville du ikke bruge en forskellig saltværdi for hver besked. Det skaber en ny nøgle hver gang, og det kan reducere ydeevnen. Og der er virkelig ikke behov for det: brugen af salt er at gøre hver nøgle (selv de samme) meget sværere at gætte. Når du har gjort det, behøver du måske ikke gøre det igen, eller ofte.

I stedet vil du bruge en IV (initialiseringsvektor) for hver besked. Det er normalt en tilfældig streng, der får de samme beskeder til at se anderledes ud og øger de beregningsmæssige omkostninger ved at knække adgangskoden. Her er den nye kode til "encrypt.gliim":

 begin-handler /encrypt public // Get salt random-string to rs length 16 // Encrypt data start-loop repeat 10 use i start-with 0 random-string to iv length 16 encrypt-data "The same message" to enc_str password "my_password" salt rs iterations 2000 init-vector iv cache @The encrypted string is <<p-out enc_str>> // Decrypt data decrypt-data enc_str password "my_password" salt rs iterations 2000 init-vector iv to dec_str cache p-out dec_str @ end-loop end-handler


Lav ansøgningen:

 gg -q


Kør det et par gange:

 gg -r --req="/encrypt" --silent-header --exec gg -r --req="/encrypt" --silent-header --exec gg -r --req="/encrypt" --silent-header --exec


Resultatet kan være:

 The encrypted string is 787909d332fd84ba939c594e24c421b00ba46d9c9a776c47d3d0a9ca6fccb1a2 The same message The encrypted string is 7fae887e3ae469b666cff79a68270ea3d11b771dc58a299971d5b49a1f7db1be The same message The encrypted string is 59f95c3e4457d89f611c4f8bd53dd5fa9f8c3bbe748ed7d5aeb939ad633199d7 The same message The encrypted string is 00f218d0bbe7b618a0c2970da0b09e043a47798004502b76bc4a3f6afc626056 The same message The encrypted string is 6819349496b9f573743f5ef65e27ac26f0d64574d39227cc4e85e517f108a5dd The same message The encrypted string is a2833338cf636602881377a024c974906caa16d1f7c47c78d9efdff128918d58 The same message The encrypted string is 04c914cd9338fcba9acb550a79188bebbbb134c34441dfd540473dd8a1e6be40 The same message The encrypted string is 05f0d51561d59edf05befd9fad243e0737e4a98af357a9764cba84bcc55cf4d5 The same message The encrypted string is ae594c4d6e72c05c186383e63c89d93880c8a8a085bf9367bdfd772e3c163458 The same message The encrypted string is 2b28cdf5a67a5a036139fd410112735aa96bc341a170dafb56818dc78efe2e00 The same message

Du kan se, at den samme besked ser anderledes ud, når den er krypteret, men når den dekrypteres, er den igen den samme. Selvfølgelig skal adgangskoden, saltet, antallet af iterationer og init-vektoren være den samme for både kryptering og dekryptering.

Bemærk brugen af "cache"-klausulen i kryptering af data og dekryptering af data. Det cacher effektivt den beregnede nøgle (givet adgangskode, salt, cipher/digest-algoritmer og antallet af iterationer), så det bliver ikke beregnet hver gang gennem løkken. Med "cache" beregnes nøglen én gang, og derefter bruges en anden IV (i "init-vector"-sætningen) for hver besked.

Hvis du lejlighedsvis vil genopbygge nøglen, skal du bruge "clear-cache"-klausulen, som giver en boolean. Hvis det er sandt, beregnes nøglen igen, ellers lades den være i fred. Se krypteringsdata for mere om dette.

Konklusion

Du har lært, hvordan du krypterer og dekrypterer data ved hjælp af forskellige ciphers, digests, salt og IV-værdier i Gliimly. Du kan også oprette en krypteret værdi, der kan læses af mennesker, og et binært output, samt kryptere både strenge og binære værdier (som dokumenter).