From 566d17f731637df6828bdf32502a0fb123882dbe Mon Sep 17 00:00:00 2001 From: Peter Palfrader Date: Thu, 9 Oct 2003 11:41:45 +0000 Subject: Initial import --- src/org/noreply/fancydress/type3/SingleLeg.java | 144 ++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 src/org/noreply/fancydress/type3/SingleLeg.java (limited to 'src/org/noreply/fancydress/type3/SingleLeg.java') diff --git a/src/org/noreply/fancydress/type3/SingleLeg.java b/src/org/noreply/fancydress/type3/SingleLeg.java new file mode 100644 index 0000000..f4a68c6 --- /dev/null +++ b/src/org/noreply/fancydress/type3/SingleLeg.java @@ -0,0 +1,144 @@ +package org.noreply.fancydress.type3; + +import org.noreply.fancydress.misc.Util; +import org.noreply.fancydress.type3.routing.*; +import org.noreply.fancydress.crypto.*; +import org.noreply.fancydress.status.*; +import java.util.*; + +public abstract class SingleLeg { + public static final int MIN_SH = 42; /* length of the invariant part of a subheader */ + public static final int SINGLE_HEADER_LEN = 2048; /* length of the invariant part of a subheader */ + private byte[] thisLeg = null; + private Routing thisRoute = null; + + public static final int MAJOR_VERSION = 0; + public static final int MINOR_VERSION = 3; + + public SingleLeg() { + } + + public byte[] asOctets() { + if (thisLeg == null) + throw new Error("Leg not yet initialized"); + return thisLeg; + } + + protected void makeLeg( + Hop[] hops, + byte[][] sharedKeys, + Routing finalRouting) + throws Mix3BadArgumentsChainTooLongException + { + if (thisLeg != null) + throw new Error("Leg already initialized"); + + int n = hops.length; + int[] size = new int[n]; + byte[][] junkKey = new byte[n][]; + byte[][] key = new byte[n][]; + byte[][] junk = new byte[n][]; + byte[][] subHeader = new byte[n+1][]; + + // Calculate the sizes of the subheaders + int paddingLength = SINGLE_HEADER_LEN; + for (int i=0; i < n; i++) { + Routing routing = i == n-1 ? finalRouting : hops[i+1].getRouting(); + + size[i] = MIN_SH + RSAPublicKey.PK_OVERHEAD_LEN + routing.getRoutingInformationLength(); + junkKey[i] = CryptoPrimitives.subKey(sharedKeys[i], "RANDOM JUNK"); + key[i] = CryptoPrimitives.subKey(sharedKeys[i], "HEADER SECRET KEY"); + + paddingLength -= size[i]; + } + + if (paddingLength < 0) + throw new Mix3BadArgumentsChainTooLongException("Chain too long"); + + // Calculate the Junk that will be appended during processing. + // J_i is the junk that node i will append, and node i+1 will see. + for (int i=0; i < n; i++) { + byte[] tmp = CryptoPrimitives.prng(junkKey[i], size[i]); + junk[i] = i == 0 ? tmp : Util.concat(junk[i-1], tmp); + byte[] stream = CryptoPrimitives.prng(key[i], SINGLE_HEADER_LEN + size[i]); + // Before we encrypt the junk, we encrypt all the data, and all + // the initial padding, but not the RSA-encrypted part. + int offset = SINGLE_HEADER_LEN - RSAPublicKey.PK_ENC_LEN - (i==0 ? 0 : junk[i-1].length); + junk[i] = CryptoPrimitives.xor(junk[i], Util.slice(stream, offset, junk[i].length)); + } + + // Create the Header, starting with the padding + subHeader[n] = CryptoPrimitives.rand(paddingLength); + for (int i=n-1; i>=0; i--) { + Routing routing = i == n-1 ? finalRouting : hops[i+1].getRouting(); + + byte[] sh0 = makeSHS(sharedKeys[i], CryptoPrimitives.zero(CryptoPrimitives.HASH_LEN), routing); + int shLength = sh0.length; + byte[] h0 = Util.concat( sh0, subHeader[i+1] ); + + byte[] rest = Util.slice( h0, RSAPublicKey.PK_MAX_DATA_LEN, h0.length - RSAPublicKey.PK_MAX_DATA_LEN); + byte[] encryptedRest = CryptoPrimitives.encrypt(key[i], rest); + + byte[] digest = CryptoPrimitives.hash( i == 0 ? encryptedRest : Util.concat(encryptedRest, junk[i-1])); + + byte[] sh = makeSHS(sharedKeys[i], digest, routing); + int underflow = Util.max(RSAPublicKey.PK_MAX_DATA_LEN - shLength, 0); + byte[] rsaPart = Util.concat( sh, Util.slice(h0, RSAPublicKey.PK_MAX_DATA_LEN - underflow, underflow)); + + RSAPublicKey pk = hops[i].getPubKey(); + byte[] esh = pk.encrypt(rsaPart); + subHeader[i] = Util.concat(esh, encryptedRest); + } + byte[] result = subHeader[0]; + + thisLeg = result; + thisRoute = hops[0].getRouting(); + } + + + /** + * create a sub header structure. + */ + static private byte[] makeSHS( + byte[] sharedSecret, + byte[] digest, + Routing routing) + { + if (sharedSecret.length != CryptoPrimitives.KEY_LEN) + throw new Error("sharedSecret must be KEY_LEN bytes long."); + if (digest.length != CryptoPrimitives.HASH_LEN) + throw new Error("digest must be HASH_LEN bytes long."); + byte[] fixedPart = new byte[MIN_SH]; + byte[] dynamicPart = routing.getRoutingInformation(); + int routingSize = dynamicPart.length; + int routingType = routing.getRoutingType(); + + int pos = 0; + fixedPart[pos] = MAJOR_VERSION; + pos++; + fixedPart[pos] = MINOR_VERSION; + pos++; + System.arraycopy(sharedSecret, 0, fixedPart, pos, CryptoPrimitives.KEY_LEN); + pos +=CryptoPrimitives.KEY_LEN; + System.arraycopy(digest, 0, fixedPart, pos, CryptoPrimitives.HASH_LEN); + pos +=CryptoPrimitives.HASH_LEN; + fixedPart[pos] = (byte) ( (routingSize >> 8) & 0xff); + pos++; + fixedPart[pos] = (byte) ( routingSize & 0xff); + pos++; + fixedPart[pos] = (byte) ( (routingType >> 8) & 0xff); + pos++; + fixedPart[pos] = (byte) ( routingType & 0xff); + pos++; + + if (pos != MIN_SH) + throw new Error("Did not fill in MIN_SH bytes!"); + + return Util.concat(fixedPart, dynamicPart); + } + + public Routing getRoute() { + return thisRoute; + } +} + -- cgit v1.2.3