Removed salt from unrestricted groups: two unrestricted groups with

the same name will now be treated as the same group (this seems more
intuitive than the alternative).
This commit is contained in:
akwizgran
2011-07-25 20:11:32 +01:00
parent b1f27757df
commit 586d1739ae
8 changed files with 34 additions and 102 deletions

View File

@@ -1,7 +1,5 @@
package net.sf.briar.api.protocol; package net.sf.briar.api.protocol;
import java.security.PublicKey;
import net.sf.briar.api.serial.Writable; import net.sf.briar.api.serial.Writable;
/** A group to which users may subscribe. */ /** A group to which users may subscribe. */
@@ -13,22 +11,9 @@ public interface Group extends Writable {
/** Returns the group's name. */ /** Returns the group's name. */
String getName(); String getName();
/**
* Returns true if messages sent to the group must be signed with a
* particular private key.
*/
boolean isRestricted();
/**
* If the group is restricted, returns null. Otherwise returns a salt
* value that is combined with the group's name to generate its unique
* identifier.
*/
byte[] getSalt();
/** /**
* If the group is restricted, returns the public key that is used to * If the group is restricted, returns the public key that is used to
* authorise all messages sent to the group. Otherwise returns null. * authorise all messages sent to the group. Otherwise returns null.
*/ */
PublicKey getPublicKey(); byte[] getPublicKey();
} }

View File

@@ -2,6 +2,5 @@ package net.sf.briar.api.protocol;
public interface GroupFactory { public interface GroupFactory {
Group createGroup(GroupId id, String name, boolean restricted, Group createGroup(GroupId id, String name, byte[] publicKey);
byte[] saltOrKey);
} }

View File

@@ -40,8 +40,7 @@ abstract class JdbcDatabase implements Database<Connection> {
"CREATE TABLE localSubscriptions" "CREATE TABLE localSubscriptions"
+ " (groupId HASH NOT NULL," + " (groupId HASH NOT NULL,"
+ " groupName VARCHAR NOT NULL," + " groupName VARCHAR NOT NULL,"
+ " restricted BOOLEAN NOT NULL," + " groupKey BINARY,"
+ " groupKey BINARY NOT NULL,"
+ " PRIMARY KEY (groupId))"; + " PRIMARY KEY (groupId))";
private static final String CREATE_MESSAGES = private static final String CREATE_MESSAGES =
@@ -90,8 +89,7 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " (contactId INT NOT NULL," + " (contactId INT NOT NULL,"
+ " groupId HASH NOT NULL," + " groupId HASH NOT NULL,"
+ " groupName VARCHAR NOT NULL," + " groupName VARCHAR NOT NULL,"
+ " restricted BOOLEAN NOT NULL," + " groupKey BINARY,"
+ " groupKey BINARY NOT NULL,"
+ " PRIMARY KEY (contactId, groupId)," + " PRIMARY KEY (contactId, groupId),"
+ " FOREIGN KEY (contactId) REFERENCES contacts (contactId)" + " FOREIGN KEY (contactId) REFERENCES contacts (contactId)"
+ " ON DELETE CASCADE)"; + " ON DELETE CASCADE)";
@@ -530,14 +528,12 @@ abstract class JdbcDatabase implements Database<Connection> {
PreparedStatement ps = null; PreparedStatement ps = null;
try { try {
String sql = "INSERT INTO localSubscriptions" String sql = "INSERT INTO localSubscriptions"
+ " (groupId, groupName, restricted, groupKey)" + " (groupId, groupName, groupKey)"
+ " VALUES (?, ?, ?, ?)"; + " VALUES (?, ?, ?)";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setBytes(1, g.getId().getBytes()); ps.setBytes(1, g.getId().getBytes());
ps.setString(2, g.getName()); ps.setString(2, g.getName());
ps.setBoolean(3, g.isRestricted()); ps.setBytes(3, g.getPublicKey());
if(g.isRestricted()) ps.setBytes(4, g.getPublicKey().getEncoded());
else ps.setBytes(4, g.getSalt());
int rowsAffected = ps.executeUpdate(); int rowsAffected = ps.executeUpdate();
assert rowsAffected == 1; assert rowsAffected == 1;
ps.close(); ps.close();
@@ -989,7 +985,7 @@ abstract class JdbcDatabase implements Database<Connection> {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
String sql = "SELECT groupId, groupName, restricted, groupKey" String sql = "SELECT groupId, groupName, groupKey"
+ " FROM localSubscriptions"; + " FROM localSubscriptions";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
rs = ps.executeQuery(); rs = ps.executeQuery();
@@ -997,9 +993,8 @@ abstract class JdbcDatabase implements Database<Connection> {
while(rs.next()) { while(rs.next()) {
GroupId id = new GroupId(rs.getBytes(1)); GroupId id = new GroupId(rs.getBytes(1));
String name = rs.getString(2); String name = rs.getString(2);
boolean restricted = rs.getBoolean(3); byte[] publicKey = rs.getBytes(3);
byte[] key = rs.getBytes(4); subs.add(groupFactory.createGroup(id, name, publicKey));
subs.add(groupFactory.createGroup(id, name, restricted, key));
} }
rs.close(); rs.close();
ps.close(); ps.close();
@@ -1017,7 +1012,7 @@ abstract class JdbcDatabase implements Database<Connection> {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
String sql = "SELECT groupId, groupName, restricted, groupKey" String sql = "SELECT groupId, groupName, groupKey"
+ " FROM contactSubscriptions" + " FROM contactSubscriptions"
+ " WHERE contactId = ?"; + " WHERE contactId = ?";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
@@ -1027,9 +1022,8 @@ abstract class JdbcDatabase implements Database<Connection> {
while(rs.next()) { while(rs.next()) {
GroupId id = new GroupId(rs.getBytes(1)); GroupId id = new GroupId(rs.getBytes(1));
String name = rs.getString(2); String name = rs.getString(2);
boolean restricted = rs.getBoolean(3); byte[] publicKey = rs.getBytes(3);
byte[] key = rs.getBytes(4); subs.add(groupFactory.createGroup(id, name, publicKey));
subs.add(groupFactory.createGroup(id, name, restricted, key));
} }
rs.close(); rs.close();
ps.close(); ps.close();
@@ -1389,17 +1383,14 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close(); ps.close();
// Store the new subscriptions // Store the new subscriptions
sql = "INSERT INTO contactSubscriptions" sql = "INSERT INTO contactSubscriptions"
+ "(contactId, groupId, groupName, restricted, groupKey)" + " (contactId, groupId, groupName, groupKey)"
+ " VALUES (?, ?, ?, ?, ?)"; + " VALUES (?, ?, ?, ?)";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt()); ps.setInt(1, c.getInt());
for(Group g : subs) { for(Group g : subs) {
ps.setBytes(2, g.getId().getBytes()); ps.setBytes(2, g.getId().getBytes());
ps.setString(3, g.getName()); ps.setString(3, g.getName());
ps.setBoolean(4, g.isRestricted()); ps.setBytes(4, g.getPublicKey());
if(g.isRestricted())
ps.setBytes(5, g.getPublicKey().getEncoded());
else ps.setBytes(5, g.getSalt());
ps.addBatch(); ps.addBatch();
} }
int[] rowsAffectedArray = ps.executeBatch(); int[] rowsAffectedArray = ps.executeBatch();

View File

@@ -1,34 +1,12 @@
package net.sf.briar.protocol; package net.sf.briar.protocol;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.KeyParser;
import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.Group;
import net.sf.briar.api.protocol.GroupFactory; import net.sf.briar.api.protocol.GroupFactory;
import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.GroupId;
import com.google.inject.Inject;
class GroupFactoryImpl implements GroupFactory { class GroupFactoryImpl implements GroupFactory {
private final KeyParser keyParser; public Group createGroup(GroupId id, String name, byte[] publicKey) {
return new GroupImpl(id, name, publicKey);
@Inject
GroupFactoryImpl(CryptoComponent crypto) {
keyParser = crypto.getKeyParser();
}
public Group createGroup(GroupId id, String name, boolean restricted,
byte[] saltOrKey) {
if(restricted) {
try {
PublicKey key = keyParser.parsePublicKey(saltOrKey);
return new GroupImpl(id, name, key);
} catch(InvalidKeySpecException e) {
throw new IllegalArgumentException(e);
}
} else return new GroupImpl(id, name, saltOrKey);
} }
} }

View File

@@ -1,7 +1,6 @@
package net.sf.briar.protocol; package net.sf.briar.protocol;
import java.io.IOException; import java.io.IOException;
import java.security.PublicKey;
import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.Group;
import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.GroupId;
@@ -12,21 +11,12 @@ class GroupImpl implements Group {
private final GroupId id; private final GroupId id;
private final String name; private final String name;
private final byte[] salt; private final byte[] publicKey;
private final PublicKey publicKey;
GroupImpl(GroupId id, String name, byte[] salt) { GroupImpl(GroupId id, String name, byte[] publicKey) {
this.id = id;
this.name = name;
this.salt = salt;
publicKey = null;
}
GroupImpl(GroupId id, String name, PublicKey publicKey) {
this.id = id; this.id = id;
this.name = name; this.name = name;
this.publicKey = publicKey; this.publicKey = publicKey;
salt = null;
} }
public GroupId getId() { public GroupId getId() {
@@ -37,24 +27,15 @@ class GroupImpl implements Group {
return name; return name;
} }
public boolean isRestricted() { public byte[] getPublicKey() {
return salt == null;
}
public byte[] getSalt() {
return salt;
}
public PublicKey getPublicKey() {
return publicKey; return publicKey;
} }
public void writeTo(Writer w) throws IOException { public void writeTo(Writer w) throws IOException {
w.writeUserDefinedTag(Tags.GROUP); w.writeUserDefinedTag(Tags.GROUP);
w.writeString(name); w.writeString(name);
w.writeBoolean(isRestricted()); if(publicKey == null) w.writeNull();
if(salt == null) w.writeBytes(publicKey.getEncoded()); else w.writeBytes(publicKey);
else w.writeBytes(salt);
} }
@Override @Override

View File

@@ -28,11 +28,12 @@ class GroupReader implements ObjectReader<Group> {
r.addConsumer(digesting); r.addConsumer(digesting);
r.readUserDefinedTag(Tags.GROUP); r.readUserDefinedTag(Tags.GROUP);
String name = r.readString(); String name = r.readString();
boolean restricted = r.readBoolean(); byte[] publicKey = null;
byte[] saltOrKey = r.readBytes(); if(r.hasNull()) r.readNull();
else publicKey = r.readBytes();
r.removeConsumer(digesting); r.removeConsumer(digesting);
// Build and return the group // Build and return the group
GroupId id = new GroupId(messageDigest.digest()); GroupId id = new GroupId(messageDigest.digest());
return groupFactory.createGroup(id, name, restricted, saltOrKey); return groupFactory.createGroup(id, name, publicKey);
} }
} }

View File

@@ -77,8 +77,7 @@ public class H2DatabaseTest extends TestCase {
random.nextBytes(raw); random.nextBytes(raw);
message = new TestMessage(messageId, MessageId.NONE, groupId, authorId, message = new TestMessage(messageId, MessageId.NONE, groupId, authorId,
timestamp, raw); timestamp, raw);
group = groupFactory.createGroup(groupId, "Group name", false, group = groupFactory.createGroup(groupId, "Group name", null);
TestUtils.getRandomId());
} }
@Before @Before
@@ -534,7 +533,7 @@ public class H2DatabaseTest extends TestCase {
MessageId childId3 = new MessageId(TestUtils.getRandomId()); MessageId childId3 = new MessageId(TestUtils.getRandomId());
GroupId groupId1 = new GroupId(TestUtils.getRandomId()); GroupId groupId1 = new GroupId(TestUtils.getRandomId());
Group group1 = groupFactory.createGroup(groupId1, "Another group name", Group group1 = groupFactory.createGroup(groupId1, "Another group name",
false, TestUtils.getRandomId()); null);
Message child1 = new TestMessage(childId1, messageId, groupId, Message child1 = new TestMessage(childId1, messageId, groupId,
authorId, timestamp, raw); authorId, timestamp, raw);
Message child2 = new TestMessage(childId2, messageId, groupId, Message child2 = new TestMessage(childId2, messageId, groupId,
@@ -759,7 +758,7 @@ public class H2DatabaseTest extends TestCase {
public void testUpdateSubscriptions() throws DbException { public void testUpdateSubscriptions() throws DbException {
GroupId groupId1 = new GroupId(TestUtils.getRandomId()); GroupId groupId1 = new GroupId(TestUtils.getRandomId());
Group group1 = groupFactory.createGroup(groupId1, "Another group name", Group group1 = groupFactory.createGroup(groupId1, "Another group name",
false, TestUtils.getRandomId()); null);
Database<Connection> db = open(false); Database<Connection> db = open(false);
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
@@ -784,7 +783,7 @@ public class H2DatabaseTest extends TestCase {
throws DbException { throws DbException {
GroupId groupId1 = new GroupId(TestUtils.getRandomId()); GroupId groupId1 = new GroupId(TestUtils.getRandomId());
Group group1 = groupFactory.createGroup(groupId1, "Another group name", Group group1 = groupFactory.createGroup(groupId1, "Another group name",
false, TestUtils.getRandomId()); null);
Database<Connection> db = open(false); Database<Connection> db = open(false);
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();

View File

@@ -64,7 +64,6 @@ public class FileReadWriteTest extends TestCase {
private final ReaderFactory readerFactory; private final ReaderFactory readerFactory;
private final WriterFactory writerFactory; private final WriterFactory writerFactory;
private final PacketWriterFactory packetWriterFactory; private final PacketWriterFactory packetWriterFactory;
private final CryptoComponent crypto;
private final Signature signature; private final Signature signature;
private final MessageDigest messageDigest, batchDigest; private final MessageDigest messageDigest, batchDigest;
private final KeyParser keyParser; private final KeyParser keyParser;
@@ -79,7 +78,7 @@ public class FileReadWriteTest extends TestCase {
readerFactory = i.getInstance(ReaderFactory.class); readerFactory = i.getInstance(ReaderFactory.class);
writerFactory = i.getInstance(WriterFactory.class); writerFactory = i.getInstance(WriterFactory.class);
packetWriterFactory = i.getInstance(PacketWriterFactory.class); packetWriterFactory = i.getInstance(PacketWriterFactory.class);
crypto = i.getInstance(CryptoComponent.class); CryptoComponent crypto = i.getInstance(CryptoComponent.class);
keyParser = crypto.getKeyParser(); keyParser = crypto.getKeyParser();
signature = crypto.getSignature(); signature = crypto.getSignature();
messageDigest = crypto.getMessageDigest(); messageDigest = crypto.getMessageDigest();
@@ -94,8 +93,7 @@ public class FileReadWriteTest extends TestCase {
// Create a test group, then write and read it to calculate its ID // Create a test group, then write and read it to calculate its ID
GroupFactory groupFactory = i.getInstance(GroupFactory.class); GroupFactory groupFactory = i.getInstance(GroupFactory.class);
Group noId = groupFactory.createGroup( Group noId = groupFactory.createGroup(
new GroupId(new byte[UniqueId.LENGTH]), "Group name", false, new GroupId(new byte[UniqueId.LENGTH]), "Group name", null);
TestUtils.getRandomId());
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
Writer w = writerFactory.createWriter(out); Writer w = writerFactory.createWriter(out);
noId.writeTo(w); noId.writeTo(w);
@@ -147,7 +145,7 @@ public class FileReadWriteTest extends TestCase {
ObjectReader<Batch> batchReader = new BatchReader(batchDigest, ObjectReader<Batch> batchReader = new BatchReader(batchDigest,
messageReader, new BatchFactoryImpl()); messageReader, new BatchFactoryImpl());
ObjectReader<Group> groupReader = new GroupReader(batchDigest, ObjectReader<Group> groupReader = new GroupReader(batchDigest,
new GroupFactoryImpl(crypto)); new GroupFactoryImpl());
ObjectReader<Subscriptions> subscriptionReader = ObjectReader<Subscriptions> subscriptionReader =
new SubscriptionReader(groupReader, new SubscriptionFactoryImpl()); new SubscriptionReader(groupReader, new SubscriptionFactoryImpl());
ObjectReader<Transports> transportReader = ObjectReader<Transports> transportReader =