test: work on KeyringTestingHelper methods

This commit is contained in:
Vincent Breitmoser 2014-07-13 16:26:26 +02:00
parent f82093c666
commit 3479850ccc

View File

@ -25,17 +25,17 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.OperationResults; import org.sufficientlysecure.keychain.service.OperationResults;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
/** /** Helper methods for keyring tests. */
* Helper for tests of the Keyring import in ProviderHelper.
*/
public class KeyringTestingHelper { public class KeyringTestingHelper {
private final Context context; private final Context context;
@ -68,40 +68,100 @@ public class KeyringTestingHelper {
return saveSuccess; return saveSuccess;
} }
public static byte[] removePacket(byte[] ring, int position) throws IOException {
Iterator<RawPacket> it = parseKeyring(ring);
ByteArrayOutputStream out = new ByteArrayOutputStream(ring.length);
int i = 0;
while(it.hasNext()) {
// at the right position, skip the packet
if(i++ == position) {
continue;
}
// write the old one
out.write(it.next().buf);
}
if (i <= position) {
throw new IndexOutOfBoundsException("injection index did not not occur in stream!");
}
return out.toByteArray();
}
public static byte[] injectPacket(byte[] ring, byte[] inject, int position) throws IOException {
Iterator<RawPacket> it = parseKeyring(ring);
ByteArrayOutputStream out = new ByteArrayOutputStream(ring.length + inject.length);
int i = 0;
while(it.hasNext()) {
// at the right position, inject the new packet
if(i++ == position) {
out.write(inject);
}
// write the old one
out.write(it.next().buf);
}
if (i <= position) {
throw new IndexOutOfBoundsException("injection index did not not occur in stream!");
}
return out.toByteArray();
}
/** This class contains a single pgp packet, together with information about its position
* in the keyring and its packet tag.
*/
public static class RawPacket { public static class RawPacket {
public int position; public int position;
// packet tag for convenience, this can also be read from the header
public int tag; public int tag;
public int length;
public int headerLength, length;
// this buf includes the header, so its length is headerLength + length!
public byte[] buf; public byte[] buf;
@Override
public boolean equals(Object other) { public boolean equals(Object other) {
return other instanceof RawPacket && Arrays.areEqual(this.buf, ((RawPacket) other).buf); return other instanceof RawPacket && Arrays.areEqual(this.buf, ((RawPacket) other).buf);
} }
@Override
public int hashCode() { public int hashCode() {
// System.out.println("tag: " + tag + ", code: " + Arrays.hashCode(buf));
return Arrays.hashCode(buf); return Arrays.hashCode(buf);
} }
} }
/** A comparator which compares RawPackets by their position */
public static final Comparator<RawPacket> packetOrder = new Comparator<RawPacket>() { public static final Comparator<RawPacket> packetOrder = new Comparator<RawPacket>() {
public int compare(RawPacket left, RawPacket right) { public int compare(RawPacket left, RawPacket right) {
return Integer.compare(left.position, right.position); return Integer.compare(left.position, right.position);
} }
}; };
/** Diff two keyrings, returning packets only present in one keyring in its associated List.
*
* Packets in the returned lists are annotated and ordered by their original order of appearance
* in their origin keyrings.
*
* @return true if keyrings differ in at least one packet
*/
public static boolean diffKeyrings(byte[] ringA, byte[] ringB, public static boolean diffKeyrings(byte[] ringA, byte[] ringB,
List<RawPacket> onlyA, List<RawPacket> onlyB) List<RawPacket> onlyA, List<RawPacket> onlyB)
throws IOException { throws IOException {
InputStream streamA = new ByteArrayInputStream(ringA); Iterator<RawPacket> streamA = parseKeyring(ringA);
InputStream streamB = new ByteArrayInputStream(ringB); Iterator<RawPacket> streamB = parseKeyring(ringB);
HashSet<RawPacket> a = new HashSet<RawPacket>(), b = new HashSet<RawPacket>(); HashSet<RawPacket> a = new HashSet<RawPacket>(), b = new HashSet<RawPacket>();
RawPacket p; RawPacket p;
int pos = 0; int pos = 0;
while(true) { while(true) {
p = readPacket(streamA); p = streamA.next();
if (p == null) { if (p == null) {
break; break;
} }
@ -110,7 +170,7 @@ public class KeyringTestingHelper {
} }
pos = 0; pos = 0;
while(true) { while(true) {
p = readPacket(streamB); p = streamB.next();
if (p == null) { if (p == null) {
break; break;
} }
@ -132,6 +192,51 @@ public class KeyringTestingHelper {
return !onlyA.isEmpty() || !onlyB.isEmpty(); return !onlyA.isEmpty() || !onlyB.isEmpty();
} }
/** Creates an iterator of RawPackets over a binary keyring. */
public static Iterator<RawPacket> parseKeyring(byte[] ring) {
final InputStream stream = new ByteArrayInputStream(ring);
return new Iterator<RawPacket>() {
RawPacket next;
@Override
public boolean hasNext() {
if (next == null) try {
next = readPacket(stream);
} catch (IOException e) {
return false;
}
return next != null;
}
@Override
public RawPacket next() {
if (!hasNext()) {
return null;
}
try {
return next;
} finally {
next = null;
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/** Read a single (raw) pgp packet from an input stream.
*
* Note that the RawPacket.position field is NOT set here!
*
* Variable length packets are not handled here. we don't use those in our test classes, and
* otherwise rely on BouncyCastle's own unit tests to handle those correctly.
*/
private static RawPacket readPacket(InputStream in) throws IOException { private static RawPacket readPacket(InputStream in) throws IOException {
// save here. this is tag + length, max 6 bytes // save here. this is tag + length, max 6 bytes
@ -149,8 +254,8 @@ public class KeyringTestingHelper {
} }
boolean newPacket = (hdr & 0x40) != 0; boolean newPacket = (hdr & 0x40) != 0;
int tag = 0; int tag;
int bodyLen = 0; int bodyLen;
if (newPacket) { if (newPacket) {
tag = hdr & 0x3f; tag = hdr & 0x3f;
@ -207,6 +312,7 @@ public class KeyringTestingHelper {
} }
RawPacket p = new RawPacket(); RawPacket p = new RawPacket();
p.tag = tag; p.tag = tag;
p.headerLength = headerLength;
p.length = bodyLen; p.length = bodyLen;
p.buf = buf; p.buf = buf;
return p; return p;