[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Double headers to protect against tagging
Dear All,
After having read properly Zooko's proposal I got the idea that we can use
two headers to avoid tagging attacks all together. It also follows from my
last email exchange with Nick.
The intuition is the following:
We have two routing headers H1 and H2 and a payload M.
Both H1 and H2 have their integrity protected by Hashes and are discarded
is changed.
Both H2 and M are encrypted using BEAR (or other all or nothing transform)
by the keys contained in H1. Additionally H2 is encrypted using H(M') as a
key to a BEAR transform.
The processing is muxh as before: The first routing header is decrypted
and checked as it goes along, and the inverse BEAR transform is applied to
the second header and the payload.
The only difference is that the last hop of the first routing header is
also doing the following: it Hashes the payload M and uses it to decrypt
the second header. Then the second header has its position exchanged with
the first on and is now in front of the packet.
The packet is passed along to the next mix which treats it as any other
packet.
Why does that help? If someone tags the first header at any point the
packet is rejected at the next hop. So the header tagging attack is not
possible.
Now if someone tries to tag the second header or the body of the message
is will be impossible to retrieve any of these (H2 depends on the body and
the body depends on secrets inside H2, creating effectively a ladder
structure). Therefore the packet will have to be dropped at the end of the
first Header.
It is still possible to run the tagging attack after the special step, but
by then the message has already traveled through the network securely
(using the first header) and the attacker cannot therefore link it back to
the original sender (although the anonymity set is reduced).
This approach has the advantages to only waste an additional header, which
is used anyway. It provides undistinguishability between forward and
return mechanisms, and is resistant against all tagging attacks.
The technical details are not yet completely worked out but I have a pretty
picture (in pdf) that shows the standard processing both conceptually and
in terms of cryptography. You can find it at:
http://www.cl.cam.ac.uk/~gd216/MixMinBEAR.pdf
(I am not sure how happy CVS is receiving PDF files, so I have not checked
it in yet)
I am looking forward to hear what you think
Yours,
George
PS: I also have some techical specs:
We redefine the header to contain the following:
Major Version, Minor Version: V [2 bytes]
Master Secret: MS [16 bytes]
Timestamp: T [2 bytes] (is that correct?)
Size: S [2 bytes]
Type: Tp [1 bit] * Note the 1bit*
Transform: Tr [1 bit] * Note the 1bit*
Hash: H [10byte]
Address Type, Next Address, Dest. Port, Expected Key: A [40bytes]
We denote a particular header composed of the above elements as:
MH(V, MS, T, S, Tp, Tr, H, A)
Define:
- if B is a byte array, B[i:j] (j bytes) is sub array starting at
byte i with length j.
- R(n) (n bytes) Generates n random bytes. Only used by client.
- Z(n) (n bytes) Generates n zero bytes
- Len(M) (2 bytes) is the length of message M (* bytes)
- x|y (Len(x)+Len(y) bytes) denotes x concatenated with y.
- PAD(M,L) (L bytes) pads the message M (Len(M) <= L) to length L
[Q Pads it with what? -RD]
- H(M) (20 bytes) is the SHA-1 hash of M (* bytes)
- RSA_OAEP_Encrypt(K,M) (128 bytes): the encryption of M (73
bytes) using the public key K as described in PKCS\#1.
- RSA_OAEP_Decrypt(K,M) (73 bytes) Gives the decryption of the
message M (128 bytes) under the private key corresponding to K.
- Encrypt(K,M) (Len(M) bytes) Rijndael in Counter mode encryption
of message M using key K.
- Decrypt(K,M,i,j) (j bytes) Rijndael counter mode decryption
using the key material byte i to j. Len(M) = j.
The encoding of apacket is now:
Input: K1...Kn keys of M1...Mn
Input: Kn+1...Km keys of Mn+1...Mm
where n and m-n have to be smaller than some constant.
(The maximum for each header "Max")
Then we construct 2 headers:
The prevJunkBlock procedure constructs the encrypted junk that a mix would
expect to see for the purpose of calculating the correct hash.
Header 1: H1
- S[1..n] = R(16) // Think of n master secrets
- J = R(128* (Max - n)) // Junk to fill the routing header.
- M = J
- for i = n to 1
H = H(M | PrevJunkBlock(i))
if i = n then tr = 1 else tr = 0
Ma = RSA_OAEP_Encrypt(Kn, MH(V, Si, T, 62k, 0, Tr, H, Mi))
Mb = Encrypt(H(Si,"SECRECY_MODE")[0:16], M)
M = Ma | Mb
Header 2: H2
- S[1..n] = R(16) // Think of n master secrets
- J = R(128* (Max - n)) // Junk to fill the routing header.
- M = J
- for i = m to n+1
H = H(M | PrevJunkBlock(i))
if i = m then tp = 1 else tp = 0
Ma = RSA_OAEP_Encrypt(Kn, MH(V, Si, T, 62k, 0, Tr, H, Mi))
Mb = Encrypt(H(Si,"SECRECY_MODE")[0:16], M)
M = Ma | Mb
Final Message:
input: message "Msg"
for i = m to n+1
Msg = BEAR(H(Si,"BEAR_BODY_MODE")[0:16],Msg)
end
H2 = BEAR( H(Msg)[0:16], H2)
for i = n to 0
H2 = BEAR(H(Si,"BEAR_HEAD_MODE")
Msg = BEAR(H(Si,"BEAR_BODY_MODE")[0:16],Msg)
end
Final message (M0,H1|H2|Msg)
In order to construct a return address the second header H2 is constructed
using a MasterMasterSecret MMS used to generate all the other Si, which is
stored
in the Mm header along with the number of hops. The message is not then
BEARed using
any of the keys inside the H2 header.
Standard processing:
MMProcess(K_x, M)
- MH(V,MS,T,S,Tp,Rt,Ru,A) = RSA_OAEP_Decrypt(K_x,M[0:128])
- Check that the OAEP structure is intact.
- Check that protocol version V is supported.
- Check T to make sure the message is valid.
- Calculate US = H(M[0:128]) and check that it has not been
seen before.
- Store US.
- if tp = 0
o Check that S = 62kb
o Check the hash H on the rest of the header
H == H(M[128:128*Max-128])
o D = Decrypt(H(MS|"SECRECY_MODE")[0:16],M[128:Max*128])
o J = Encrypt(H(MS|"JUNK_GENERATION_MODE")[0:16], Z(128))
o M = M[128:128*Max] | J | M[128*Max:62k-128*Max]
o if tr = 1
+ H2 = BEAR( H(M[128*Max*2:62k])[0:16], M[128*Max:128*Max])
+ M = M[128*Max:128*Max] | M[0:128*Max] | M[128*2*Max: 62k -
128*2*Max]
o Send (K_x, M) to the network
- else
[The procedure goes on as before taking into account
that SURB messages need to be decrypted before it is
given to the application.]