1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
/* $Id$ */
package org.noreply.fancydress.type3;
import org.noreply.fancydress.type3.routing.*;
import org.noreply.fancydress.status.*;
import org.noreply.fancydress.crypto.*;
import org.noreply.fancydress.misc.*;
public class SURB extends SingleLeg {
public static final byte[] VERSION = {0, 1};
public static final String ARMOR_VERSION = "0.2";
private byte[] sharedSecret;
public SURB (HalfPath path, byte[] secret, RoutingDestination address) throws Mix3BadArgumentsChainTooLongException {
super();
byte[] seed;
byte[] validateHash;
byte[] validate = Util.toOctets("Validate");
Hop[] hops = path.getHops();
do {
seed = CryptoPrimitives.rand(20);
seed[0] &= 0x7f;
validateHash = CryptoPrimitives.hash(seed, secret, validate);
} while (validateHash[validateHash.length-1] == 0);
byte[] key = Util.slice(CryptoPrimitives.hash(seed, secret, Util.toOctets("Generate")), 0, CryptoPrimitives.KEY_LEN);
byte[] stream = CryptoPrimitives.prng(key, CryptoPrimitives.KEY_LEN*(hops.length + 1));
sharedSecret = Util.slice(stream, CryptoPrimitives.KEY_LEN*hops.length, CryptoPrimitives.KEY_LEN);
byte[][] sharedKeys = new byte[hops.length][];
for (int i=0; i<hops.length; i++)
sharedKeys[i] = Util.slice(stream, (hops.length-i-1)*CryptoPrimitives.KEY_LEN, CryptoPrimitives.KEY_LEN);
address.setDecodingHandle(seed);
makeLeg(hops, sharedKeys, address);
};
/*
Begin Marker: 4 octets
Version: 2 octets
Use-by-Date: 4 octets
SURB header: 2048 octets
Routing Size: 2 octets
Routing Type: 2 octets
Encryption key: 16 octets
Routing Info: (Routing Size) octets
*/
public String export() {
byte[] beginMarker = Util.toOctets("SURB");
int useBy = 1068595200; //FIXME // Y2k36
RoutingForward route = getRoute().asSwap();
byte[] routingInformation = route.getRoutingInformation();
int routingSize = routingInformation.length;
int routingType = route.getRoutingType();
byte[] result = new byte[4+2+4+SINGLE_HEADER_LEN+2+2+CryptoPrimitives.KEY_LEN+routingSize];
int pos = 0;
System.arraycopy(beginMarker, 0, result, pos, beginMarker.length);
pos += beginMarker.length;
System.arraycopy(VERSION, 0, result, pos, VERSION.length);
pos += VERSION.length;
result[pos] = (byte) ( (useBy >>24) & 0xff);
pos++;
result[pos] = (byte) ( (useBy >>16) & 0xff);
pos++;
result[pos] = (byte) ( (useBy >> 8) & 0xff);
pos++;
result[pos] = (byte) ( (useBy ) & 0xff);
pos++;
System.arraycopy(super.asOctets(), 0, result, pos, SINGLE_HEADER_LEN);
pos += SINGLE_HEADER_LEN;
result[pos] = (byte) ( (routingSize >> 8) & 0xff);
pos++;
result[pos] = (byte) ( routingSize & 0xff);
pos++;
result[pos] = (byte) ( (routingType >> 8) & 0xff);
pos++;
result[pos] = (byte) ( routingType & 0xff);
pos++;
System.arraycopy(sharedSecret, 0, result, pos, CryptoPrimitives.KEY_LEN);
pos += CryptoPrimitives.KEY_LEN;
System.arraycopy(routingInformation, 0, result, pos, routingSize);
pos += routingSize;
if (pos != result.length)
throw new Error("did not fill in expected number of bytes");
String[] headers = new String[1];
headers[0] = "Version: "+ARMOR_VERSION;
return Util.armor(result, "TYPE III REPLY BLOCK", headers);
}
}
|