package io.airlift.airship.coordinator.auth.ssh; import com.google.common.io.ByteStreams; import java.io.ByteArrayInputStream; import java.io.IOException; import java.math.BigInteger; public class DerReader { private final ByteArrayInputStream in; public DerReader(byte[] data) { in = new ByteArrayInputStream(data); } public BigInteger readBigInteger() { byte[] data = readEntry(DerType.INTEGER); return new BigInteger(1, data); } public byte[] readEntry(DerType expectedType) { int type = readNextByte(); if (type != expectedType.getValue()) { throw new IllegalStateException("Next entry is not an " + expectedType); } int length = readLength(); return readNextBytes(length); } public boolean isComplete() { return in.available() == 0; } private int readLength() { int value = readNextByte(); // single byte (no length) if (value < (1 << 7)) { return value; } int numberOfBytes = value & 0x0F; int length = 0; switch (numberOfBytes) { case 4: length = readNextByte() | (length << 8); case 3: length = readNextByte() | (length << 8); case 2: length = readNextByte() | (length << 8); case 1: length = readNextByte() | (length << 8); break; default: throw new IllegalArgumentException("Entry length is invalid"); } return length; } private int readNextByte() { int next = in.read(); if (next < 0) { throw new IllegalArgumentException("Corruption: expected more bytes"); } return next; } private byte[] readNextBytes(int length) { try { byte[] data = new byte[length]; ByteStreams.readFully(in, data); return data; } catch (IOException e) { throw new IllegalArgumentException("Corruption: expected more bytes"); } } }