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; package net.sf.briar.api.crypto;
import java.security.GeneralSecurityException;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
public interface KeyParser { 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; boolean eof() throws IOException;
void setReadLimit(long limit); void setReadLimit(long limit);
void resetReadLimit(); void resetReadLimit();
long getRawBytesRead();
void close() throws IOException; void close() throws IOException;
boolean hasBoolean() throws IOException; boolean hasBoolean() throws IOException;

View File

@@ -6,6 +6,7 @@ import java.util.Map;
public interface Writer { public interface Writer {
long getRawBytesWritten();
void close() throws IOException; void close() throws IOException;
void writeBoolean(boolean b) 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.PublicKey;
import java.security.Signature; import java.security.Signature;
import java.security.SignatureException; import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import net.sf.briar.api.crypto.KeyParser; import net.sf.briar.api.crypto.KeyParser;
import net.sf.briar.api.protocol.AuthorId; 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 // Hash the author's nick and public key to get the author ID
String nick = r.readUtf8(); String nick = r.readUtf8();
byte[] encodedKey = r.readRaw(); byte[] encodedKey = r.readRaw();
PublicKey publicKey = keyParser.parsePublicKey(encodedKey);
messageDigest.reset(); messageDigest.reset();
messageDigest.update(nick.getBytes("UTF-8")); messageDigest.update(nick.getBytes("UTF-8"));
messageDigest.update((byte) 0); // Null separator messageDigest.update((byte) 0); // Null separator
@@ -60,12 +60,17 @@ class MessageParserImpl implements MessageParser {
AuthorId author = new AuthorId(messageDigest.digest()); AuthorId author = new AuthorId(messageDigest.digest());
// Skip the message body // Skip the message body
r.readRaw(); 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 // 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.initVerify(publicKey);
signature.update(raw, 0, length); signature.update(raw, 0, messageLength);
if(!signature.verify(sig)) throw new SignatureException(); if(!signature.verify(sig)) throw new SignatureException();
// Hash the message, including the signature, to get the message ID // Hash the message, including the signature, to get the message ID
messageDigest.reset(); messageDigest.reset();
@@ -73,12 +78,4 @@ class MessageParserImpl implements MessageParser {
MessageId id = new MessageId(messageDigest.digest()); MessageId id = new MessageId(messageDigest.digest());
return new MessageImpl(id, parent, group, author, timestamp, raw); 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 final InputStream in;
private boolean started = false, eof = false, readLimited = false; private boolean started = false, eof = false, readLimited = false;
private byte next; private byte next;
private long readLimit = 0L; private long rawBytesRead = 0L, readLimit = 0L;
private byte[] buf = null; private byte[] buf = null;
ReaderImpl(InputStream in) { ReaderImpl(InputStream in) {
@@ -31,12 +31,12 @@ class ReaderImpl implements Reader {
} }
private byte readNext(boolean eofAcceptable) throws IOException { private byte readNext(boolean eofAcceptable) throws IOException {
started = true;
int i = in.read(); int i = in.read();
if(i == -1) { if(i == -1) {
eof = true; eof = true;
if(!eofAcceptable) throw new FormatException(); if(!eofAcceptable) throw new FormatException();
} } else rawBytesRead++;
started = true;
if(i > 127) i -= 256; if(i > 127) i -= 256;
next = (byte) i; next = (byte) i;
return next; return next;
@@ -53,6 +53,12 @@ class ReaderImpl implements Reader {
readLimit = 0L; 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 { public void close() throws IOException {
in.close(); in.close();
} }
@@ -134,9 +140,11 @@ class ReaderImpl implements Reader {
if(buf == null || buf.length < length) buf = new byte[length]; if(buf == null || buf.length < length) buf = new byte[length];
buf[0] = next; buf[0] = next;
int offset = 1, read = 0; int offset = 1, read = 0;
while(offset < length && read != -1) { while(offset < length) {
read = in.read(buf, offset, length - offset); 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(); if(offset < length) throw new FormatException();
readNext(true); readNext(true);
@@ -307,7 +315,7 @@ class ReaderImpl implements Reader {
readNull(); readNull();
return null; return null;
} }
throw new IllegalStateException(); throw new FormatException();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

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

View File

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

View File

@@ -3,6 +3,7 @@ package net.sf.briar.serial;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
@@ -343,6 +344,27 @@ public class ReaderImplTest extends TestCase {
assertTrue(r.eof()); 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) { private void setContents(String hex) {
in = new ByteArrayInputStream(StringUtils.fromHexString(hex)); in = new ByteArrayInputStream(StringUtils.fromHexString(hex));
r = new ReaderImpl(in); r = new ReaderImpl(in);

View File

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