
🔒 Kryptera och dekryptera filer i PHP: OpenSSL och Sodium istället för mcrypt
Kryptera en fil innan du sparar den till servern och var säker på att ingen, inte ens serveradministratören, kan läsa den utan nyckeln. Låter som ett grundläggande behov, men när mcrypt lämnade PHP slutade det välbekanta tillvägagångssättet att fungera.
Tillägget mcrypt markerades som föråldrat i PHP 7.1 och togs bort helt i PHP 7.2 redan 2017. Idag, på PHP 8, leder ett försök att anropa mcrypt_encrypt() till ett fatalt fel. Samtidigt ligger konfidentiella filer kvar på servrar: databassäkerhetskopior, CSV-filer med personuppgifter, PDF-kontrakt, orderexporter.
Goda nyheter: PHP erbjuder två fungerande mekanismer direkt ur lådan, OpenSSL och Sodium. Båda kräver ingen extra installation av tillägg på modern hosting, båda är snabbare och säkrare än mcrypt. Här följer en praktisk guide för att kryptera och dekryptera filer på PHP 8 med kod du kan kopiera och köra.
💡 Snabb översikt:
- Varför mcrypt är dött och vilka PHP-versioner som påverkas
- Steg-för-steg filkryptering via OpenSSL med AES-256-CBC
- Dekryptering med skydd mot datamanipulation via HMAC
- Sodium-alternativ för PHP 7.2 och senare
- När du ska välja OpenSSL och när du ska välja Sodium
Varför mcrypt inte längre är ett alternativ
Biblioteket mcrypt har inte uppdaterats sedan 2007. Kritiska sårbarheter hittades i dess kod, och inga underhållsansvariga fanns kvar. PHP-teamet fattade ett beslut: i PHP 7.1 markerades tillägget som föråldrat, och i PHP 7.2, som släpptes i november 2017, uteslöts det helt ur kärnan.
Om du migrerar ett gammalt projekt med mcrypt, kontrollera phpinfo(). På PHP 7.2+ finns ingen rad med "mcrypt support: enabled". Att anropa mcrypt_encrypt(), mcrypt_decrypt() eller strömfiltren mcrypt.tripledes / mdecrypt.tripledes ger felet "Call to undefined function".
Tekniskt sett är mcrypt tillgängligt via PECL med kommandot pecl install mcrypt. Men att installera ett tillägg som inte stöds och har kända sårbarheter på en produktionsserver för ett enda äldre skript är en dålig idé. Skriv om krypteringen med OpenSSL: det är inbyggt i PHP sedan version 5.3 och kommer inte att försvinna.
Filkryptering via OpenSSL, steg för steg
OpenSSL i PHP representeras av funktionerna openssl_encrypt() och openssl_decrypt(). De arbetar med rådata och stöder dussintals algoritmer, från AES-128-CBC till AES-256-GCM. För filer använder vi AES-256-CBC: det är kryptografiskt starkt och kräver inte PHP 7.1 till skillnad från GCM med extra taggparametrar.
Steg 1: generera krypteringsnyckel
Nyckeln är hela schemats huvudhemlighet. Den måste vara kryptografiskt slumpmässig, inte manuellt påhittad. Ingen "secret-password" från exempel, endast openssl_random_pseudo_bytes().
Skriptet nedan genererar en 256-bitars nyckel och matar ut den i format för infogning i wp-config.php. Kör en gång via kommandoraden och spara resultatet:
1 <?php 2 // Generating a random 256-bit key (32 bytes) 3 $encryption_key = base64_encode(openssl_random_pseudo_bytes(32)); 4 echo "define('FILE_ENCRYPTION_KEY', '" . $encryption_key . "');\n";
Funktionen openssl_random_pseudo_bytes(32) returnerar 32 byte av kryptografiskt kvalitativ slumpmässighet. base64_encode konverterar binärdata till en sträng som är praktisk att lagra i konfigurationsfiler. Nyckeln måste ligga utanför dokumentroten, i wp-config.php eller .env, men inte i temakod.
Steg 2: funktion för filkryptering
Skriptet läser en fil från disk, krypterar med AES-256-CBC-algoritmen, lägger till en slumpmässig IV i början och HMAC-signatur för integritetsverifiering, sparar resultatet. Lägg till koden i functions.php i ett barntema eller i ett anpassat tillägg.
Varning: innan du kör på en produktionsserver, gör en fullständig säkerhetskopia. Testa kryptering-dekryptering på en filkopia i en testkatalog. Om nyckeln förloras är det omöjligt att dekryptera data, AES-256 kan inte knäckas med brute force.
1 <?php 2 function encrypt_file(string $sourcePath, string $destPath, string $key): bool 3 { 4 if (!file_exists($sourcePath)) { 5 throw new RuntimeException('Source file not found: ' . $sourcePath); 6 } 7 8 $plaintext = file_get_contents($sourcePath); 9 if ($plaintext === false) { 10 throw new RuntimeException('Failed to read file'); 11 } 12 13 $cipher = 'aes-256-cbc'; 14 $ivLength = openssl_cipher_iv_length($cipher); 15 $iv = openssl_random_pseudo_bytes($ivLength); 16 17 $ciphertext = openssl_encrypt( 18 $plaintext, 19 $cipher, 20 base64_decode($key), 21 OPENSSL_RAW_DATA, 22 $iv 23 ); 24 25 if ($ciphertext === false) { 26 throw new RuntimeException('Encryption error'); 27 } 28 29 // HMAC signature for integrity verification during decryption 30 $hmac = hash_hmac('sha256', $iv . $ciphertext, base64_decode($key), true); 31 32 // File format: IV (16 bytes) + HMAC (32 bytes) + ciphertext 33 $result = file_put_contents($destPath, $iv . $hmac . $ciphertext); 34 35 return $result !== false; 36 }
Vad som händer här rad för rad:
openssl_cipher_iv_length('aes-256-cbc')returnerar 16, längden på initialiseringsvektorn för denna algoritm.openssl_random_pseudo_bytes($ivLength)skapar en slumpmässig IV. Den gör att identisk data krypterad med samma nyckel producerar olika chiffertext vid varje körning.OPENSSL_RAW_DATAtalar om för funktionen att returnera binärdata, inte base64. Vi sparar rå chiffertext för kompakthet.hash_hmac('sha256', ...)beräknar en kontrollsumma från paketet av IV och chiffertext. Under dekryptering kommer vi att räkna om HMAC och jämföra: om data har modifierats eller korrumperats kommer jämförelsen inte att stämma.- Filen sparas i formatet:
[IV 16 bytes][HMAC 32 bytes][ciphertext]. Inga avgränsare, positionerna är fasta utifrån längderna.
Steg 3: dekrypteringsfunktion
Den omvända processen: läs IV, läs HMAC, läs chiffertext, räkna om HMAC och jämför via hash_equals(), dekryptera. Koden läggs till i samma fil:
1 <?php 2 function decrypt_file(string $sourcePath, string $key): string|false 3 { 4 if (!file_exists($sourcePath)) { 5 throw new RuntimeException('Encrypted file not found: ' . $sourcePath); 6 } 7 8 $data = file_get_contents($sourcePath); 9 if ($data === false) { 10 throw new RuntimeException('Failed to read file'); 11 } 12 13 $cipher = 'aes-256-cbc'; 14 $ivLength = openssl_cipher_iv_length($cipher); 15 $hmacLength = 32; // sha256 = 32 bytes 16 17 $iv = substr($data, 0, $ivLength); 18 $hmac = substr($data, $ivLength, $hmacLength); 19 $ciphertext = substr($data, $ivLength + $hmacLength); 20 21 // Integrity check: recompute HMAC and compare 22 $calculatedHmac = hash_hmac( 23 'sha256', 24 $iv . $ciphertext, 25 base64_decode($key), 26 true 27 ); 28 29 if (!hash_equals($hmac, $calculatedHmac)) { 30 throw new RuntimeException('File corrupted or key invalid'); 31 } 32 33 $plaintext = openssl_decrypt( 34 $ciphertext, 35 $cipher, 36 base64_decode($key), 37 OPENSSL_RAW_DATA, 38 $iv 39 ); 40 41 return $plaintext; 42 }
Nyckelpunkt: hash_equals() istället för ===. Vanlig strängjämförelse är sårbar för timingattacker, en angripare kan gissa HMAC byte för byte genom att mäta serverns svarstid. hash_equals() jämför strängar på konstant tid oavsett vid vilket tecken de skiljer sig åt.
Användningsexempel med verkliga sökvägar
1 <?php 2 $key = FILE_ENCRYPTION_KEY; // from wp-config.php 3 4 // Encrypting the database backup 5 encrypt_file( 6 __DIR__ . '/backup.sql', 7 __DIR__ . '/backup.sql.enc', 8 $key 9 ); 10 11 // Decrypting and serving for download 12 $decrypted = decrypt_file(__DIR__ . '/backup.sql.enc', $key); 13 header('Content-Type: application/octet-stream'); 14 header('Content-Disposition: attachment; filename="backup.sql"'); 15 echo $decrypted;
Funktionerna är universella: de fungerar med alla filtyper, bilder, PDF, CSV, SQL-dumpar. Storleken begränsas endast av tillgängligt RAM, eftersom filen läses in i minnet i sin helhet. För gigabyte-stora filer kommer strömmande bearbetning med chunk-buffring att behövas, men för den överväldigande majoriteten av praktiska uppgifter är denna kod tillräcklig.
Alternativ: Sodium (libsodium)
Tillägget Sodium är inbyggt i PHP från och med version 7.2 och blev en del av kärnan i PHP 8.1. Det erbjuder ett enklare API jämfört med OpenSSL: inget behov av att manuellt hantera IV och HMAC, autentiserad kryptering fungerar direkt ur lådan.
1 <?php 2 function sodium_encrypt_file(string $sourcePath, string $destPath, string $key): bool 3 { 4 $plaintext = file_get_contents($sourcePath); 5 $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); 6 $ciphertext = sodium_crypto_secretbox($plaintext, $nonce, base64_decode($key)); 7 return file_put_contents($destPath, $nonce . $ciphertext) !== false; 8 } 9 10 function sodium_decrypt_file(string $sourcePath, string $key): string|false 11 { 12 $data = file_get_contents($sourcePath); 13 $nonce = substr($data, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); 14 $ciphertext = substr($data, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); 15 $result = sodium_crypto_secretbox_open($ciphertext, $nonce, base64_decode($key)); 16 return $result !== false ? $result : false; 17 }
Notera: Sodium verifierar integriteten själv. Om data har modifierats eller nyckeln är felaktig returnerar sodium_crypto_secretbox_open() helt enkelt false, inga separata HMAC-kontroller krävs. Koden är hälften så lång.
En nackdel: Sodium kräver PHP 7.2 eller senare. Om projektet körs på PHP 7.0-7.1 är OpenSSL det enda alternativet. Men i praktiken år 2026 är det redan svårt att hitta webbhotell med PHP under 7.4: enligt WordPress.orgs data för juni 2026 är andelen PHP 7.0-7.1 mindre än 0,3% av alla installationer.
OpenSSL eller Sodium: två urvalskriterier
Valet mellan de två tillvägagångssätten kokar ner till två faktorer:
- PHP-version. PHP 7.2+, ta Sodium, det är säkrare som standard och låter dig inte misslyckas med HMAC-implementationen. PHP 7.0-7.1, endast OpenSSL. Under PHP 7.0 är det dags att uppdatera servern, inte uppfinna lösningar med PECL-mcrypt.
- Dataportabilitet mellan miljöer. OpenSSL finns tillgängligt överallt, inklusive PHP 5.3+. Om krypterade filer måste vara läsbara på dev-server, i produktion och hos kunden är OpenSSL mer tillförlitligt ur kompatibilitetssynpunkt. Sodium-chiffertext kommer endast att dekrypteras där Sodium finns.
I praktiken använder vi OpenSSL på projekt där kompatibilitet mellan olika miljöer är viktig. Sodium där hela stacken är uppdaterad till PHP 8 och säkerhet kommer först.
I videon bryter Dave Hollingworth ner båda tillvägagångssätten i detalj med koddemonstration och förklaring av de kryptografiska primitiverna bakom varje. Materialet kompletterar artikeln: gränsfall visas, installation av biblioteket defuse/php-encryption via Composer och prestandajämförelse av OpenSSL och Sodium på verklig data.
⁉️🤔 Vanliga frågor
Kan jag använda md5() eller sha1() för filkryptering?
Nej.
md5()ochsha1()är hashfunktioner, de är per definition irreversibla. En krypterad fil måste kunna dekrypteras tillbaka, och en hash kan inte dekrypteras. Hashar används för integritetsverifiering (som HMAC i koden ovan) och lösenordslagring viapassword_hash(), men inte för innehållskryptering.
Vad gör man om krypteringsnyckeln försvinner?
Att dekryptera data utan nyckeln är omöjligt. Lagra nyckeln i
wp-config.phputanför dokumentroten och säkerhetskopiera den separat från fil- och databassäkerhetskopior. Lägg inte nyckeln i ett Git-repository, lägg tillwp-config.phpi.gitignoreeller använd miljövariabler.
Varför behövs IV om nyckeln redan är hemlig?
Utan en slumpmässig IV producerar identisk data krypterad med samma nyckel identisk chiffertext. En angripare som ser upprepade block får information om filstrukturen. IV gör varje krypteringskörning unik: samma fil krypterad två gånger med en nyckel producerar två olika chiffertexter.
Kan jag kryptera stora filer, flera gigabyte?
Funktionerna ovan läser in filen i minnet i sin helhet, för gigabyte-data kommer detta att leda till minnesutmattning. För strömmande kryptering använd
openssl_encrypt()i en loop med chunk-buffring (till exempel 1 MB vardera) eller biblioteketdefuse/php-encryption, som stöder strömmande läge direkt ur lådan.
Fungerar denna kod på PHP 8.3?
Ja. Både OpenSSL och Sodium stöds fullt ut i PHP 8. Koden är testad på aktuella PHP-versioner och använder inga föråldrade funktioner. På PHP 8.3 upprätthålls kompatibilitet, det finns inga bakåtinkompatibiliteter i OpenSSL-tillägget.
Filkryptering 2026: praktisk dom
Mcrypt lämnade PHP, och det är till det bättre. Två inbyggda ersättningsverktyg är både säkrare och snabbare och kräver ingen PECL-dans med tamburin. OpenSSL fungerar överallt, Sodium är enklare och mer tillförlitligt som standard.
Kort sagt: nytt projekt på PHP 8, börja med Sodium, koden blir renare. Migrera gammal kod från mcrypt, skriv om till OpenSSL, det är tillgängligt även på PHP 7.0. Och kryptografins huvudregel: lagra nycklar separat från krypterad data. Nyckelförlust är lika med dataförlust, och brute force hjälper inte här.
Börja med ett testskript på en filkopia: säkerställ att cykeln "krypterad → dekrypterad → byte-för-byte matchad" fungerar utan fel. Och vilken metod använder du i dina projekt, OpenSSL, Sodium eller något annat? Skriv i kommentarerna.



