加密和完善的完美方式解密密码,PHP中的文件?

时间:2012-08-20 04:16:51

标签: php file codeigniter encryption blowfish

我对这个主题进行了一系列研究,但遗憾的是我找不到用PHP加密和解密文件的完美方法。这意味着我正在尝试做的是找到一些方法来加密&解密我的项目而不用担心破解者知道我的算法。如果某些算法需要分泌&隐藏,它无法解决我的问题,而一旦逻辑通过任何地方共享,或者他们闯入我的服务器并获取源文件,那么它应该是一些使用相同的解密算法解密它的方法。以前我在StackOverFlow网站上发现了几篇很棒的帖子,但它仍然无法回答我的问题。

  

从我通过阅读得出的结论来加密世界密码的最佳方式。 Blowfish加密。这是一种具有1000次迭代的散列算法,这使得破解者需要7年才能使用相同规格的GPU进行解密。

显然,这使得在单向散列时无法解密。

  1. How do you use bcrypt for hashing passwords in PHP?
  2. Why do salts make dictionary attacks 'impossible'?
  3.   

    在PHP中加密和解密密码的最佳方法,因为这个问题引用它。请参考我通过网络找到的内容,sha1和md5都是破解的&破碎的算法,甚至我们改变算法

    $encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $string, MCRYPT_MODE_CBC, md5(md5($key))));
    

    $encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, sha1(md5($key)), $string, MCRYPT_MODE_CBC, sha1(md5(md5($key)))));
    

    是不是只是增加了解密它的韧性,但在时间问题上仍然可以破解?

    1. Best way to use PHP to encrypt and decrypt passwords?
    2.   

      我正在考虑使用我们的服务器处理器/硬盘GUID来生成salt并加密密码。

      当cracker访问服务器时,仍然有一些愚蠢的方法,他们可以使用PHP来回应GUID并进行解密。或者,如果它有效,几年后我的网站将遇到麻烦。原因是硬盘,处理器永远不会永远存在。当我的处理器或硬盘耗尽时,这是我的网站关闭并丢失所有凭据的时间。

      更新

        

      发现这个问题在PHP中使用blowfish进行解密。它是否正在解决找到加密的安全方式并且难以被其他人解密的问题?

      1. How to decrypt using Blowfish algorithm in php?
      2. 任何人都可以建议我应该如何克服这个问题?谢谢。

6 个答案:

答案 0 :(得分:5)

查看这篇文章齐全的文章A reversible password encryption routine for PHP,适用于那些希望密码加密例程可逆的PHP开发人员。

即使此类用于密码加密,您也可以使用它来加密/解密任何文本。

function encryption_class() {
    $this->errors = array();

    // Each of these two strings must contain the same characters, but in a different order.
    // Use only printable characters from the ASCII table.
    // Do not use single quote, double quote or backslash as these have special meanings in PHP.
    // Each character can only appear once in each string.
    $this->scramble1 = '! #$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~';
    $this->scramble2 = 'f^jAE]okIOzU[2&q1{3`h5w_794p@6s8?BgP>dFV=m D<TcS%Ze|r:lGK/uCy.Jx)HiQ!#$~(;Lt-R}Ma,NvW+Ynb*0X';

    if (strlen($this->scramble1) <> strlen($this->scramble2)) {
        trigger_error('** SCRAMBLE1 is not same length as SCRAMBLE2 **', E_USER_ERROR);
    } // if

    $this->adj = 1.75;  // this value is added to the rolling fudgefactors
    $this->mod = 3;     // if divisible by this the adjustment is made negative
}

<强>注意

如果您使用的是PHP版本&gt; = 5.3.3,那么您必须将班级名称从encryption_class更改为__construct

<强>原因:

As of PHP 5.3.3, methods with the same name as the last element of a namespaced class name will no longer be treated as constructor.

<强>用法:

$crypt = new encryption_class();

$crypt->setAdjustment(1.75); // 1st adjustment value (optional)
$crypt->setModulus(3); // 2nd adjustment value (optional)

/**
 * 
 * @param string $key - Your encryption key
 * @param string $sourceText - The source text to be encrypted
 * @param integer $encLen - positive integer indicating the minimum length of encrypted text
 * @return string - encrypted text
 */
$encrypt_result = $crypt->encrypt($key, $sourceText, $encLen);

/**
 * 
 * @param string $key - Your encryption key (same used for encryption)
 * @param string $encrypt_result - The text to be decrypted
 * @return string - decrypted text
 */
$decrypt_result = $crypt->decrypt($key, $encrypt_result);

<强>更新

上面的课程不是用于加密文件,但你可以!!!

  1. base64_encode您的源文本(文件内容)
  2. 用于实际加密,将上面的enc / dec类应用于base64编码的文本
  3. 用于解密,将上面的enc / dec类应用于实际加密的文本
  4. base64_decode将为您提供实际的文件内容(您可以使用此内容保存文件副本)
  5. 我已加密图像,解密并保存到新文件中!签出代码。

    //class for encrypt/decrypt routines 
    require 'class.encryption.php';
    
    //configuring your security levels
    $key = 'This is my secret key; with symbols (@$^*&<?>/!#_+), cool eh?!!! :)';
    $adjustment = 1.75;
    $modulus = 2;
    
    //customizing
    $sourceFileName = 'source-image.png';
    $destFileName = 'dest-image.png';
    $minSpecifiedLength = 512;
    
    //base64 encoding file contents, to get all characters in our range
    //binary too!!!
    $sourceText = base64_encode(file_get_contents($sourceFileName));
    
    $crypt = new encryption_class();
    $crypt->setAdjustment($adjustment); //optional
    $crypt->setModulus($modulus); //optional
    
    //encrypted text
    $encrypt_result = $crypt->encrypt($key, $sourceText, $minSpecifiedLength);
    
    //receive initial file contents after decryption
    $decrypt_result = base64_decode($crypt->decrypt($key, $encrypt_result));
    
    //save as new file!!!
    file_put_contents($destFileName, $decrypt_result);
    

答案 1 :(得分:4)

请记住,为了破解密码,黑客必须首先访问加密密码。为了做到这一点,他们必须妥协服务器的安全性,如果网站编码正确(适当的转义或准备好的语句),这应该是不可能的。

最强大但最简单的加密形式之一是XOR,但它完全取决于密钥。如果密钥与编码文本的长度相同,那么没有该密钥就完全不可破解。即使密钥长度只有文本的一半也不太可能被破坏。

最后,无论您选择何种方法,都可以通过FTP / SSH /允许您访问服务器文件的密码来保护。如果您自己的密码被泄露,黑客可以看到所有内容。

答案 2 :(得分:4)

您的问题会导致两个不同的答案。这是一个重要的区别,您是否需要稍后解密数据(如文件),或者您是否可以使用单向哈希(用于密码)。

单向散列

如果你不需要解密你的数据(密码),你应该使用哈希函数。这样更安全,因为即使攻击者控制了您的服务器和数据库,他也无法检索原始密码。由于用户经常将密码用于多个网站,因此至少他也无法访问其他网站。

正如您已经说过的,今天最推荐的哈希函数之一是 bcrypt 。尽管它起源于河豚算法,但它实际上是一个哈希函数(不是加密)。 Bcrypt专门用于哈希密码,因此很慢(需要计算时间)。建议使用像[{3}}这样完善的库,如果你想了解如何实现它,你可以阅读这个phpass,我试图解释最重要的点。

加密

如果以后需要解密您的数据(文件),您无法阻止控制服务器的攻击者也可以解密文件(在所有服务器都必须能够解密之后)解密它)。所有这些都增加了存储密钥的位置的问题。你唯一能做的就是让关键变得更难。

这意味着,如果您将密钥存储在一个文件中,它应该是之外的根目录,因此它无法从互联网访问。您可以将其存储在不同的服务器上,因此攻击者需要控制两台服务器,但是您将面临服务器之间安全通信的问题。在任何情况下,你都可以使盗窃更加困难,但你无法完全阻止它。

根据您的方案,您可以在计算机上本地加密文件,并仅将加密文件存储在服务器上。

,服务器无法自行解密文件,因此它们是安全的。

答案 3 :(得分:1)

经过对PHP的一些研究,特别是随机数生成,使用PHP安全加密的唯一方法是使用OpenSSL包装器。特别是mcrypt的创建者是一堆蠢货,只看一下不在他们的样本中如何执行加密的例子:

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "This is a very secret key";
$text = "Meet me at 11 o'clock behind the monument.";
echo strlen($text) . "\n";

$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, $iv);
echo strlen($crypttext) . "\n";

请注意,默认情况下,MCRYPT_RAND没有播种。此外,上述代码中至少有大约5个错误,他们无法修复它。

[编辑]见下面的修改样本。请注意,此样本也不是很安全(如上所述)。此外,通常你不应该加密密码......

# the key should be random binary, use scrypt, bcrypt or PBKDF2 to convert a string into a key
# key is specified using hexadecimals
$key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");
echo "Key size (in bits): " . $key_size * 8 . "\n";
$plaintext = "This string was AES-256 / CBC / ZeroBytePadding encrypted.";
echo "Plain text: " . $plain_text . "\n";
$ciphertext_base64 = encryptText($key, $plaintext);
echo  $ciphertext_base64 . "\n";


function encryptText(string $key_hex, string $plaintext) {

    # --- ENCRYPTION ---


    # show key size use either 16, 24 or 32 byte keys for AES-128, 192 and 256 respectively
    $key_size =  strlen($key);


    # create a random IV to use with CBC encoding
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

    # use an explicit encoding for the plain text
    $plaintext_utf8 = utf8_encode($plaintext);

    # creates a cipher text compatible with AES (Rijndael block size = 128) to keep the text confidential 
    # only suitable for encoded input that never ends with value 00h (because of default zero padding)
    $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext_utf8, MCRYPT_MODE_CBC, $iv);

    # prepend the IV for it to be available for decryption
    $ciphertext = $iv . $ciphertext;

    # encode the resulting cipher text so it can be represented by a string
    $ciphertext_base64 = base64_encode($ciphertext);

    return $ciphertext_base64;
}


# === WARNING ===

# Resulting cipher text has no integrity or authenticity added
# and is not protected against padding oracle attacks.

# --- DECRYPTION ---

$ciphertext_dec = base64_decode($ciphertext_base64);

# retrieves the IV, iv_size should be created using mcrypt_get_iv_size()
$iv_dec = substr($ciphertext_dec, 0, $iv_size);

# retrieves the cipher text (everything except the $iv_size in the front)
$ciphertext_dec = substr($ciphertext_dec, $iv_size);

# may remove 00h valued characters from end of plain text
$plaintext_utf8_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);

echo  $plaintext_utf8_dec . "\n";

答案 4 :(得分:1)

所以你已经知道了salting和hashing,但是你也可以“拉伸”你的密码,而不是只是对每个密码进行一次哈希,你可以哈希几千次。这将减缓暴力攻击并延长哈希算法的生命周期。有趣的是,它通过故意减慢你的服务器...

我建议的是编写自己的自定义哈希函数。首先,你在密码中添加salt,然后选择一个哈希算法(比如sha512,或者可能是为了这个目的而设计效率低的新算法)并将其哈希(例如10,000次),然后将其存储在数据库中。正如您所知,当用户登录而不是反转哈希时,您只需通过相同的算法运行他们的输入,看看它是否匹配。

编写自己的哈希函数的好处在于,当更新哈希算法时,因为旧的哈希算法已经变得容易受到暴力攻击,所有你需要做的就是添加到你的哈希函数,获取旧哈希的结果算法,重新盐化它,并使用您的新算法再次散列它。您可以使用当时被认为是安全的任何哈希算法。然后,您可以使用哈希函数的新部分简单地重新散列已存储在数据库中的每个密码,从而确保向后兼容性。根据您拥有的用户数量和服务器的速度,执行此更新可能只需要几秒钟。

但是,仍有一个漏洞。如果黑客拥有您的数据库的旧副本并且破解了它,他仍然知道尚未更改其密码的任何用户的密码。解决此问题的唯一方法是要求您的用户偶尔更改其密码,这些密码可能适用于您的网站,也可能不适合您的网站,具体取决于其中包含的信息的性质。一些安全专业人士建议用户只有在密码被破坏时才更改密码,因为如果系统管理密码太困难,他们就会开始做一些不安全的事情,例如将密码保存在键盘下面,这对于某些组织来说是一个比永远不会更改密码的用户。如果您的网站是论坛或评论网站或具有此类性质的网站,您应该考虑用户遭受黑客攻击会损失多少用户,将数据恢复到遭受黑客入侵之前的状态是多么容易,以及如果您的密码政策太烦人,他们会认为您的网站值得更新密码。

一种可能的哈希函数:

function the_awesomest_hash($password)
{
    $salt1 = "awesomesalt!";
    $password = $salt1 . $password;
    for($i = 0; $i < 10000; $i++)
    {
        $password = hash('sha512', $password);
    }
    // Some time has passed, and you have added to your hash function
    $salt2 = "niftysalt!";
    $password = $salt2 . $password;
    for($i = 0; $i < 10000; $i++)
    {
        $password = hash('futuresuperhash1024', $password);
    }
    return $password;
}

现在,为了更新数据库中已有的所有密码,您可以通过此函数运行它们:

function update_hash($password)
{
    // This is the last part of your the_awesomest_hash() function
    $salt2 = "niftysalt!";
    $password = $salt2 . $password;
    for($i = 0; $i < 10000; $i++)
    {
        $password = hash('futuresuperhash1024', $password);
    }
    return $password;
}

我喜欢编写自己的哈希函数,因为在更新它们时,更容易跟踪到底发生了什么。

答案 5 :(得分:-1)

到目前为止,我知道保存密码的最佳方法是使用joomla中使用的salted hash。你还可以添加额外的密钥到md5哈希以及传统的base64。我写了一个类似的脚本,试图找到它但不能。

Joomla使用盐渍md5密码。取你给出的哈希密码:30590cccd0c7fd813ffc724591aea603:WDmIt53GwY2X7TvMqDXaMWJ1mrdZ1sKb

如果您的密码是'密码',那么: md5('passwordWDmIt53GwY2X7TvMqDXaMWJ1mrdZ1sKb')= 30590cccd0c7fd813ffc724591aea603

所以,拿你的密码。生成随机的32个字符的字符串。计算与随机字符串连接的密码的md5。存储md5结果加上a:加上数据库中随机的32个字符串。