基于盐密钥加密/解密字符串


Encrypt/Decrypt a string based on a salt key

我想知道是否有可能在我的数据库中保存一个加密的文本字段,并有能力根据盐和授权密码解密这段文本?

例如:

$Salt = $_POST['Salt']; 
$Password = $Query_Results['Password'];
if ($salt == $Stored_Salt AND $Authorized_Password == $Password){
  //Perform a decryption of the stored results
   echo $Decrypted_TextField;
}

我正在创建一个完全加密/编码的数据库。除了标识符的整数字段外,没有任何内容是纯文本。其他一切都将被加密/编码…许多字段将使用单向加密,但有些字段需要容纳双向加密类型。

我不能在数据库中存放未加密的文本。所有东西在存储前都需要加密。但是这个方法对我来说是一个未知的过程。所以我想知道如果我能得到一些帮助在哪里开始

这听起来像你可能想做一些更多的背景加密一般,和DB加密选项具体(你没有提到数据存储,但有MySQL和Postgres选项完全加密)。一般来说,"自己滚动"几乎总是一个坏主意,不幸的是,在mcrypt()和openssl_*()函数之间,坦率地说,向新手提供了太多的选项(例如将EBC和CBC作为同样有效的选项)。虽然此线程https://security.stackexchange.com/questions/18197/why-shouldnt-we-roll-our-own主要讨论创建"新颖"加密原语的无用性,但该原则也适用于实现应用程序和数据库级加密的幼稚尝试。

作为一个实际问题,您可能要处理的最具挑战性的事情是密码/密钥管理问题。下面的代码将所有责任都放在客户端(发送方)身上——除非您保存提交的密码(这有点违背了整个目的),否则如果用户忘记或将来无法提供密码,数据库中的加密数据将不可恢复。(是的,如果你真的想要沿着牦牛剃须的路径,有多密钥信封加密的选项)。

如果您将密钥/密码存储在服务器端,那么您充其量只是在对手的路径上设置了一个小障碍:如果她能够设法读取您的密钥文件,她就可以检索数据。但最糟糕的是,通过在本地保存密码,您会给用户一种错误的安全感,如果这是财务、健康或其他受保护的信息,您和您的组织将承担该责任的负担。

最后,这里有一个成熟的库:http://phpseclib.sourceforge.net/crypt/examples.html,但在我看来,它为新手用户提供了太多的选项(例如,请参阅代码生成器中的默认EBC模式)。对于密码散列,请仔细查看phpPass库:http://www.openwall.com/phpass/.

话虽如此,这里是一个简单的双向,相当强大的加密的工作开始,随机生成的初始化向量和盐,以及256位AES对称(例如,非公钥)密码。在OSX Lion上测试;CentOS/RedHat 6 .

祝你好运!

//$message = escapeshellarg( $_POST['message'] );
$message = 'This is my very secret data SSN# 009-68-1234';  
// Set to some reasonable limit for DB.
// Make sure to size DB column +60 chars 
$max_msg_size = 1000;
$message = substr($message, 0, $max_msg_size);
// User's password (swap for actual form post)
//$password = escapeshellarg( $_POST['password'] );
$password = 'opensesame';
// Salt to add entropy to users' supplied passwords
// Make sure to add complexity/length requirements to users passwords!
// Note: This does not need to be kept secret
$salt = sha1(mt_rand());
// Initialization Vector, randomly generated and saved each time
// Note: This does not need to be kept secret
$iv = substr(sha1(mt_rand()), 0, 16);
echo "'n Password: $password 'n Message: $message 'n Salt: $salt 'n IV: $iv'n";
$encrypted = openssl_encrypt(
  "$message", 'aes-256-cbc', "$salt:$password", null, $iv
);
$msg_bundle = "$salt:$iv:$encrypted";
echo " Encrypted bundle = $msg_bundle 'n'n ";
// Save it... (make sure to use bind variables/prepared statements!)
/* db_write( "insert into sensitive_table encrypted_msg values (:msg_bundle)",
    $msg_bundle ); */

现在检索它:

//  Retrieve from DB... 
//$password = escapeshellarg( $_POST['password'] );
$password = 'opensesame';
// Swap with actual db retrieval code here
//$saved_bundle = db_read( "select encrypted_msg from sensitive_table" );
$saved_bundle = $msg_bundle;
// Parse iv and encrypted string segments
$components = explode( ':', $saved_bundle );;
var_dump($components);
$salt          = $components[0];
$iv            = $components[1];
$encrypted_msg = $components[2];
$decrypted_msg = openssl_decrypt(
  "$encrypted_msg", 'aes-256-cbc', "$salt:$password", null, $iv
);
if ( $decrypted_msg === false ) {
  die("Unable to decrypt message! (check password) 'n");
}
$msg = substr( $decrypted_msg, 41 );
echo "'n Decrypted message: $decrypted_msg 'n";
样本输出:

 Password: opensesame 
 Message: This is my very secret data SSN# 009-68-1234 
 Salt: 3f12ce187d5c5bcc3b0d5acf1e76fad8b684ff37 
 IV: 00c1d3b4c6a6f4c3 
 Encrypted bundle = 3f12ce187d5c5bcc3b0d5acf1e76fad8b684ff37:00c1d3b4c6a6f4c3:KB6k+GlM+0EHbETUgEe8Lck0nF5qBz+51wc5LtmS4XMOm0Pfyyr2PIXMVEyzs/41 
 array(3) {
  [0]=>
  string(40) "3f12ce187d5c5bcc3b0d5acf1e76fad8b684ff37"
  [1]=>
  string(16) "00c1d3b4c6a6f4c3"
  [2]=>
  string(64) "KB6k+GlM+0EHbETUgEe8Lck0nF5qBz+51wc5LtmS4XMOm0Pfyyr2PIXMVEyzs/41"
}
 Decrypted message: This is my very secret data SSN# 009-68-1234 

不是一个完整的答案,而是一个关于盐的工作原理的扩展,因为注释太长了。

salt不应该被当作字符串来比较,它应该是最终用户不需要输入的密码的一部分,但对该用户来说是唯一的。它用于防止一个密码泄露到多个帐户。

假设我们有一个非常简单的系统,Bob的密码是ABCDEF

通过我们的哈希算法传递ABCDEF得到(例如)ED6522687

如果攻击者访问了密码列表,他们只能看到存储的哈希值。

当然,如果Jane也使用相同的密码,她的哈希值也将是ED6522687 -这意味着如果您闯入任何一个帐户(通过暴力破解,社会工程等),您将访问两个帐户,因为您可以看到它们的哈希值匹配。

salt是指在对每个用户唯一且可重复的散列之前对密码进行一些操作。盐应该是可预测的,所以假设鲍勃和简的盐是随机数。

现在,如果你对bob的密码ABCDEF123进行哈希,你会得到一个与Jane的密码ABCDEF456不同的哈希值。

注意,这个并不是的完整解释。其他需要考虑的事项:

    在这种情况下没有随机数这样的东西,只有加密安全的随机数-它们的随机程度是复杂的,与熵和其他有趣的东西有关。
  • 哈希计算的速度是阻碍暴力破解的主要因素——像bcrypt这样的哈希算法被设计成计算成本很高。不像(比如说)SHA2
  • 用户没有理由提交(甚至知道)他们的盐。

另一个通常不被强调的观察…你永远不应该相信你在网上读到的关于这类话题的任何东西——有太多的人没有完全理解(我认为我自己就是其中之一)。因此,请将此作为自己不这样做的理由,而不是如何做的指南。