6

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!

  • 3
    Salting a key is very strange terminology. Salts are usually used with hashing. An IV takes a similar role to a salt in symmetric encryption. Can you link that tutorial? – CodesInChaos Sep 05 '11 at 17:40
  • Here you go: http://robnapier.net/blog/ –  Sep 05 '11 at 17:43
  • 2
    He's using a salt in his key derivation function(which is related to hashing). So the salt is only used in getting the key from a password. – CodesInChaos Sep 05 '11 at 17:50
  • What would I add though, to the code above to make the key secure? Because as of now, it is not at all secure. The ciphertext can not be the same if I encrypt the same exact data with the same exact key over and over again. –  Sep 05 '11 at 17:59
  • 2
    That would be an IV, as was just stated by @CodeInChaos. – President James K. Polk Sep 05 '11 at 18:01
  • Can you please show me how to implement both the IV and Salt in my encryption? I read the post by Rob Napier, and could not get it working. –  Sep 05 '11 at 18:16
  • I'm not sure if the IV is needed when you already salt your key derivation. The salt already makes sure a key isn't reused. So I don't see how an IV would improve security. – CodesInChaos Sep 05 '11 at 18:25
  • That makes sense, you can always work your way around the initialization vector, but the salt is a must. But do you think you can give me a hand in how to implement the salt? –  Sep 05 '11 at 18:34
  • Rob Napier has a high level framework so you don't have to (and shouldn't) implement it yourself [RNCryptor](https://github.com/rnapier/RNCryptor). – jbtule Feb 25 '13 at 14:27

3 Answers3

15

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.

Ivo
  • 5,378
  • 2
  • 18
  • 18
  • Thanks for this information, though you didn't need to explain encryption from the very beginning. –  Sep 24 '11 at 15:24
  • 1
    @TwoDumpling I like to start from the beginning. :) The IV should be a set of random bytes that are generated for every message. It seems the library provides a way to generate an IV, which should probably be secure - `NSData* iv = [FBEncryptorAES generateIv];` You generate a new IV for every new message you encrypt - and package the IV along with the encrypted message. The decryption function takes the same IV in. It is important for the IV to be random, and unique for each message; it does not need to be secret. – Ivo Sep 24 '11 at 16:58
  • That library (FBEncryptor) doesn't seem to deal with PBE- Password-Based Encryption (A.K.A, generating a secure key from a password). But yes, the same ideas happen with a salt. Either you can be happy with using a plain ascii key, or do some hashing on it yourself, or find another library which provides the functions to spit out a good secure binary key from an ascii one. – Ivo Sep 24 '11 at 17:16
  • Thanks a lot for taking the time to explain it. Encryption principles seems a lot more clear to me now. – moxy Oct 14 '12 at 16:13
  • Thank you for the education it is a very complex domain. – Klajd Deda Feb 05 '16 at 13:47
1

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:

NSString *saltedKey = [key stringByAppendingString:salt];

Unless salt is being used in a different way in the article you read this should be correct.

Community
  • 1
  • 1
tgt
  • 1,308
  • 1
  • 10
  • 16
  • First off, I don't think it's that simple. Second, then wouldn't the user have to enter the salted key back in, to decrypt the ciphertext? But the user wouldn't know the salt because it was generated 'secretly,' which is sort of the whole point. The user should only enter the key itself, which should be salted. –  Sep 19 '11 at 22:08
  • You generate the salt and then store it along with the salted, hashed password. When the user logs in just get the salt and repeat the process of appending the salt and encrypting it to check its the same. – tgt Sep 22 '11 at 12:34
  • Yes but the key is data not a string. The password is the string. I shouldn't be appending an alphanumeric string to a piece of data. Are you telling me I should append the random string to the 'password' which then goes through the conversion process into a key? –  Dec 24 '11 at 19:57
1

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.

Kevin Stricker
  • 17,178
  • 5
  • 45
  • 71
  • Thanks for this information. I am confused however, on how to implement the salt. Would you be able to provide some code or links to a library I could use? –  Sep 20 '11 at 22:18
  • That blog post you linked to seems to do a reasonable job. What part are you having trouble with exactly? – Kevin Stricker Sep 20 '11 at 22:49