Related
When encrypting with AES, you need to have a key size of either 128, 192 or 256 bits. But on various encrypting websites you can use any key that can even be 1 character long (8 bits).
http://aesencryption.net/
For example, on that website I can use any key I want and it will encrypt/decrypt just fine.
How does that work? How is it possible to use keys that aren't even the correct length?
Many encryption tools (and libraries) allow you to provide a 'password', which it uses to derive an appropriately sized key. In order to prevent ambiguity, the term cryptographic key is often used to refer to the N-bit key used with an encryption algorithm.
If you look at the code on the page you linked, it's calculating a SHA-1 hash of the key you gave it, and taking the first 16 bytes as a 128-bit cryptographic key.
PHP, OpenSSL (and others)
Many web sites specifically use PHP mcrypt_encrypt. PHP mcrypt used to accept keys and IV's of any size. What happened was that a key unsupported by the algorithm was extended to the first available size larger than the key bytes given. If the key was too large, it was cut down to the highest key size.
For PHP this changed in 5.6.0:
Invalid key and iv sizes are no longer accepted. mcrypt_encrypt() will now throw a warning and return FALSE if the inputs are invalid. Previously keys and IVs were padded with '\0' bytes to the next valid size.
This will probably break quite a few sites.
Note that this kind of key expansion is absolutely not best practice and is not just frowned upon by cryptography experts. Instead a key derivation function or KDF should be used.
Hashing using a hash function
Hashing using a cryptographic hash such as MD5 or SHA-1 can be used as a poor mans KDF. It doesn't provide the protection that a PBKDF offers though (see below). It is relatively safe to take the (leftmost) bytes if a key of shorter size is required. If a hash is used it should be clear from the API or source code.
This seems to be the method used in the example in the question.
Seeding a random number generator
Unless it is abundantly clear from the API what algorithm is used and that the DRBG a given seed is not mixed with previous seed data (e.g. by the operating system) then this method should not be used. In general using the key/password as seed to a random number generator will lead to catastrophic failure. This method should be fought with all possible means. A random number generator is not a KDF. Unfortunately there are many people following bad examples.
Password encryption
Instead, for password based encryption (PBE), a PBKDF (Password Based Key Derivation Function) should be used. Examples of PBKDFs are PBKDF2, bcrypt or scrypt. This is usually explicit in the API or clearly visible in source code. A good PBKDF uses a salt, possibly a pepper (secret value) and a work factor or iteration count. This makes the password - which usually does contain less entropy than a full key - to be somewhat more safe. It won't protect against really weak keys though.
Secret key derivation
If you have a secret that does contain enough entropy then the salt and work factor are not needed (a salt can however make your KDF much more secure). A work factor only adds a constant amount of time to your key derivation - if brute force attacks are already not feasible because of the amount of entropy the work factor will only slow down the intended user and CPU. Arguably the most advanced KBKDF currently is HKDF. It may be tricky to find KDFs implemented in cryptographic libraries.
The http://aesencryption.net/ algorithm takes a key in string form and remaps it to an array which has a length accepted by Rijndael. If longer than 256 bits, the key is truncated to that length, otherwise it is padded with '\0' bytes until it reaches one of the accepted lengths for the algorithm, that is 128, 160, 192, 224 or 256 bits.
I reproduced the behaviour of this site by taking the key, converting it to an array and eventually truncating / padding it.
You can use the algorithm below to reproduce the key transformation of the site http://aesencryption.net
public static byte[] transformKey(String inputKey){
int keySize = Math.min(((((sessionKey.length * 8 - 128) / 32) + 1) * 32) + 128, 256) / 8;
sessionKey = Arrays.copyOf(sessionKey, keySize);
for (int i = key.getBytes().length; i < sessionKey.length; i++) {
sessionKey[i] = '\0';
}
return sessionKey;
}
NOTE: the for cycle is useless because Arrays.copyOf already pads the array with zeroes.
Will any encryption scheme safely allow me to encrypt the same integer repeatedly, with different random material prepended each time? It seems like the kind of operation that might get me in hot water.
I want to prevent spidering of items at my web application, but still have persistent item IDs/URLs so content links don't expire over time. My security requirements aren't really high for this, but I'd rather not do something totally moronic that obviously compromises the secret.
// performed on each ID before transmitting item search results to the client
public int64 encryptWithRandomPadding(int32 id) {
int32 randomPadding = getNextRandomInt32();
return encrypt(((int64)randomPadding << 32) + id), SECRET);
}
// performed on an encrypted/padded ID for which the client requests details
public int32 decryptAndRemoveRandomPadding(int64 idToDecrypt) {
int64 idWithPadding = decrypt(idToDecrypt, SECRET);
return (int32)idWithPadding;
}
static readonly string SECRET = "thesecret";
Generated IDs/URLs are permanent, the encrypted IDs are sparsely populated (less than 1 in uint32.Max are unique, and I could add another constant padding to reduce the likelyhood of a guess existing), and the client may run the same search and get the same results with different representative IDs each time. I think it meets my requirements, unless there's a blatant cryptographic issue.
Example:
encrypt(rndA + item1) -> tokenA
encrypt(rndB + item1) -> tokenB
encrypt(rndC + item2) -> tokenC
encrypt(rndD + item175) -> tokenD
Here, there is no way to identify that tokenA and tokenB both point to identical items; this prevents a spider from removing duplicate search results without retrieving them (while retrieving increments the usage meter). Additionally, item2 may not exist.
Knowing that re-running a search will return the same int32 padded multiple ways with the same secret, can I do this safely with any popular crypto algorithms? Thanks, crypto experts!
note: this is a follow-up to a question that didn't work out as I'd hoped: Encrypt integer with a secret and shared salt
If your encryption is secure, then random padding makes cracking neither easier nor harder. For a message this short, a single block long, either everything is compromised or nothing is. Even with a stream cipher, you'd still need the key to get any further; the point of good encryption is that you don't need extra randomness. Zero padding or other known messages at least a block long at the beginning are obviously to be avoided if possible, but that's not the issue here. It's pure noise, and once someone discovered that, they'd just skip ahead and start cracking from there.
Now, in a stream cipher, you can add all the randomness in the beginning and the later bytes will still be the same with the same key, don't forget that. This only actually does anything at all for a block cipher, otherwise you'd have to xor the random bits into the real value to get any use out of it.
However, you might be better off using a MAC as padding: with proper encryption, the encrypted mac won't give any information away, but it looks semi-randomish and you can use it to verify that there were no errors or malicious attacks during decryption. Any hash function you like can create the MAC, even a simple CRC-32, without giving anything away after encryption.
(A cryptographer might find a way to shave a bit or two off due to the relatedness, will tons of plaintexts if they knew beforehand how they were related, but that's still far beyond practicality.)
As you asked before, you can safely throw in an unecrypted salt in front of every message; a salt can only compromise an encrypted value if the implementation is broken or the key compromised, as long as the salt is properly mixed into the key, particularly if you can mix it into the expanded key schedule before decryption. Modern hash algorithms with lots of bits are really good at that, but even mixing into a regular input key will always have the same security as the key alone.
How hard is it for a given ciphertext generated by a given (symmetric or asymmetric) encryption algorithm working on a plaintext/key pair, to find a different plaintext/key pair that yields the same cyphertext?
And how hard is it two find two plaintext/key pairs lead to the same cyphertext?
What led to this question, is another question that might turn out to have nothing to do with the above questions:
If you have a ciphertext and a key and want to decrypt it using some decryption routine, the routine usually tells you, if the key was correct. But how does it know it? Does it look for some pattern in the resulted plaintext, that indicates, that the decryption was successful? Does there exists another key results in some different plaintext, that contains the pattern and is also reported "valid" by the routine?
Follow-up question inspired by answers and comments:
If the allowed plaintext/key pairs where restricted in the on of the following (or both) way(s):
1) The plaintext starts with the KCV (Key check value) of the key.
2) The plaintext starts with a hash value of some plaintext/key combination
Would this make the collision finding infeasible? Is it even clear, that such a plaintext/key exists=
The answer to your question the way you phrased it, is that there is no collision resistance what so ever.
Symmetric case
Let's presume you got a plain text PT with a length that is a multiple of the block length of the underlying block cipher. You generate a random IV and encrypt the plain text using a key K, CBC mode and no padding.
Producing a plain text PT' and key K' that produces the same cipher text CT is easy. Simply select K' at random, decrypt CT using key K' and IV, and you get your colliding PT'.
This gets a bit more complicated if you also use padding, but it is still possible. If you use PKCS#5/7 padding, just keep generating keys until you find one such that the last octet of your decrypted text PT' is 0x01. This will take on average 128 attempts.
To make such collision finding infeasible, you have to use a message authentication code (MAC).
Asymmetric case
Something similar applies to RSA public key encryption. If you use no padding (which obviously isn't recommended and possibly not even supported by most cryptographic libraries), and use a public key (N,E) for encrypting PT into CT, simply generate a second key pair (N',E',D') such that N' > N, then PT' = CT^D' (mod N) will encrypt into CT under (N',E').
If you are using PKCS#1 v1.5 padding for your RSA encryption, the most significant octet after the RSA private key operation has to be 0x02, which it will be with a probability of approximately one in 256. Furthermore the first 0x00 valued octet has to occur no sooner than at index 9, which will happen with a high probability (approximately 0,97). Hence, on average you will have to generate on average some 264 random RSA key pairs of the same bit size, before you hit one that for some plain text could have produced the same cipher text.
If your are using RSA-OAEP padding, the private key decryption is however guaranteed to fail unless the cipher text was generated using the the corresponding public key.
If you're encrypting some plaintext (length n), then there are 2n unique input strings, and each must result in a unique ciphertext (otherwise it wouldn't be reversible). Therefore, all possible strings of length n are valid ciphertexts. But this is true for all keys. Therefore, for any given ciphertext, there are 2k ways of obtaining it, each with a different key of length k.
Therefore, to answer your first question: very easy! Just pick an arbitrary key, and "decrypt" the ciphertext. You will get the plaintext that matches the key.
I'm not sure what you mean by "the routine usually tells you if the key was correct".
One simple way to check the validity of a key is to add a known part to the plaintext before encryption. If the decryption doesn't reproduce that, it's not the right key.
The known part should not be a constant, since that would be an instant crib. But it could be e.g. be a hash of the plaintext; if hashing the decrypted text yields the same hash value, the key is probably correct (with the exception of hash collisions).
From what I can see, Microsoft's RSA CSP always generates identical bitlength pseudo prime numbers. So if the key size is 1024, the P and Q values seem to be (?) guaranteed to be 512 bits each? Does anyone know for sure if this, in fact, is the case?
I'm building an interoperability module between my own RSA implementation and Microsoft's. In my case I have built in a small random variance between P & Q values so for 1024 bit key I could end up with one value being 506 bits and the other 518. On purely experimental basis, if I lock the variance to 0 (i.e. the P & Q values are equal in size) -- Things work the way they should, I soon as I make the size variable Microsoft RSA object responds with "Bad Data" during import process.
I'm looking for a confirmation that Microsoft enforces equal key sizes, so if anyone has any information on it, please post
Before someone has a chance to ask why I had to implement my own RSA provider : CryptoAPI doesn't play nice in a multithreaded environment, it locks the machine keystore on CryptoServiceProvider calls; which means "File not found" (rather cryptic) errors if accessed from multiple threads
For those that care, take a look here: http://blogs.msdn.com/b/alejacma/archive/2007/12/03/rsacryptoserviceprovider-fails-when-used-with-asp-net.aspx
Microsoft's RSA CSP generates and uses private keys which it can export and import in the format described on this page, and looks like this:
BLOBHEADER blobheader;
RSAPUBKEY rsapubkey;
BYTE modulus[rsapubkey.bitlen/8];
BYTE prime1[rsapubkey.bitlen/16];
BYTE prime2[rsapubkey.bitlen/16];
BYTE exponent1[rsapubkey.bitlen/16];
BYTE exponent2[rsapubkey.bitlen/16];
BYTE coefficient[rsapubkey.bitlen/16];
BYTE privateExponent[rsapubkey.bitlen/8];
So private keys that the CSP can handle (and in particular generate) must have the following properties:
The modulus length, in bits, must be a multiple of 16.
The length of each prime factor must be no more than half the length of the modulus.
The private exponent must not be longer than the modulus.
The private exponent, reduced modulo p-1 (resp. q-1) must be no longer than half the modulus.
Technically, there are infinitely many possible values for the private exponent d, and similarly for exponent1 and exponent2 because all that mathematically matters are the value of d modulo p-1 and q-1; it has been suggested to accept slightly longer private exponent parts if they end up with a lower Hamming weight, because this would lead to some performance benefits. Bottom-line: the format described above will not let you do that.
Other characteristics that the key must have to be acceptable to Microsoft's code (but not directly reported in the description above):
The numerical value of the first prime (p, aka prime1) must be greater than the numerical value of the second prime (q, aka prime2).
The public exponent (here encoded within the rsapubkey field) must fit in a 32-bit integer (unsigned).
Therefore there are many RSA key pairs which are nominally valid as per the RSA standard, but which cannot be handled by Microsoft RSA CSP code. Noteworthy is the last constraint, on the public exponent size: this means that the constraint is more general than just the CSP; if you setup a SSL server where the server's public key (in its certificate) has a public exponent which does not fit in 32 bits, then Internet Explorer will not be able to connect to it.
So, in practice, if you generate RSA key pairs, you will have to make sure that they comply with the rules above. Do not worry: to the best of our knowledge, these rules do not lower security.
My own work/experimentations, doing Mono's (managed) RSA implementation and unit tests, shows that Microsoft implementation requires specific byte[] size when importing RSA parameter values.
It's also a common interoperability issue (there are some SO questions about it) when people using BigInteger to convert their parameters since they often are a bit smaller (e.g. 1 byte less) than what MS expect and needs to be 0-padded.
So I'm pretty sure you can pad your smaller value to make MS accept it, but you'll likely not be able to make it accept a larger value.
In an asymetric encryption scheme, I was wondering if it's possible to achieve the following:
Bob sends to Alice his public key
Alice alters Bob's public key and encrypt some document with it
Alice sends the encrypted document to Bob
Bob retrieve the document but can't decrypt it with his private key
Later, Alice sends some additional information (probably related to the method she used to alter Bob's public key) to Bob
Bob uses this additional information to modify his private key and successfully decrypt the document
Anyone?
I am assuming RSA for the keys generation, encryption and decryption but if it's easier to do with another scheme feel free to comment.
(I assume you talk about RSA.)
Yes it is possible, but not 100%.
The public key is a part of the private key. It contains the modulus and the exponent of the key.
You can completely forget changing the modulus, because you would have to generate a new rsa keypair, which is the same problem as the one we are trying to solve.
But it is possible to change the exponent. You can select any (prime) number between 1 and your exponent as the new exponent and hope that it is coprime with the totient. Without knowing the totient it's impossible to select always a correct exponent. To find out the totient you would have to know the prime factors of the key, which means that you would have to break the key (have fun!).
So, it's actually impossible to have a 100% percent working method to do that, at least not while knowing only the public key.
If you need more information about the theory check here
I hope my idea works.
Let us assume that (e,d,n) is a tuple of the RSA public exponent. The RSA private exponent and the RSA modulus n :
Select a prime number, say p, between 1 and a 256 bit integer.
To encrypt a message m, compute the new public exponent as e*p and the ciphertext as:
c= m^{e*p} mod n.
To decrypt, the receiver should know the prime p, so you send this p later to him, with this he computes
(1) P = p^{-1} mod phi(n)
and
(2) m^e=c^{P} mod n
and
finally m=(m^e)^d mod n. This works as the receiver knows phi(n).
By the way, where can we use this? Is there any application you have in mind for this?
As silky implies in his answer, the way in which RSA is usually used to encrypt a document is in combination with a symmetric algorithm, like AES. A secure random key is generated for the AES algorithm, the documented is encrypted with that AES key, and the AES key is encrypted with the recipient's public key. Both parts are supplied to the recipient.
You can adapt this to your situation simply by sending only the document encrypted with the AES key in the first step, and withholding the AES key encrypted with the recipient's public key until the second step. The first part will be on the order of the original file size, and the second part will be a small, constant size (on the order of the RSA key size).
Hmm, interesting.
You're referring to RSA, I assume?
FYI, RSA isn't actually used to encrypt documents. It's used to exchange keys (keys for a symmetric algorithm, like AES).
So what you're really talking about is an approach that changes the keys.
Technically (mathmatically) if you put a different number in, you'll get a different number out. So that's not an issue; changing the public key in some fashion will (assuming you convince your RSA implementation to use it, or prepare an appropriately different number) result in a different symmetric key, thus an undecryptable document by Bob (because he'll expect a different key).
Really, though, I'm not so sure you care about this. It's a fairly useless thing to do. Perhaps, however, you're actually interested in Key Splitting (or "Secret Sharing" as wikipedia seems to call it).
HTH. I'm by no means an expert.