Is there exist a ciphering approach such that encrypting and decrypting order is arbitrary? Like using two padlocks on the same lock loop.
That is, if there are two keys (or keypairs) K1, K2, message M, and the cryptogram C is obtained as (for example) C=M*K1*K2 (where * denotes ciphering), then the message M can be retrieved in each of the following ways: 1) M=C*K1*K2, 2) M=C*K2*K1 (here * denotes deciphering).
Obviously, XOR is a trivial candidate. Do any cryptographically strong examples exist?
Take any strong block cipher (e.g. AES) and run it in Output Feedback Mode or Counter Mode.
Since OFB and CTR are essentially just XOR with a cryptographic pseudo-random stream, this will have the property you seek. Just make sure your K1 and K2 are independent.
Also, since OFB and CTR are NIST-approved (and widely-used) block cipher modes, they will be "cryptographically strong" as long as you implement them correctly and use a strong underlying block cipher.
What you ask for is known as a commutative cipher. One application of such ciphers is Shamir's three pass protocol (which is often explained using padlocks).
It is unclear what you mean by "cryptographically strong". I.e. one requirement that is frequently necessary is that an adversary can not learn the message if he learns the encryption of the message with K1, then encryption of the message with K2 and the encryption of the message with both K1 and K2. This requirement is obvious in the case of Shamir's three pass protocol.
It is easy to see that stream ciphers do not satisfy the requirement above. Hence it would misleading to call a stream cipher a "cryptgraphically strong commutative cipher". Equally easy to break under the assumptions above is Rasmus Fabers proposal (which I think is a construction proposed by Bruce Schneier for something a little different).
Strong commutative ciphers can be based for example on modular exponentiation. The Massey-Omura protocol is a great example.
If the size of the cryptogram is not an issue, you can easily construct such a cipher based on any other cipher:
Have the first encryptor generate a random bitmask B1 of size >= M. Encrypt the bitmask with the original cipher and key and transmit this encryption together with B1 ^ M.
Similarly, the next encryptor generate a new random bitmask B2, encrypts it with his key and transmits both encrypted bitmasks and B2^(B1^M). (and so on for N encryptors).
To decrypt, just decrypt each of the bitmasks in any order and xor them onto the masked message.
Related
I am using node and the crypto module to encrypt and decrypt a large binary file. I encrypt the file using crypto.createCipheriv and decrypt it using crypto.createDecipheriv.
For the encryption I use a random IV as follows:
const iv = crypto.randomBytes(16);
const encrypt = crypto.createCipheriv('aes-128-cbc', key, iv)
What I don't understand, do I need to pass a random IV for createDecipheriv as well? The SO here says:
The IV needs to be identical for encryption and decryption.
Can the IV be static? And if it can't, is it considered to be a secret? Where would I store the IV? In the payload?
If I use different random IVs for the encryption and decryption, my payload gets decrypted but the first 16 bytes are corrupt. This means, it looks like the IV needs to be the same but from a security perspective there is also not much value as the payload is decrypted except 16 bytes.
Can anyone elaborate what the go-to approach is? Thanks for your help!
The Key+IV pair must never be duplicated on two encryptions using CBC. Doing so leaks information about the first block (in all cases), and is creates duplicate cipher texts (which is a problem if you ever encrypt the same message prefix twice).
So, if your key changes for every encryption, then your IV could be static. But no one does that. They have a key they reuse. So the IV must change.
There is no requirement that it be random. It just shouldn't repeat and it must not be predictable (in cases where the attacker can control the messages). Random is the easiest way to do that. Anything other than random requires a lot of specialized knowledge to get right, so use random.
Reusing a Key+IV pair in CBC weakens the security of the cipher, but does not destroy it, as in CTR. IV reused with CTR can lead to trivial decryptions. In CBC, it generally just leaks information. It's a serious problem, but it is not catastrophic. (Not all insecure configurations are created equal.)
The IV is not a secret. Everyone can know it. So it is typically prepended to the ciphertext.
For security reasons, the IV needs to be chosen to meet cryptographic randomness security requirements (i.e. use crypto.randomBytes( ) in node). This was shown in Phil Rogaway's research paper. The summary is in Figure 1.2 of the paper, which I transcribe here:
CBC (SP 800-38A): An IV-based encryption scheme, the mode is secure as a probabilistic encryption scheme, achieving indistinguishability from random bits, assuming a random IV. Confidentiality is not achieved if the IV is merely a nonce, nor if it is a nonce enciphered under the same key used by the scheme, as the standard incorrectly suggests to do.
The normal way to implement this is to include the IV prepended to the ciphertext. The receiving party extracts the IV and then decrypts the ciphertext. The IV is not a secret, instead it is just used to bring necessary security properties into the mode of operation.
However, be aware that encryption with CBC does not prevent people from tampering with the data. If an attacker fiddles with ciphertext bits within a block, it affects exactly two plaintext blocks, one of which is in a very controlled way.
To make a very long story short, GCM is a better mode to use to prevent such abuses. In that case, you do not need a random IV, but instead you must never let the IV repeat (in cryptography, we call this property a "nonce"). Luke Park gives an example of how to implement it, here. He uses randomness for the nonce, which achieves the nonce property for all practical purposes (unless you are encrypting 2^48 texts, which is crazy large).
But whatever mode you do, you must never repeat an IV for a given key, which is a very common mistake.
How to determine the padding scheme used in a RSA encrypted message?
The best way is probably to perform PKCS#1 v1.5 or OAEP decryption and see if you hit gold. The unpadding will fail if the wrong algorithm is chosen.
It is possible to raw decipher and then look at the resulting scheme by representing the padded message as hexadecimals. If the resulting octet string (byte array) starts with 0002 then it's likely PKCS#1 v1.5 padding. If it starts with 00 and then a random looking byte it's probably OAEP. As you can see, this is just a heuristic, not a full fledged algorithm. Note that OAEP's MFG1 can be parameterized with a hash function, but usually SHA-1 is used.
RSA-KEM is not used much, but as it results in a completely random key seed (possibly excluding the first bit), there is no way to test for RSA-KEM other than to expect RSA-KEM if the ciphertext and private key can be verified to be correct and the value doesn't match one of the other schemes / lacks structure.
The protocol should define which algorithm is used. Leaving the choice of algorithm to the decryption routine opens up your implementation to attacks. The security proof of ciphers doesn't allow for other algorithms to be chosen.
So you can use above to analyze the protocol, but please do not use it in your implementation to choose between algorithms in the field.
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).
I'm wondering if there is some strong (like AES or so.) encryption function that works like this:
symetric
2 keys: plaintext -> 2keys ->ciphered text, however it must not matter order of keys, i.e
Key1 (Key2 (plaintext)) == Key2 (Key1(plaintext))
e.g. "commutative"
(also required for decryption - you need two keys, doesn't matter order)
thanks
This can be easily done by putting any block encryption algorithm into CTR mode. CTR mode with a single key looks like:
ciphertext = plaintext XOR cipher(key, counter)
Where counter is initialized to your IV and incremented for each block. Decryption is exactly the same operation. As such, if you CTR-encrypt twice with two keys, you get:
ciphertext = plaintext XOR cipher(key0, counter) XOR cipher(key1, counter)
And since XOR is commutative, you can reverse it in either order.
This has the nice property that you don't need to have all keys in the same location. Consider: Alice, Bob, and Charlie are participating in a protocol in which Charlie will double encrypt data for both Alice and Bob (this protocol will assume all point-to-point communication is secured through usual SSL-like channels):
Alice and Bob perform an authenticated Diffie-Hellman exchange to produce the IV. This IV is then sent to Charlie.
Alice computes digest(key0, IV + ctr) for ctr = 0...number-of-ciphertext-blocks, and sends the result KS_A to Charlie
Bob computes digest(key1, IV + ctr) for ctr = 0...number-of-ciphertext-blocks, and sends the result KS_B to Charlie
Charlie computes KS_A XOR KS_B XOR plaintext, and sends the resulting ciphertext to both Alice and Bob.
Alice and Bob each sign a tuple (IV, hash(ciphertext), description-of-encrypted-data). This is attached to the ciphertext.
Later, to decrypt:
Charlie (performing the decryption) sends the signed (IV, hash(ciphertext)) tuples to each of Alice and Bob, as well as the ciphertext.
Alice verifies his signed tuple, computes KS_A, and sends ciphertext XOR KS_A = D_A to Charlie
Bob verifies his signed tuple, computes KS_B, and sends ciphertext XOR KS_B = D_B to Charlie
Charlie computes KS = D_A XOR D_B = KS_A XOR KS_B
Charlie computes plaintext = ciphertext XOR KS
The purpose of the signed tuple here and DH exchange is to ensure Alice and Bob can't be tricked into decryption the wrong stream by sending them a different IV. This may not be relevant in your usage scenario. Also, the role of Charlie may be played by Alice or Bob in a real implementation.
If you're worried about the potential security risks of CTR mode, one other option would be to use CTR-mode encryption on a session key, which in turn is used to encrypt in a more normal mode, such as CBC. That is:
sessionkey = RANDOM
IV_0 = RANDOM
IV_1 = RANDOM
enc_sessionkey = sessionkey XOR cipher(key0, IV_0) XOR cipher(key1, IV_0)
ciphertext = enc_sessionkey + IV_0 + IV_1 + cipherCBC(IV_1, sessionkey, plaintext)
Although some other posters have commented on secret sharing, this is overkill if you don't need the property that only a subset of keys are needed for decryption - ie, with secret sharing you might encrypt with three keys, but require only any two to decrypt. If you want to require all keys, secret sharing schemes aren't really necessary.
It's not a commutative encryption, but there are well-proven algorithms for secret sharing (note, this is not the same thing as "key agreement.")
Two of the best known methods are Shamir's and Blakley's. In general, these algorithms take a secret and produce many "shares". When enough shares are available to reach a threshold, the secret can be recovered. In the simplest case, two shares are required, but the threshold can be higher.
To explain Shamir's method in simple terms, think about a line on a graph. If you know any two points on the line, you know everything about the line. Any string of bytes, like the encryption key of a symmetric cipher, is just a large number, in base-256. Shamir's algorithm treats this secret as the line's "y-intercept" (the y-coordinate of the line when x=0). Then the line's slope chosen randomly. The y-coordinates of the line at x=1, x=2, x=3, … are computed, and each point is given to a different share-holder.
If any two of these share-holders get together, they can draw a line through their two points, back to the y-axis. The y-coordinate at where it crosses the axis is the original secret. However, each share-holder has only one point; by themselves, they can't guess anything about the original secret.
The threshold can be increased by increasing the degree of the polynomial. For example, if a parabola is used instead of a line, three shares are needed instead of two.
There's more to a real implementation, like the use of modular arithmetic, but this is the concept behind it. Blakley's approach is similar, but it uses the intersection of planes to encode the secret.
You can play around with an implementation of Shamir's method online.
You can make a commutative encryption algorithm, but the encryption methods must then be limited to commutative operations. This will limit the strength of the encryption function because it greatly reduces the possible encryption methods that can be used. Thus, if a hacker wanted to break your algorithm and new it was commutative, it would greatly improve his chances of breaking it because of the reduction in decryption methods he would need to try. However, it might be okay for your purposes, depending on how much hacking you expect.
Also, I'm not sure if "secret splitting" is what you are going for, as mentioned by atk. I've looked at it briefly, but from what I've seen (at least for the basic case) you can't perform the operations separately, as both keys need to be provided together to perform the encrypt/decrypt actions. In other words you can't call encrypt with one person's key to get a result that you can call encrypt on with a second key. However, if you have both keys available at once, this might be a good method to try.
You're talking about secret splitting. Yes, there's been a lot of research on it. Wikipedia would be a good starting point.
I understand that block ciphers are more popular in software as opposed to stream ciphers which are typically hardware based. However, why can't a key be reused in stream ciphers? Is it because of patterns that may form?
A stream cipher is an encryption system which works over a given sequence of input bits. Most stream ciphers work by generating from the key a long sequence of random-looking bits, which are then combined (by bitwise XOR) with the data to encrypt. This is a (crude) emulation of one-time pad.
A block cipher is a generic cryptographic element which works over "blocks" which are sequences of bits with a fixed length (e.g. 128 bits for AES). The block cipher is a permutation of the blocks; the key selects which permutation we are talking about. A block cipher alone cannot process an arbitrary long message; the block cipher and the data must be used within an elaborate construction called a mode of operation (also often called a "chaining mode").
There is a chaining mode for block ciphers called "CTR" as "counter mode": in this mode, the block cipher is used to encrypt successive values of a counter (the counter having the size of a block). The resulting encrypted blocks are then concatenated, resulting in an arbitrarily long sequence of bits which depend only on the key. It suffices then to XOR that sequence with the data to encrypt. In other words, CTR mode turns a block cipher into a stream cipher. Another popular chaining mode is CBC, which does not fit the model of a stream cipher.
With stream ciphers, what must be avoided at all costs is reusing the same key-dependent sequence of bits for two distinct messages; this would yield the infamous "two-times pad" which can be broken quite easily (by exploiting redundancies in the two encrypted messages). With a block cipher in CTR mode, this translates to reusing the same counter values. This is why CTR mode requires a random Initial Value (IV) which is the counter value you begin encryption with. By choosing a new random IV, with sufficiently large blocks, you avoid with very high probability any overlap in the sequences of counter values that you use.
The concept of IV is not specific to block ciphers; some stream ciphers also use an IV (e.g. the one in the eSTREAM portfolio). When a stream cipher has an IV, reusing the key is no problem -- provided that you use proper IV (i.e. IV generated with a cryptographically strong RNG in the complete space of possible IV, with uniform probability). However, some other stream ciphers do not have an IV, in particular the widely used RC4. Reusing the same key would mean reusing the exact same sequence of generated bits, and that's bad.
Note that some chaining modes other than CTR also need an IV, which should be unique for each message encrypted with a given key. Block ciphers do not alleviate the need for that.
because when reusing the key in stream cipher the stream cipher
general function is encryption=(plaintext+key)%2
and modulo 2 is considered xor
so reusing the key for encryption function will cause the cipher text to repeat it self after some length
so a random generators are used to produce key every time in the encryption operation
like LFSR to produce random key every time
one time pad is also used
Block cipher: Block cipher is like encrypting a message block by block.
It's breaking the block by block then after encryption of the message.
Stream cipher: Stream cipher is like a bit by bit encryption of the original message.