programing

PHP를 사용한 가장 간단한 양방향 암호화

randomtip 2023. 1. 15. 12:54
반응형

PHP를 사용한 가장 간단한 양방향 암호화

일반적인 PHP 설치에서 양방향 암호화를 수행하는 가장 간단한 방법은 무엇입니까?

스트링 키로 데이터를 암호화하고 같은 키를 사용하여 상대편에서 암호를 해독할 수 있어야 합니다.

보안은 코드 휴대성만큼 중요하지 않기 때문에 가능한 한 심플하게 하고 싶습니다.현재 RC4 실장을 사용하고 있습니다만, 네이티브로 서포트되고 있는 것을 찾을 수 있으면, 불필요한 코드를 많이 절약할 수 있을 것 같습니다.

중요:특별한 사용 사례가 없는 한 암호를 암호화하지 말고 암호 해시 알고리즘을 사용하십시오.서버측 어플리케이션에서 비밀번호를 암호화한다고 하는 것은 정보가 없거나 위험한 시스템 설계를 기술하고 있는 것입니다.패스워드를 안전하게 보존하는 것은 암호화와는 전혀 별개의 문제입니다.

통지를 받다.안전한 시스템을 설계합니다.

PHP에서의 휴대용 데이터 암호화

만약 당신이 PHP 5.4 이후를 사용하고 있고 스스로 암호화 모듈을 쓰고 싶지 않다면 인증된 암호화를 제공하는 기존 라이브러리를 사용하는 것을 추천합니다.내가 링크한 라이브러리는 PHP가 제공하는 것에만 의존하며 소수의 보안 연구자들에 의해 정기적으로 검토되고 있다(나 자신도 포함).

PECL 확장기능을 필요로 하는 것을 막는 것이 아니라면, PHP로 쓸 수 있는 것보다 libsodium을 적극 추천합니다.

갱신(2016-06-12) :이제 sodium_compat을 사용하여 PECL 확장을 설치하지 않고도 동일한 암호 libsodium을 사용할 수 있습니다.

암호 공학에 도전하고 싶다면, 계속 읽어보세요.


우선, 인증되지 않은 암호화의 위험성암호 해독의 원리를 알아보는 시간을 가져야 합니다.

  • 암호화된 데이터는 여전히 악의적인 사용자에 의해 조작될 수 있습니다.
  • 암호화된 데이터를 인증하면 조작을 방지할 수 있습니다.
  • 암호화되지 않은 데이터를 인증해도 조작을 방지할 수 없습니다.

암호화 및 복호화

PHP에서의 암호화는 실제로 간단합니다(사용할 예정이며, 정보를 암호화하는 방법에 대해 몇 가지 결정을 내리면,컨설팅openssl_get_cipher_methods()사용하시는 시스템에서 지원되는 메서드 목록을 참조해 주세요.최적의 선택은 CTR 모드의 AES입니다.

  • aes-128-ctr
  • aes-192-ctr
  • aes-256-ctr

현재 AES 키 사이즈가 큰 문제라고 생각할 이유는 없습니다(256비트모드에서의 키 스케줄링이 나쁘기 때문에 큰 것이 좋다고는 할 수 없습니다).

주의: 이 제품 포기 소프트웨어이며 보안에 영향을 수 있는 패치되지 않은 버그가 있기 때문에 사용하지 않습니다.이러한 이유로 다른 PHP 개발자도 피하도록 권장하고 있습니다.

Open을 사용한 간단한 암호화/복호화 래퍼SSL

class UnsafeCrypto
{
    const METHOD = 'aes-256-ctr';
    
    /**
     * Encrypts (but does not authenticate) a message
     * 
     * @param string $message - plaintext message
     * @param string $key - encryption key (raw binary expected)
     * @param boolean $encode - set to TRUE to return a base64-encoded 
     * @return string (raw binary)
     */
    public static function encrypt($message, $key, $encode = false)
    {
        $nonceSize = openssl_cipher_iv_length(self::METHOD);
        $nonce = openssl_random_pseudo_bytes($nonceSize);
        
        $ciphertext = openssl_encrypt(
            $message,
            self::METHOD,
            $key,
            OPENSSL_RAW_DATA,
            $nonce
        );
        
        // Now let's pack the IV and the ciphertext together
        // Naively, we can just concatenate
        if ($encode) {
            return base64_encode($nonce.$ciphertext);
        }
        return $nonce.$ciphertext;
    }
    
    /**
     * Decrypts (but does not verify) a message
     * 
     * @param string $message - ciphertext message
     * @param string $key - encryption key (raw binary expected)
     * @param boolean $encoded - are we expecting an encoded string?
     * @return string
     */
    public static function decrypt($message, $key, $encoded = false)
    {
        if ($encoded) {
            $message = base64_decode($message, true);
            if ($message === false) {
                throw new Exception('Encryption failure');
            }
        }

        $nonceSize = openssl_cipher_iv_length(self::METHOD);
        $nonce = mb_substr($message, 0, $nonceSize, '8bit');
        $ciphertext = mb_substr($message, $nonceSize, null, '8bit');
        
        $plaintext = openssl_decrypt(
            $ciphertext,
            self::METHOD,
            $key,
            OPENSSL_RAW_DATA,
            $nonce
        );
        
        return $plaintext;
    }
}

사용 예

$message = 'Ready your ammunition; we attack at dawn.';
$key = hex2bin('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f');

$encrypted = UnsafeCrypto::encrypt($message, $key);
$decrypted = UnsafeCrypto::decrypt($encrypted, $key);

var_dump($encrypted, $decrypted);

데모: https://3v4l.org/jl7qR


위의 간단한 암호화 라이브러리는 여전히 사용하기에 안전하지 않습니다.암호를 해독하기 전에 암호문을 인증하고 확인해야 합니다.

주의: 디폴트로는UnsafeCrypto::encrypt()원시 이진 문자열을 반환합니다.바이너리 세이프 형식(base64 인코딩)으로 보존할 필요가 있는 경우는, 다음과 같이 호출합니다.

$message = 'Ready your ammunition; we attack at dawn.';
$key = hex2bin('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f');

$encrypted = UnsafeCrypto::encrypt($message, $key, true);
$decrypted = UnsafeCrypto::decrypt($encrypted, $key, true);

var_dump($encrypted, $decrypted);

데모: http://3v4l.org/f5K93

간단한 인증 래퍼

class SaferCrypto extends UnsafeCrypto
{
    const HASH_ALGO = 'sha256';
    
    /**
     * Encrypts then MACs a message
     * 
     * @param string $message - plaintext message
     * @param string $key - encryption key (raw binary expected)
     * @param boolean $encode - set to TRUE to return a base64-encoded string
     * @return string (raw binary)
     */
    public static function encrypt($message, $key, $encode = false)
    {
        list($encKey, $authKey) = self::splitKeys($key);
        
        // Pass to UnsafeCrypto::encrypt
        $ciphertext = parent::encrypt($message, $encKey);
        
        // Calculate a MAC of the IV and ciphertext
        $mac = hash_hmac(self::HASH_ALGO, $ciphertext, $authKey, true);
        
        if ($encode) {
            return base64_encode($mac.$ciphertext);
        }
        // Prepend MAC to the ciphertext and return to caller
        return $mac.$ciphertext;
    }
    
    /**
     * Decrypts a message (after verifying integrity)
     * 
     * @param string $message - ciphertext message
     * @param string $key - encryption key (raw binary expected)
     * @param boolean $encoded - are we expecting an encoded string?
     * @return string (raw binary)
     */
    public static function decrypt($message, $key, $encoded = false)
    {
        list($encKey, $authKey) = self::splitKeys($key);
        if ($encoded) {
            $message = base64_decode($message, true);
            if ($message === false) {
                throw new Exception('Encryption failure');
            }
        }
        
        // Hash Size -- in case HASH_ALGO is changed
        $hs = mb_strlen(hash(self::HASH_ALGO, '', true), '8bit');
        $mac = mb_substr($message, 0, $hs, '8bit');
        
        $ciphertext = mb_substr($message, $hs, null, '8bit');
        
        $calculated = hash_hmac(
            self::HASH_ALGO,
            $ciphertext,
            $authKey,
            true
        );
        
        if (!self::hashEquals($mac, $calculated)) {
            throw new Exception('Encryption failure');
        }
        
        // Pass to UnsafeCrypto::decrypt
        $plaintext = parent::decrypt($ciphertext, $encKey);
        
        return $plaintext;
    }
    
    /**
     * Splits a key into two separate keys; one for encryption
     * and the other for authenticaiton
     * 
     * @param string $masterKey (raw binary)
     * @return array (two raw binary strings)
     */
    protected static function splitKeys($masterKey)
    {
        // You really want to implement HKDF here instead!
        return [
            hash_hmac(self::HASH_ALGO, 'ENCRYPTION', $masterKey, true),
            hash_hmac(self::HASH_ALGO, 'AUTHENTICATION', $masterKey, true)
        ];
    }
    
    /**
     * Compare two strings without leaking timing information
     * 
     * @param string $a
     * @param string $b
     * @ref https://paragonie.com/b/WS1DLx6BnpsdaVQW
     * @return boolean
     */
    protected static function hashEquals($a, $b)
    {
        if (function_exists('hash_equals')) {
            return hash_equals($a, $b);
        }
        $nonce = openssl_random_pseudo_bytes(32);
        return hash_hmac(self::HASH_ALGO, $a, $nonce) === hash_hmac(self::HASH_ALGO, $b, $nonce);
    }
}

사용 예

$message = 'Ready your ammunition; we attack at dawn.';
$key = hex2bin('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f');

$encrypted = SaferCrypto::encrypt($message, $key);
$decrypted = SaferCrypto::decrypt($encrypted, $key);

var_dump($encrypted, $decrypted);

데모: 원시 바이너리, base64 인코딩


사람이 경우SaferCrypto실제 가동 환경의 라이브러리 또는 동일한 개념의 구현에 앞서 상주 암호학자에게 두 번째 의견을 구할 것을 강력히 권장합니다.내가 알아차리지도 못하는 실수를 알려줄 거야

평판이 좋은 암호화 라이브러리를 사용하는 것이 훨씬 더 나을 것입니다.

편집 완료:

openssl_encrypt()openssl_decrypt()를 사용해야 합니다.

Scott가 말했듯이, Mcrypt는 2007년 이후로 업데이트가 되지 않았기 때문에 좋은 생각이 아닙니다.

PHP에서 Mcrypt를 삭제하는 RFC도 있습니다.https://wiki.php.net/rfc/mcrypt-viking-funeral

및 를 해당 파라미터와 함께 사용합니다.매우 쉽고 간단한 암호화 패키지를 사용할 수 있습니다.

편집

이 있은 지 후 4개월입니다.mcrypt확장 기능은 현재 폐지되어 최종적으로 PHP에서 삭제되고 있습니다.

openssl_encrypt()를 사용한 암호화 openssl_encrypt 함수는 데이터를 안전하고 쉽게 암호화하는 방법을 제공합니다.

다음 스크립트에서는 AES128 암호화 방식을 사용하지만 암호화 대상에 따라 다른 종류의 암호화 방식을 고려할 수 있습니다.

<?php
$message_to_encrypt = "Yoroshikune";
$secret_key = "my-secret-key";
$method = "aes128";
$iv_length = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($iv_length);

$encrypted_message = openssl_encrypt($message_to_encrypt, $method, $secret_key, 0, $iv);

echo $encrypted_message;
?>

다음은 사용되는 변수에 대한 설명입니다.

message_to_password :암호화할 secret_key 데이터:암호화의 '패스워드'입니다.너무 쉬운 것을 선택하지 않도록 하고, 비밀키를 다른 사람과 공유하지 않도록 주의해 주세요.암호화 방법입니다.여기서는 AES128을 선택했습니다.iv_length and iv : bytes encrypted_message : 암호화된 메시지를 포함하는 변수

openssl_decrypt()를 사용한 복호화 데이터를 암호화하면 처음에 변수에 포함시킨 메시지를 재사용하기 위해 복호화가 필요할 수 있습니다.그러기 위해서는 openssl_decrypt() 함수를 사용합니다.

<?php
$message_to_encrypt = "Yoroshikune";
$secret_key = "my-secret-key";
$method = "aes128";
$iv_length = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($iv_length);
$encrypted_message = openssl_encrypt($message_to_encrypt, $method, $secret_key, 0, $iv);

$decrypted_message = openssl_decrypt($encrypted_message, $method, $secret_key, 0, $iv);

echo $decrypted_message;
?>

openssl_decrypt()에 의해 제안된 복호화 메서드는 openssl_encrypt()에 가깝습니다.

유일한 차이점은 $message_to_encrypt()를 추가하는 대신 이미 암호화된 메시지를 openssl_decrypt()의 첫 번째 인수로 추가해야 한다는 것입니다.

주의: 암호를 해독하려면 개인 키와 iv를 저장해야 합니다.

PHP 7.2는 완전히 다른 으로 이동했습니다.Mcrypt현재 암호화는 유지보수가능력에 기반하고 있습니다.Libsodium도서관.

모든 암호화 요구는 기본적으로 다음과 같이 해결할 수 있습니다.Libsodium도서관.

// On Alice's computer:
$msg = 'This comes from Alice.';
$signed_msg = sodium_crypto_sign($msg, $secret_sign_key);


// On Bob's computer:
$original_msg = sodium_crypto_sign_open($signed_msg, $alice_sign_publickey);
if ($original_msg === false) {
    throw new Exception('Invalid signature');
} else {
    echo $original_msg; // Displays "This comes from Alice."
}

Libsodium 문서: https://github.com/paragonie/pecl-libsodium-doc

중요: 이 답변은 PHP 5에만 유효하며, PHP 7에서는 내장된 암호화 기능을 사용합니다.

여기에서는, 심플하지만, 충분히 안전한 실장은 다음과 같습니다.

  • CBC 모드에서의 AES-256 암호화
  • PBKDF2: 일반 텍스트 암호를 사용하여 암호화 키 생성
  • 암호화된 메시지를 인증하기 위한 HMAC.

코드와 예는, https://stackoverflow.com/a/19445173/1387163 를 참조해 주세요.

언급URL : https://stackoverflow.com/questions/9262109/simplest-two-way-encryption-using-php

반응형