Files
briar/components/net/sf/briar/protocol/MessageEncoderImpl.java

136 lines
4.6 KiB
Java

package net.sf.briar.protocol;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Signature;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.protocol.Author;
import net.sf.briar.api.protocol.AuthorId;
import net.sf.briar.api.protocol.Group;
import net.sf.briar.api.protocol.GroupId;
import net.sf.briar.api.protocol.Message;
import net.sf.briar.api.protocol.MessageEncoder;
import net.sf.briar.api.protocol.MessageId;
import net.sf.briar.api.protocol.Types;
import net.sf.briar.api.serial.Consumer;
import net.sf.briar.api.serial.Writer;
import net.sf.briar.api.serial.WriterFactory;
import com.google.inject.Inject;
class MessageEncoderImpl implements MessageEncoder {
private final Signature authorSignature, groupSignature;
private final SecureRandom random;
private final MessageDigest messageDigest;
private final WriterFactory writerFactory;
@Inject
MessageEncoderImpl(CryptoComponent crypto, WriterFactory writerFactory) {
authorSignature = crypto.getSignature();
groupSignature = crypto.getSignature();
random = crypto.getSecureRandom();
messageDigest = crypto.getMessageDigest();
this.writerFactory = writerFactory;
}
public Message encodeMessage(MessageId parent, byte[] body)
throws IOException, GeneralSecurityException {
return encodeMessage(parent, null, null, null, null, body);
}
public Message encodeMessage(MessageId parent, Group group, byte[] body)
throws IOException, GeneralSecurityException {
return encodeMessage(parent, group, null, null, null, body);
}
public Message encodeMessage(MessageId parent, Group group,
PrivateKey groupKey, byte[] body) throws IOException,
GeneralSecurityException {
return encodeMessage(parent, group, groupKey, null, null, body);
}
public Message encodeMessage(MessageId parent, Group group, Author author,
PrivateKey authorKey, byte[] body) throws IOException,
GeneralSecurityException {
return encodeMessage(parent, group, null, author, authorKey, body);
}
public Message encodeMessage(MessageId parent, Group group,
PrivateKey groupKey, Author author, PrivateKey authorKey,
byte[] body) throws IOException, GeneralSecurityException {
if((author == null) != (authorKey == null))
throw new IllegalArgumentException();
if((group == null || group.getPublicKey() == null) !=
(groupKey == null))
throw new IllegalArgumentException();
if(body.length > Message.MAX_BODY_LENGTH)
throw new IllegalArgumentException();
ByteArrayOutputStream out = new ByteArrayOutputStream();
Writer w = writerFactory.createWriter(out);
// Initialise the consumers
Consumer digestingConsumer = new DigestingConsumer(messageDigest);
w.addConsumer(digestingConsumer);
Consumer authorConsumer = null;
if(authorKey != null) {
authorSignature.initSign(authorKey);
authorConsumer = new SigningConsumer(authorSignature);
w.addConsumer(authorConsumer);
}
Consumer groupConsumer = null;
if(groupKey != null) {
groupSignature.initSign(groupKey);
groupConsumer = new SigningConsumer(groupSignature);
w.addConsumer(groupConsumer);
}
// Write the message
w.writeUserDefinedId(Types.MESSAGE);
if(parent == null) w.writeNull();
else parent.writeTo(w);
if(group == null) w.writeNull();
else group.writeTo(w);
if(author == null) w.writeNull();
else author.writeTo(w);
long timestamp = System.currentTimeMillis();
w.writeInt64(timestamp);
byte[] salt = new byte[Message.SALT_LENGTH];
random.nextBytes(salt);
w.writeBytes(salt);
w.writeBytes(body);
// Sign the message with the author's private key, if there is one
if(authorKey == null) {
w.writeNull();
} else {
w.removeConsumer(authorConsumer);
byte[] sig = authorSignature.sign();
if(sig.length > Message.MAX_SIGNATURE_LENGTH)
throw new IllegalArgumentException();
w.writeBytes(sig);
}
// Sign the message with the group's private key, if there is one
if(groupKey == null) {
w.writeNull();
} else {
w.removeConsumer(groupConsumer);
byte[] sig = groupSignature.sign();
if(sig.length > Message.MAX_SIGNATURE_LENGTH)
throw new IllegalArgumentException();
w.writeBytes(sig);
}
// Hash the message, including the signatures, to get the message ID
w.removeConsumer(digestingConsumer);
byte[] raw = out.toByteArray();
MessageId id = new MessageId(messageDigest.digest());
GroupId groupId = group == null ? null : group.getId();
AuthorId authorId = author == null ? null : author.getId();
return new MessageImpl(id, parent, groupId, authorId, timestamp, raw);
}
}