Added accessors for the amount of raw data read and written by readers and writers - this fixes a fixme in MessageParserImpl.

This commit is contained in:
akwizgran
2011-07-12 20:27:37 +01:00
parent 22a67cc0d2
commit c3643a037b
9 changed files with 78 additions and 23 deletions

View File

@@ -1,9 +1,9 @@
package net.sf.briar.api.crypto;
import java.security.GeneralSecurityException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
public interface KeyParser {
PublicKey parsePublicKey(byte[] encodedKey) throws GeneralSecurityException;
PublicKey parsePublicKey(byte[] encodedKey) throws InvalidKeySpecException;
}

View File

@@ -9,6 +9,7 @@ public interface Reader {
boolean eof() throws IOException;
void setReadLimit(long limit);
void resetReadLimit();
long getRawBytesRead();
void close() throws IOException;
boolean hasBoolean() throws IOException;

View File

@@ -6,6 +6,7 @@ import java.util.Map;
public interface Writer {
long getRawBytesWritten();
void close() throws IOException;
void writeBoolean(boolean b) throws IOException;

View File

@@ -7,6 +7,7 @@ import java.security.MessageDigest;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import net.sf.briar.api.crypto.KeyParser;
import net.sf.briar.api.protocol.AuthorId;
@@ -52,7 +53,6 @@ class MessageParserImpl implements MessageParser {
// Hash the author's nick and public key to get the author ID
String nick = r.readUtf8();
byte[] encodedKey = r.readRaw();
PublicKey publicKey = keyParser.parsePublicKey(encodedKey);
messageDigest.reset();
messageDigest.update(nick.getBytes("UTF-8"));
messageDigest.update((byte) 0); // Null separator
@@ -60,12 +60,17 @@ class MessageParserImpl implements MessageParser {
AuthorId author = new AuthorId(messageDigest.digest());
// Skip the message body
r.readRaw();
// Read the signature and work out how long the signed message is
byte[] sig = r.readRaw();
int length = raw.length - sig.length - bytesToEncode(sig.length);
// Verify the signature
int messageLength = (int) r.getRawBytesRead();
byte[] sig = r.readRaw();
PublicKey publicKey;
try {
publicKey = keyParser.parsePublicKey(encodedKey);
} catch(InvalidKeySpecException e) {
throw new FormatException();
}
signature.initVerify(publicKey);
signature.update(raw, 0, length);
signature.update(raw, 0, messageLength);
if(!signature.verify(sig)) throw new SignatureException();
// Hash the message, including the signature, to get the message ID
messageDigest.reset();
@@ -73,12 +78,4 @@ class MessageParserImpl implements MessageParser {
MessageId id = new MessageId(messageDigest.digest());
return new MessageImpl(id, parent, group, author, timestamp, raw);
}
// FIXME: Work out a better way of doing this
private int bytesToEncode(int i) {
if(i >= 0 && i <= Byte.MAX_VALUE) return 2;
if(i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) return 3;
if(i >= Short.MIN_VALUE && i <= Short.MAX_VALUE) return 4;
return 6;
}
}

View File

@@ -18,7 +18,7 @@ class ReaderImpl implements Reader {
private final InputStream in;
private boolean started = false, eof = false, readLimited = false;
private byte next;
private long readLimit = 0L;
private long rawBytesRead = 0L, readLimit = 0L;
private byte[] buf = null;
ReaderImpl(InputStream in) {
@@ -31,12 +31,12 @@ class ReaderImpl implements Reader {
}
private byte readNext(boolean eofAcceptable) throws IOException {
started = true;
int i = in.read();
if(i == -1) {
eof = true;
if(!eofAcceptable) throw new FormatException();
}
} else rawBytesRead++;
started = true;
if(i > 127) i -= 256;
next = (byte) i;
return next;
@@ -53,6 +53,12 @@ class ReaderImpl implements Reader {
readLimit = 0L;
}
public long getRawBytesRead() {
if(eof) return rawBytesRead;
else if(started) return rawBytesRead - 1L; // Exclude lookahead byte
else return 0L;
}
public void close() throws IOException {
in.close();
}
@@ -134,9 +140,11 @@ class ReaderImpl implements Reader {
if(buf == null || buf.length < length) buf = new byte[length];
buf[0] = next;
int offset = 1, read = 0;
while(offset < length && read != -1) {
while(offset < length) {
read = in.read(buf, offset, length - offset);
if(read != -1) offset += read;
if(read == -1) break;
offset += read;
rawBytesRead += read;
}
if(offset < length) throw new FormatException();
readNext(true);
@@ -307,7 +315,7 @@ class ReaderImpl implements Reader {
readNull();
return null;
}
throw new IllegalStateException();
throw new FormatException();
}
@SuppressWarnings("unchecked")

View File

@@ -13,11 +13,16 @@ import net.sf.briar.api.serial.Writer;
class WriterImpl implements Writer {
private final OutputStream out;
private long rawBytesWritten = 0L;
WriterImpl(OutputStream out) {
this.out = out;
}
public long getRawBytesWritten() {
return rawBytesWritten;
}
public void close() throws IOException {
out.flush();
out.close();
@@ -26,27 +31,32 @@ class WriterImpl implements Writer {
public void writeBoolean(boolean b) throws IOException {
if(b) out.write(Tag.TRUE);
else out.write(Tag.FALSE);
rawBytesWritten++;
}
public void writeUint7(byte b) throws IOException {
if(b < 0) throw new IllegalArgumentException();
out.write(b);
rawBytesWritten++;
}
public void writeInt8(byte b) throws IOException {
out.write(Tag.INT8);
out.write(b);
rawBytesWritten += 2;
}
public void writeInt16(short s) throws IOException {
out.write(Tag.INT16);
out.write((byte) (s >> 8));
out.write((byte) ((s << 8) >> 8));
rawBytesWritten += 3;
}
public void writeInt32(int i) throws IOException {
out.write(Tag.INT32);
writeInt32Bits(i);
rawBytesWritten += 5;
}
private void writeInt32Bits(int i) throws IOException {
@@ -59,6 +69,7 @@ class WriterImpl implements Writer {
public void writeInt64(long l) throws IOException {
out.write(Tag.INT64);
writeInt64Bits(l);
rawBytesWritten += 9;
}
private void writeInt64Bits(long l) throws IOException {
@@ -87,11 +98,13 @@ class WriterImpl implements Writer {
public void writeFloat32(float f) throws IOException {
out.write(Tag.FLOAT32);
writeInt32Bits(Float.floatToRawIntBits(f));
rawBytesWritten += 5;
}
public void writeFloat64(double d) throws IOException {
out.write(Tag.FLOAT64);
writeInt64Bits(Double.doubleToRawLongBits(d));
rawBytesWritten += 9;
}
public void writeUtf8(String s) throws IOException {
@@ -99,12 +112,14 @@ class WriterImpl implements Writer {
byte[] b = s.getBytes("UTF-8");
writeIntAny(b.length);
out.write(b);
rawBytesWritten += b.length + 1;
}
public void writeRaw(byte[] b) throws IOException {
out.write(Tag.RAW);
writeIntAny(b.length);
out.write(b);
rawBytesWritten += b.length + 1;
}
public void writeRaw(Raw r) throws IOException {
@@ -113,6 +128,7 @@ class WriterImpl implements Writer {
public void writeList(List<?> l) throws IOException {
out.write(Tag.LIST_DEF);
rawBytesWritten++;
writeIntAny(l.size());
for(Object o : l) writeObject(o);
}
@@ -135,14 +151,17 @@ class WriterImpl implements Writer {
public void writeListStart() throws IOException {
out.write(Tag.LIST_INDEF);
rawBytesWritten++;
}
public void writeListEnd() throws IOException {
out.write(Tag.END);
rawBytesWritten++;
}
public void writeMap(Map<?, ?> m) throws IOException {
out.write(Tag.MAP_DEF);
rawBytesWritten++;
writeIntAny(m.size());
for(Entry<?, ?> e : m.entrySet()) {
writeObject(e.getKey());
@@ -152,13 +171,16 @@ class WriterImpl implements Writer {
public void writeMapStart() throws IOException {
out.write(Tag.MAP_INDEF);
rawBytesWritten++;
}
public void writeMapEnd() throws IOException {
out.write(Tag.END);
rawBytesWritten++;
}
public void writeNull() throws IOException {
out.write(Tag.NULL);
rawBytesWritten++;
}
}

View File

@@ -12,6 +12,7 @@ import java.security.MessageDigest;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Collections;
@@ -82,10 +83,12 @@ public class BundleReadWriteTest extends TestCase {
keyPair = KeyPairGenerator.getInstance(KEY_PAIR_ALGO).generateKeyPair();
sig = Signature.getInstance(SIGNATURE_ALGO);
digest = MessageDigest.getInstance(DIGEST_ALGO);
final KeyFactory keyFactory = KeyFactory.getInstance(KEY_PAIR_ALGO);
keyParser = new KeyParser() {
public PublicKey parsePublicKey(byte[] encodedKey) throws GeneralSecurityException {
public PublicKey parsePublicKey(byte[] encodedKey)
throws InvalidKeySpecException {
EncodedKeySpec e = new X509EncodedKeySpec(encodedKey);
return KeyFactory.getInstance(KEY_PAIR_ALGO).generatePublic(e);
return keyFactory.generatePublic(e);
}
};
assertEquals(digest.getDigestLength(), UniqueId.LENGTH);

View File

@@ -3,6 +3,7 @@ package net.sf.briar.serial;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -343,6 +344,27 @@ public class ReaderImplTest extends TestCase {
assertTrue(r.eof());
}
@Test
public void testGetRawBytesRead() throws IOException {
setContents("F4" + "00" + "F4" + "00");
assertEquals(0L, r.getRawBytesRead());
Map<Object, Object> m = r.readMap(Object.class, Object.class);
assertEquals(2L, r.getRawBytesRead());
assertEquals(Collections.emptyMap(), m);
m = r.readMap(Object.class, Object.class);
assertEquals(4L, r.getRawBytesRead());
assertEquals(Collections.emptyMap(), m);
assertTrue(r.eof());
assertEquals(4L, r.getRawBytesRead());
}
@Test
public void testReadEmptyInput() throws IOException {
setContents("");
assertTrue(r.eof());
assertEquals(0L, r.getRawBytesRead());
}
private void setContents(String hex) {
in = new ByteArrayInputStream(StringUtils.fromHexString(hex));
r = new ReaderImpl(in);

View File

@@ -211,5 +211,6 @@ public class WriterImplTest extends TestCase {
byte[] expected = StringUtils.fromHexString(hex);
assertTrue(StringUtils.toHexString(out.toByteArray()),
Arrays.equals(expected, out.toByteArray()));
assertEquals(expected.length, w.getRawBytesWritten());
}
}