PHP를 사용한 가장 간단한 양방향 암호화
일반적인 PHP 설치에서 양방향 암호화를 수행하는 가장 간단한 방법은 무엇입니까?
문자열 키로 데이터를 암호화 할 수 있어야하고 같은 키를 사용하여 다른 쪽 끝을 해독해야합니다.
보안은 코드의 이식성만큼 큰 문제가 아니므로 가능한 한 간단하게 유지할 수 있기를 바랍니다. 현재 RC4 구현을 사용하고 있지만 기본적으로 지원되는 것을 찾을 수 있으면 불필요한 코드를 많이 저장할 수 있습니다.
편집 :
실제로 openssl_encrypt () & openssl_decrypt ()를 사용해야합니다
으로 스콧은 말한다, Mcrypt 라이브러리는 2007 년부터 업데이트되지 않은으로 좋은 생각이 아니다.
PHP에서 Mcrypt 라이브러리를 제거하는 RFC도있다 - https://wiki.php.net/rfc/mcrypt-viking-funeral
중요 사항 : 매우 특별한 사용 사례 가없는 경우 비밀번호를 암호화하지 말고 비밀번호 해시 알고리즘을 대신 사용하십시오. 누군가 서버 측 응용 프로그램에서 암호를 암호화 한다고 말하면 정보가 없거나 위험한 시스템 설계를 설명하는 것입니다. 암호를 안전하게 저장하는 것은 암호화와 완전히 별개의 문제입니다.
정보를 받으십시오. 안전한 시스템을 설계하십시오.
PHP의 휴대용 데이터 암호화
PHP 5.4 이상을 사용 하고 있고 암호화 모듈을 직접 작성하지 않으려면 인증 된 암호화를 제공하는 기존 라이브러리를 사용 하는 것이 좋습니다 . 필자가 링크 한 라이브러리는 PHP가 제공하는 것에 만 의존하며 소수의 보안 연구원들이 주기적으로 검토하고 있습니다. (자신도 포함되어 있습니다.)
이식성 목표가 PECL 확장을 요구하지 않으면 libsodium 은 PHP로 작성할 수있는 것보다 강력히 권장됩니다.
업데이트 (2016-06-12) : 이제 PECL 확장을 설치하지 않고도 sodium_compat 를 사용하고 동일한 암호화 라이브러리를 사용할 수 있습니다 .
암호화 엔지니어링에 손을 대고 싶다면 계속 읽으십시오.
먼저 인증되지 않은 암호화 및 암호화 운명 원칙 의 위험 을 배우는 시간을 가져야합니다 .
- 악의적 인 사용자가 암호화 된 데이터를 조작 할 수 있습니다.
- 암호화 된 데이터를 인증하면 변조가 방지됩니다.
- 암호화되지 않은 데이터를 인증해도 변조가 방지되지는 않습니다.
암호화 및 암호 해독
PHP의 암호화는 실제로 간단합니다 (우리는 사용 openssl_encrypt()
하고 openssl_decrypt()
정보를 암호화하는 방법에 대한 결정을 한 후에 결정 openssl_get_cipher_methods()
합니다. 시스템에서 지원되는 방법 목록을 참조하십시오 . 가장 좋은 방법 은 CTR 모드의 AES입니다 .
aes-128-ctr
aes-192-ctr
aes-256-ctr
것을 믿을 이유 현재 없습니다 AES 키 크기 에 대한 걱정에 상당한 문제가 (더 큰 아마이다는 하지 때문에 256 비트 모드에서 나쁜 키 스케줄링, 더 나은).
참고 : 우리는 사용하지 않는 mcrypt
것이 있기 때문에 밴던 및이 패치되지 않은 버그 보안에 영향을 줄 수 있습니다. 이러한 이유 때문에 다른 PHP 개발자들도이를 피하는 것이 좋습니다.
OpenSSL을 사용한 간단한 암호화 / 복호화 래퍼
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);
위의 간단한 암호화 라이브러리는 여전히 안전하지 않습니다. 암호를 해독하기 전에 암호문 을 인증하고 확인해야합니다 .
Note: By default, UnsafeCrypto::encrypt()
will return a raw binary string. Call it like this if you need to store it in a binary-safe format (base64-encoded):
$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);
Demo: http://3v4l.org/f5K93
Simple Authentication Wrapper
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);
}
}
Usage Example
$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);
Demos: raw binary, base64-encoded
If anyone wishes to use this SaferCrypto
library in a production environment, or your own implementation of the same concepts, I strongly recommend reaching out to your resident cryptographers for a second opinion before you do. They'll be able tell you about mistakes that I might not even be aware of.
You will be much better off using a reputable cryptography library.
Use mcrypt_encrypt()
and mcrypt_decrypt()
with corresponding parameters. Really easy and straight forward, and you use a battle-tested encryption package.
EDIT
5 years and 4 months after this answer, the mcrypt
extension is now in the process of deprecation and eventual removal from PHP.
PHP 7.2 moved completely away from Mcrypt
and the encryption now is based on the maintainable Libsodium
library.
All your encryption needs can be basically resolved through Libsodium
library.
// 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 documentation: https://github.com/paragonie/pecl-libsodium-doc
Here is simple but secure enough implementation:
- AES-256 encryption in CBC mode
- PBKDF2 to create encryption key out of plain-text password
- HMAC to authenticate the encrypted message.
Code and examples are here: https://stackoverflow.com/a/19445173/1387163
참고URL : https://stackoverflow.com/questions/9262109/simplest-two-way-encryption-using-php
'IT story' 카테고리의 다른 글
PowerShell을 사용하여 디렉토리의 파일을 반복 (0) | 2020.05.01 |
---|---|
언어는 어떻게 확장됩니까? (0) | 2020.05.01 |
속성 서명에서 C #의 => 할당은 무엇입니까? (0) | 2020.05.01 |
PHP 용 코드 난독 화 장치가 있습니까? (0) | 2020.05.01 |
자식 기록에서 특정 개정을 어떻게 제거합니까? (0) | 2020.05.01 |