내가 말하고 싶은 건:
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
했지만 작동하지 않았습니다.
답변
추가 작업을 수행하기 전에 암호화 와 인증 의 차이점 과 단순히 암호화가 아닌 인증 된 암호화를 원하는 이유 를 이해 하십시오 .
인증 된 암호화를 구현하려면 암호화 한 다음 MAC을 사용하려고합니다. 암호화 및 인증 순서는 매우 중요합니다! 이 질문에 대한 기존의 답변 중 하나가이 실수를 범했습니다. PHP로 작성된 많은 암호화 라이브러리와 마찬가지로.
당신은해야 자신의 암호화를 구현하지 않도록 하고, 대신 보안 라이브러리에 의해 작성하고 암호 전문가 검토를 사용합니다.
업데이트 : PHP 7.2는 이제 libsodium을 제공합니다 ! 최상의 보안을 위해 PHP 7.2 이상을 사용하도록 시스템을 업데이트하고이 답변의 libsodium 조언 만 따르십시오.
사용 libsodium 당신은 PECL에 액세스 할 수있는 경우 (또는 sodium_compat 당신이 PECL없이 libsodium을 원하는 경우); 그렇지 않으면 …
defuse / php-encryption 사용 ; 자신의 암호화를 굴리지 마십시오!
위에 링크 된 두 라이브러리 모두 인증 된 암호화를 자신의 라이브러리에 쉽고 쉽게 구현할 수 있습니다.
인터넷에있는 모든 암호화 전문가의 일반적인 지식에 반하여 자체 암호화 라이브러리를 작성하고 배포하려는 경우 다음 단계를 수행해야합니다.
암호화 :
- CTR 모드에서 AES를 사용하여 암호화합니다. GCM을 사용할 수도 있습니다 (별도의 MAC이 필요 없음). 또한 ChaCha20 및 Salsa20 (의해 제공 libsodium ) 스트림 암호이며, 특별한 모드가 필요하지 않습니다.
- 위에서 GCM을 선택하지 않은 경우 HMAC-SHA-256을 사용하여 암호문을 인증해야합니다 (또는 스트림 암호의 경우 Poly1305-대부분의 libsodium API가이를 수행함). MAC은 암호문뿐만 아니라 IV도 포함해야합니다!
복호화 :
- Poly1305 또는 GCM을 사용하지 않는 한 암호문의 MAC을 다시 계산하고이를 사용하여 보낸 MAC과 비교하십시오.
hash_equals()
. 실패하면 중단하십시오. - 메시지를 해독하십시오.
다른 디자인 고려 사항 :
- 압축하지 마십시오. 암호문은 압축 할 수 없습니다. 암호화 전에 일반 텍스트를 압축하면 정보가 유출 될 수 있습니다 (예 : CRLS 및 BREACH on TLS).
- 당신이 사용 확인
mb_strlen()
및mb_substr()
사용'8bit'
방지하기 위해 문자 설정 모드mbstring.func_overload
문제. - IV는 CSPRNG를 사용하여 생성되어야합니다 . 당신이 사용하는 경우
mcrypt_create_iv()
, 사용을하지 마십시오MCRYPT_RAND
!- random_compat 도 확인하십시오 .
- AEAD 구문을 사용하지 않는 한 항상 MAC을 암호화 한 다음!
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 자 암호 만 사용하지 마십시오. 암호화 키가 엉망이됩니다.
답변
나는 파티에 늦었지만 올바른 방법을 찾고 있는데이 페이지를 방문한 것은 Google 검색 결과에서 가장 많이 나온 것 중 하나이므로 문제에 대한 견해를 공유하고 싶습니다. 이 게시물을 작성할 당시의 최신 정보 (2017 년 초). PHP 7.1.0로부터 mcrypt_decrypt
및 mcrypt_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 함수 를 참조하십시오 .
답변
하지 말아야 할 것
경고 :
이 답변은 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;
}
?>
답변
라 라벨 프레임 워크
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 자의 임의 문자열을 설정하십시오. 그렇지 않으면 암호화 된 값이 안전하지 않습니다.
답변
업데이트
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);
답변
역사적 참고 사항 : 이것은 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) 여기에 나열된 모든 종류의 쉽게 구현할 수있는 암호화는 우발적이거나 의도적 인 누출의 경우 눈을 피하거나 노출을 제한하려는 아주 중요한 정보를 합리적으로 보호 할 수 있습니다. 그러나 키가 웹 서버에서 일반 텍스트로 저장되는 방식으로 볼 때 데이터를 얻을 수 있으면 해독 키를 얻을 수 있습니다.
그것이 재미있을 것입니다 🙂
답변
라이브러리를 사용하지 않으려면 (필수) 다음과 같은 것을 사용하십시오 (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);