복붙노트

PHP에서 데이터를 암호화 / 해독하는 방법?

PHP

PHP에서 데이터를 암호화 / 해독하는 방법?

저는 현재 학생이고 PHP를 공부하고 있습니다. PHP에서 간단한 암호화 / 해독을하려고합니다. 나는 온라인 조사를했고 그 중 일부는 (적어도 나를 위해) 혼란 스러웠습니다.

여기에 내가하려고하는 것이있다.

나는이 필드 (UserID, Fname, Lname, Email, Password)로 구성된 표를 가지고있다.

내가 원하는 것은 모든 필드를 암호화 한 다음 해독해야합니다 (암호화 알고리즘이 아니라면 sha256을 암호화 / 해독에 사용할 수 있습니까?).

내가 배우고 싶은 또 다른 일은 좋은 "소금"과 결합 된 편도 해시 (sha256)를 만드는 방법입니다. (기본적으로 나는 단지 암호화 / 해독, 해시 (sha256) + 소금의 간단한 구현을 원한다) 선생님 / 부인, 당신의 대답은 큰 도움이 될 것이며 대단히 감사하게 될 것입니다. 고마워 ++

해결법

  1. ==============================

    1.테이블 정의로 시작하기 :

    테이블 정의로 시작하기 :

    - UserID
    - Fname
    - Lname
    - Email
    - Password
    - IV
    

    변경 사항은 다음과 같습니다.

    암호화 및 모드

    최상의 암호화 암호와 모드를 선택하는 것은이 답변의 범위를 벗어나지 만 최종 선택은 암호화 키와 초기화 벡터의 크기에 영향을줍니다. 이 게시물을 위해 우리는 AES-256-CBC를 사용할 것입니다.이 블록은 고정 블록 크기가 16 바이트이고 키 크기가 16, 24 또는 32 바이트입니다.

    암호화 키

    좋은 암호화 키는 신뢰할 수있는 난수 생성기에서 생성 된 이진 BLOB입니다. 다음 예가 권장됩니다 (> = 5.3).

    $key_size = 32; // 256 bits
    $encryption_key = openssl_random_pseudo_bytes($key_size, $strong);
    // $strong will be true if the key is crypto safe
    

    이 작업은 한 번 또는 여러 번 수행 할 수 있습니다 (암호화 키 체인을 만들려는 경우). 가능한 한 비공개로 유지하십시오.

    IV

    초기화 벡터는 암호화에 임의성을 추가하고 CBC 모드에 필요합니다. 이 값은 이상적으로는 기술적으로 한 번만 (기술적으로 암호화 키당 한 번) 사용해야하므로 행의 일부를 업데이트하면 다시 생성해야합니다.

    IV를 생성하는 데 도움이되는 함수가 제공됩니다.

    $iv_size = 16; // 128 bits
    $iv = openssl_random_pseudo_bytes($iv_size, $strong);
    

    이전의 $ encryption_key와 $ iv를 사용하여 이름 필드를 암호화하자. 이렇게하려면 블록 크기에 데이터를 채워 넣어야합니다.

    function pkcs7_pad($data, $size)
    {
        $length = $size - strlen($data) % $size;
        return $data . str_repeat(chr($length), $length);
    }
    
    $name = 'Jack';
    $enc_name = openssl_encrypt(
        pkcs7_pad($name, 16), // padded data
        'AES-256-CBC',        // cipher and mode
        $encryption_key,      // secret key
        0,                    // options (not used)
        $iv                   // initialisation vector
    );
    

    IV와 같이 암호화 된 출력은 2 진입니다. 이러한 값을 데이터베이스에 저장하는 작업은 BINARY 또는 VARBINARY와 같은 지정된 열 유형을 사용하여 수행 할 수 있습니다.

    IV와 같은 출력 값은 2 진수입니다. 이 값들을 MySQL에 저장하려면 BINARY 또는 VARBINARY 컬럼을 사용하는 것을 고려해야한다. 이것이 옵션이 아니면 base64_encode () 또는 bin2hex ()를 사용하여 바이너리 데이터를 텍스트 표현으로 변환 할 수 있으므로 33 %에서 100 % 더 많은 저장 공간이 필요합니다.

    저장된 값의 암호 해독은 비슷합니다.

    function pkcs7_unpad($data)
    {
        return substr($data, 0, -ord($data[strlen($data) - 1]));
    }
    
    $row = $result->fetch(PDO::FETCH_ASSOC); // read from database result
    // $enc_name = base64_decode($row['Name']);
    // $enc_name = hex2bin($row['Name']);
    $enc_name = $row['Name'];
    // $iv = base64_decode($row['IV']);
    // $iv = hex2bin($row['IV']);
    $iv = $row['IV'];
    
    $name = pkcs7_unpad(openssl_decrypt(
        $enc_name,
        'AES-256-CBC',
        $encryption_key,
        0,
        $iv
    ));
    

    생성 된 암호 텍스트의 무결성을 향상 시키려면 암호 키 (암호화 키와 다른)와 암호 텍스트에서 생성 된 서명을 추가하십시오. 암호문이 해독되기 전에 먼저 서명이 확인됩니다 (일정 시간 비교 방법이 바람직 함).

    // generate once, keep safe
    $auth_key = openssl_random_pseudo_bytes(32, $strong);
    
    // authentication
    $auth = hash_hmac('sha256', $enc_name, $auth_key, true);
    $auth_enc_name = $auth . $enc_name;
    
    // verification
    $auth = substr($auth_enc_name, 0, 32);
    $enc_name = substr($auth_enc_name, 32);
    $actual_auth = hash_hmac('sha256', $enc_name, $auth_key, true);
    
    if (hash_equals($auth, $actual_auth)) {
        // perform decryption
    }
    

    참고 사항 : hash_equals ()

    가역 암호를 데이터베이스에 저장하는 것은 가능한 한 피해야합니다. 그 내용을 알기보다는 암호 만 확인하기를 원할 것입니다. 사용자가 비밀번호를 잊어 버린 경우 원래 비밀번호를 보내지 않고 재설정하도록 허용하는 것이 좋습니다 (비밀번호 재설정은 제한된 기간 동안 만 수행 할 수 있음).

    해시 함수를 적용하는 것은 단방향 연산입니다. 이후에는 원래의 데이터를 공개하지 않고도 검증에 안전하게 사용할 수 있습니다. brute force 방법은 상대적으로 길이가 짧고 많은 사람들이 패스워드를 선택하기 힘들 기 때문에 폭로하는 방법입니다.

    MD5 또는 SHA1과 같은 해시 알고리즘은 파일 내용을 알려진 해시 값과 비교하여 확인했습니다. 이 검증은 정확하면서도 가능한 한 빨리 검증 할 수 있도록 최적화되어 있습니다. 상대적으로 제한된 출력 공간을 감안할 때 알려진 암호와 각각의 해시 출력 인 레인보우 테이블을 사용하여 데이터베이스를 쉽게 구축 할 수있었습니다.

    해시하기 전에 암호에 소금을 추가하면 무지개 표가 쓸모 없게되지만 최근의 하드웨어 향상으로 인해 무차별 조회가 실행 가능한 접근 방식이되었습니다. 그래서 의도적으로 느리고 최적화하기 만해도 불가능한 해시 알고리즘이 필요한 것입니다. 또한 기존 암호 해시를 검증하는 기능에 영향을 미치지 않고 더 빠른 하드웨어의로드를 늘려 미래의 증거가 될 수 있어야합니다.

    현재 두 가지 인기있는 선택 방법이 있습니다.

    이 대답은 bcrypt의 예제를 사용합니다.

    세대

    비밀번호 해시는 다음과 같이 생성 할 수 있습니다.

    $password = 'my password';
    $random = openssl_random_pseudo_bytes(18);
    $salt = sprintf('$2y$%02d$%s',
        13, // 2^n cost factor
        substr(strtr(base64_encode($random), '+', '.'), 0, 22)
    );
    
    $hash = crypt($password, $salt);
    

    salt는 openssl_random_pseudo_bytes ()로 생성되어 데이터의 임의의 blob을 형성하고 base64_encode () 및 strtr ()을 통해 실행되어 [A-Za-z0-9 /.]의 필수 알파벳과 일치시킵니다.

    crypt () 함수는 알고리즘 (Blowfish의 경우 $ 2y $), 비용 요소 (3GHz 시스템에서 13의 인수는 약 0.40s)와 22 자의 소금을 기반으로 해싱을 수행합니다.

    확인

    사용자 정보를 포함하는 행을 가져온 후에는 다음과 같은 방법으로 암호를 확인합니다.

    $given_password = $_POST['password']; // the submitted password
    $db_hash = $row['Password']; // field with the password hash
    
    $given_hash = crypt($given_password, $db_hash);
    
    if (isEqual($given_hash, $db_hash)) {
        // user password verified
    }
    
    // constant time string compare
    function isEqual($str1, $str2)
    {
        $n1 = strlen($str1);
        if (strlen($str2) != $n1) {
            return false;
        }
        for ($i = 0, $diff = 0; $i != $n1; ++$i) {
            $diff |= ord($str1[$i]) ^ ord($str2[$i]);
        }
        return !$diff;
    }
    

    암호를 확인하려면 crypt ()를 다시 호출하지만 이전에 계산 된 해시를 소금 값으로 전달합니다. 주어진 암호가 해시와 일치하면 반환 값은 동일한 해시를 산출합니다. 해시를 확인하려면 타이밍 공격을 피하기 위해 상수 시간 비교 함수를 사용하는 것이 좋습니다.

    PHP 5.5로 암호 해싱

    PHP 5.5에서는 위의 해시 방법을 단순화하는 데 사용할 수있는 암호 해시 함수를 소개했습니다.

    $hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 13]);
    

    확인 :

    if (password_verify($given_password, $db_hash)) {
        // password valid
    }
    

    참고 : password_hash (), password_verify ()

  2. ==============================

    2.나는 이것이 전에 답변을했다고 생각합니다 ...하지만 어쨌든, 당신이 데이터를 암호화 / 해독하려는 경우 SHA256을 사용할 수 없습니다

    나는 이것이 전에 답변을했다고 생각합니다 ...하지만 어쨌든, 당신이 데이터를 암호화 / 해독하려는 경우 SHA256을 사용할 수 없습니다

    //Key
    $key = 'SuperSecretKey';
    
    //To Encrypt:
    $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, 'I want to encrypt this', MCRYPT_MODE_ECB);
    
    //To Decrypt:
    $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_ECB);
    
  3. ==============================

    3.이 질문을 이해하려면 먼저 SHA256이 무엇인지 이해해야합니다. SHA256은 암호화 해시 기능입니다. 암호 해시 함수는 단방향 함수이며 그 출력은 암호로 안전합니다. 즉, 해시 (데이터 암호화와 동일)를 계산하기는 쉽지만 해시를 사용하여 원래 입력을 얻는 것은 어렵습니다 (데이터 해독과 동일). 암호화 해시 함수를 사용하면 해독이 계산 상 수행 불가능하므로 SHA256을 사용하여 해독을 수행 할 수 없습니다.

    이 질문을 이해하려면 먼저 SHA256이 무엇인지 이해해야합니다. SHA256은 암호화 해시 기능입니다. 암호 해시 함수는 단방향 함수이며 그 출력은 암호로 안전합니다. 즉, 해시 (데이터 암호화와 동일)를 계산하기는 쉽지만 해시를 사용하여 원래 입력을 얻는 것은 어렵습니다 (데이터 해독과 동일). 암호화 해시 함수를 사용하면 해독이 계산 상 수행 불가능하므로 SHA256을 사용하여 해독을 수행 할 수 없습니다.

    사용하려는 것은 양방향 기능이지만 더 구체적으로 블록 암호입니다. 데이터의 암호화와 암호 해독을 모두 허용하는 함수. 함수 mcrypt_encrypt와 mcrypt_decrypt는 기본적으로 Blowfish 알고리즘을 사용합니다. PHP의 mcrypt 사용은이 매뉴얼에서 찾을 수 있습니다. 암호 mcrypt 사용을 선택하는 암호 정의 목록도 있습니다. Blowfish의 위키는 Wikipedia에서 찾을 수 있습니다. 블록 암호는 알려진 키와 함께 알려진 크기와 위치의 블록으로 입력을 암호화하므로 나중에 데이터를 키를 사용하여 암호 해독 할 수 있습니다. 이것은 SHA256에서 제공 할 수없는 것입니다.

    $key = 'ThisIsTheCipherKey';
    
    $ciphertext = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, 'This is plaintext.', MCRYPT_MODE_CFB);
    
    $plaintext = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $encrypted, MCRYPT_MODE_CFB);
    
  4. ==============================

    4.다음은 openssl_encrypt를 사용하는 예제입니다.

    다음은 openssl_encrypt를 사용하는 예제입니다.

    //Encryption:
    $textToEncrypt = "My Text to Encrypt";
    $encryptionMethod = "AES-256-CBC";
    $secretHash = "encryptionhash";
    $iv = mcrypt_create_iv(16, MCRYPT_RAND);
    $encryptedText = openssl_encrypt($textToEncrypt,$encryptionMethod,$secretHash, 0, $iv);
    
    //Decryption:
    $decryptedText = openssl_decrypt($encryptedText, $encryptionMethod, $secretHash, 0, $iv);
    print "My Decrypted Text: ". $decryptedText;
    
  5. ==============================

    5.OpenSSL_decrypt ()를 사용할 때 false를 얻지 않고 어떻게 암호화하고 해독하는지 알아내는 데는 꽤 시간이 걸렸습니다.

    OpenSSL_decrypt ()를 사용할 때 false를 얻지 않고 어떻게 암호화하고 해독하는지 알아내는 데는 꽤 시간이 걸렸습니다.

        // cryptographic key of a binary string 16 bytes long (because AES-128 has a key size of 16 bytes)
        $encryption_key = '58adf8c78efef9570c447295008e2e6e'; // example
        $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
        $encrypted = openssl_encrypt($plaintext, 'aes-256-cbc', $encryption_key, OPENSSL_RAW_DATA, $iv);
        $encrypted = $encrypted . ':' . base64_encode($iv);
    
        // decrypt to get again $plaintext
        $parts = explode(':', $encrypted);
        $decrypted = openssl_decrypt($parts[0], 'aes-256-cbc', $encryption_key, OPENSSL_RAW_DATA, base64_decode($parts[1])); 
    

    암호화 된 문자열을 URL을 통해 전달하려면 다음 문자열을 urlencode해야합니다.

        $encrypted = urlencode($encrypted);
    

    무슨 일이 벌어지고 있는지 더 잘 이해하려면 다음을 읽어보십시오.

    16 바이트 길이의 키를 생성하려면 다음을 사용할 수 있습니다.

        $bytes = openssl_random_pseudo_bytes(16);
        $hex = bin2hex($bytes);
    

    openssl의 오류 메시지를 보려면 다음을 사용할 수 있습니다. echo openssl_error_string ();

    희망이 도움이됩니다.

  6. ==============================

    6.

         function my_simple_crypt( $string, $action = 'e' ) {
            // you may change these values to your own
            $secret_key = 'my_simple_secret_key';
            $secret_iv = 'my_simple_secret_iv';
    
            $output = false;
            $encrypt_method = "AES-256-CBC";
            $key = hash( 'sha256', $secret_key );
            $iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );
    
            if( $action == 'e' ) {
                $output = base64_encode( openssl_encrypt( $string, $encrypt_method, $key, 0, $iv ) );
            }
            else if( $action == 'd' ){
                $output = openssl_decrypt( base64_decode( $string ), $encrypt_method, $key, 0, $iv );
            }
    
            return $output;
        }
    
  7. from https://stackoverflow.com/questions/10916284/how-to-encrypt-decrypt-data-in-php by cc-by-sa and MIT license