Avatar billede Mik2000 Professor
20. januar 2022 - 20:26 Der er 19 kommentarer

PHP encrypt decrypt

Jeg håber virkelig der er en der kan hjælpe

Jeg er stødt på et ældre projekt hos en kammerat som han stadig bruger og har bedt om hjælp til, men vi er begge lidt i tvivl om what to do

Det benytter nogle funktioner som er udgået, og han skal opdaterer
mcrypt_encrypt, mcrypt_decrypt, mcrypt_get_iv_size

Han har noget data i databasen som er krypteret og bliver dekrypteret med nedenstående kode. Han kører på PHP 7.0 hvor det virker, men skal opgradere til 7.4 eller 8.0 eller 8.1 (skal helst virke på alle dem det nye)

Der er ikke tale om password så de skal hashes, men derimod data som bare skal ligge mere sikkert og krypteret. Den henter tit ud, så der skal være god afvejning mellem sikkerhed og hvor tungt det bliver.

Så spørgsmål:
1: Hvad er alternativet til nedenstående?

2: Og vil det kræve man henter alt data ud, dekrypterer det med det gamle script, for så at kunne krypterer det med et nyt script - eller hvordan gør man smartest?

ENCRYPT
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_DEV_URANDOM);
       
$encrypted = ase64_encode($iv.mcrypt_encrypt(MCRYPT_RIJNDAEL_128, hash('sha256', $code, true), $string, MCRYPT_MODE_CBC, $iv));

DECRYPT
$data = base64_decode($string);

$iv = substr($data, 0, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));

$decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, hash('sha256', $code, true), substr($data, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC)), MCRYPT_MODE_CBC, $iv), "\0");
20. januar 2022 - 20:35 #1
De funktioner er der ikke pr. default i PHP 8. På en linux skal man installere libmcrypt-dev.

Hvor kører hans hjemmeside?
Avatar billede Mik2000 Professor
20. januar 2022 - 22:01 #2
Kan jeg ikke lige huske - men han har vist desværre ikke adgang til at kunne installere på webhotellet.
Jeg læste nogle skrev man skulle skifte til openssl_encrypt som var med i PHP - men tænker det kræver man:
1: Finder ud af hvordan det bruges
2: Henter alt ud og dekryptere det
3: Krypterer alt med openssl_encrypt
4: Og derefter bruger openssl_decrypt
Er det den smarteste løsning?
20. januar 2022 - 22:13 #3
Du kan nok ikke installere det på et gængs webhotel, men spørg supporten om de kan. Den eneste forskel er at det ikke følger med som standard, og er lidt gammel.

Men hvis de ikke vil, så er det du skriver nok en løsning.

openssl er formentlig installeret.
Avatar billede arne_v Ekspert
21. januar 2022 - 03:47 #4
openssl kan godt dekryptere mcrypt data.


<?php
$key = 'hemmeligt';
$key2 = substr(hash('sha256', $key, true), 0, 16);
$p1 = 'This is a little test!';
echo "|$p1|\r\n";
$iv = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
$c = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key2, $p1, MCRYPT_MODE_CBC, $iv);
$p2 = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key2, $c, MCRYPT_MODE_CBC, $iv);
echo "|$p2|\r\n";
$p3 = openssl_decrypt($c, 'AES-128-CBC', $key2, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
echo "|$p3|\r\n";
?>


Output:


|This is a little test!|
|This is a little test!
Avatar billede arne_v Ekspert
21. januar 2022 - 03:50 #5
Ups. De nul bytes giver lidt problemer.


<?php
$key = 'hemmeligt';
$key2 = substr(hash('sha256', $key, true), 0, 16);
$p1 = 'This is a little test!';
echo "|$p1|\r\n";
$iv = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
$c = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key2, $p1, MCRYPT_MODE_CBC, $iv);
$p2 = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key2, $c, MCRYPT_MODE_CBC, $iv);
$p2 = rtrim($p2, "\0");
echo "|$p2|\r\n";
$p3 = openssl_decrypt($c, 'AES-128-CBC', $key2, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
$p3 = rtrim($p3, "\0");
echo "|$p3|\r\n";
?>



|This is a little test!|
|This is a little test!|
|This is a little test!|
Avatar billede Mik2000 Professor
21. januar 2022 - 16:25 #6
arne_v
Det lyder godt - så kan man i virkeligheden lade det ligge måske og så bare bruge
openssl_decrypt og openssl_encrypt

Lige et par spørgsmål:
1: Kan man også encrypte til samme format med openssl_encrypt (så database kan bibeholdes som den er)

2: Når jeg skal decrypte, så er denne brugt til at lave iv (iv er ikke gemt i database eller lign)
$iv = substr($data, 0, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));

Men den kan jeg jo ikke længere bruge, så hvordan får jeg $iv til openssl_decrypt funktionen?
Avatar billede arne_v Ekspert
21. januar 2022 - 16:57 #7
re 2)

$iv = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);

kan erstattes af:

$iv = openssl_random_pseudo_bytes(16);

og jo du gemmer $iv i databasen!

...  base64_encode($iv . mcrypt_encrypt( ...

og den teknik kan bruges uændret - den afhænger ikke af mcrypt vs openssl.
Avatar billede arne_v Ekspert
21. januar 2022 - 17:10 #8
re 1)

Ja.

Med et lille hack.

<?php
$key = 'hemmeligt';
$key2 = substr(hash('sha256', $key, true), 0, 16);
$p1 = 'This is a little test!';
echo "|$p1|\r\n";
$iv = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
$c = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key2, $p1, MCRYPT_MODE_CBC, $iv);
$p2 = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key2, $c, MCRYPT_MODE_CBC, $iv);
$p2 = rtrim($p2, "\0");
echo "|$p2|\r\n";
$p3 = openssl_decrypt($c, 'AES-128-CBC', $key2, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
$p3 = rtrim($p3, "\0");
echo "|$p3|\r\n";
echo base64_encode($c) . "\r\n";
$p1x = $p1;
while(strlen($p1x) % 16 != 0) $p1x .= "\0"; // hack
$cx = openssl_encrypt($p1x, 'AES-128-CBC', $key2, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
echo base64_encode($cx) . "\r\n";
$p3x = openssl_decrypt($cx, 'AES-128-CBC', $key2, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
$p3x = rtrim($p3x, "\0");
echo "|$p3x|\r\n";
?>


|This is a little test!|
|This is a little test!|
|This is a little test!|
t7Ag1CHqmIr8+hMvx/GaE7gq6gibsVJ2/wiXiERrmHA=
t7Ag1CHqmIr8+hMvx/GaE7gq6gibsVJ2/wiXiERrmHA=
|This is a little test!|
Avatar billede Mik2000 Professor
21. januar 2022 - 20:51 #9
Mange tak for svar igen Arne :)

Der er stadig noget der fejler, men måske jeg har gjort det forkert
Der kommer i hvert fald noget forkert ud

Jeg har dette
String = Det der er gemt i databasen
$code = min hemmelige kode

KODE:
---------------------
$data = base64_decode($string);

$iv = openssl_random_pseudo_bytes(16);

$key = substr(hash('sha256', $code, true), 0, 16);

$decrypted = openssl_decrypt($data, 'AES-128-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);

$decrypted = rtrim($decrypted, "\0");
---------------------

Det er måske den måde jeg bruger $data her
openssl_decrypt($data
for ved ikke om det kun er en del af det der skal bruges da gammel sætning var
$decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, hash('sha256', $code, true), substr($data, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC)), MCRYPT_MODE_CBC, $iv), "\0");
Avatar billede arne_v Ekspert
21. januar 2022 - 21:08 #10
Den kode ser forkert ud.

Når du krypterer så:
- generer random iv
- gem base64 encode af iv concat encrypt af data

Når du dekrypterer:
- hent og base64 decode data
- split data i iv og rigtige data
- decrypt rigtige data
Avatar billede Mik2000 Professor
21. januar 2022 - 22:28 #11
Nåh ja det giver mening. Har prøvet det nu men stadig med forkert resultat
Før brugte jeg mcrypt_get_iv_size til at splitte og fandt openssl_cipher_iv_length som jeg tænker matcher

Jeg får samme iv og datastring som før så må have lavet en fejl i selve openssl_decrypt funktionen

String = Det der er gemt i databasen
$code = min hemmelige kode

-----------------------------------
$data = base64_decode($string);
       
$iv = substr($data, 0, openssl_cipher_iv_length('AES-128-CBC'));
       
$key = substr(hash('sha256', $code, true), 0, 16);
       
$dataString = substr($data, openssl_cipher_iv_length('AES-128-CBC'));
$decrypted = openssl_decrypt($dataString, 'AES-128-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
       
$decrypted = rtrim($decrypted, "\0");
-----------------------------------
Avatar billede Mik2000 Professor
21. januar 2022 - 22:35 #12
Jeg tror måske det er noget med længden på passphrase for i den gamle var længden ikke kun 16

Men selvom jeg laver den om til
$key =hash('sha256', $code, true);

Så løser det ikke det - det giver samme resultat
Avatar billede arne_v Ekspert
21. januar 2022 - 22:51 #13
Altså IV size er altid 16 for AES, så jeg ville bare hardcode den.

Du skal huske at ændre værdien hvis du nogensinde skifter algoritme til noget som ikke har block size 16. Men det er næppe noget som sker i nærmste fremtid.

Evt.:

$ivsize = ...;

og så bruge $ivsize i koden.
Avatar billede arne_v Ekspert
21. januar 2022 - 22:52 #14
AES-128 har en 16 byte key og AES-256 har en 32 bit key. 16 byte * 8 bits/byte = 128 bit og 32 byte * 8 bit/byte = 256 bit.
Avatar billede arne_v Ekspert
21. januar 2022 - 22:54 #15
Jeg tror at der er noget trivielt galt.
Avatar billede arne_v Ekspert
21. januar 2022 - 23:03 #16

<?php
$key = 'hemmeligt';
$key2 = substr(hash('sha256', $key, true), 0, 16);
$p1 = 'This is a little test!';
echo "|$p1|\r\n";
$iv = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
$c = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key2, $p1, MCRYPT_MODE_CBC, $iv);
$dbstr = $iv . $c;
$dbstr64 = base64_encode($dbstr);
echo "$dbstr64\r\n";
$dbstr = base64_decode($dbstr64);
$dbstr_part1 = substr($dbstr, 0, 16);
$dbstr_part2 = substr($dbstr, 16);
$p2 = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key2, $dbstr_part2, MCRYPT_MODE_CBC, $dbstr_part1);
$p2 = rtrim($p2, "\0");
echo "|$p2|\r\n";
$p3 = openssl_decrypt($dbstr_part2, 'AES-128-CBC', $key2, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $dbstr_part1);
$p3 = rtrim($p3, "\0");
echo "|$p3|\r\n";
$p1x = $p1;
while(strlen($p1x) % 16 != 0) $p1x .= "\0"; // hack
$cx = openssl_encrypt($p1x, 'AES-128-CBC', $key2, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
$dbstr = $iv . $cx;
$dbstr64 = base64_encode($dbstr);
echo "$dbstr64\r\n";
?>



|This is a little test!|
n7lRHCgX9FcqS++wrid7LKfmFcV3foI5x1r2FzpVqwbbD/7pf/1372mvK1g++F3p
|This is a little test!|
|This is a little test!|
n7lRHCgX9FcqS++wrid7LKfmFcV3foI5x1r2FzpVqwbbD/7pf/1372mvK1g++F3p
Avatar billede arne_v Ekspert
22. januar 2022 - 15:59 #17
Men jeg vil anbefake at skifte fra zero padding til PKCS5 padding.
Avatar billede Mik2000 Professor
23. januar 2022 - 22:30 #18
Jeg har virkelig nogle problemer fordi den er længere end 16 og openssl_decrypt vil ikke acceptere det

Så jeg tror jeg går en anden vej

Jeg tænker jeg henter alt ud med den gamle kode, og encrypter det med helt ny openssl_encrypt

Hvis jeg alligevel skal gøre det, så kan jeg ligeså godt gøre det korrekt

Så den bedste måde at gøre det (sikkert vs. load) hvis man ser helt bort fra den data jeg har - er det stadig som ovenstående?
Avatar billede arne_v Ekspert
24. januar 2022 - 17:48 #19
Jeg kigge lidt på det.

Mcrypt er underlig. Hvis man angiber 128 bit algoritme og giver den en 256 bit key, så skifter den til en 256 bit algoritme.

WTF????

<?php
$key = 'hemmeligt';
$key2 = hash('sha256', $key, true); // NOT trim from 32 to 16 bytes !!!!
$p1 = 'This is a little test!';
echo "p original = |$p1|\r\n";
$iv = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
$c = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key2, $p1, MCRYPT_MODE_CBC, $iv);
$dbstr = $iv . $c;
$dbstr64 = base64_encode($dbstr);
echo "db mcrypt encrypt = $dbstr64\r\n";
$dbstr = base64_decode($dbstr64);
$dbstr_part1 = substr($dbstr, 0, 16);
$dbstr_part2 = substr($dbstr, 16);
$p2 = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key2, $dbstr_part2, MCRYPT_MODE_CBC, $dbstr_part1);
$p2 = rtrim($p2, "\0");
echo "p mcrypt_decrypt = |$p2|\r\n";
$p3 = openssl_decrypt($dbstr_part2, 'AES-256-CBC', $key2, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $dbstr_part1); // 256 not 128
$p3 = rtrim($p3, "\0");
echo "p openssl decrypt = |$p3|\r\n";
$p1x = $p1;
while(strlen($p1x) % 16 != 0) $p1x .= "\0"; // hack
$cx = openssl_encrypt($p1x, 'AES-256-CBC', $key2, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); // 256 not 128
$dbstr = $iv . $cx;
$dbstr64 = base64_encode($dbstr);
echo "db openssl encrypt = $dbstr64\r\n";
?>


p original = |This is a little test!|
db mcrypt encrypt = /R3xY3XkK8+Mu+jHWjgjaySejVbhuiNsv7kyld9j+yO70mN+TUsFIlzj2udP2GIa
p mcrypt_decrypt = |This is a little test!|
p openssl decrypt = |This is a little test!|
db openssl encrypt = /R3xY3XkK8+Mu+jHWjgjaySejVbhuiNsv7kyld9j+yO70mN+TUsFIlzj2udP2GIa
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester





CIO
Årets CIO 2022: Nu skal Danmarks dygtigste CIO findes - er det dig? Eller kender du en, du vil indstille?