PHP 문자열을 어떻게 암호화하고 해독합니까?


225

내가 말하고 싶은 건:

Original String + Salt or Key --> Encrypted String
Encrypted String + Salt or Key --> Decrypted (Original String)

어쩌면 다음과 같은 것 :

"hello world!" + "ABCD1234" --> Encrypt --> "2a2ffa8f13220befbe30819047e23b2c" (may be, for e.g)
"2a2ffa8f13220befbe30819047e23b2c" --> Decrypt with "ABCD1234" --> "hello world!"
  • PHP에서 어떻게 할 수 있습니까?

을 사용하려고 시도 Crypt_Blowfish했지만 작동하지 않았습니다.


35
@Rogue 그는 해시를 원하지 않고 AES와 같은 대칭 암호화를 원하지만 그게 무엇인지 모릅니다. (지금 그는 :))
Patashu

얼마나 안전해야합니까?

3
@ 夏 期 劇場, 대칭 암호화를 '소금'하지 않고 키를 사용합니다. 키는 비밀로 유지해야합니다. 소금은 보안에 해를 끼치 지 않고 공개 될 수 있으며 (모든 사람의 소금이 다른 한) 암호 해싱에 사용되는 용어입니다.
Patashu

2
AES-256과 같은 암호화 알고리즘 인 Salt (개인 키), 공개 키가 필요합니다. wpy.me/blog/15-encrypt-and-decrypt-data-in-php-using-aes-256
wappy

8
@CristianFlorea이 블로그 게시물의 작성자는 대칭 암호화와 관련하여 약간의 의미가없는 용어를 사용합니다. AES에는 공개 키가 없으며 소금도 없습니다. 하나의 키가 있습니다. 비밀로 유지해야합니다. 일부 작동 모드에는 비밀이 필요하지 않은 IV가 있지만 IV는 소금이 아니며 (모드에 따라 요구 사항이 다를 수 있음) 비밀 일 필요는 없지만 실제 암호화 키는 절대 공개 할 수 없습니다. 공개 / 개인 키는 비대칭 암호화에 적용되지만 AES와는 아무런 관련이 없습니다.
cpast

답변:


410

추가 작업을 수행하기 전에 암호화인증 의 차이점 과 단순히 암호화가 아닌 인증 된 암호화를 원하는 이유 를 이해 하십시오 .

인증 된 암호화를 구현하려면 암호화 한 다음 MAC을 사용하려고합니다. 암호화 및 인증 순서는 매우 중요합니다! 이 질문에 대한 기존의 답변 중 하나가이 실수를 범했습니다. PHP로 작성된 많은 암호화 라이브러리와 마찬가지로.

당신은해야 자신의 암호화를 구현하지 않도록 하고, 대신 보안 라이브러리에 의해 작성하고 암호 전문가 검토를 사용합니다.

업데이트 : PHP 7.2는 이제 libsodium을 제공합니다 ! 최상의 보안을 위해 PHP 7.2 이상을 사용하도록 시스템을 업데이트하고이 답변의 libsodium 조언 만 따르십시오.

사용 libsodium 당신은 PECL에 액세스 할 수있는 경우 (또는 sodium_compat 당신이 PECL없이 libsodium을 원하는 경우); 그렇지 않으면 ...
defuse / php-encryption 사용 ; 자신의 암호화를 굴리지 마십시오!

위에 링크 된 두 라이브러리 모두 인증 된 암호화를 자신의 라이브러리에 쉽고 쉽게 구현할 수 있습니다.

인터넷에있는 모든 암호화 전문가의 일반적인 지식에 반하여 자체 암호화 라이브러리를 작성하고 배포하려는 경우 다음 단계를 수행해야합니다.

암호화 :

  1. CTR 모드에서 AES를 사용하여 암호화합니다. GCM을 사용할 수도 있습니다 (별도의 MAC이 필요 없음). 또한 ChaCha20 및 Salsa20 (의해 제공 libsodium ) 스트림 암호이며, 특별한 모드가 필요하지 않습니다.
  2. 위에서 GCM을 선택하지 않은 경우 HMAC-SHA-256을 사용하여 암호문을 인증해야합니다 (또는 스트림 암호의 경우 Poly1305-대부분의 libsodium API가이를 수행함). MAC은 암호문뿐만 아니라 IV도 포함해야합니다!

복호화 :

  1. Poly1305 또는 GCM을 사용하지 않는 한 암호문의 MAC을 다시 계산하고이를 사용하여 보낸 MAC과 비교하십시오. hash_equals() . 실패하면 중단하십시오.
  2. 메시지를 해독하십시오.

다른 디자인 고려 사항 :

  1. 압축하지 마십시오. 암호문은 압축 할 수 없습니다. 암호화 전에 일반 텍스트를 압축하면 정보가 유출 될 수 있습니다 (예 : CRLS 및 BREACH on TLS).
  2. 당신이 사용 확인 mb_strlen()mb_substr()사용 '8bit'방지하기 위해 문자 설정 모드 mbstring.func_overload문제.
  3. IV는 CSPRNG를 사용하여 생성되어야합니다 . 당신이 사용하는 경우 mcrypt_create_iv(), 사용을하지 마십시오MCRYPT_RAND !
  4. AEAD 구문을 사용하지 않는 한 항상 MAC을 암호화 한 다음!
  5. bin2hex(), base64_encode(), 등 캐시 타이밍을 통해 암호화 키에 대한 정보가 누수 될 수 있습니다. 가능하면 피하십시오.

여기에 제공된 조언을 따를지라도 암호화에는 많은 문제가 발생할 수 있습니다. 암호 전문가가 항상 구현을 검토하도록하십시오. 지역 대학에서 암호화 학생과 개인적인 친구가 될만큼 운이 좋지 않은 경우 언제든지 암호화 스택 교환을 시도 할 수 있습니다 포럼에서 조언을 구할 수 있습니다.

구현에 대한 전문적인 분석이 필요한 경우, 평판이 좋은 보안 컨설턴트 팀을 고용 하여 PHP 암호화 코드 (공개 : 내 고용주) 를 검토 할 수 있습니다 .

중요 : 암호화를 사용하지 않는 경우

비밀번호를 암호화 하지 마십시오 . 당신이 원하는 해시 이러한 암호 해싱 알고리즘 중 하나를 사용하는 대신 그들 :

비밀번호 저장에 범용 해시 기능 (MD5, SHA256)을 사용하지 마십시오.

URL 매개 변수를 암호화하지 마십시오 . 작업에 대한 잘못된 도구입니다.

Libsodium을 사용한 PHP 문자열 암호화 예제

PHP <7.2에 있거나 libsodium이 설치되어 있지 않은 경우 sodium_compat 를 사용하여 동일한 결과를 얻을 수 있습니다 (느리기는하지만).

<?php
declare(strict_types=1);

/**
 * Encrypt a message
 * 
 * @param string $message - message to encrypt
 * @param string $key - encryption key
 * @return string
 * @throws RangeException
 */
function safeEncrypt(string $message, string $key): string
{
    if (mb_strlen($key, '8bit') !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
        throw new RangeException('Key is not the correct size (must be 32 bytes).');
    }
    $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

    $cipher = base64_encode(
        $nonce.
        sodium_crypto_secretbox(
            $message,
            $nonce,
            $key
        )
    );
    sodium_memzero($message);
    sodium_memzero($key);
    return $cipher;
}

/**
 * Decrypt a message
 * 
 * @param string $encrypted - message encrypted with safeEncrypt()
 * @param string $key - encryption key
 * @return string
 * @throws Exception
 */
function safeDecrypt(string $encrypted, string $key): string
{   
    $decoded = base64_decode($encrypted);
    $nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
    $ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');

    $plain = sodium_crypto_secretbox_open(
        $ciphertext,
        $nonce,
        $key
    );
    if (!is_string($plain)) {
        throw new Exception('Invalid MAC');
    }
    sodium_memzero($ciphertext);
    sodium_memzero($key);
    return $plain;
}

그런 다음 테스트하십시오.

<?php
// This refers to the previous code block.
require "safeCrypto.php"; 

// Do this once then store it somehow:
$key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
$message = 'We are all living in a yellow submarine';

$ciphertext = safeEncrypt($message, $key);
$plaintext = safeDecrypt($ciphertext, $key);

var_dump($ciphertext);
var_dump($plaintext);

Halite-더 쉽게 만들어지는 Libsodium

내가 작업했던 프로젝트 중 하나라는 암호화 라이브러리 암염 보다 쉽고 직관적 libsodium 수 있도록하는 것을 목표로.

<?php
use \ParagonIE\Halite\KeyFactory;
use \ParagonIE\Halite\Symmetric\Crypto as SymmetricCrypto;

// Generate a new random symmetric-key encryption key. You're going to want to store this:
$key = new KeyFactory::generateEncryptionKey();
// To save your encryption key:
KeyFactory::save($key, '/path/to/secret.key');
// To load it again:
$loadedkey = KeyFactory::loadEncryptionKey('/path/to/secret.key');

$message = 'We are all living in a yellow submarine';
$ciphertext = SymmetricCrypto::encrypt($message, $key);
$plaintext = SymmetricCrypto::decrypt($ciphertext, $key);

var_dump($ciphertext);
var_dump($plaintext);

모든 기본 암호화는 libsodium에 의해 처리됩니다.

defuse / php-encryption을 사용한 예

<?php
/**
 * This requires https://github.com/defuse/php-encryption
 * php composer.phar require defuse/php-encryption
 */

use Defuse\Crypto\Crypto;
use Defuse\Crypto\Key;

require "vendor/autoload.php";

// Do this once then store it somehow:
$key = Key::createNewRandomKey();

$message = 'We are all living in a yellow submarine';

$ciphertext = Crypto::encrypt($message, $key);
$plaintext = Crypto::decrypt($ciphertext, $key);

var_dump($ciphertext);
var_dump($plaintext);

참고 : Crypto::encrypt()16 진수로 인코딩 된 출력을 반환합니다.

암호화 키 관리

"암호"를 사용하고 싶은 유혹이 있다면 지금 중지하십시오. 사람이 기억할 수있는 암호가 아닌 임의의 128 비트 암호화 키가 필요합니다.

다음과 같이 장기간 사용하기 위해 암호화 키를 저장할 수 있습니다.

$storeMe = bin2hex($key);

요청시 다음과 같이 검색 할 수 있습니다.

$key = hex2bin($storeMe);

내가 강하게 단지 장기간 사용을 위해 임의로 생성 된 키 대신 키와 암호를 모든 종류의를 저장하는 것이 좋습니다 (또는 키를 파생합니다).

Defuse의 라이브러리를 사용하는 경우 :

"하지만 정말 암호를 사용하고 싶습니다."

좋지 않은 생각이지만, 안전하게하는 방법은 다음과 같습니다.

먼저 임의의 키를 생성하여 상수로 저장하십시오.

/**
 * Replace this with your own salt! 
 * Use bin2hex() then add \x before every 2 hex characters, like so:
 */
define('MY_PBKDF2_SALT', "\x2d\xb7\x68\x1a\x28\x15\xbe\x06\x33\xa0\x7e\x0e\x8f\x79\xd5\xdf");

추가 작업을 추가 하고이 상수를 키로 사용하여 많은 상심을 구할 수 있습니다!

그런 다음 PBKDF2 (예 : 이와 같이)를 사용하여 비밀번호로 직접 암호화하지 않고 비밀번호에서 적절한 암호화 키를 도출하십시오.

/**
 * Get an AES key from a static password and a secret salt
 * 
 * @param string $password Your weak password here
 * @param int $keysize Number of bytes in encryption key
 */
function getKeyFromPassword($password, $keysize = 16)
{
    return hash_pbkdf2(
        'sha256',
        $password,
        MY_PBKDF2_SALT,
        100000, // Number of iterations
        $keysize,
        true
    );
}

16 자 암호 만 사용하지 마십시오. 암호화 키가 엉망이됩니다.


3
비밀번호를 암호화하지 말고 해시하여 password_hash()확인하십시오 password_verify().
Scott Arciszewski

2
"압축하지 마십시오." HTTP, spdy 및 기타 프로토콜처럼 말입니까? TLS 전에? 절대 주의자 조언이 많습니까?
Tiberiu-Ionuț Stan

1
@ScottArciszewski 나는 키에 대한 귀하의 의견을 좋아합니다 "// 이것을 한 번 수행 한 다음 어떻게 든 그것을 저장하십시오 :".. 어떻게 든, lol :))) 어떻게이 '키'(객체)를 일반 문자열로 하드 코딩합니까? 문자열 자체로 키 자체가 필요합니다. 어떻게 든이 객체에서 얻을 수 있습니까? 감사합니다
Andrew

2
Thx, 나는 당신의 나트륨 예제를 작동시키기 위해 한 줄을 수정해야했습니다.function getKeyFromPassword($password, $keysize = \Sodium\CRYPTO_SECRETBOX_KEYBYTES)
Alexey Ozerov

1
와! URL 매개 변수를 암호화하지 않는다고 언급하면 ​​+1입니다. : 정말 당신이 제공하는 기사를 좋아 paragonie.com/blog/2015/09/...
Lynnell 엠마누엘 네리

73

나는 파티에 늦었지만 올바른 방법을 찾고 있는데이 페이지를 방문한 것은 Google 검색 결과에서 가장 많이 나온 것 중 하나이므로 문제에 대한 견해를 공유하고 싶습니다. 이 게시물을 작성할 당시의 최신 정보 (2017 년 초). PHP 7.1.0로부터 mcrypt_decryptmcrypt_encrypt그래서 미래 증명 코드를 사용해야 구축되지 할 것입니다 openssl_encrypt openssl_decrypt을

당신은 다음과 같은 것을 할 수 있습니다 :

$string_to_encrypt="Test";
$password="password";
$encrypted_string=openssl_encrypt($string_to_encrypt,"AES-128-ECB",$password);
$decrypted_string=openssl_decrypt($encrypted_string,"AES-128-ECB",$password);

중요 : 이것은 안전하지 않은 ECB 모드를 사용합니다 . 암호화 공학의 충돌 과정을 거치지 않고 간단한 솔루션을 원한다면 직접 작성하지 말고 라이브러리를 사용하십시오.

보안 요구에 따라 다른 치퍼 방식도 사용할 수 있습니다. 사용 가능한 chipper 메소드를 찾으려면 openssl_get_cipher_methods 함수 를 참조하십시오 .


10
고마워, 나는이 간단하고 명확한 대답이 더 많이지지되지 않는다는 것에 놀랐다. 오히려 내가 원하는 것은 간단한 문자열을 암호화 / 해독하는 경우 최고 답변과 같은 주제에 대한 10 페이지 토론을 읽지 않습니다.
laurent

4
이것은 안전한 답변이 아닙니다. ECB 모드를 사용 해서는 안됩니다. "간단하고 명확한 대답"을 원하면 library를 사용하십시오 .
Scott Arciszewski

2
@ ScottArciszewski, 예 간단한 코드를 찾는 동안 너무 빨리 말했음을 인정합니다. 그 후 IV를 추가하고 내 코드에서 CBC를 사용하여 사용하기에 충분합니다.
laurent

이것을 읽고 재고하십시오 . CBC 모드를 사용하면 공격자가 메시지를 완전히 변경할 수 있습니다. 메시지가 파일 인 경우 공격자는 비트를 뒤집고 calc.exe를 팝업 할 수 있습니다. 인증되지 않은 암호화의 위험은 심각합니다.
Scott Arciszewski

7
그것은 모두 유스 케이스에 달려 있습니다! 이것이 완벽하게 미세한 경우가 있습니다. 예를 들어 GET 매개 변수를 페이지에서 페이지로 전달하고 싶습니다.prod_id=123 싶지만 모두에게 123을 읽을 수있게하고 싶지는 않지만 읽을 수는 있지만 문제가되지는 않습니다. 123을 사용자 지정 값으로 대체 할 수있는 공격자는 해를 끼치 지 않으며 다른 제품의 세부 정보 만 얻을 수 있지만 Joe Average User는 세부 정보를 얻는 방법에 대한 단서가 없습니다. 예를 들어 제품 124. 이와 같은 시나리오의 경우 완벽한 솔루션이며 보안을위한 필수 솔루션입니다!
Emil Borconi

43

하지 말아야 할 것

경고 :
이 답변은 ECB를 사용합니다 . ECB는 암호화 모드가 아니며 빌딩 블록 일뿐입니다. 이 답변에 설명 된대로 ECB를 사용해도 실제로 문자열을 안전하게 암호화하지는 않습니다. 코드에서 ECB를 사용하지 마십시오. 좋은 해결책 은 Scott의 답변 을 참조하십시오 .

나는 그것을 스스로 얻었다. 실제로 나는 구글에서 일부 답변을 발견하고 뭔가를 수정했습니다. 그러나 결과는 완전히 안전하지 않습니다.

<?php
define("ENCRYPTION_KEY", "!@#$%^&*");
$string = "This is the original data string!";

echo $encrypted = encrypt($string, ENCRYPTION_KEY);
echo "<br />";
echo $decrypted = decrypt($encrypted, ENCRYPTION_KEY);

/**
 * Returns an encrypted & utf8-encoded
 */
function encrypt($pure_string, $encryption_key) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
    return $encrypted_string;
}

/**
 * Returns decrypted original string
 */
function decrypt($encrypted_string, $encryption_key) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $decrypted_string = mcrypt_decrypt(MCRYPT_BLOWFISH, $encryption_key, $encrypted_string, MCRYPT_MODE_ECB, $iv);
    return $decrypted_string;
}
?>

8
보안을 강화하기 위해 "MCRYPT_MODE_ECB"대신 "MCRYPT_MODE_CBC"사용자를 사용할 수 있습니다.
Parixit

10
Ramesh, 이것은 원시 암호화 된 데이터를 얻기 때문입니다. :이 같은 base64로를 사용하여 암호화 된 데이터의 더 좋은 버전을 얻을 수있는 base64_encode(encrypt($string))암호를 해독하기 : -decrypt(base64_decode($encrypted))
mendezcode을

82
경고 : 이것은 안전하지 않습니다 . ECB 모드, ECB 대신 AES의 그것은 이전 암호 (복어)를 사용하여,이 인증되지 않고, 정맥 주사를하지 않고 문자열에 사용되지 않으며, 키 등등 이진없는 소위 커뮤니티 실제로 정지 암호화 upvoting해야 / "암호화" 하고 안전한 것으로 알려진 답변을지지하는 해독 . 확실하지 않다면 투표하지 마십시오.
Maarten Bodewes 2013

3
나는 php.net/manual/en/function.mcrypt-encrypt.php 의 샘플 코드를 mcrypt_encrypt교체 하여 이미 이것을 수행했습니다 . 지금 검토 하면 끝에 rtrim문자 가 있어야합니다 "\0".
Maarten Bodewes

4
정답은 자신의 mcrypt 코드를 작성하는 대신 defuse / php-encryption 과 같은 것을 사용하는 것 입니다.
Scott Arciszewski

18

라 라벨 프레임 워크

Laravel 프레임 워크를 사용하는 경우 내부 기능을 사용하여보다 쉽게 ​​암호화하고 해독 할 수 있습니다.

$string = 'Some text to be encrypted';
$encrypted = \Illuminate\Support\Facades\Crypt::encrypt($string);
$decrypted_string = \Illuminate\Support\Facades\Crypt::decrypt($encrypted);

var_dump($string);
var_dump($encrypted);
var_dump($decrypted_string);

참고 : config / app.php 파일의 키 옵션에서 16, 24 또는 32 자의 임의 문자열을 설정하십시오. 그렇지 않으면 암호화 된 값이 안전하지 않습니다.


1
물론 사용하기 쉬울 수 있습니다. 그러나 안전합니까? stackoverflow.com/a/30159120/781723 의 문제를 어떻게 해결 합니까? 인증 된 암호화를 사용합니까? 부 채널 취약성을 피하고 일정한 시간 평등 검사를 보장합니까? 암호 / 암호 구문이 아닌 진정한 임의의 키를 사용합니까? 적절한 작동 모드를 사용합니까? 무작위 IV를 올바르게 생성합니까?
DW

10

업데이트

PHP 7 준비 버전. PHP OpenSSL Library의 openssl_encrypt 함수를 사용합니다 .

class Openssl_EncryptDecrypt {
    function encrypt ($pure_string, $encryption_key) {
        $cipher     = 'AES-256-CBC';
        $options    = OPENSSL_RAW_DATA;
        $hash_algo  = 'sha256';
        $sha2len    = 32;
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = openssl_random_pseudo_bytes($ivlen);
        $ciphertext_raw = openssl_encrypt($pure_string, $cipher, $encryption_key, $options, $iv);
        $hmac = hash_hmac($hash_algo, $ciphertext_raw, $encryption_key, true);
        return $iv.$hmac.$ciphertext_raw;
    }
    function decrypt ($encrypted_string, $encryption_key) {
        $cipher     = 'AES-256-CBC';
        $options    = OPENSSL_RAW_DATA;
        $hash_algo  = 'sha256';
        $sha2len    = 32;
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = substr($encrypted_string, 0, $ivlen);
        $hmac = substr($encrypted_string, $ivlen, $sha2len);
        $ciphertext_raw = substr($encrypted_string, $ivlen+$sha2len);
        $original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $encryption_key, $options, $iv);
        $calcmac = hash_hmac($hash_algo, $ciphertext_raw, $encryption_key, true);
        if(function_exists('hash_equals')) {
            if (hash_equals($hmac, $calcmac)) return $original_plaintext;
        } else {
            if ($this->hash_equals_custom($hmac, $calcmac)) return $original_plaintext;
        }
    }
    /**
     * (Optional)
     * hash_equals() function polyfilling.
     * PHP 5.6+ timing attack safe comparison
     */
    function hash_equals_custom($knownString, $userString) {
        if (function_exists('mb_strlen')) {
            $kLen = mb_strlen($knownString, '8bit');
            $uLen = mb_strlen($userString, '8bit');
        } else {
            $kLen = strlen($knownString);
            $uLen = strlen($userString);
        }
        if ($kLen !== $uLen) {
            return false;
        }
        $result = 0;
        for ($i = 0; $i < $kLen; $i++) {
            $result |= (ord($knownString[$i]) ^ ord($userString[$i]));
        }
        return 0 === $result;
    }
}

define('ENCRYPTION_KEY', '__^%&Q@$&*!@#$%^&*^__');
$string = "This is the original string!";

$OpensslEncryption = new Openssl_EncryptDecrypt;
$encrypted = $OpensslEncryption->encrypt($string, ENCRYPTION_KEY);
$decrypted = $OpensslEncryption->decrypt($encrypted, ENCRYPTION_KEY);

1
이것은 더 좋고 훨씬 안전한 버전입니다. 감사합니다, 그것은 예상대로 작동합니다.

1
암호화 키를 어떻게 작성하고 어디에 보관합니까?
user2800464

7

역사적 참고 사항 : 이것은 PHP4 당시 작성되었습니다. 이것이 우리가 지금 "레거시 코드"라고 부르는 것입니다.

나는 역사적인 대답을 위해이 답변을 남겼습니다. 그러나 일부 방법은 더 이상 사용되지 않으며 DES 암호화 방법은 권장되지 않습니다.

나는 두 가지 이유로이 코드를 업데이트하지 않았습니다 : 1) 더 이상 PHP에서 직접 암호화 방법으로 작업하지 않으며, 2)이 코드는 여전히 의도 된 목적을 제공합니다. 암호화가 작동하는 방법에 대한 최소의 간단한 개념 PHP에서.

사람들이 10-20 줄 이하의 코드로 시작할 수있는 유사하게 "모두를위한 PHP 암호화"종류의 소스를 찾으면 의견으로 알려주십시오.

그 외에도 초기 PHP4 미니멀리즘 암호화 답변의 클래식 에피소드를 즐기십시오.


이상적으로는 널리 사용되고 매우 유용한 다양한 작업으로 mcrypt PHP 라이브러리에 액세스하거나 액세스 할 수 있습니다. 다음은 여러 종류의 암호화와 예제 코드에 대한 요약입니다. PHP의 암호화 기술

//Listing 3: Encrypting Data Using the mcrypt_ecb Function 

<?php 
echo("<h3> Symmetric Encryption </h3>"); 
$key_value = "KEYVALUE"; 
$plain_text = "PLAINTEXT"; 
$encrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $plain_text, MCRYPT_ENCRYPT); 
echo ("<p><b> Text after encryption : </b>"); 
echo ( $encrypted_text ); 
$decrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $encrypted_text, MCRYPT_DECRYPT); 
echo ("<p><b> Text after decryption : </b>"); 
echo ( $decrypted_text ); 
?> 

몇 가지 경고 :

1) 단방향 해시가 수행 할 때는 가역적 또는 "대칭"암호화를 사용하지 마십시오.

2) 신용 카드 나 주민등록번호와 같이 데이터가 진정으로 민감한 경우 중지하십시오. 간단한 코드 덩어리가 제공하는 것 이상이 필요하지만이 목적을 위해 설계된 암호화 라이브러리와 필요한 방법을 연구하는 데 상당한 시간이 필요합니다. 또한 소프트웨어 암호화는 아마도 민감한 데이터 보안의 <10 %입니다. 그것은 원자력 발전소를 재배치하는 것과 같습니다. 작업이 위험하고 어렵다는 것을 인정하십시오. 재정적 처벌은 엄청날 수 있으므로 서비스를 사용하고 책임을지는 것이 좋습니다.

3) 여기에 나열된 모든 종류의 쉽게 구현할 수있는 암호화는 우발적이거나 의도적 인 누출의 경우 눈을 피하거나 노출을 제한하려는 아주 중요한 정보를 합리적으로 보호 할 수 있습니다. 그러나 키가 웹 서버에서 일반 텍스트로 저장되는 방식으로 볼 때 데이터를 얻을 수 있으면 해독 키를 얻을 수 있습니다.

그것이 재미있을 것입니다 :)


9
DES. AES는 어디에 있습니까?
Patashu

2
감사! 그러나 몇 가지 문제가 있습니다. 내가지고있어 M�������f=�_=암호화 된 하나 이상한 문자. 간단한 문자를 얻을 수 없습니까? 처럼 : 2a2ffa8f13220befbe30819047e23b2c. 또한 LENGTH의 $key_value(8 고정으로 고정)와 LENGTH의 출력을 변경할 수 $encrypted_text없습니까? (길이가 32 또는 64이거나 더 이상 될 수는
없습니까

3
@ 夏 期 劇場 암호화 결과는 이진 데이터입니다. 사람이 읽을 수 있어야하는 경우 base64 또는 16 진 인코딩을 사용하십시오. '키 값의 길이를 변경할 수 없습니까?' 다른 대칭 암호화 알고리즘에는 키 값에 대한 요구 사항이 다릅니다. '및 출력 길이 ...'암호화 된 텍스트의 길이는 원본 텍스트보다 길어야합니다. 그렇지 않으면 원본 텍스트를 다시 작성하기에 충분한 정보가 없습니다. (이것은 Pigeonhole 원칙의 적용입니다.) BTW, DES 대신 AES를 사용해야합니다. DES는 쉽게 깨지기 쉽고 더 이상 안전하지 않습니다.
Patashu

8
PHP 5.5.0부터 mcrypt_ecb는 더 이상 사용되지 않습니다.이 기능에 의존하는 것은 권장하지 않습니다. php.net/manual/en/function.mcrypt-ecb.php
Hafez Divandari

1
@BrianDHall 이것이 여전히 투표권을 얻는 이유는 ECB 모드가 안전하지 않고 (CBC, CTR, GCM 또는 Poly1305 사용) DES가 약하고 (AES를 원함 MCRYPT_RIJNDAEL_128) 암호문이 인증되어야하기 때문입니다 ( hash_hmac(), 검증 됨). 와 함께 hash_equals()).
Scott Arciszewski

7

라이브러리를 사용하지 않으려면 (필수) 다음과 같은 것을 사용하십시오 (PHP 7).

function sign($message, $key) {
    return hash_hmac('sha256', $message, $key) . $message;
}

function verify($bundle, $key) {
    return hash_equals(
      hash_hmac('sha256', mb_substr($bundle, 64, null, '8bit'), $key),
      mb_substr($bundle, 0, 64, '8bit')
    );
}

function getKey($password, $keysize = 16) {
    return hash_pbkdf2('sha256',$password,'some_token',100000,$keysize,true);
}

function encrypt($message, $password) {
    $iv = random_bytes(16);
    $key = getKey($password);
    $result = sign(openssl_encrypt($message,'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv), $key);
    return bin2hex($iv).bin2hex($result);
}

function decrypt($hash, $password) {
    $iv = hex2bin(substr($hash, 0, 32));
    $data = hex2bin(substr($hash, 32));
    $key = getKey($password);
    if (!verify($data, $key)) {
      return null;
    }
    return openssl_decrypt(mb_substr($data, 64, null, '8bit'),'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv);
}

$string_to_encrypt='John Smith';
$password='password';
$encrypted_string=encrypt($string_to_encrypt, $password);
$decrypted_string=decrypt($encrypted_string, $password);

이것이 stackoverflow.com/a/16606352/126833을 대체 할 수 있습니까 ? 호스트가 PHP 7.2로 업그레이드 될 때까지 전자를 사용했습니다.
anjanesh

@anjanesh 당신은 이것으로 오래된 데이터를 해독 할 수 없습니다 (다른 알고리즘 + 이것도 서명을 확인합니다)
Ascon

2
귀하의 경우 아마 다음을 수행해야합니다.define("ENCRYPTION_KEY", "123456*"); $string = "This is the original data string!"; $encrypted = openssl_encrypt($string, 'BF-ECB', ENCRYPTION_KEY); $decrypted = openssl_decrypt($encrypted,'BF-ECB',ENCRYPTION_KEY);
Ascon

이것은 슈퍼입니다!
anjanesh

2

다음은 AES256 CBC를 사용하여 PHP로 문자열을 암호화 / 복호화하는 간단한 방법입니다 .

function encryptString($plaintext, $password, $encoding = null) {
    $iv = openssl_random_pseudo_bytes(16);
    $ciphertext = openssl_encrypt($plaintext, "AES-256-CBC", hash('sha256', $password, true), OPENSSL_RAW_DATA, $iv);
    $hmac = hash_hmac('sha256', $ciphertext.$iv, hash('sha256', $password, true), true);
    return $encoding == "hex" ? bin2hex($iv.$hmac.$ciphertext) : ($encoding == "base64" ? base64_encode($iv.$hmac.$ciphertext) : $iv.$hmac.$ciphertext);
}

function decryptString($ciphertext, $password, $encoding = null) {
    $ciphertext = $encoding == "hex" ? hex2bin($ciphertext) : ($encoding == "base64" ? base64_decode($ciphertext) : $ciphertext);
    if (!hash_equals(hash_hmac('sha256', substr($ciphertext, 48).substr($ciphertext, 0, 16), hash('sha256', $password, true), true), substr($ciphertext, 16, 32))) return null;
    return openssl_decrypt(substr($ciphertext, 48), "AES-256-CBC", hash('sha256', $password, true), OPENSSL_RAW_DATA, substr($ciphertext, 0, 16));
}

용법:

$enc = encryptString("mysecretText", "myPassword");
$dec = decryptString($enc, "myPassword");

0

아래 코드는 특수 문자가있는 모든 문자열에 대해 PHP에서 작동합니다.

   // Encrypt text --

    $token = "9611222007552";

      $cipher_method = 'aes-128-ctr';
      $enc_key = openssl_digest(php_uname(), 'SHA256', TRUE);  
      $enc_iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher_method));  
      $crypted_token = openssl_encrypt($token, $cipher_method, $enc_key, 0, $enc_iv) . "::" . bin2hex($enc_iv);
    echo    $crypted_token;
    //unset($token, $cipher_method, $enc_key, $enc_iv);

    // Decrypt text  -- 

    list($crypted_token, $enc_iv) = explode("::", $crypted_token);  
      $cipher_method = 'aes-128-ctr';
      $enc_key = openssl_digest(php_uname(), 'SHA256', TRUE);
      $token = openssl_decrypt($crypted_token, $cipher_method, $enc_key, 0, hex2bin($enc_iv));
    echo   $token;
    //unset($crypted_token, $cipher_method, $enc_key, $enc_iv);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.