I was looking for libraries to implement an encryption system and was interested in using the NaCl: Networking and Cryptography library specifically the box function. Obviously, it uses symmetric encryption XSalsa20, Curve25519 for public-private cryptography and Poly1305 for authentication as the primitives for it.
However, the documentation looks to be insufficient in the way the they've been used. For example, it mentions that to compute the key it uses the sender's private key and the receiver's public key to compute the secret key. But it doesn't explain how. Can anyone shed any light on it?
If I were to use the same public and private key, I wouldn't the same key to be generated on the next attempt and it would be disastrous. Does anyone know of the explanation behind it or hook me up with some more documentation on how the functions work rather than how the functions can be used?
How does crypto_box work?
box uses a Diffie-Hellman key exchange on the two keys and hashes the result. Then it uses that as the key for secret_box.
crypto_box is equivalent to crypto_box_beforenm followed by crypto_box_afternm.
crypto_box_beforenm is the hashed key-exchange which works as described in the Curve25519 paper, using elliptic curve Diffie-Hellman key exchange on Curve25519 hashing the result with HSalsa. This yields a 32 byte shared key.
k = Hash(Curve25519(b, A)) = Hash(Curve25519(a, B))
crypto_box_afternm is identical to crypto_secret_box. It takes a 24 byte nonce and a 32 byte key. It's an authenticated stream cipher using XSalsa20 for encryption and Poly1305 as MAC. The first 32 bytes of the output of XSalsa20 are used for the MAC, the rest are xored into the plaintext to encrypt it.
What happens if you use it multiple times?
If you take two fixed key-pairs, the result of the key exchange will always be the same.
But the symmetric part secret_box is secure even when you use a key several times, as long as you never reuse a nonce for that key, i.e. the (key, nonce) pair must be unique.
This property is pretty much the same for all modern authenticated stream ciphers, such as AES-GCM or XSalsa20-Poly1305.
Common ways to create a unique nonce are:
Use an 8 byte prefix and a random 16 byte value (stateless, random 16 bytes are most likely unique)
Use a 16 byte prefix and a 8 byte counter (stateful, useful in a connection where you increment for each packet)
For example, it mentions that to compute the key it uses the sender's
private key and the receiver's public key to compute the secret key.
But it doesn't explain how. Can anyone shed any light on it?
There is a nice, understandable video, but in german language: https://www.youtube.com/watch?v=aC05R9xqbgE. This video explains it for both the "discrete logarithm" and the "elliptic curve" solution.
In the "elliptic curve" scenario, the public key P is a point (with x and y coordinates) on the curve. P is calculated by multiplication of a Generator G (defined by the curve) with a secret key K.To calulate the secret key S, just do a multiplication of the peer's point P (peer's public key) with the own secret key K (a scalar number). Both peers make this operation:
S_Alice = P_Bob mult K_Alice = G mult K_Bob mult K_Alice
S_Bob = P_Alice mult K_Bob = G mult K_Alice mult K_Bob
As the curve is a commutative group, the order of the multiplications does not matter, so from the above calculations you can see that in the end both Bob and Alice calculated an identical key.
Related
When sending a message encrypted with asymmetric encryption, e.g.
Long long, very long message here. // encrypted with recipents public key
Signed by John Doe // encrypted with own private key
Does one want to be consistent with their own digital signature? Is there a standard format, or a widly used convention for the signature part? Or even, are there any conventions or is it just completely random what each person wants to put there?
Edit:
I guess my question isn't meant to be about standards per se. Rather about conventions if one would send the example format message in an instant messenger or email for example.
First - the users signs with its private key, not encrypts..
And now to the topic:
There are several protocols to pass encrypted and signed data.
If you are using (web) services, you may have a look at WS-Security or XML signature
If you are looking for a more generalised standard, you may search "CMS Cryptographic Message Syntax" or PKCS#7
As well there are tools specific protocols, such as using openssl, in-document signatures (pdf, word,..) ... which are not standards per se, but commonly used.
You mention in a comment:
First - the users signs with its private key, not encrypts.. Yes, but doesn't the signing mean encrypting a signature with your private key (so that anyone can check it with your public key), like in my example?
Though the answer to this comment is generally: no.
Cryptographic signatures can be constructed in quite a lot of different ways. In RSA, the signing operation resembles some elements of the encryption, but this is a coincidence.
For example, take some the Schnorr signature scheme for elliptic curves:
(In this example, G is a base point for some secure elliptic curve E.
All variables between brackets are scalars modulo the order of E.)
Setup:
Alice has a private key x (random).
Bob has Alice's public key P_A = [x]G.
Alice signs a message m:
k := random()
Q := [k]G
c := H(Q||P_A||m)
r := k + c*x
Alice outputs s := (Q, r)
Bob verifies s over m:
c := H(Q||P_A||m)
Check if [r]G == Q + [c]P_A
As you can see, there is no real notion of "encryption" here. It is just a protocol.
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.
What is the correct (acceptable) way to derive an, lets say 128 bit AES key from the secret derived in a DH negotiation?
Use the first 128 bit
Hash the secret and use the first 128 bit
Use some more complicated derivation function
How would you derive a set of keys in a "correct" manner?
I would use a standard. One such standard is NIST Special Pub 800-56A. See in particular section 5.8.
For instance, in TLS used pseudo-random function, which is based on SHA1 and MD5 hash over shared secret (i.e. DH key exchange value), string label (to distinguish different cases for which key is generated, HMAC, cipher and so on), and shared random parameter (both client and server generates his own half of random parameter).
So, i'd recommend to add some random data generated by both client and server, and hash it together with DH key exchange value.
Is it possible to encrypt in one order and decrypt in another? For example I've got the following:
plain_text.txt
Public/Private Key pair 1
Public/Private Key pair 2
Example
Encryption:
public1(public2(plain_text.txt))
Decryption:
private1(private2(encrypted))
Is there any encryption algorithm that allows this? Is it even possible?
In most cases you can't change the order of the decryption.
Schemes that allow to reorder decryption are called commutative cryptosystems.
One public key cryptosystem that can be used to build a commutative cryptosystem is
the ElGamal encryption.
Here is just the main idea: Assume g is a generator of
a suitable group G, for which computing discrete logarithms is hard.
Let xA and xB be two private keys,
hA = g xA , and
hB = g xB
be the corresponding public keys. Both keys pairs use the same group
G (i.e. the same modulus p if we use G = Z/(p)). It is one advantage of the
ElGamal scheme that it still is secure if two users share the same group (or modulus).
RSA on the other hand will be insecure.
Encrypting a message m with hA gives the ciphertext
(m hAr, gr).
Note that knowing the secret key xA allows to decrypt because
(gr)xA = hAr
To encrypt the ciphertext a second time one would first re-encrypt the existing
ciphertext with A's public key.
He chooses a random r' and computes
(m hAr hAr', grgr') =
(m hAr+r', gr+r').
The result is just another valid encryption with A's public key.
This re-encryption is necessary to avoid an attack that works for example
against RSA with equal modulus as shown below.
Next, one would encrypt with B's public key giving
(m hAr+r' hBs, gr+r', gs).
Decryption is possible in either order, e.g. knowing xA allows to compute
(gr+r')xA = hAr+r'
and hence one can compute
(m hBs, gs),
which is just what we want: an encryption of m with B's public key.
There are a number of subtleties that need to be observed to get a secure implementation.
And getting this right isn't easy.
For more info see for example the Phd of Stephen Weis, which contains a chapter on commutative encryption.
There are a number of problems if the same idea is tried with "textbook RSA". First to make the encryption commutative it is necessary that both users A and B share the same modulus.
E.g. A uses (n, eA, dA) and B uses (n, eB, dB), where n is the modulus, eA, eB the public keys and dA, dB the secret keys. However, knowing for example (n, eA, dA) allows to factor n, and hence compute B's secret key, which is of course one big flaw.
Now we could encrypt m as
meA mod n,
encrypt again as
meAeB mod n,
decrypt with A's secret key giving
meB mod n,
and decrypt again with B's secret key to get m. That looks fine until one notices that
an attacker who can intercept the two ciphertexts c = meA mod n and c' = meB mod n can use Euclid's algorithm to find r,s such that
r eA + s eB = 1
and then compute
m = cr (c')s mod n.
The idea also works against the solution using RC4 proposed in another answer. Weis's thesis contains a detailed description of the attack.
With most public implementations of RSA it would not be possible. The decryption routine expects the plaintext to be in a specific format (i. e. properly padded) and fails if it's not. Again, on encryption it would apply padding to the plaintext, instead of using the blob as it is.
/*
The math of RSA allows for that, AFAIK, as long as the moduli of the two keys are coprime (which is true almost always). But you'll probably have to roll your own implementation.
*/
Another problem is that the numeric value of the plaintext block should be smaller than the modulus. So the modulus of the first key should be smaller than that of the second key, otherwise no guarantee that the first cyphertext would be a proper plaintext for the second encryption round.
OpenSSL has, I vaguely recall, a no-padding mode. You might have some luck with that.
EDIT: in general, coming up with your own cryptographic primitives is a bad idea in 99.9% cases. If your interest is purely academic, then be my guest; but if you're after a specific piece of applied functionality (i. e. encrypt something so that the consent of two nontrusting parties is needed to decrypt), then you're definitely on the wrong track.
EDIT2: the math of RSA allows for that if the moduli are identical. Scratch paragraph two. But having two keys share the same modulus compromises security very much. If Alice has private key (m, d) and Cindy as private key (m, d') - assuming same m - then Alice can determine d' in O(m) time, given a single plaintext/cyphertext pair from Cindy. Not good.
With public key/private key encryption, the answer is no. PubK1(PubK2(plain.text)) => encrypted.text. You must decrypt with PrivK2(PrivK1(encrypted.text)).
However, if you use a symmetric stream cipher such as RC4, then you could change the order of the decryption (A xor B xor C = C xor B xor A). But that is not a public/private key algorithm obviously.
This would only be true if the encryption algorithm behaved as a specific kind of mathematical group. Most (all?) block encryption algorithms are not such groups.
AFAIK this should be possible with slight modification to RSA. I do not know of any tool which can actually do it though.
No, it does not work. Very simply, you cannot guarantee unique decryption because one modulus is bigger than the other.
EDIT: I'm assuming this is RSA. If not, then I'd have to think about some of the others.
EDIT2: If you are always willing to use the smaller modulus first, then it does work.
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.