【问题标题】:Salt a key for secure encryption Cocoa?为安全加密 Cocoa 加盐密钥?
【发布时间】:2011-11-10 18:57:21
【问题描述】:

我正在阅读有关如何对密钥进行加盐以确保加密安全的教程,但无法充分利用它。我对密码学知之甚少,需要一些帮助。我正在使用 commoncrypto 来加密文件,并且已经完成,除了它不安全的事实......

这就是我所拥有的:

- (NSData *)AES256EncryptWithKey:(NSString *)key
{
   // 'key' should be 32 bytes for AES256, will be null-padded otherwise
   char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
   bzero( keyPtr, sizeof( keyPtr ) ); // fill with zeroes (for padding)

    NSLog(@"You are encrypting something...");

   // fetch key data
   [key getCString:keyPtr maxLength:sizeof( keyPtr ) encoding:NSUTF8StringEncoding];

   NSUInteger dataLength = [self length];

   //See the doc: For block ciphers, the output size will always be less than or 
   //equal to the input size plus the size of one block.
   //That's why we need to add the size of one block here
   size_t bufferSize = dataLength + kCCBlockSizeAES128;
   void *buffer = malloc( bufferSize );

   size_t numBytesEncrypted = 0;
   CCCryptorStatus cryptStatus = CCCrypt( kCCEncrypt, kCCAlgorithmAES128,     kCCOptionPKCS7Padding,
                                      keyPtr, kCCKeySizeAES256,
                                      NULL /* initialization vector (optional) */,
                                      [self bytes], dataLength, /* input */
                                      buffer, bufferSize, /* output */
                                      &numBytesEncrypted );
   if( cryptStatus == kCCSuccess )
   {
      //the returned NSData takes ownership of the buffer and will free it on deallocation
  return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];

   }

   free( buffer ); //free the buffer
   return nil;
}

如果有人可以帮助我,并确切地告诉我我将如何实施盐,那就太好了!再次感谢!

【问题讨论】:

  • Salting a key 是一个非常奇怪的术语。盐通常与散列一起使用。 IV 在对称加密中的作用类似于盐。你能链接那个教程吗?
  • 他在他的密钥派生函数中使用了盐(这与散列有关)。所以盐只用于从密码中获取密钥。
  • 我会在上面的代码中添加什么以确保密钥安全?因为到目前为止,它根本不安全。如果我一遍又一遍地用相同的确切密钥加密相同的确切数据,密文就不可能相同。
  • 这将是一个 IV,正如 @CodeInChaos 刚刚所说的那样。

标签: cocoa encryption key aes salt


【解决方案1】:

dYhG9pQ1qyJfIxfs2guVoU7jr9oniR2GF8MbC9mi

加密文本

AKA 把它弄得乱七八糟,试图让它难以辨认。这是你在密码学中玩的游戏。为此,您需要使用确定性函数。

加密涉及使用一个接受两个参数的函数:通常是一个短的、固定长度的参数和一个任意长度的参数。它产生与第二个参数相同大小的输出。

我们称第一个参数为key;第二,明文;和输出,密文。

这将有一个反函数(有时是相同的),它具有相同的签名,但给出的密文将返回明文(当使用相同的密钥时)。

显然,一个好的加密函数的属性是明文不容易从密文中确定,而不知道密钥。更好的方法会产生与随机噪声无法区分的密文。

Hashing 涉及一个函数,它接受一个任意大小的参数,并返回一个固定大小的输出。在这里,目标是给定一个特定的输出,应该很难找到会产生它的任何输入。它是一个单向函数,所以它没有逆函数。同样,如果输出看起来完全随机,那就太棒了。

决定论的问题

以上内容都非常好,但是在设计这些功能的实现时,我们的最终目标是难以理解的问题:它们是确定性的!这不利于产生随机输出。

虽然我们可以设计仍然产生看起来非常随机的输出的函数,但感谢confusion and diffusion,它们仍然会在相同输入的情况下提供相同的输出。我们都需要这个,但不喜欢它。我们永远无法使用非确定性加密系统破译任何东西,但我们不喜欢可重复的结果!可重复意味着可分析……可确定(呵呵)。我们不希望敌人看到相同的两个密文并知道它们来自相同的输入,这将为他们提供信息(以及破解密码系统的有用技术,如rainbow tables)。我们如何解决这个问题?

输入:在开头插入一些随机的东西。

我们就是这样打败它的!每次我们使用我们的函数时,我们都会在实际输入中添加(或者有时更好地添加)一些独特随机输入。这使得即使我们给出相同的输入,我们的确定性函数也会给出不同的输出。我们将唯一的随机输入(在散列时称为盐;在加密时称为初始化向量或 IV)与密文一起发送。敌人是否看到这个随机输入并不重要;我们的真实输入已经受到我们的密钥(或单向哈希)的保护。我们真正担心的是我们的输出总是不同的,所以它是不可分析的;我们已经做到了。

我如何应用这些知识?

好的。因此,每个人都有自己的应用程序,并在其中拥有保护应用程序部分的密码系统。

现在我们不想用密码系统重新发明轮子(最糟糕的想法。曾经。),所以一些真正知识渊博的人已经想出了可以构建任何系统的优秀组件(即 AES、RSA、SHA2 , HMAC, PBKDF2)。但是,如果每个人都使用相同的组件,那么仍然会引入一些可重复性!幸运的是,如果每个人在他们自己的密码系统中使用不同的密钥和唯一的初始随机输入,他们应该没问题。

已经够了!谈实施!

让我们谈谈你的例子。你想做一些简单的加密。我们想要什么?好吧,A)我们想要一个好的随机密钥,B)我们想要一个好的随机 IV。这将使我们的密文尽可能安全。我可以看到您没有提供随机 IV - 这样做是更好的做法。从 [安全/加密] 随机源获取一些字节,然后将其放入。您将这些字节与密文一起存储/发送。是的,这确实意味着密文的长度比明文大,但这是一个很小的代价。

那么那把钥匙呢?有时我们想要一个可记住的密钥(例如密码),而不是计算机喜欢的一个很好的随机密钥(如果您可以选择只使用随机密钥 - 改为这样做)。我们可以妥协吗?是的!我们是否应该将 ASCII 字符密码转换为字节来生成密钥?不!

ASCII 字符根本不是很随机(哎呀,它们通常只使用大约 8 位中的 6-7 位)。如果有的话,我们想要做的就是让我们的密钥至少看起来是随机的。我们如何做到这一点?好吧,散列恰好对此有好处。如果我们想重用我们的密钥怎么办?我们将再次获得相同的哈希...可重复性!

幸运的是,我们使用了另一种形式的唯一随机输入——盐。制作一个唯一的随机盐,并将其附加到您的密钥中。然后哈希它。然后使用字节来加密您的数据。发送时添加盐和IV以及您的密文,您应该能够在最后解密。

快完成了?不!您看到我在上一段中描述的散列解决方案了吗? 真正的密码学家会称之为业余。你会相信一个业余的系统吗?不!我要讨论为什么它是业余的吗?不,因为你不需要知道。基本上,这还不够他们喜欢的真正超级加扰。

您需要知道的是,他们已经为这个问题设计了一个更好的系统。它被称为PBKDF2。找到它的实现,然后[学习] 使用它。

现在您的所有数据都是安全的。

【讨论】:

  • 感谢您提供此信息,尽管您不需要从一开始就解释加密。
  • @TwoDumpling 我喜欢从头开始。 :) IV 应该是为每条消息生成的一组随机字节。似乎该库提供了一种生成 IV 的方法,这可能应该是安全的 - NSData* iv = [FBEncryptorAES generateIv]; 您为每条加密的新消息生成一个新的 IV - 并将 IV 与加密的消息一起打包。解密函数采用相同的 IV。IV 必须是随机的,并且对于每条消息都是唯一的,这一点很重要;它不需要保密。
  • 该库 (FBEncryptor) 似乎不处理 PBE-基于密码的加密(A.K.A,从密码生成安全密钥)。但是,是的,同样的想法也发生在盐上。您可以对使用普通的 ascii 密钥感到满意,或者自己对其进行一些哈希处理,或者找到另一个库,该库提供了从 ascii 密钥中提取出良好安全二进制密钥的功能。
  • 非常感谢您花时间解释它。加密原理现在对我来说似乎更清楚了。
  • 感谢您的教育,这是一个非常复杂的领域。
【解决方案2】:

加盐只是在输入键的末尾添加一个随机字符串。

所以生成一个一定长度的随机字符串:

Generate a random alphanumeric string in cocoa

然后只需使用以下命令将其附加到密钥:

NSString *saltedKey = [key stringByAppendingString:salt];

除非在您阅读的文章中以不同的方式使用盐,否则这应该是正确的。

【讨论】:

  • 首先,我认为没有那么简单。其次,那么用户是否不必重新输入加盐密钥来解密密文?但是用户不会知道盐,因为它是“秘密”生成的,这就是重点。用户应该只输入密钥本身,这应该是加盐的。
  • 您生成盐,然后将其与盐化的散列密码一起存储。当用户登录时,只需获取 salt 并重复添加 salt 并对其进行加密以检查其是否相同的过程。
  • 是的,但关键是数据而不是字符串。密码是字符串。我不应该将字母数字字符串附加到一条数据。你是在告诉我我应该将随机字符串附加到“密码”,然后通过转换过程变成密钥?
【解决方案3】:

随机盐的正常使用方式:

@Ca1icoJack 说您所要做的就是生成一些随机数据并将其附加到末尾是完全正确的。数据通常是二进制而不是字母数字。然后将盐与每个散列密码一起未加密存储,并与用户的明文密码连接,以便在每次输入密码时检查散列。

如果 SALT 未加密地存储在散列密码旁边,那么它的意义何在?

假设有人可以访问您的散列密码。人工选择的密码很容易通过彩虹表被发现。添加哈希意味着彩虹表不仅需要包含具有人们可能使用的字母数字字符的任何可能组合的值,还需要包含随机二进制盐,这在此时是相当不切实际的。因此,基本上添加盐意味着可以访问散列密码和盐的蛮力攻击者都需要弄清楚盐是如何连接到密码的(通常在之前或之后) 暴力破解每个密码,因为现成的彩虹表不包含任何随机二进制数据。

编辑:但我说的是加密的,而不是散列的:

好吧,我没看仔细,别理我。有人将不得不暴力破解密钥,无论它是否经过加密。我能看到的唯一可辨别的好处是,正如那篇文章所说,避免使用相同的密钥(从用户的角度来看)用于加密相同的数据产生相同的结果。由于不同的原因,这在加密中很有用(加密的消息往往有重复的部分,可以用来帮助更容易地破解加密),但评论者正确地指出,在这种情况下它通常不被称为盐。

无论如何,技巧将盐连接起来,并将其与每一位加密数据一起存储。

【讨论】:

  • 感谢您提供此信息。但是,我对如何实施盐感到困惑。您能否提供一些我可以使用的库的代码或链接?
  • 您链接到的那篇博文似乎做得很合理。你到底在哪方面有问题?
猜你喜欢
  • 2012-07-05
  • 2017-08-11
  • 1970-01-01
  • 2011-06-29
  • 2014-10-18
  • 2016-02-19
  • 2015-07-04
  • 2013-08-23
相关资源
最近更新 更多