diff --git a/briar-api/src/org/briarproject/api/blogs/BlogConstants.java b/briar-api/src/org/briarproject/api/blogs/BlogConstants.java
index 60f06a641b5591ed79c35d32e785d3265358cff6..738e012a3ef2872f1c341aacc7e5a6a68d5a7da5 100644
--- a/briar-api/src/org/briarproject/api/blogs/BlogConstants.java
+++ b/briar-api/src/org/briarproject/api/blogs/BlogConstants.java
@@ -22,6 +22,12 @@ public interface BlogConstants {
 	/** The maximum length of a blog post's body in bytes. */
 	int MAX_BLOG_POST_BODY_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024;
 
+	/* Blog Sharing Constants */
+	String BLOG_TITLE = "blogTitle";
+	String BLOG_DESC = "blogDescription";
+	String BLOG_AUTHOR_NAME = "blogAuthorName";
+	String BLOG_PUBLIC_KEY = "blogPublicKey";
+
 	// Metadata keys
 	String KEY_DESCRIPTION = "description";
 	String KEY_TITLE = "title";
diff --git a/briar-api/src/org/briarproject/api/blogs/BlogInvitationMessage.java b/briar-api/src/org/briarproject/api/blogs/BlogInvitationMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..9306da5726c5a74cea45a1524f573949c6f686df
--- /dev/null
+++ b/briar-api/src/org/briarproject/api/blogs/BlogInvitationMessage.java
@@ -0,0 +1,26 @@
+package org.briarproject.api.blogs;
+
+import org.briarproject.api.clients.SessionId;
+import org.briarproject.api.contact.ContactId;
+import org.briarproject.api.sharing.InvitationMessage;
+import org.briarproject.api.sync.MessageId;
+
+public class BlogInvitationMessage extends InvitationMessage {
+
+	private final String blogTitle;
+
+	public BlogInvitationMessage(MessageId id, SessionId sessionId,
+			ContactId contactId, String blogTitle, String message,
+			boolean available, long time, boolean local, boolean sent,
+			boolean seen, boolean read) {
+
+		super(id, sessionId, contactId, message, available, time, local, sent,
+				seen, read);
+		this.blogTitle = blogTitle;
+	}
+
+	public String getBlogTitle() {
+		return blogTitle;
+	}
+
+}
diff --git a/briar-api/src/org/briarproject/api/blogs/BlogSharingManager.java b/briar-api/src/org/briarproject/api/blogs/BlogSharingManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..ec9f23e49df4910fc2bdc5935fd98b4e9eed4cbd
--- /dev/null
+++ b/briar-api/src/org/briarproject/api/blogs/BlogSharingManager.java
@@ -0,0 +1,60 @@
+package org.briarproject.api.blogs;
+
+import org.briarproject.api.contact.Contact;
+import org.briarproject.api.contact.ContactId;
+import org.briarproject.api.db.DbException;
+import org.briarproject.api.sharing.SharingManager;
+import org.briarproject.api.sync.ClientId;
+import org.briarproject.api.sync.GroupId;
+
+import java.util.Collection;
+
+public interface BlogSharingManager
+		extends SharingManager<Blog, BlogInvitationMessage> {
+
+	/**
+	 * Returns the unique ID of the blog sharing client.
+	 */
+	ClientId getClientId();
+
+	/**
+	 * Sends an invitation to share the given blog with the given contact
+	 * and sends an optional message along with it.
+	 */
+	void sendInvitation(GroupId groupId, ContactId contactId,
+			String message) throws DbException;
+
+	/**
+	 * Responds to a pending blog invitation
+	 */
+	void respondToInvitation(Blog b, Contact c, boolean accept)
+			throws DbException;
+
+	/**
+	 * Returns all blogs sharing messages sent by the Contact
+	 * identified by contactId.
+	 */
+	Collection<BlogInvitationMessage> getInvitationMessages(
+			ContactId contactId) throws DbException;
+
+	/**
+	 * Returns all blogs to which the user could subscribe.
+	 */
+	Collection<Blog> getAvailable() throws DbException;
+
+	/**
+	 * Returns all contacts who are sharing the given blog with us.
+	 */
+	Collection<Contact> getSharedBy(GroupId g) throws DbException;
+
+	/**
+	 * Returns the IDs of all contacts with whom the given blog is shared.
+	 */
+	Collection<Contact> getSharedWith(GroupId g) throws DbException;
+
+	/**
+	 * Returns true if the blog not already shared and no invitation is open
+	 */
+	boolean canBeShared(GroupId g, Contact c) throws DbException;
+
+}
diff --git a/briar-api/src/org/briarproject/api/blogs/BlogSharingMessage.java b/briar-api/src/org/briarproject/api/blogs/BlogSharingMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..105b0d2a3f981c27db33f36fbc072b296f93689c
--- /dev/null
+++ b/briar-api/src/org/briarproject/api/blogs/BlogSharingMessage.java
@@ -0,0 +1,89 @@
+package org.briarproject.api.blogs;
+
+import org.briarproject.api.FormatException;
+import org.briarproject.api.clients.SessionId;
+import org.briarproject.api.data.BdfDictionary;
+import org.briarproject.api.data.BdfList;
+import org.briarproject.api.sharing.SharingMessage.Invitation;
+import org.briarproject.api.sync.GroupId;
+
+import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME;
+import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC;
+import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY;
+import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE;
+import static org.briarproject.api.sharing.SharingConstants.INVITATION_MSG;
+import static org.briarproject.api.sharing.SharingConstants.SESSION_ID;
+
+public interface BlogSharingMessage {
+
+	class BlogInvitation extends Invitation {
+
+		private final String blogTitle;
+		private final String blogDesc;
+		private final String blogAuthorName;
+		private final byte[] blogPublicKey;
+
+		public BlogInvitation(GroupId groupId, SessionId sessionId,
+				String blogTitle, String blogDesc, String blogAuthorName,
+				byte[] blogPublicKey, String message) {
+
+			super(groupId, sessionId, message);
+
+			this.blogTitle = blogTitle;
+			this.blogDesc = blogDesc;
+			this.blogAuthorName = blogAuthorName;
+			this.blogPublicKey = blogPublicKey;
+		}
+
+		@Override
+		public BdfList toBdfList() {
+			BdfList list = super.toBdfList();
+			list.add(blogTitle);
+			list.add(blogDesc);
+			list.add(BdfList.of(blogAuthorName, blogPublicKey));
+			if (message != null) list.add(message);
+			return list;
+		}
+
+		@Override
+		public BdfDictionary toBdfDictionary() {
+			BdfDictionary d = toBdfDictionaryHelper();
+			d.put(BLOG_TITLE, blogTitle);
+			d.put(BLOG_DESC, blogDesc);
+			d.put(BLOG_AUTHOR_NAME, blogAuthorName);
+			d.put(BLOG_PUBLIC_KEY, blogPublicKey);
+			if (message != null) d.put(INVITATION_MSG, message);
+			return d;
+		}
+
+		public static BlogInvitation from(GroupId groupId, BdfDictionary d)
+				throws FormatException {
+
+			SessionId sessionId = new SessionId(d.getRaw(SESSION_ID));
+			String blogTitle = d.getString(BLOG_TITLE);
+			String blogDesc = d.getString(BLOG_DESC);
+			String blogAuthorName = d.getString(BLOG_AUTHOR_NAME);
+			byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY);
+			String message = d.getOptionalString(INVITATION_MSG);
+
+			return new BlogInvitation(groupId, sessionId, blogTitle,
+					blogDesc, blogAuthorName, blogPublicKey, message);
+		}
+
+		public String getBlogTitle() {
+			return blogTitle;
+		}
+
+		public String getBlogDesc() {
+			return blogDesc;
+		}
+
+		public String getBlogAuthorName() {
+			return blogAuthorName;
+		}
+
+		public byte[] getBlogPublicKey() {
+			return blogPublicKey;
+		}
+	}
+}
diff --git a/briar-api/src/org/briarproject/api/event/BlogInvitationReceivedEvent.java b/briar-api/src/org/briarproject/api/event/BlogInvitationReceivedEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..12d8d4cc4b8dec2dd91f2cf4bf1f80322f56f421
--- /dev/null
+++ b/briar-api/src/org/briarproject/api/event/BlogInvitationReceivedEvent.java
@@ -0,0 +1,18 @@
+package org.briarproject.api.event;
+
+import org.briarproject.api.blogs.Blog;
+import org.briarproject.api.contact.ContactId;
+
+public class BlogInvitationReceivedEvent extends InvitationReceivedEvent {
+
+	private final Blog blog;
+
+	public BlogInvitationReceivedEvent(Blog blog, ContactId contactId) {
+		super(contactId);
+		this.blog = blog;
+	}
+
+	public Blog getBlog() {
+		return blog;
+	}
+}
diff --git a/briar-api/src/org/briarproject/api/event/BlogInvitationResponseReceivedEvent.java b/briar-api/src/org/briarproject/api/event/BlogInvitationResponseReceivedEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6344ad928dd3c5e14155ad7c8dd7c70c69e3f38
--- /dev/null
+++ b/briar-api/src/org/briarproject/api/event/BlogInvitationResponseReceivedEvent.java
@@ -0,0 +1,18 @@
+package org.briarproject.api.event;
+
+import org.briarproject.api.contact.ContactId;
+
+public class BlogInvitationResponseReceivedEvent extends InvitationResponseReceivedEvent {
+
+	private final String blogTitle;
+
+	public BlogInvitationResponseReceivedEvent(String blogTitle,
+			ContactId contactId) {
+		super(contactId);
+		this.blogTitle = blogTitle;
+	}
+
+	public String getBlogTitle() {
+		return blogTitle;
+	}
+}
diff --git a/briar-core/src/org/briarproject/sharing/BlogInviteeSessionState.java b/briar-core/src/org/briarproject/sharing/BlogInviteeSessionState.java
new file mode 100644
index 0000000000000000000000000000000000000000..7bb3295b7b02a925718b08ca2da3875a25d58980
--- /dev/null
+++ b/briar-core/src/org/briarproject/sharing/BlogInviteeSessionState.java
@@ -0,0 +1,57 @@
+package org.briarproject.sharing;
+
+import org.briarproject.api.clients.SessionId;
+import org.briarproject.api.contact.ContactId;
+import org.briarproject.api.data.BdfDictionary;
+import org.briarproject.api.sync.GroupId;
+import org.briarproject.api.sync.MessageId;
+
+import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME;
+import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC;
+import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY;
+import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE;
+
+public class BlogInviteeSessionState extends InviteeSessionState {
+
+	private final String blogTitle;
+	private final String blogDesc;
+	private final String blogAuthorName;
+	private final byte[] blogPublicKey;
+
+	public BlogInviteeSessionState(SessionId sessionId, MessageId storageId,
+			GroupId groupId, State state, ContactId contactId, GroupId blogId,
+			String blogTitle, String blogDesc, String blogAuthorName,
+			byte[] blogPublicKey) {
+		super(sessionId, storageId, groupId, state, contactId, blogId);
+
+		this.blogTitle = blogTitle;
+		this.blogDesc = blogDesc;
+		this.blogAuthorName = blogAuthorName;
+		this.blogPublicKey = blogPublicKey;
+	}
+
+	public BdfDictionary toBdfDictionary() {
+		BdfDictionary d = super.toBdfDictionary();
+		d.put(BLOG_TITLE, getBlogTitle());
+		d.put(BLOG_DESC, getBlogDesc());
+		d.put(BLOG_AUTHOR_NAME, getBlogAuthorName());
+		d.put(BLOG_PUBLIC_KEY, getBlogPublicKey());
+		return d;
+	}
+
+	public String getBlogTitle() {
+		return blogTitle;
+	}
+
+	public String getBlogDesc() {
+		return blogDesc;
+	}
+
+	public String getBlogAuthorName() {
+		return blogAuthorName;
+	}
+
+	public byte[] getBlogPublicKey() {
+		return blogPublicKey;
+	}
+}
diff --git a/briar-core/src/org/briarproject/sharing/BlogSharerSessionState.java b/briar-core/src/org/briarproject/sharing/BlogSharerSessionState.java
new file mode 100644
index 0000000000000000000000000000000000000000..16ef1355b2183ab4d45c7074fef9e4b5c37b5e41
--- /dev/null
+++ b/briar-core/src/org/briarproject/sharing/BlogSharerSessionState.java
@@ -0,0 +1,57 @@
+package org.briarproject.sharing;
+
+import org.briarproject.api.clients.SessionId;
+import org.briarproject.api.contact.ContactId;
+import org.briarproject.api.data.BdfDictionary;
+import org.briarproject.api.sync.GroupId;
+import org.briarproject.api.sync.MessageId;
+
+import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME;
+import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC;
+import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY;
+import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE;
+
+public class BlogSharerSessionState extends SharerSessionState {
+
+	private final String blogTitle;
+	private final String blogDesc;
+	private final String blogAuthorName;
+	private final byte[] blogPublicKey;
+
+	public BlogSharerSessionState(SessionId sessionId, MessageId storageId,
+			GroupId groupId, State state, ContactId contactId, GroupId blogId,
+			String blogTitle, String blogDesc, String blogAuthorName,
+			byte[] blogPublicKey) {
+		super(sessionId, storageId, groupId, state, contactId, blogId);
+
+		this.blogTitle = blogTitle;
+		this.blogDesc = blogDesc;
+		this.blogAuthorName = blogAuthorName;
+		this.blogPublicKey = blogPublicKey;
+	}
+
+	public BdfDictionary toBdfDictionary() {
+		BdfDictionary d = super.toBdfDictionary();
+		d.put(BLOG_TITLE, getBlogTitle());
+		d.put(BLOG_DESC, getBlogDesc());
+		d.put(BLOG_AUTHOR_NAME, getBlogAuthorName());
+		d.put(BLOG_PUBLIC_KEY, getBlogPublicKey());
+		return d;
+	}
+
+	public String getBlogTitle() {
+		return blogTitle;
+	}
+
+	public String getBlogDesc() {
+		return blogDesc;
+	}
+
+	public String getBlogAuthorName() {
+		return blogAuthorName;
+	}
+
+	public byte[] getBlogPublicKey() {
+		return blogPublicKey;
+	}
+}
diff --git a/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java b/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..ba67ff635ee898c342994773cf8f5b4dd9787160
--- /dev/null
+++ b/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java
@@ -0,0 +1,293 @@
+package org.briarproject.sharing;
+
+import org.briarproject.api.FormatException;
+import org.briarproject.api.blogs.Blog;
+import org.briarproject.api.blogs.BlogFactory;
+import org.briarproject.api.blogs.BlogInvitationMessage;
+import org.briarproject.api.blogs.BlogManager;
+import org.briarproject.api.blogs.BlogSharingManager;
+import org.briarproject.api.blogs.BlogSharingMessage.BlogInvitation;
+import org.briarproject.api.clients.ClientHelper;
+import org.briarproject.api.clients.MessageQueueManager;
+import org.briarproject.api.clients.PrivateGroupFactory;
+import org.briarproject.api.clients.SessionId;
+import org.briarproject.api.contact.ContactId;
+import org.briarproject.api.data.BdfDictionary;
+import org.briarproject.api.data.BdfList;
+import org.briarproject.api.data.MetadataEncoder;
+import org.briarproject.api.data.MetadataParser;
+import org.briarproject.api.db.DatabaseComponent;
+import org.briarproject.api.db.DbException;
+import org.briarproject.api.db.Transaction;
+import org.briarproject.api.event.BlogInvitationReceivedEvent;
+import org.briarproject.api.event.BlogInvitationResponseReceivedEvent;
+import org.briarproject.api.identity.Author;
+import org.briarproject.api.identity.AuthorFactory;
+import org.briarproject.api.sync.ClientId;
+import org.briarproject.api.sync.GroupId;
+import org.briarproject.api.sync.MessageId;
+import org.briarproject.api.system.Clock;
+import org.briarproject.util.StringUtils;
+
+import java.security.SecureRandom;
+
+import javax.inject.Inject;
+
+import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME;
+import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC;
+import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY;
+import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE;
+
+class BlogSharingManagerImpl extends
+		SharingManagerImpl<Blog, BlogInvitation, BlogInvitationMessage, BlogInviteeSessionState, BlogSharerSessionState, BlogInvitationReceivedEvent, BlogInvitationResponseReceivedEvent>
+		implements BlogSharingManager {
+
+	static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
+			"bee438b5de0b3a685badc4e49d76e72d"
+					+ "21e01c4b569a775112756bdae267a028"));
+
+	private final BlogManager blogManager;
+
+	private final SFactory sFactory;
+	private final IFactory iFactory;
+	private final ISFactory isFactory;
+	private final SSFactory ssFactory;
+	private final IRFactory irFactory;
+	private final IRRFactory irrFactory;
+
+	@Inject
+	BlogSharingManagerImpl(AuthorFactory authorFactory, BlogFactory blogFactory,
+			BlogManager blogManager, ClientHelper clientHelper, Clock clock,
+			DatabaseComponent db, MessageQueueManager messageQueueManager,
+			MetadataEncoder metadataEncoder, MetadataParser metadataParser,
+			PrivateGroupFactory privateGroupFactory, SecureRandom random) {
+
+		super(db, messageQueueManager, clientHelper, metadataParser,
+				metadataEncoder, random, privateGroupFactory, clock);
+		this.blogManager = blogManager;
+
+		sFactory = new SFactory(authorFactory, blogFactory, blogManager);
+		iFactory = new IFactory();
+		isFactory = new ISFactory();
+		ssFactory = new SSFactory();
+		irFactory = new IRFactory(sFactory);
+		irrFactory = new IRRFactory();
+	}
+
+	@Override
+	public ClientId getClientId() {
+		return CLIENT_ID;
+	}
+
+	@Override
+	protected ClientId getShareableClientId() {
+		return blogManager.getClientId();
+	}
+
+	@Override
+	protected BlogInvitationMessage createInvitationMessage(MessageId id,
+			BlogInvitation msg, ContactId contactId, boolean available,
+			long time, boolean local, boolean sent, boolean seen,
+			boolean read) {
+		return new BlogInvitationMessage(id, msg.getSessionId(), contactId,
+				msg.getBlogTitle(), msg.getMessage(), available, time, local,
+				sent, seen, read);
+	}
+
+	@Override
+	protected ShareableFactory<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState> getSFactory() {
+		return sFactory;
+	}
+
+	@Override
+	protected InvitationFactory<BlogInvitation, BlogSharerSessionState> getIFactory() {
+		return iFactory;
+	}
+
+	@Override
+	protected InviteeSessionStateFactory<Blog, BlogInviteeSessionState> getISFactory() {
+		return isFactory;
+	}
+
+	@Override
+	protected SharerSessionStateFactory<Blog, BlogSharerSessionState> getSSFactory() {
+		return ssFactory;
+	}
+
+	@Override
+	protected InvitationReceivedEventFactory<BlogInviteeSessionState, BlogInvitationReceivedEvent> getIRFactory() {
+		return irFactory;
+	}
+
+	@Override
+	protected InvitationResponseReceivedEventFactory<BlogSharerSessionState, BlogInvitationResponseReceivedEvent> getIRRFactory() {
+		return irrFactory;
+	}
+
+	static class SFactory implements
+			ShareableFactory<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState> {
+
+		private final AuthorFactory authorFactory;
+		private final BlogFactory blogFactory;
+		private final BlogManager blogManager;
+
+		SFactory(AuthorFactory authorFactory, BlogFactory BlogFactory,
+				BlogManager BlogManager) {
+			this.authorFactory = authorFactory;
+			this.blogFactory = BlogFactory;
+			this.blogManager = BlogManager;
+		}
+
+		@Override
+		public BdfList encode(Blog f) {
+			return BdfList.of(f.getName(), f.getDescription(),
+					BdfList.of(f.getAuthor().getName(),
+							f.getAuthor().getPublicKey()));
+		}
+
+		@Override
+		public Blog get(Transaction txn, GroupId groupId)
+				throws DbException {
+			return blogManager.getBlog(txn, groupId);
+		}
+
+		@Override
+		public Blog parse(BdfList shareable) throws FormatException {
+			Author author = authorFactory
+					.createAuthor(shareable.getList(2).getString(0),
+							shareable.getList(2).getRaw(1));
+			return blogFactory
+					.createBlog(shareable.getString(0), shareable.getString(1),
+							author);
+		}
+
+		@Override
+		public Blog parse(BlogInvitation msg) {
+			Author author = authorFactory.createAuthor(msg.getBlogAuthorName(),
+					msg.getBlogPublicKey());
+			return blogFactory
+					.createBlog(msg.getBlogTitle(), msg.getBlogDesc(), author);
+		}
+
+		public Blog parse(BlogInviteeSessionState state) {
+			Author author = authorFactory
+					.createAuthor(state.getBlogAuthorName(),
+							state.getBlogPublicKey());
+			return blogFactory
+					.createBlog(state.getBlogTitle(), state.getBlogDesc(),
+							author);
+		}
+
+		@Override
+		public Blog parse(BlogSharerSessionState state) {
+			Author author = authorFactory
+					.createAuthor(state.getBlogAuthorName(),
+							state.getBlogPublicKey());
+			return blogFactory
+					.createBlog(state.getBlogTitle(), state.getBlogDesc(),
+							author);
+		}
+	}
+
+	static class IFactory implements
+			InvitationFactory<BlogInvitation, BlogSharerSessionState> {
+		@Override
+		public BlogInvitation build(GroupId groupId, BdfDictionary d)
+				throws FormatException {
+			return BlogInvitation.from(groupId, d);
+		}
+
+		@Override
+		public BlogInvitation build(BlogSharerSessionState localState) {
+			return new BlogInvitation(localState.getGroupId(),
+					localState.getSessionId(), localState.getBlogTitle(),
+					localState.getBlogDesc(), localState.getBlogAuthorName(),
+					localState.getBlogPublicKey(), localState.getMessage());
+		}
+	}
+
+	static class ISFactory implements
+			InviteeSessionStateFactory<Blog, BlogInviteeSessionState> {
+		@Override
+		public BlogInviteeSessionState build(SessionId sessionId,
+				MessageId storageId, GroupId groupId,
+				InviteeSessionState.State state, ContactId contactId,
+				GroupId blogId, BdfDictionary d) throws FormatException {
+			String blogTitle = d.getString(BLOG_TITLE);
+			String blogDesc = d.getString(BLOG_DESC);
+			String blogAuthorName = d.getString(BLOG_AUTHOR_NAME);
+			byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY);
+			return new BlogInviteeSessionState(sessionId, storageId,
+					groupId, state, contactId, blogId, blogTitle, blogDesc,
+					blogAuthorName, blogPublicKey);
+		}
+
+		@Override
+		public BlogInviteeSessionState build(SessionId sessionId,
+				MessageId storageId, GroupId groupId,
+				InviteeSessionState.State state, ContactId contactId,
+				Blog blog) {
+			return new BlogInviteeSessionState(sessionId, storageId,
+					groupId, state, contactId, blog.getId(), blog.getName(),
+					blog.getDescription(), blog.getAuthor().getName(),
+					blog.getAuthor().getPublicKey());
+		}
+	}
+
+	static class SSFactory implements
+			SharerSessionStateFactory<Blog, BlogSharerSessionState> {
+		@Override
+		public BlogSharerSessionState build(SessionId sessionId,
+				MessageId storageId, GroupId groupId,
+				SharerSessionState.State state, ContactId contactId,
+				GroupId blogId, BdfDictionary d) throws FormatException {
+			String blogTitle = d.getString(BLOG_TITLE);
+			String blogDesc = d.getString(BLOG_DESC);
+			String blogAuthorName = d.getString(BLOG_AUTHOR_NAME);
+			byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY);
+			return new BlogSharerSessionState(sessionId, storageId,
+					groupId, state, contactId, blogId, blogTitle, blogDesc,
+					blogAuthorName, blogPublicKey);
+		}
+
+		@Override
+		public BlogSharerSessionState build(SessionId sessionId,
+				MessageId storageId, GroupId groupId,
+				SharerSessionState.State state, ContactId contactId,
+				Blog blog) {
+			return new BlogSharerSessionState(sessionId, storageId,
+					groupId, state, contactId, blog.getId(), blog.getName(),
+					blog.getDescription(), blog.getAuthor().getName(),
+					blog.getAuthor().getPublicKey());
+		}
+	}
+
+	static class IRFactory implements
+			InvitationReceivedEventFactory<BlogInviteeSessionState, BlogInvitationReceivedEvent> {
+
+		private final SFactory sFactory;
+
+		IRFactory(SFactory sFactory) {
+			this.sFactory = sFactory;
+		}
+
+		@Override
+		public BlogInvitationReceivedEvent build(
+				BlogInviteeSessionState localState) {
+			Blog blog = sFactory.parse(localState);
+			ContactId contactId = localState.getContactId();
+			return new BlogInvitationReceivedEvent(blog, contactId);
+		}
+	}
+
+	static class IRRFactory implements
+			InvitationResponseReceivedEventFactory<BlogSharerSessionState, BlogInvitationResponseReceivedEvent> {
+		@Override
+		public BlogInvitationResponseReceivedEvent build(
+				BlogSharerSessionState localState) {
+			String title = localState.getBlogTitle();
+			ContactId c = localState.getContactId();
+			return new BlogInvitationResponseReceivedEvent(title, c);
+		}
+	}
+}
diff --git a/briar-core/src/org/briarproject/sharing/BlogSharingValidator.java b/briar-core/src/org/briarproject/sharing/BlogSharingValidator.java
new file mode 100644
index 0000000000000000000000000000000000000000..26b89bb52c512c118e02ea5075226e42b5829eda
--- /dev/null
+++ b/briar-core/src/org/briarproject/sharing/BlogSharingValidator.java
@@ -0,0 +1,98 @@
+package org.briarproject.sharing;
+
+import org.briarproject.api.FormatException;
+import org.briarproject.api.clients.BdfMessageContext;
+import org.briarproject.api.clients.ClientHelper;
+import org.briarproject.api.clients.SessionId;
+import org.briarproject.api.data.BdfDictionary;
+import org.briarproject.api.data.BdfList;
+import org.briarproject.api.data.MetadataEncoder;
+import org.briarproject.api.sync.Group;
+import org.briarproject.api.sync.Message;
+import org.briarproject.api.system.Clock;
+import org.briarproject.clients.BdfMessageValidator;
+
+import javax.inject.Inject;
+
+import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME;
+import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC;
+import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE;
+import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY;
+import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_DESC_LENGTH;
+import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_TITLE_LENGTH;
+import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
+import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
+import static org.briarproject.api.sharing.SharingConstants.INVITATION_MSG;
+import static org.briarproject.api.sharing.SharingConstants.LOCAL;
+import static org.briarproject.api.sharing.SharingConstants.SESSION_ID;
+import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT;
+import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT;
+import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE;
+import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION;
+import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE;
+import static org.briarproject.api.sharing.SharingConstants.TIME;
+import static org.briarproject.api.sharing.SharingConstants.TYPE;
+import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
+
+class BlogSharingValidator extends BdfMessageValidator {
+
+	@Inject
+	BlogSharingValidator(ClientHelper clientHelper,
+			MetadataEncoder metadataEncoder, Clock clock) {
+		super(clientHelper, metadataEncoder, clock);
+	}
+
+	@Override
+	protected BdfMessageContext validateMessage(Message m, Group g,
+			BdfList body) throws FormatException {
+
+		BdfDictionary d = new BdfDictionary();
+		long type = body.getLong(0);
+		byte[] id = body.getRaw(1);
+		checkLength(id, SessionId.LENGTH);
+
+		if (type == SHARE_MSG_TYPE_INVITATION) {
+			checkSize(body, 5, 6);
+
+			String name = body.getString(2);
+			checkLength(name, 1, MAX_BLOG_TITLE_LENGTH);
+
+			String desc = body.getString(3);
+			checkLength(desc, 1, MAX_BLOG_DESC_LENGTH);
+
+			BdfList author = body.getList(4);
+			checkSize(author, 2);
+
+			String authorName = author.getString(0);
+			checkLength(name, 1, MAX_AUTHOR_NAME_LENGTH);
+
+			byte[] publicKey = author.getRaw(1);
+			checkLength(publicKey, 1, MAX_PUBLIC_KEY_LENGTH);
+
+			d.put(BLOG_TITLE, name);
+			d.put(BLOG_DESC, desc);
+			d.put(BLOG_AUTHOR_NAME, authorName);
+			d.put(BLOG_PUBLIC_KEY, publicKey);
+
+			if (body.size() > 5) {
+				String msg = body.getString(5);
+				checkLength(msg, 0, MAX_MESSAGE_BODY_LENGTH);
+				d.put(INVITATION_MSG, msg);
+			}
+		} else {
+			checkSize(body, 2);
+			if (type != SHARE_MSG_TYPE_ACCEPT &&
+					type != SHARE_MSG_TYPE_DECLINE &&
+					type != SHARE_MSG_TYPE_LEAVE &&
+					type != SHARE_MSG_TYPE_ABORT) {
+				throw new FormatException();
+			}
+		}
+		// Return the metadata
+		d.put(TYPE, type);
+		d.put(SESSION_ID, id);
+		d.put(LOCAL, false);
+		d.put(TIME, m.getTimestamp());
+		return new BdfMessageContext(d);
+	}
+}
diff --git a/briar-core/src/org/briarproject/sharing/SharingModule.java b/briar-core/src/org/briarproject/sharing/SharingModule.java
index 228af6ed93b0703e31d4d377b20d3ad8474935bf..d62c7dccf7945810b7d271e85c4ac43e78131268 100644
--- a/briar-core/src/org/briarproject/sharing/SharingModule.java
+++ b/briar-core/src/org/briarproject/sharing/SharingModule.java
@@ -1,5 +1,6 @@
 package org.briarproject.sharing;
 
+import org.briarproject.api.blogs.BlogSharingManager;
 import org.briarproject.api.clients.ClientHelper;
 import org.briarproject.api.clients.MessageQueueManager;
 import org.briarproject.api.contact.ContactManager;
@@ -19,12 +20,46 @@ import dagger.Provides;
 public class SharingModule {
 
 	public static class EagerSingletons {
+		@Inject
+		BlogSharingValidator blogSharingValidator;
 		@Inject
 		ForumSharingValidator forumSharingValidator;
 		@Inject
 		ForumSharingManager forumSharingManager;
 	}
 
+	@Provides
+	@Singleton
+	BlogSharingValidator provideBlogSharingValidator(
+			MessageQueueManager messageQueueManager, ClientHelper clientHelper,
+			MetadataEncoder metadataEncoder, Clock clock) {
+
+		BlogSharingValidator
+				validator = new BlogSharingValidator(clientHelper,
+				metadataEncoder, clock);
+		messageQueueManager.registerMessageValidator(
+				BlogSharingManagerImpl.CLIENT_ID, validator);
+
+		return validator;
+	}
+
+	@Provides
+	@Singleton
+	BlogSharingManager provideBlogSharingManager(
+			LifecycleManager lifecycleManager,
+			ContactManager contactManager,
+			MessageQueueManager messageQueueManager,
+			BlogSharingManagerImpl blogSharingManager) {
+
+		lifecycleManager.registerClient(blogSharingManager);
+		contactManager.registerAddContactHook(blogSharingManager);
+		contactManager.registerRemoveContactHook(blogSharingManager);
+		messageQueueManager.registerIncomingMessageHook(
+				BlogSharingManagerImpl.CLIENT_ID, blogSharingManager);
+
+		return blogSharingManager;
+	}
+
 	@Provides
 	@Singleton
 	ForumSharingValidator provideForumSharingValidator(