mcrypt เลิกใช้แล้วทางเลือกอื่นคืออะไร?


103

Mcrypt นามสกุลถูกเลิกใช้จะถูกลบออกใน PHP 7.2 ตามความคิดเห็นที่โพสต์ที่นี่ ดังนั้นฉันกำลังมองหาวิธีอื่นในการเข้ารหัสรหัสผ่าน

ตอนนี้ฉันกำลังใช้บางอย่างเช่น

mcrypt_encrypt(MCRYPT_RIJNDAEL_128, md5($key, true), $string, MCRYPT_MODE_CBC, $iv)

ฉันต้องการความคิดเห็นของคุณสำหรับวิธีที่ดีที่สุด / แข็งแกร่งที่สุดในการเข้ารหัสรหัสผ่านแน่นอนว่ารหัสผ่านที่เข้ารหัสควรได้รับการสนับสนุนโดย PHP 7.xx และควรถอดรหัสได้เนื่องจากลูกค้าของฉันต้องการมีตัวเลือกในการ 'กู้คืน' รหัสผ่านโดยไม่ต้องสร้างใหม่ หนึ่ง.


9
ทำไมคุณต้องเข้ารหัส / ถอดรหัสรหัสผ่าน? ทำไมไม่เพียงแค่แฮชด้วยpassword_hashและยืนยันด้วยpassword_verify?
Don't Panic

3
"รหัสผ่านที่เข้ารหัสควรถอดรหัสได้ด้วย" - ทำไม? ฟังดูไม่ปลอดภัยเกินไป มีเหตุผลพิเศษไหม
Funk Forty Niner

24
"เนื่องจากลูกค้าของฉันต้องการมีตัวเลือกในการ" กู้คืน "รหัสผ่านของตนโดยไม่ต้องสร้างรหัสใหม่" - ไม่ปลอดภัยและควรได้รับตัวเลือกในการรีเซ็ตรหัสผ่านแทน
Funk Forty Niner

4
อย่าเข้ารหัสรหัสผ่านเมื่อผู้โจมตีได้รับฐานข้อมูลเขาจะได้รับคีย์เข้ารหัสด้วย ทำซ้ำบน HMAC ด้วยเกลือแบบสุ่มเป็นระยะเวลาประมาณ 100ms และประหยัดเกลือด้วยแฮช ใช้ฟังก์ชันเช่น password_hash, PBKDF2, Bcrypt และฟังก์ชันที่คล้ายกัน ประเด็นคือการทำให้ผู้โจมตีใช้เวลามากในการค้นหารหัสผ่านด้วยกำลังดุร้าย
zaph

2
จากคู่มือ php -> ฟังก์ชั่นนี้ได้รับการเลิกใช้งานเมื่อ PHP 7.1.0 การใช้ฟังก์ชันนี้เป็นสิ่งที่ไม่ควรทำอย่างยิ่ง ทางเลือกคือโซเดียม -> php.net/manual/en/book.sodium.php
MarcoZen

คำตอบ:


47

แนวทางปฏิบัติที่ดีที่สุดในการแฮชรหัสผ่านจึงไม่สามารถถอดรหัสได้ ทำให้สิ่งนี้ยากขึ้นเล็กน้อยสำหรับผู้โจมตีที่อาจเข้าถึงฐานข้อมูลหรือไฟล์ของคุณ

ถ้าคุณต้องเข้ารหัสข้อมูลของคุณและมีมันถอดรหัสกลับคืนมา, คู่มือในการรักษาความปลอดภัยการเข้ารหัส / ถอดรหัสสามารถใช้ได้ที่https://paragonie.com/white-paper/2015-secure-php-data-encryption เพื่อสรุปลิงก์ดังกล่าว:

  • ใช้Libsodium - นามสกุล PHP
  • หากคุณไม่สามารถใช้ Libsodium ได้ให้ใช้การเข้ารหัส defuse / php - รหัส PHP แบบตรง
  • หากคุณไม่สามารถใช้ Libsodium หรือ defuse / php-encryption ให้ใช้OpenSSL - เซิร์ฟเวอร์จำนวนมากจะติดตั้งสิ่งนี้ไว้แล้ว หากไม่มีก็สามารถคอมไพล์ด้วย --with-openssl [= DIR]

1
ควรลอง openssl เป็นอันดับแรกเนื่องจากเป็นเรื่องธรรมดามากซึ่งไม่ใช่ libsodium ไม่ควรใช้ Raw php เว้นแต่ส่วนขยายเนทีฟทั้งหมดจะหมดหากมีคำถาม
JSON

แม้ว่า OpenSSL เป็นเรื่องธรรมดามากดูเหมือนว่า PHP ที่ 7 จะใช้ libsodium แกนเข้ารหัสของ securityintelligence.com/news/...
Shadi

1
โปรดทราบว่ามีไลบรารีชื่อSodium-compat( github.com/paragonie/sodium_compat ) ซึ่งทำงานใน PHP> = 5.2.4
RaelB

30

ตามที่แนะนำโดย@rqLizardคุณสามารถใช้ฟังก์ชันopenssl_encrypt/ openssl_decryptPHP แทนซึ่งเป็นทางเลือกที่ดีกว่ามากในการใช้AES (The Advanced Encryption Standard) หรือที่เรียกว่าการเข้ารหัส Rijndael

ตามความคิดเห็นของ Scottต่อไปนี้ที่ php.net :

หากคุณกำลังเขียนโค้ดในการเข้ารหัสข้อมูล / การเข้ารหัสในปี 2015 ที่คุณควรใช้และopenssl_encrypt() openssl_decrypt()ไลบรารีพื้นฐาน ( libmcrypt) ถูกละทิ้งไปตั้งแต่ปี 2550 และทำงานได้แย่กว่า OpenSSL มาก (ซึ่งใช้ประโยชน์จากAES-NIโปรเซสเซอร์ที่ทันสมัยและปลอดภัยในการกำหนดเวลาแคช)

นอกจากนี้MCRYPT_RIJNDAEL_256ไม่ใช่AES-256เป็นรูปแบบอื่นของรหัสบล็อก Rijndael หากคุณต้องการAES-256ในการmcryptที่คุณจะต้องใช้MCRYPT_RIJNDAEL_128ด้วยกุญแจ 32 ไบต์ OpenSSL ทำให้ชัดเจนยิ่งขึ้นว่าคุณกำลังใช้โหมดใด (เช่นaes-128-cbcเทียบกับaes-256-ctr)

OpenSSL ยังใช้ช่องว่างภายใน PKCS7 ด้วยโหมด CBC แทนที่จะเป็นช่องว่างภายใน NULL byte ของ mcrypt ดังนั้น mcrypt จึงมีแนวโน้มที่จะทำให้โค้ดของคุณเสี่ยงต่อการโจมตีจาก padding oracle มากกว่า OpenSSL

สุดท้ายหากคุณไม่ได้รับรองความถูกต้องของการเข้ารหัส (เข้ารหัสจากนั้น MAC) แสดงว่าคุณทำผิด

อ่านเพิ่มเติม:

ตัวอย่างโค้ด

ตัวอย่าง # 1

AES Authenticated Encryption ในโหมด GCM ตัวอย่างสำหรับ PHP 7.1+

<?php
//$key should have been previously generated in a cryptographically safe way, like openssl_random_pseudo_bytes
$plaintext = "message to be encrypted";
$cipher = "aes-128-gcm";
if (in_array($cipher, openssl_get_cipher_methods()))
{
    $ivlen = openssl_cipher_iv_length($cipher);
    $iv = openssl_random_pseudo_bytes($ivlen);
    $ciphertext = openssl_encrypt($plaintext, $cipher, $key, $options=0, $iv, $tag);
    //store $cipher, $iv, and $tag for decryption later
    $original_plaintext = openssl_decrypt($ciphertext, $cipher, $key, $options=0, $iv, $tag);
    echo $original_plaintext."\n";
}
?>

ตัวอย่าง # 2

ตัวอย่างการเข้ารหัส AES Authenticated สำหรับ PHP 5.6+

<?php
//$key previously generated safely, ie: openssl_random_pseudo_bytes
$plaintext = "message to be encrypted";
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext_raw = openssl_encrypt($plaintext, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv);
$hmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary=true);
$ciphertext = base64_encode( $iv.$hmac.$ciphertext_raw );

//decrypt later....
$c = base64_decode($ciphertext);
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = substr($c, 0, $ivlen);
$hmac = substr($c, $ivlen, $sha2len=32);
$ciphertext_raw = substr($c, $ivlen+$sha2len);
$original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv);
$calcmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary=true);
if (hash_equals($hmac, $calcmac))//PHP 5.6+ timing attack safe comparison
{
    echo $original_plaintext."\n";
}
?>

ตัวอย่าง # 3

จากตัวอย่างข้างต้นฉันได้เปลี่ยนรหัสต่อไปนี้ซึ่งมีจุดมุ่งหมายเพื่อเข้ารหัสรหัสเซสชันของผู้ใช้:

class Session {

  /**
   * Encrypts the session ID and returns it as a base 64 encoded string.
   *
   * @param $session_id
   * @return string
   */
  public function encrypt($session_id) {
    // Get the MD5 hash salt as a key.
    $key = $this->_getSalt();
    // For an easy iv, MD5 the salt again.
    $iv = $this->_getIv();
    // Encrypt the session ID.
    $encrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $session_id, MCRYPT_MODE_CBC, $iv);
    // Base 64 encode the encrypted session ID.
    $encryptedSessionId = base64_encode($encrypt);
    // Return it.
    return $encryptedSessionId;
  }

  /**
   * Decrypts a base 64 encoded encrypted session ID back to its original form.
   *
   * @param $encryptedSessionId
   * @return string
   */
  public function decrypt($encryptedSessionId) {
    // Get the MD5 hash salt as a key.
    $key = $this->_getSalt();
    // For an easy iv, MD5 the salt again.
    $iv = $this->_getIv();
    // Decode the encrypted session ID from base 64.
    $decoded = base64_decode($encryptedSessionId);
    // Decrypt the string.
    $decryptedSessionId = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $decoded, MCRYPT_MODE_CBC, $iv);
    // Trim the whitespace from the end.
    $session_id = rtrim($decryptedSessionId, "\0");
    // Return it.
    return $session_id;
  }

  public function _getIv() {
    return md5($this->_getSalt());
  }

  public function _getSalt() {
    return md5($this->drupal->drupalGetHashSalt());
  }

}

เข้าสู่:

class Session {

  const SESS_CIPHER = 'aes-128-cbc';

  /**
   * Encrypts the session ID and returns it as a base 64 encoded string.
   *
   * @param $session_id
   * @return string
   */
  public function encrypt($session_id) {
    // Get the MD5 hash salt as a key.
    $key = $this->_getSalt();
    // For an easy iv, MD5 the salt again.
    $iv = $this->_getIv();
    // Encrypt the session ID.
    $ciphertext = openssl_encrypt($session_id, self::SESS_CIPHER, $key, $options=OPENSSL_RAW_DATA, $iv);
    // Base 64 encode the encrypted session ID.
    $encryptedSessionId = base64_encode($ciphertext);
    // Return it.
    return $encryptedSessionId;
  }

  /**
   * Decrypts a base 64 encoded encrypted session ID back to its original form.
   *
   * @param $encryptedSessionId
   * @return string
   */
  public function decrypt($encryptedSessionId) {
    // Get the Drupal hash salt as a key.
    $key = $this->_getSalt();
    // Get the iv.
    $iv = $this->_getIv();
    // Decode the encrypted session ID from base 64.
    $decoded = base64_decode($encryptedSessionId, TRUE);
    // Decrypt the string.
    $decryptedSessionId = openssl_decrypt($decoded, self::SESS_CIPHER, $key, $options=OPENSSL_RAW_DATA, $iv);
    // Trim the whitespace from the end.
    $session_id = rtrim($decryptedSessionId, '\0');
    // Return it.
    return $session_id;
  }

  public function _getIv() {
    $ivlen = openssl_cipher_iv_length(self::SESS_CIPHER);
    return substr(md5($this->_getSalt()), 0, $ivlen);
  }

  public function _getSalt() {
    return $this->drupal->drupalGetHashSalt();
  }

}

เพื่อความชัดเจนการเปลี่ยนแปลงข้างต้นไม่ใช่การแปลงที่แท้จริงเนื่องจากการเข้ารหัสทั้งสองใช้ขนาดบล็อกที่แตกต่างกันและข้อมูลที่เข้ารหัสต่างกัน นอกจากนี้ช่องว่างภายในเริ่มต้นแตกต่างกันMCRYPT_RIJNDAELรองรับเฉพาะช่องว่างภายในที่ไม่ได้มาตรฐานเท่านั้น @zaph


หมายเหตุเพิ่มเติม (จากความคิดเห็นของ @ zaph):

  • Rijndael 128 ( MCRYPT_RIJNDAEL_128) คือเทียบเท่ากับAESแต่Rijndael 256 ( MCRYPT_RIJNDAEL_256) ไม่ได้เป็น AES-256เป็น 256 ระบุบล็อกขนาด 256 บิตในขณะที่AESมีเพียงหนึ่งช่วงตึกขนาด 128 บิต ดังนั้นโดยพื้นฐานแล้ว Rijndael ที่มีขนาดบล็อก 256 บิต ( MCRYPT_RIJNDAEL_256) จึงถูกตั้งชื่อผิดเนื่องจากตัวเลือกของผู้พัฒนาmcrypt @zaph
  • Rijndael ที่มีขนาดบล็อก 256 อาจมีความปลอดภัยน้อยกว่าขนาดบล็อก 128 บิตเนื่องจากหลังมีการตรวจทานและการใช้งานมากขึ้น ประการที่สองความสามารถในการทำงานร่วมกันถูกขัดขวางในขณะที่ AES พร้อมใช้งานโดยทั่วไปโดยที่ Rijndael ที่มีขนาดบล็อก 256 บิตไม่ได้
  • การเข้ารหัสด้วยขนาดบล็อกที่แตกต่างกันสำหรับ Rijndael ทำให้เกิดข้อมูลที่เข้ารหัสที่แตกต่างกัน

    ตัวอย่างเช่นMCRYPT_RIJNDAEL_256(ไม่เทียบเท่าAES-256) กำหนดตัวแปรบล็อก Rijndael ที่แตกต่างกันโดยมีขนาด 256 บิตและขนาดคีย์ตามคีย์ที่ส่งผ่านโดยที่aes-256-cbcRijndael มีขนาดบล็อก 128 บิตโดยมีขนาดคีย์เป็น 256 บิต ดังนั้นพวกเขาจึงใช้ขนาดบล็อกที่แตกต่างกันซึ่งสร้างข้อมูลเข้ารหัสที่แตกต่างกันอย่างสิ้นเชิงเนื่องจาก mcrypt ใช้ตัวเลขเพื่อระบุขนาดบล็อกโดยที่ OpenSSL ใช้ตัวเลขเพื่อระบุขนาดคีย์ (AES มีขนาดบล็อกเพียง 128 บิตเดียว) โดยพื้นฐานแล้ว AES คือ Rijndael ที่มีขนาดบล็อก 128 บิตและขนาดคีย์ 128, 192 และ 256 บิต ดังนั้นจึงควรใช้ AES ซึ่งเรียกว่า Rijndael 128 ใน OpenSSL


1
โดยทั่วไปการใช้ Rijndael ที่มีขนาดบล็อก 256 บิตเป็นความผิดพลาดเนื่องจากตัวเลือกของผู้พัฒนา mcrypt Rijndael เพิ่มเติมที่มีขนาดบล็อก 256 อาจมีความปลอดภัยน้อยกว่าที่มีขนาดบล็อก 128 บิตเนื่องจากรุ่นหลังมีการตรวจสอบและใช้งานมากขึ้น นอกจากนี้ความสามารถในการทำงานร่วมกันยังถูกขัดขวางในขณะที่ AES โดยทั่วไปจะพร้อมใช้งาน Rijndael ที่มีขนาดบล็อก 256 บิตไม่ได้
zaph

ทำไมคุณ$session_id = rtrim($decryptedSessionId, "\0");? เป็นไปได้ไหมที่openssl_decryptจะส่งคืนอักขระที่ไม่ต้องการในตอนท้าย? จะเกิดอะไรขึ้นถ้าตัวแปรเข้ารหัสลงท้ายด้วย 0 (เช่นencrypt("abc0")?
hlscalon

@hiscalon "\0"ไม่ใช่"0"แต่เป็นอักขระ NULL ซึ่งมีรหัส ASCII คือ 0x00 (เลขฐานสิบหก 0)
kiamlaluno

11

การใช้งาน Rijndael แบบ Pure-PHP มีอยู่พร้อมกับphpseclib ที่มีให้เป็นแพ็คเกจสำหรับนักแต่งเพลงและทำงานบน PHP 7.3 (ทดสอบโดยฉัน)

มีหน้าหนึ่งในเอกสาร phpseclib ซึ่งสร้างโค้ดตัวอย่างหลังจากที่คุณป้อนตัวแปรพื้นฐาน (การเข้ารหัสโหมดขนาดคีย์ขนาดบิต) ผลลัพธ์ต่อไปนี้สำหรับ Rijndael, ECB, 256, 256:

รหัสที่มี mycrypt

$decoded = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, ENCRYPT_KEY, $term, MCRYPT_MODE_ECB);

ทำงานเช่นนี้กับไลบรารี

$rijndael = new \phpseclib\Crypt\Rijndael(\phpseclib\Crypt\Rijndael::MODE_ECB);
$rijndael->setKey(ENCRYPT_KEY);
$rijndael->setKeyLength(256);
$rijndael->disablePadding();
$rijndael->setBlockLength(256);

$decoded = $rijndael->decrypt($term);

* $termคือbase64_decoded


11

ตามรายละเอียดของคำตอบอื่น ๆ ที่นี่ทางออกที่ดีที่สุดที่ฉันพบคือการใช้ OpenSSL มันถูกสร้างขึ้นใน PHP และคุณไม่จำเป็นต้องมีไลบรารีภายนอก ตัวอย่างง่ายๆมีดังนี้

ในการเข้ารหัส:

function encrypt($key, $payload) {
  $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
  $encrypted = openssl_encrypt($payload, 'aes-256-cbc', $key, 0, $iv);
  return base64_encode($encrypted . '::' . $iv);
}

ในการถอดรหัส:

function decrypt($key, $garble) {
    list($encrypted_data, $iv) = explode('::', base64_decode($garble), 2);
    return openssl_decrypt($encrypted_data, 'aes-256-cbc', $key, 0, $iv);
}

ลิงค์อ้างอิง: https://www.shift8web.ca/2017/04/how-to-encrypt-and-execute-your-php-code-with-mcrypt/


กรรมดีมากมายเพื่อน! มีเพียงสิ่งเดียว: หากรหัสผ่านถูกเข้ารหัสด้วยรหัสเก่ารหัสถอดรหัสใหม่จะไม่สามารถตรวจสอบได้ จะต้องมีการบันทึกใหม่และเข้ารหัสด้วยรหัสใหม่นี้
Lumis

สคริปต์การย้ายข้อมูลอย่างง่ายจะช่วยแก้ปัญหานั้นได้ ใช้วิธีเดิมในการถอดรหัสจากนั้นวิธีใหม่ในการเข้ารหัสและจัดเก็บ อีกทางเลือกหนึ่งคือการเพิ่มแฟล็กลงในตารางของผู้ใช้และการเขียนสคริปต์ในการรีเซ็ตรหัสผ่านแบบบังคับในบัญชีผู้ใช้ทั้งหมดที่ต้องเปลี่ยนรหัสผ่าน
cecil merrel aka bringrainfire

8

คุณสามารถใช้phpseclibแพคเกจ pollyfill คุณไม่สามารถใช้ open ssl หรือ libsodium สำหรับเข้ารหัส / ถอดรหัสด้วย rijndael 256 ได้อีกปัญหาคุณไม่จำเป็นต้องเปลี่ยนรหัสใด ๆ


2
นี่เป็นประโยชน์อย่างยิ่งขอบคุณ ต้องลบส่วนขยาย php-mcrypt แล้วมันก็ใช้งานได้เหมือนมีเสน่ห์
DannyB

ฉันติดตั้งmcrypt_compatโดยการรันcomposer require phpseclib/mcrypt_compatแต่ยังคงได้รับPHP Fatal error: Uncaught Error: Call to undefined function mcrypt_get_key_size() in /app/kohana/classes/Kohana/Encrypt.php:124ฉันใช้ php 7.2.26และ Kohana framwork มีขั้นตอนอื่น ๆ ที่ต้องดำเนินการหลังจากติดตั้งด้วยนักแต่งเพลงหรือไม่
M-Dahab

เข้าใจแล้ว คุณต้องเพิ่มrequire APPPATH . '/vendor/autoload.php';ที่ด้านล่างของbootstrap.php.
M-Dahab

3

คุณควรใช้ OpenSSL มากกว่าmcryptเนื่องจากมีการพัฒนาและบำรุงรักษาอย่างแข็งขัน ให้ความปลอดภัยการบำรุงรักษาและการพกพาที่ดีขึ้น ประการที่สองทำการเข้ารหัส / ถอดรหัส AES ได้เร็วขึ้นมาก โดยใช้ช่องว่างภายใน PKCS7 เป็นค่าเริ่มต้น แต่คุณสามารถระบุได้OPENSSL_ZERO_PADDINGว่าต้องการหรือไม่ หากต้องการใช้กับคีย์ไบนารี 32 ไบต์คุณสามารถระบุaes-256-cbcได้ชัดเจนกว่าMCRYPT_RIJNDAEL_128.

นี่คือตัวอย่างรหัสโดยใช้ Mcrypt:

ไลบรารีการเข้ารหัส AES-256-CBC ที่ไม่ผ่านการตรวจสอบความถูกต้องซึ่งเขียนด้วย Mcrypt พร้อมด้วย PKCS7 padding

/**
 * This library is unsafe because it does not MAC after encrypting
 */
class UnsafeMcryptAES
{
    const CIPHER = MCRYPT_RIJNDAEL_128;

    public static function encrypt($message, $key)
    {
        if (mb_strlen($key, '8bit') !== 32) {
            throw new Exception("Needs a 256-bit key!");
        }
        $ivsize = mcrypt_get_iv_size(self::CIPHER);
        $iv = mcrypt_create_iv($ivsize, MCRYPT_DEV_URANDOM);

        // Add PKCS7 Padding
        $block = mcrypt_get_block_size(self::CIPHER);
        $pad = $block - (mb_strlen($message, '8bit') % $block, '8bit');
        $message .= str_repeat(chr($pad), $pad);

        $ciphertext = mcrypt_encrypt(
            MCRYPT_RIJNDAEL_128,
            $key,
            $message,
            MCRYPT_MODE_CBC,
            $iv
        );

        return $iv . $ciphertext;
    }

    public static function decrypt($message, $key)
    {
        if (mb_strlen($key, '8bit') !== 32) {
            throw new Exception("Needs a 256-bit key!");
        }
        $ivsize = mcrypt_get_iv_size(self::CIPHER);
        $iv = mb_substr($message, 0, $ivsize, '8bit');
        $ciphertext = mb_substr($message, $ivsize, null, '8bit');

        $plaintext = mcrypt_decrypt(
            MCRYPT_RIJNDAEL_128,
            $key,
            $ciphertext,
            MCRYPT_MODE_CBC,
            $iv
        );

        $len = mb_strlen($plaintext, '8bit');
        $pad = ord($plaintext[$len - 1]);
        if ($pad <= 0 || $pad > $block) {
            // Padding error!
            return false;
        }
        return mb_substr($plaintext, 0, $len - $pad, '8bit');
    }
}

และนี่คือเวอร์ชันที่เขียนโดยใช้ OpenSSL:

/**
 * This library is unsafe because it does not MAC after encrypting
 */
class UnsafeOpensslAES
{
    const METHOD = 'aes-256-cbc';

    public static function encrypt($message, $key)
    {
        if (mb_strlen($key, '8bit') !== 32) {
            throw new Exception("Needs a 256-bit key!");
        }
        $ivsize = openssl_cipher_iv_length(self::METHOD);
        $iv = openssl_random_pseudo_bytes($ivsize);

        $ciphertext = openssl_encrypt(
            $message,
            self::METHOD,
            $key,
            OPENSSL_RAW_DATA,
            $iv
        );

        return $iv . $ciphertext;
    }

    public static function decrypt($message, $key)
    {
        if (mb_strlen($key, '8bit') !== 32) {
            throw new Exception("Needs a 256-bit key!");
        }
        $ivsize = openssl_cipher_iv_length(self::METHOD);
        $iv = mb_substr($message, 0, $ivsize, '8bit');
        $ciphertext = mb_substr($message, $ivsize, null, '8bit');

        return openssl_decrypt(
            $ciphertext,
            self::METHOD,
            $key,
            OPENSSL_RAW_DATA,
            $iv
        );
    }
}

ที่มา: หากคุณกำลังพิมพ์ดีด Mcrypt Word Into PHP รหัสของคุณคุณกำลังทำมันผิด


2

ฉันใช้สิ่งนี้กับ PHP 7.2.x มันใช้งานได้ดีสำหรับฉัน:

public function make_hash($userStr){
        try{
            /** 
             * Used and tested on PHP 7.2x, Salt has been removed manually, it is now added by PHP 
             */
             return password_hash($userStr, PASSWORD_BCRYPT);
            }catch(Exception $exc){
                $this->tempVar = $exc->getMessage();
                return false;
            }
        }

จากนั้นพิสูจน์ตัวตนแฮชด้วยฟังก์ชันต่อไปนี้:

public function varify_user($userStr,$hash){
        try{
            if (password_verify($userStr, $hash)) {
                 return true;
                }
            else {
                return false;
                }
            }catch(Exception $exc){
                $this->tempVar = $exc->getMessage();
                return false;
            }
        }

ตัวอย่าง:

  //create hash from user string

 $user_password = $obj->make_hash2($user_key);

และในการพิสูจน์ตัวตนแฮชนี้ให้ใช้รหัสต่อไปนี้:

if($obj->varify_user($key, $user_key)){
      //this is correct, you can proceed with  
    }

นั่นคือทั้งหมด


1

ตามที่ระบุไว้คุณไม่ควรจัดเก็บรหัสผ่านของผู้ใช้ในรูปแบบที่สามารถถอดรหัสได้ การเข้ารหัสแบบย้อนกลับเป็นเส้นทางที่ง่ายสำหรับแฮกเกอร์ในการค้นหารหัสผ่านของผู้ใช้ของคุณซึ่งครอบคลุมไปถึงการวางบัญชีผู้ใช้ของคุณในไซต์อื่น ๆ หากพวกเขาใช้รหัสผ่านเดียวกันที่นั่น

PHP มีฟังก์ชั่นที่ทรงพลังสำหรับการเข้ารหัสแฮชทางเดียวแบบสุ่ม - เค็มpassword_hash()และpassword_verify(). เนื่องจากแฮชเป็นแบบสุ่มโดยอัตโนมัติจึงไม่มีวิธีใดที่แฮกเกอร์จะใช้ตารางแฮชรหัสผ่านที่รวบรวมไว้ล่วงหน้าเพื่อทำวิศวกรรมย้อนกลับรหัสผ่าน ตั้งค่าPASSWORD_DEFAULTตัวเลือกและ PHP เวอร์ชันในอนาคตจะใช้อัลกอริทึมที่แข็งแกร่งขึ้นโดยอัตโนมัติเพื่อสร้างแฮชรหัสผ่านโดยที่คุณไม่ต้องอัปเดตโค้ด



0

ฉันสามารถแปลวัตถุ Crypto ของฉันได้

  • รับสำเนา php พร้อม mcrypt เพื่อถอดรหัสข้อมูลเก่า ฉันไปที่http://php.net/get/php-7.1.12.tar.gz/from/a/mirrorรวบรวมแล้วเพิ่มส่วนขยาย ext / mcrypt (กำหนดค่าสร้าง; ทำการติดตั้ง) ฉันคิดว่าฉันต้องเพิ่มบรรทัด extenstion = mcrypt.so ใน php.ini ด้วย ชุดของสคริปต์สำหรับสร้างข้อมูลเวอร์ชันกลางโดยที่ข้อมูลทั้งหมดไม่ได้เข้ารหัส

  • สร้างคีย์สาธารณะและส่วนตัวสำหรับ openssl

    openssl genrsa -des3 -out pkey.pem 2048
    (set a password)
    openssl rsa -in pkey.pem -out pkey-pub.pem -outform PEM -pubout
  • ในการเข้ารหัส (โดยใช้คีย์สาธารณะ) ให้ใช้ openssl_seal จากสิ่งที่ฉันได้อ่านแล้ว openssl_encrypt โดยใช้คีย์ RSA จำกัด ไว้ที่ 11 ไบต์น้อยกว่าความยาวของคีย์ (ดูhttp://php.net/manual/en/function.openssl-public-encrypt.phpความคิดเห็นโดย Thomas Horsten)

    $pubKey = openssl_get_publickey(file_get_contents('./pkey-pub.pem'));
    openssl_seal($pwd, $sealed, $ekeys, [ $pubKey ]);
    $encryptedPassword = base64_encode($sealed);
    $key = base64_encode($ekeys[0]);

คุณอาจจัดเก็บไบนารีดิบ

  • การถอดรหัส (โดยใช้คีย์ส่วนตัว)

    $passphrase="passphrase here";
    $privKey = openssl_get_privatekey(file_get_contents('./pkey.pem'), $passphrase);
    // I base64_decode() from my db columns
    openssl_open($encryptedPassword, $plain, $key, $privKey);
    echo "<h3>Password=$plain</h3>";

ป.ล. คุณไม่สามารถเข้ารหัสสตริงว่าง ("")

PPS นี่สำหรับฐานข้อมูลรหัสผ่านที่ไม่ใช้สำหรับการตรวจสอบผู้ใช้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.