加盐用于安全加密的密钥 Cocoa?
我正在阅读有关如何对密钥加盐以确保加密安全的教程,但没能充分理解它。我对密码学了解不多,需要一些帮助。我正在使用 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;
}
如果有人可以帮助我,并向我展示如何实现盐,那就会太棒了!再次感谢!
I was reading a tutorial on how to salt a key to make your encryption secure, but couldn't make much of it. I don't know a lot about cryptography, and need some help. I am using commoncrypto to encrypt files, and am done, except for the fact that it isn't secure...
This is what I have:
- (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;
}
If someone can help me out, and show me exactly how I would implement salt, that would be great! Thanks again!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
dYhG9pQ1qyJfIxfs2guVoU7jr9oniR2GF8MbC9mi
加密文本
,又称混淆文本,试图使其难以辨认。这就是你在密码学中玩的游戏。为此,您可以使用确定性函数。
加密涉及使用一个带有两个参数的函数:通常是一个短的固定长度参数和一个任意长度的参数。它产生与第二个参数大小相同的输出。
我们称第一个参数为key;第二,明文;和输出,密文。
这将有一个反函数(有时是相同的),它具有相同的签名,但给定密文将返回明文(当使用相同的密钥时)。
显然,好的加密函数的特性是,在不知道密钥的情况下,不容易从密文中确定明文。更好的方法会产生与随机噪声无法区分的密文。
散列涉及一种函数,该函数采用任意大小的一个参数,并返回固定大小的输出。这里的目标是,给定一个特定的输出,应该很难找到任何会产生它的输入。它是一个单向函数,因此没有反函数。同样,如果输出看起来完全随机,那就太棒了。
确定性的问题
上面的内容都很好,但是在设计这些函数的实现时,我们的最终目标是不可解读性,但存在一个问题:它们是确定性的!这不利于产生随机输出。
虽然我们可以设计出仍然产生看起来非常随机的输出的函数,但由于混淆和扩散,它们给定相同的输入,仍然会给出相同的输出。我们都需要这个,但又不喜欢它。我们永远无法用非确定性的加密系统破译任何东西,但我们不喜欢可重复的结果!可重复意味着可分析...可确定(呵呵)。我们不希望敌人看到相同的两个密文并知道它们来自相同的输入,这将为他们提供信息(以及破解加密系统的有用技术,例如 彩虹表)。我们如何解决这个问题呢?
输入:在开始处插入一些随机的内容。
这就是我们战胜它的方法!每次使用我们的函数时,我们都会在实际输入中添加一些唯一随机输入(或者有时更好,附加)。这使得即使我们给出相同的输入,我们的确定性函数也会给出不同的输出。我们发送唯一的随机输入(散列时,称为盐;加密时,称为初始化向量,或 IV)以及密文。敌人是否看到这个随机输入并不重要;重要的是。我们的真实输入已经受到我们的密钥(或单向哈希)的保护。我们真正担心的是我们的输出始终不同,因此无法分析;我们已经实现了这一点。
我如何应用这些知识?
好的。因此,每个人都有自己的应用程序,并在其中使用加密系统来保护应用程序的某些部分。
现在我们不想用密码系统重新发明轮子(最糟糕的想法),所以一些真正知识渊博的人已经想出了可以构建任何系统的好组件(即 AES、RSA、SHA2、HMAC、 PBKDF2)。但如果每个人都使用相同的组件,那么仍然会引入一些可重复性!幸运的是,如果每个人在自己的密码系统中使用不同的密钥和独特的初始随机输入,那么他们应该没问题。
已经够了!谈谈实施!
我们来谈谈你的例子。您想做一些简单的加密。我们想要什么?好吧,A)我们想要一个好的随机密钥,B)我们想要一个好的随机 IV。这将使我们的密文尽可能安全。我可以看到您没有提供随机 IV - 最好这样做。从[安全/加密]随机源获取一些字节,然后将其放入。您可以将这些字节与密文一起存储/发送。是的,这确实意味着密文的长度比明文大,但这是一个很小的代价。
现在那把钥匙呢?有时我们想要一个容易记住的密钥(例如密码),而不是计算机喜欢的一个漂亮的随机密钥(如果您可以选择仅使用随机密钥 - 那就这样做)。我们能达成妥协吗?是的!我们是否应该将 ASCII 字符密码转换为字节来制作密钥?天啊不!
ASCII 字符根本不是很随机(哎呀,它们通常只使用 8 位中的大约 6-7 位)。如果有的话,我们想要做的就是让我们的密钥至少看起来是随机的。我们该怎么做?嗯,散列恰好对此有好处。如果我们想重复使用我们的密钥怎么办?我们将再次获得相同的哈希值...可重复性!
幸运的是,我们使用另一种形式的独特随机输入——盐。制作一个独特的随机盐,并将其附加到您的密钥中。然后散列它。然后使用字节来加密您的数据。发送时添加盐和 IV 以及密文,最后您应该能够解密。
快完成了吗?不!您看到我在上一段中描述的哈希解决方案了吗? 真正的密码学家会称其为业余。你会相信一个业余的系统吗?不!我要讨论为什么它是业余的吗?不,因为你不需要知道。基本上,它只是不够真正超级混乱,不符合他们的喜好。
您需要知道的是,他们已经针对这个问题设计了一个更好的系统。它称为 PBKDF2。找到它的实现,然后[学习]使用它。
现在您的所有数据都是安全的。
dYhG9pQ1qyJfIxfs2guVoU7jr9oniR2GF8MbC9mi
Enciphering text
AKA jumbling it around, to try and make it indecipherable. This is the game you play in cryptography. To do this, you use deterministic functions.
Encrypting involves using a function which takes two parameters: usually a short, fixed length one, and an arbitrary length one. It produces output the same size as the second parameter.
We call the first parameter the key; the second, the plaintext; and the output, the ciphertext.
This will have an inverse function (which is sometimes the same one), which has the same signature, but given instead ciphertext will return the plaintext (when using the same key).
Obviously the property of a good encryption function is that the plaintext is not easily determinable from the ciphertext, without knowing the key. An even better one will produce ciphertext that is indistinguishable from random noise.
Hashing involves a function which takes one parameter, of arbitrary size, and returns an output of fixed size. Here, the goal is that given a particular output, it should be hard to find any input that will produce it. It is a one-way function, so it has no inverse. Again, it's awesome if the output looks completely random.
The problem with determinism
The above is all very well and good, but we have a problem with our ultimate goals of indecipherability when designing implementations of these functions: they're deterministic! That's no good for producing random output.
While we can design functions that still produce very random-looking output, thanks to confusion and diffusion, they're still going to give the same output given the same input. We both need this, and don't like it. We would never be able to decipher anything with a non-deterministic crypto system, but we don't like repeatable results! Repeatable means analysable... determinable (huh.). We don't want the enemy to see the same two ciphertexts and know that they came from the same input, that would be giving them information (and useful techniques for breaking crypto-systems, like rainbow tables). How do we solve this problem?
Enter: some random stuff inserted at the start.
That's how we defeat it! We prepend (or sometimes better, append), some unique random input with our actual input, everytime we use our functions. This makes our deterministic functions give different output even when we give the same input. We send the unique random input (when hashing, called a salt; when encrypting, called an Initialisation Vector, or IV) along with the ciphertext. It's not important whether the enemy sees this random input; our real input is already protected by our key (or the one-way hash). All that we were actually worried about is that our output is different all the time, so that it's non-analysable; and we've achieved this.
How do I apply this knowledge?
OK. So everybody has their app, and within it their cryptosystem protecting parts of the app.
Now we don't want to go reinventing the wheel with cryptosystems (Worst. Idea. Ever.), so some really knowledgable people have already come up with good components that can build any system (i.e, AES, RSA, SHA2, HMAC, PBKDF2). But if everyone is using the same components, then that still introduces some repeatability! Fortunately, if everyone uses different keys, and unique initial random inputs, in their own cryptosytem, they should be fine.
Enough already! Talk about implementation!
Let's talk about your example. You're wanting to do some simple encryption. What do we want for that? Well, A) we want a good random key, and B) we want a good random IV. This will make our ciphertext as secure as it can get. I can see you haven't supplied a random IV - it's better practice to do so. Get some bytes from a [secure/crypto]-random source, and chuck it in. You store/send those bytes along with the ciphertext. Yes, this does mean that the ciphertext is a constant length bigger than the plaintext, but it's a small price to pay.
Now what about that key? Sometimes we want a remember-able key (like.. a password), rather than a nice random one that computers like (if you have the option to just use a random key - do that instead). Can we get a compromise? Yes! Should we translate ASCII character passwords into bytes to make the key? HELL NO!
ASCII characters aren't very random at all (heck, they generally only use about 6-7 bits out of 8). If anything, what we want to do is make our key at least look random. How do we do this? Well, hashing happens to be good for this. What if we want to reuse our key? We'll get the same hash... repeatability again!
Luckily, we use the other form of unique random input - a salt. Make a unique random salt, and append that to your key. Then hash it. Then use the bytes to encrypt your data. Add the salt AND the IV along with your ciphertext when you send it, and you should be able to decrypt on the end.
Almost done? NO! You see the hashing solution I described in the paragraph above? Real cryptographers would call it amateurish. Would you trust a system which is amateurish? No! Am I going to discuss why it's amateurish? No, 'cus you don't need to know. Basically, it's just not REALLY-SUPER-SCRAMBLED enough for their liking.
What you need to know is that they've already devised a better system for this very problem. It's called PBKDF2. Find an implementation of it, and [learn to] use that instead.
Now all your data is secure.
加盐仅涉及在输入密钥的末尾添加一个随机字符串。
因此,生成一定长度的随机字符串:
在 cocoa 中生成随机字母数字字符串
然后只需将其附加到密钥中即可:
除非在您阅读的文章中以不同的方式使用盐,否则这应该是正确的。
Salting just involves adding a random string to the end of the input key.
So generate a random string of some length:
Generate a random alphanumeric string in cocoa
And then just append it to the key using:
Unless salt is being used in a different way in the article you read this should be correct.
通常如何使用随机盐:
@Ca1icoJack 说的完全正确,您所要做的就是生成一些随机数据并将其附加到末尾。不过,数据通常是二进制的,而不是字母数字的。然后,盐会以未加密的方式与每个哈希密码一起存储,并与用户的明文密码连接起来,以便在每次输入密码时检查哈希值。
如果 SALT 以未加密的方式存储在哈希密码旁边,那么它还有什么意义?
假设有人可以访问您的哈希密码。人类选择的密码很容易通过彩虹表被发现。添加哈希意味着彩虹表不仅需要包含具有人们可能使用的字母数字字符的任何可能组合的值,而且还需要包含随机二进制盐,这在此时是相当不切实际的。因此,基本上添加盐意味着有权访问散列密码和盐的暴力攻击者需要弄清楚盐如何与密码连接(通常是之前或之后)和 单独暴力破解每个密码,因为现成的彩虹表不包含任何随机二进制数据。
编辑:但我说的是加密的,而不是散列的:
好吧,我没有仔细阅读,忽略我。有人将不得不暴力破解密钥,无论它是否经过加密。我能看到的唯一明显的好处是,正如该文章所说,避免使用相同的密钥(从用户的角度)来加密相同的数据产生相同的结果。由于不同的原因,这在加密中很有用(加密的消息往往有重复的部分,可以用来帮助更容易地破解加密),但评论者正确地指出,在这种情况下它通常不被称为盐。
无论如何,技巧是连接盐,并将其与每一位加密数据一起存储。
How a random salt is normally used:
@Ca1icoJack is completely correct in saying that all you have to do is generate some random data and append it to the end. The data is usually binary as opposed to alphanumeric though. The salt is then stored unencrypted alongside each hashed password, and gets concatenated with the user's plaintext password in order to check the hash every time the password gets entered.
What the is the point of a SALT if it's stored unencrypted next to the hashed password?
Suppose someone gets access to your hashed passwords. Human chosen passwords are fairly vulnerable to being discovered via rainbow tables. Adding a hash means the rainbow table needs to not only include the values having any possible combination of alphanumeric characters a person might use, but also the random binary salt, which is fairly impractical at this point in time. So, basically adding a salt means that a brute force attacker who has access to both the hashed password and the salt needs to both figure how how the salt was concatenated to the password (before or after, normally) and brute force each password individually, since readily available rainbow tables don't include any random binary data.
Edit: But I said encrypted, not hashed:
Okay, I didn't read very carefully, ignore me. Someone is going to have to brute-force the key whether it's salted or not with encryption. The only discernable benefit I can see would be as that article says to avoid having the same key (from the user's perspective) used to encrypt the same data produce the same result. That is useful in encryption for different reasons (encrypted messages tend to have repeating parts which could be used to help break the encryption more easily) but the commenters are correct in noting that it is normally not called an salt in this instance.
Regardless, the trick is to concatenate the salt, and store it alongside each bit of encrypted data.