Suppose we wish to broadcast a stream to a set of users securely. How can we achieve integrity? We cannot use MAC's, otherwise the users could forge packets to each other. We cannot sign the entire stream: this solution is vulnerable to packet loss, and also the whole stream would have to be buffered for verification. We cannot sign each packet individually, as this is too inefficient.
Method 1 (Combinatorial)
We describe a simple scheme based on families of coverfree subsets. It is a too inefficient for practical purposes.
There are users and a single source. The source has several MAC keys , where will be determined later.
The th receiver has a set of keys .
To send a message , the source transmits .
Recipient accepts a packet if all the MAC's corresponding to their set verify.
At the bare minimum, we want 1-security, that is, any user should not be able to forge a packet for any other user , so we must have . The best way to do this is to use all subsets of size from the set of keys, so we need , so .
More generally, for -security (i.e. so that no group of users can forge a packet), we require a family of -coverfree subsets, which can be done with . Thus the packet size is quadratic in . It can be shown that a smaller packet size implies nonrepudiation, that is, a MAC that short would in fact be a signature.
Method 2 (TESLA)
This solution uses time for security. Assume the total clock skew is , and that the total routing time is less than or equal to some time .
We use hash chains, i.e:
For setup, give to all recipients, for some sufficiently large . The source has . Then:
Time : send
Time : send
Time : send . By this stage, all users should have received .
Time : send , and also send
Time : all users can validate
To validate the first packet:
-
Check that is in the hash chain
-
Verify
-
Reject if received after time
Note that this scheme requires the users to buffer packets for time steps.
It has been shown [Jacobson-Coppersmith] that one can construct a hash chain where computing any element of it takes time in space.
Method 3 (Signing) [Wong and Lam]
Signing every packet is too expensive, but signing many packets is vulnerable to packet loss. The solution is to sign many packets at once but verify them individually.
For example, suppose we have four packets . We construct a hash tree (diagram will be here when Mozilla supports SVG :-) (e.g. if we label the tree nodes , we have
and transmit the packet plus enough nodes of the tree to derive the root node:
-
send
-
send
-
send
-
send
The overhead is hashes plus a signature per packet.
However, this method requires buffering at the source. We can use one-time signatures to alleviate this.
One-Time Signatures are signatures that can be constructed and verified very quickly, but can only be used once (or a few times).
For example [Lamport], consider the following scheme:
-
Private key: .
-
Public key:
-
Sign(): compute . The signature is where is the bit of .
Another example. BiBa OTS (Bins and balls):
-
Let be the security parameter. Let be a hash function where .
-
Private key:
-
Public key:
-
Sign(): find such that . The signature is ("Find two balls that hit the same bin.")
We can now remove the buffering problem as follows. Build a hash tree from the public keys of some one-time signature scheme. Sign the tree and transmit the public keys with signatures (so we commit to public keys instead of packets), and simply sign each packet.
Method 4: Expanders
Build a directed acyclic graph (DAG) using the packets as nodes. Then proceed as in the previous scheme, except this time we use a hash DAG, instead of a hash tree.
To resist up to packets being lost, we need a graph that remains connected even if nodes are removed.
An -expander graph is a graph such that for all , we have if (?) .
There exist methods of constructing constant degree expanders on nodes such that removing nodes for some constant does not disconnect the graph.