src/net/java/otr4j/io/OtrOutputStream.java
changeset 895 b2e1b45382a4
parent 810 0ff0059f2ec3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/net/java/otr4j/io/OtrOutputStream.java	Fri Apr 15 03:01:09 2011 +0200
@@ -0,0 +1,140 @@
+package net.java.otr4j.io;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+
+import javax.crypto.interfaces.DHPublicKey;
+
+import net.java.otr4j.io.messages.SignatureM;
+import net.java.otr4j.io.messages.MysteriousT;
+import net.java.otr4j.io.messages.SignatureX;
+
+import org.bouncycastle2.util.BigIntegers;
+
+public class OtrOutputStream extends FilterOutputStream implements
+		SerializationConstants {
+
+	public OtrOutputStream(OutputStream out) {
+		super(out);
+	}
+
+	private void writeNumber(int value, int length) throws IOException {
+		byte[] b = new byte[length];
+		for (int i = 0; i < length; i++) {
+			int offset = (b.length - 1 - i) * 8;
+			b[i] = (byte) ((value >>> offset) & 0xFF);
+		}
+		write(b);
+	}
+
+	public void writeBigInt(BigInteger bi) throws IOException {
+		byte[] b = BigIntegers.asUnsignedByteArray(bi);
+		writeData(b);
+	}
+
+	public void writeByte(int b) throws IOException {
+		writeNumber(b, TYPE_LEN_BYTE);
+	}
+
+	public void writeData(byte[] b) throws IOException {
+		int len = (b == null || b.length < 0) ? 0 : b.length;
+		writeNumber(len, DATA_LEN);
+		if (len > 0)
+			write(b);
+	}
+
+	public void writeInt(int i) throws IOException {
+		writeNumber(i, TYPE_LEN_INT);
+
+	}
+
+	public void writeShort(int s) throws IOException {
+		writeNumber(s, TYPE_LEN_SHORT);
+
+	}
+
+	public void writeMac(byte[] mac) throws IOException {
+		if (mac == null || mac.length != TYPE_LEN_MAC)
+			throw new IllegalArgumentException();
+
+		write(mac);
+	}
+
+	public void writeCtr(byte[] ctr) throws IOException {
+		if (ctr == null || ctr.length < 1)
+			return;
+
+		int i = 0;
+		while (i < TYPE_LEN_CTR && i < ctr.length) {
+			write(ctr[i]);
+			i++;
+		}
+	}
+
+	public void writeDHPublicKey(DHPublicKey dhPublicKey) throws IOException {
+		byte[] b = BigIntegers.asUnsignedByteArray(dhPublicKey.getY());
+		writeData(b);
+	}
+
+	public void writePublicKey(PublicKey pubKey) throws IOException {
+		if (!(pubKey instanceof DSAPublicKey))
+			throw new UnsupportedOperationException(
+					"Key types other than DSA are not supported at the moment.");
+
+		DSAPublicKey dsaKey = (DSAPublicKey) pubKey;
+
+		writeShort(0);
+
+		DSAParams dsaParams = dsaKey.getParams();
+		writeBigInt(dsaParams.getP());
+		writeBigInt(dsaParams.getQ());
+		writeBigInt(dsaParams.getG());
+		writeBigInt(dsaKey.getY());
+
+	}
+
+	public void writeTlvData(byte[] b) throws IOException {
+		int len = (b == null || b.length < 0) ? 0 : b.length;
+		writeNumber(len, TLV_LEN);
+		if (len > 0)
+			write(b);
+	}
+
+	public void writeSignature(byte[] signature, PublicKey pubKey)
+			throws IOException {
+		if (!pubKey.getAlgorithm().equals("DSA"))
+			throw new UnsupportedOperationException();
+		out.write(signature);
+	}
+
+	public void writeMysteriousX(SignatureX x) throws IOException {
+		writePublicKey(x.longTermPublicKey);
+		writeInt(x.dhKeyID);
+		writeSignature(x.signature, x.longTermPublicKey);
+	}
+
+	public void writeMysteriousX(SignatureM m) throws IOException {
+		writeBigInt(m.localPubKey.getY());
+		writeBigInt(m.remotePubKey.getY());
+		writePublicKey(m.localLongTermPubKey);
+		writeInt(m.keyPairID);
+	}
+
+	public void writeMysteriousT(MysteriousT t) throws IOException {
+		writeShort(t.protocolVersion);
+		writeByte(t.messageType);
+		writeByte(t.flags);
+
+		writeInt(t.senderKeyID);
+		writeInt(t.recipientKeyID);
+		writeDHPublicKey(t.nextDH);
+		writeCtr(t.ctr);
+		writeData(t.encryptedMessage);
+
+	}
+}