I have some code that I am using to encrypt and decrypt some strings in an ios application. The code involves the use of CCCrypt. Is there a reliable way to test the validity of a key used without actually storing the key anywhere? From my research it seems as though the only way to come close to telling if the key is valid is by using key lengths and key hashes. Can anyone guide me in the proper direction for this?
Getting to the answer requires a little bit of background about proper encryption. You may know this already, but most people do this wrong so I'm covering it. (If you're encrypting with a password and don't encode at least an HMAC, two salts, and an IV, you're doing it wrong.)
First, you must use an HMAC (see CCHmac()) any time you encrypt with an unauthenticated mode (such as AES-CBC). Otherwise attackers can modify your ciphertext in ways that cause it to decrypt into a different message. See modaes for an example of this attack. An HMAC is a cryptographically secure hash based on a key.
Second, if your are using password-based encryption, you must use a KDF to convert it into a key. The most common is PBKDF2. You cannot just copy password bytes into a key.
Assuming you're using a password this way, you generally generate two keys, one for encryption and one for HMAC.
OK, with those parts in place, you can verify that the password is correct because the HMAC will fail if it isn't. This is how RNCryptor does it.
There are two problems with this simple approach: you have to process the entire file before you can verify the password, and there is no way to detect file corruption vs bad password.
To fix these issues somewhat, you can add a small block of extra data that you HMAC separately. You then verify that small block rather than the whole file. This is basically how aescrypt does it. Specifically, they generate a "real" key for encrypting the entire file, and then encrypt that key with a PBKDF2-generated key and HMAC that separately. Some forms of corruption still look like bad passwords, but it's a little easier to tell them apart this way.
You can store a known value encrypted with the key in your database. validating if the key is correct is then straightforward: you encrypt the known string, and compare it to the encrypted output in the database. If you stick with a single block of data, then you don't have to worry about modes of operation and you can keep it simple.
It is also possible to store a hash of the key, but I would treat the key as a password, and take all the defensive measures you would take in storing a password in your database (e.g. use bcrypt, salt the hash, etc).
If you can't store these values, you can decrypt something where you don't know the actual contents, but perhaps know some properties of the message (e.g. ASCII text, has today's date somewhere in the string, etc) and test the decrypted message for those properties. Then if the decrypted block that doesn't have those properties (e.g. has bytes with MSB set, no instance of the date), you know the key is invalid. There is a possibility of a false positive in this case, but chances are very low.
Generally I agree with Peter Elliott. However, I have couple of additional comments:
a) If keys were randomly generated then storing hashes of the keys are safe
b) You can always attach to encrypted message (if you can control that) a hash of orginial message. In such case, you can decrypt message, get hash of decrypted message and compare it with the hash of original message. If they are eqaul then correct key was used for decryption.
Related
I want to store a secret key ("abc123") that I will use in the header of my REST API requests. My server will check this secret key. If it matches "abc123", then allow the request to be made.
I'm thinking about a simple solution like:
let secret = "abc123"
But are there going to be any downfalls to this?
Crazy as it sounds, this is probably the best solution. Everything else is more complicated, but not much more secure. Any fancy obfuscation techniques you use are just going to be reverse engineered almost as quickly as they'll find this key. But this static key solution, while wildly insecure, is nearly as secure than the other solutions while imposing nearly no extra complexity. I love it.
It will be broken almost immediately, but so will all the other solutions. So keep it simple.
The one thing that you really want to do here is use HTTPS and pin your certificates. And I'd pick a long, random key that isn't a word. Ideally, it should be a completely random string of bytes, stored as raw values (not characters) so that it doesn't stand out so obviously in your binary. If you want to get crazy, apply a SHA256 to it before sending it (so the actual key never shows up in your binary). Again, this is trivial to break, but it's easy, and won't waste a lot of time developing.
It is unlikely that any effort longer than an hour will be worth the trouble to implement this feature. If you want lots more on the topic, see Secure https encryption for iPhone app to webpage and its links.
By hardcoding the string in your app, it's possible for attackers to decrypt your binary (via tools like dumpdecrypt) and get your string without much trouble (a simple hexdump would include any strings in your app).
There are a few workarounds for this. You could implement an endpoint on your REST API which returns your credentials, that you could then call on launch. Of course, this has its own non-trivial security concerns, and requires an extra HTTP call. I usually wouldn't do it this way.
Another option is to obfuscate the secret key somehow. By doing that, attackers won't be able to instantly recognize your key after decryption. cocoapods-keys is one option which uses this method.
There's no perfect solution here – the best you can do is make it as difficult as possible for an attacker to get a hold of your keys.
(Also, be sure to use HTTPS when sending requests, otherwise that's another good way to compromise your keys.)
While in-band tokens are commonly used for some schemes, you're probably eventually going to implement TLS to protect the network traffic and the tokens. This as Rob Napier mentions in another reply.
Using your own certificate chain here allows the use of existing TLS security and authentication mechanisms and the iOS keychain, and also gives you the option of revoking TLS credentials if (when?) that becomes necessary, and also allows the client to pin its connections to your servers and detect server spoofing if that becomes necessary.
Your own certificate authority and your own certificate chain is free, and your own certificates are — once you get the root certificate loaded into the client — are just as secure as commercially-purchased certificates.
In short, this certificate-based approach combines encryption and authentication, using the existing TLS mechanisms.
It looks like you are using access tokens. I would use Keychain for access tokens. For Client IDs, I would just keep them as a variable because client ids don't change while access tokens change per user, or even per refresh token and keychain is a safe place to store user credentials.
I have used the PFConfig object (a dictionary) that allows you to retrieve in your app values of variables stored as Server environment parameters.
Similar to the environment variables that can be retrieved using ENV in web sites server side programming like Ruby or PHP.
In my opinion this is about as secure as using Environment variables in Ruby or similar.
PFConfig.getConfigInBackgroundWithBlock{
(config: PFConfig?, error: NSError?) -> Void in
if error == nil {
if let mySecret = config["mySecret"] as? String {
// myFunction(mySecret)
}
}
I want to store a secret key ("abc123") that I will use in the header of my REST API requests. My server will check this secret key. If it matches "abc123", then allow the request to be made.
I'm thinking about a simple solution like:
let secret = "abc123"
But are there going to be any downfalls to this?
Crazy as it sounds, this is probably the best solution. Everything else is more complicated, but not much more secure. Any fancy obfuscation techniques you use are just going to be reverse engineered almost as quickly as they'll find this key. But this static key solution, while wildly insecure, is nearly as secure than the other solutions while imposing nearly no extra complexity. I love it.
It will be broken almost immediately, but so will all the other solutions. So keep it simple.
The one thing that you really want to do here is use HTTPS and pin your certificates. And I'd pick a long, random key that isn't a word. Ideally, it should be a completely random string of bytes, stored as raw values (not characters) so that it doesn't stand out so obviously in your binary. If you want to get crazy, apply a SHA256 to it before sending it (so the actual key never shows up in your binary). Again, this is trivial to break, but it's easy, and won't waste a lot of time developing.
It is unlikely that any effort longer than an hour will be worth the trouble to implement this feature. If you want lots more on the topic, see Secure https encryption for iPhone app to webpage and its links.
By hardcoding the string in your app, it's possible for attackers to decrypt your binary (via tools like dumpdecrypt) and get your string without much trouble (a simple hexdump would include any strings in your app).
There are a few workarounds for this. You could implement an endpoint on your REST API which returns your credentials, that you could then call on launch. Of course, this has its own non-trivial security concerns, and requires an extra HTTP call. I usually wouldn't do it this way.
Another option is to obfuscate the secret key somehow. By doing that, attackers won't be able to instantly recognize your key after decryption. cocoapods-keys is one option which uses this method.
There's no perfect solution here – the best you can do is make it as difficult as possible for an attacker to get a hold of your keys.
(Also, be sure to use HTTPS when sending requests, otherwise that's another good way to compromise your keys.)
While in-band tokens are commonly used for some schemes, you're probably eventually going to implement TLS to protect the network traffic and the tokens. This as Rob Napier mentions in another reply.
Using your own certificate chain here allows the use of existing TLS security and authentication mechanisms and the iOS keychain, and also gives you the option of revoking TLS credentials if (when?) that becomes necessary, and also allows the client to pin its connections to your servers and detect server spoofing if that becomes necessary.
Your own certificate authority and your own certificate chain is free, and your own certificates are — once you get the root certificate loaded into the client — are just as secure as commercially-purchased certificates.
In short, this certificate-based approach combines encryption and authentication, using the existing TLS mechanisms.
It looks like you are using access tokens. I would use Keychain for access tokens. For Client IDs, I would just keep them as a variable because client ids don't change while access tokens change per user, or even per refresh token and keychain is a safe place to store user credentials.
I have used the PFConfig object (a dictionary) that allows you to retrieve in your app values of variables stored as Server environment parameters.
Similar to the environment variables that can be retrieved using ENV in web sites server side programming like Ruby or PHP.
In my opinion this is about as secure as using Environment variables in Ruby or similar.
PFConfig.getConfigInBackgroundWithBlock{
(config: PFConfig?, error: NSError?) -> Void in
if error == nil {
if let mySecret = config["mySecret"] as? String {
// myFunction(mySecret)
}
}
I am sorry for the stupid question but I am novice in the token usage and maybe don't understand something.
I started to read about JWT and I am confused about it's structure. The documentation says that it has three parts:
header
payload
signature
I understand that in payload we keep information and in signature part we keep a signature for payload check. But what is the purpose of the header part? It says that typically it consists of two parts: the type of the token, which is JWT, and the hashing algorithm being used, such as HMAC SHA256 or RSA.
If server has signed the token then he knows which method it uses. So, it isn't a helpful information for the server. It will not use this information at all.
Isn't it a hint for hackers? They will know which method your server uses. I am not sure that it is a good practice for increase a security.
I am apologize if this is a stupid question and in reality we really need to keep information about our method of signature for some purposes but I haven't found the information with explanation why do we need this.
The producer of the JWT may have several different available methods for protecting it. It may use symmetric or asymmetric keys with a particular algorithm or key length and it may have different keys for each combination. Such information can be included in the header so that the receiver knows which key and algorithm to use to verify and/or decrypt the JWT.
The receiver and the sender may not be controlled by the same party so in that case it is certainly useful information so that the receiver knows how to verify/decrypt the token if there are multiple methods that the sender could have used. But even in the case that it is controlled by the same party, as you seem to imply, it may allow for smooth upgrades in crypto algorithms, keys or key lengths.
Imagine your server rolling over to a new keypair for signing the JWT that it produces and consumes itself. Then you may want to still be able to verify the existing tokens out there - signed with the old key - for a while. In that case you need to know which key was used to sign the JWT when you receive one.
Context: I'm updating my WordPress plugin to authenticate against the YouTube v3 API using a server key that has to be requested and entered by the user of the plugin.
Problem: I would like to perform validation of some kind on that key before using it, but can't seem to find documentation of the format a Google API server key adheres to. Based on (a very limited) number of examples it seems as though a key is:
is 39 characters long
is case-sensitive
consists of letters, numbers and at least dashes
So the question, obviously: Is this documented somewhere? Can anyone confirm or expand?
thanks,
frank
I couldn’t find any published key format either. Maybe because they want to keep the freedom to change the format in the future. If you want to be on the safe side, you should probably just do sanity checks well above the observed format. For example <=1024 bytes and non-control ascii characters, or even base64, or just don’t do any validation at all and let Google do that.
How about taking the key and passing it to a server-side script that attempts to use the key for some call. Then if it works return a success, else fail and call this async for the validation. Just seems more reliable than trying to decoded or anticipate the format of the hash.
I'm building an XML-based webservice in Rails to serve as the backend for an iPhone app, and I'm wondering how I can best achieve an auth scheme that will let me use both GET and POST requests -- i.e. one that doesn't require auth sent in the body of an XML payload.
The wrinkle here is that I'm not using regular HTTP auth. Instead, I'm creating a SHA1 digest of the iPhone's hardware ID (concatenated w/ a "secret" string pre-digest) along with the unhashed ID. I validate it on the server by attempting to re-create the digest w/ the hardware ID from the request and matching it against the hashed hardware ID from the request.
My question is this: should I create my service so that every action on every resource expects a payload of POSTed XML containing the security context in a common XML structure, or is there a better way to do it?
In other words, I'd like to use GET for things like /show, /index, etc. But as my app currently stands, I can't do that, since I need to send an XML payload containing the security context.
Perhaps there's a good way to achieve effectively the same thing with headers a la Google's web API's?
Every security context looks like this:
<request-wrapper>
<security-context>
<username>joefoo</username>
<hardware-id>AE7D128BCA9206E59901</hardware-id>
<hashed-hardware-id>cfd7983850301f97f6fdc26b553d1b6170f18bde</hashed-hardware-id>
</security-context>
...
(remainder of request payload)
...
</request-wrapper>
This is my first XML service in Rails, so I'd appreciate any general practice advice in this vein as well.
Thanks!
Your authentication scheme is subject to replay attacks if the "secret string" stays the same over the lifetime of the device.
Additionally, the "secret key" (if it is embedded in your application) can be dumped via strings (or other tool) breaking your scheme entirely.
I would instead use an asymmetric key to setup a one-time secret key, and then use it to hash a counter or something. If you need the hardware id for some reason, hash it plus the counter. This is basically a dumbed down SSL implementation, so you might as well just do that frankly (generating your own certificate, and doing the rare mutual authentication; but still...).
Remember, inventing your own security scheme is almost always a bad idea.
I'm thinking that it might be best to simply use custom headers for this and then access them in my controller filters w/ things like:
request.headers['username']
request.headers['hardware-id']
request.headers['hashedhardware-id']
Any thoughts on whether this is a good/bad idea?
How about creating an SHA1 digest of the entire XML request, instead of just the hardware-id? That way you're making replay attacks a lot harder. Sure, without a timestamp and (possibly) a nonce to make each request unique, a hacker could still replay the exact same request multiple times (maybe using up account credits or whatever), but at least they couldn't take the digest from an existing request and change the request details to make it do whatever they wanted.
Suggested steps:
Take your XML (without any hashed-hardware-id in it) and turn it into a byte array.
Create an SHA1 digest of the XML byte array.
Base-64 encode the XML byte array and the SHA1 digest byte array (separately).
Send the base-64-encoded XML as one request parameter, and the base-64-encoded signature as the other, either using GET or POST.