package net.java.otr4j.io; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.interfaces.DSAParams; import java.security.interfaces.DSAPublicKey; import java.security.spec.DSAPublicKeySpec; import java.security.spec.InvalidKeySpecException; import javax.crypto.interfaces.DHPublicKey; import net.java.otr4j.crypto.OtrCryptoEngineImpl; import net.java.otr4j.io.messages.SignatureX; public class OtrInputStream extends FilterInputStream implements SerializationConstants { public OtrInputStream(InputStream in) { super(in); } private int readNumber(int length) throws IOException { byte[] b = new byte[length]; read(b); int value = 0; for (int i = 0; i < b.length; i++) { int shift = (b.length - 1 - i) * 8; value += (b[i] & 0x000000FF) << shift; } return value; } public int readByte() throws IOException { return readNumber(TYPE_LEN_BYTE); } public int readInt() throws IOException { return readNumber(TYPE_LEN_INT); } public int readShort() throws IOException { return readNumber(TYPE_LEN_SHORT); } public byte[] readCtr() throws IOException { byte[] b = new byte[TYPE_LEN_CTR]; read(b); return b; } public byte[] readMac() throws IOException { byte[] b = new byte[TYPE_LEN_MAC]; read(b); return b; } public BigInteger readBigInt() throws IOException { byte[] b = readData(); return new BigInteger(1, b); } public byte[] readData() throws IOException { int dataLen = readNumber(DATA_LEN); byte[] b = new byte[dataLen]; read(b); return b; } public PublicKey readPublicKey() throws IOException { int type = readShort(); switch (type) { case 0: BigInteger p = readBigInt(); BigInteger q = readBigInt(); BigInteger g = readBigInt(); BigInteger y = readBigInt(); DSAPublicKeySpec keySpec = new DSAPublicKeySpec(y, p, q, g); KeyFactory keyFactory; try { keyFactory = KeyFactory.getInstance("DSA"); } catch (NoSuchAlgorithmException e) { throw new IOException(); } try { return keyFactory.generatePublic(keySpec); } catch (InvalidKeySpecException e) { throw new IOException(); } default: throw new UnsupportedOperationException(); } } public DHPublicKey readDHPublicKey() throws IOException { BigInteger gyMpi = readBigInt(); try { return new OtrCryptoEngineImpl().getDHPublicKey(gyMpi); } catch (Exception ex) { throw new IOException(); } } public byte[] readTlvData() throws IOException { int len = readNumber(TYPE_LEN_SHORT); byte[] b = new byte[len]; in.read(b); return b; } public byte[] readSignature(PublicKey pubKey) throws IOException { if (!pubKey.getAlgorithm().equals("DSA")) throw new UnsupportedOperationException(); DSAPublicKey dsaPubKey = (DSAPublicKey) pubKey; DSAParams dsaParams = dsaPubKey.getParams(); byte[] sig = new byte[dsaParams.getQ().bitLength() / 4]; read(sig); return sig; } public SignatureX readMysteriousX() throws IOException { PublicKey pubKey = readPublicKey(); int dhKeyID = readInt(); byte[] sig = readSignature(pubKey); return new SignatureX(pubKey, dhKeyID, sig); } }