--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/net/java/otr4j/io/OtrOutputStream.java Sun Dec 05 18:43:51 2010 +0100
@@ -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.bouncycastle.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);
+
+ }
+}