diff --git a/nacl/__init__.py b/nacl/__init__.py
index 2dcf301c7ebbff9aeb40769984d5ffb1c74e0722..4107460e32739e454d63bfdd56f2269cf8e7bf66 100644
--- a/nacl/__init__.py
+++ b/nacl/__init__.py
@@ -4,10 +4,11 @@ from __future__ import division
 from . import __about__
 from . import hash  # pylint: disable=W0622
 from . import signing
+from .encoding import encoder
 from .random import random
 
 
-__all__ = ["hash", "random"] + __about__.__all__
+__all__ = ["encoder", "hash", "random"] + __about__.__all__
 
 
 # - Meta Information -
diff --git a/nacl/encoding.py b/nacl/encoding.py
new file mode 100644
index 0000000000000000000000000000000000000000..92db5ffd2cab0b2a2bbb0f1507e6026dbba732ba
--- /dev/null
+++ b/nacl/encoding.py
@@ -0,0 +1,78 @@
+import base64
+import binascii
+
+from . import six
+
+
+class Encoder(object):
+
+    def __init__(self):
+        self._registry = {}
+
+    def __getitem__(self, name):
+        if isinstance(name, six.string_types):
+            return self._registry[name]
+        return name
+
+    def register(self, name, cls=None):
+        if cls is None:
+            def inner(cls):
+                self._registry[name] = cls()
+                return cls
+            return inner
+        else:
+            self._registry[name] = cls()
+
+
+# Global encoder
+encoder = Encoder()
+
+
+@encoder.register("raw")
+class RawEncoder(object):
+
+    def encode(self, data):
+        return data
+
+    def decode(self, data):
+        return data
+
+
+@encoder.register("hex")
+class HexEncoder(object):
+
+    def encode(self, data):
+        return binascii.hexlify(data)
+
+    def decode(self, data):
+        return binascii.unhexlify(data)
+
+
+@encoder.register("base16")
+class Base16Encoder(object):
+
+    def encode(self, data):
+        return base64.b16encode(data)
+
+    def decode(self, data):
+        return base64.b16decode(data)
+
+
+@encoder.register("base32")
+class Base32Encoder(object):
+
+    def encode(self, data):
+        return base64.b32encode(data)
+
+    def decode(self, data):
+        return base64.b32decode(data)
+
+
+@encoder.register("base64")
+class Base64Encoder(object):
+
+    def encode(self, data):
+        return base64.b64encode(data)
+
+    def decode(self, data):
+        return base64.b64decode(data)
diff --git a/nacl/hash.py b/nacl/hash.py
index c2ef41124708b8c56fd818e3f7fa4ef6a5877bd3..b8e80a568c04fcb02a496cd18e30d1cff7a3f49d 100644
--- a/nacl/hash.py
+++ b/nacl/hash.py
@@ -1,29 +1,24 @@
 from __future__ import absolute_import
 from __future__ import division
 
-import binascii
-
 from . import nacl
+from .encoding import encoder
 from .exceptions import CryptoError
 
 
-def sha256(message, binary=False):
+def sha256(message, encoding="hex"):
     digest = nacl.ffi.new("unsigned char[]", nacl.lib.crypto_hash_sha256_BYTES)
     if not nacl.lib.crypto_hash_sha256(digest, message, len(message)):
         raise CryptoError("Hashing failed")
     digest = nacl.ffi.buffer(digest, nacl.lib.crypto_hash_sha256_BYTES)[:]
 
-    if binary:
-        return digest
-    return binascii.hexlify(digest)
+    return encoder[encoding].encode(digest)
 
 
-def sha512(message, binary=False):
+def sha512(message, encoding="hex"):
     digest = nacl.ffi.new("unsigned char[]", nacl.lib.crypto_hash_sha512_BYTES)
     if not nacl.lib.crypto_hash_sha512(digest, message, len(message)):
         raise CryptoError("Hashing failed")
     digest = nacl.ffi.buffer(digest, nacl.lib.crypto_hash_sha512_BYTES)[:]
 
-    if binary:
-        return digest
-    return binascii.hexlify(digest)
+    return encoder[encoding].encode(digest)
diff --git a/nacl/signing.py b/nacl/signing.py
index 53a33112462be63ddfa3e6e899c493cb710a890d..b99001a29d9c3dc87f01f4b1189c0b142369ec5e 100644
--- a/nacl/signing.py
+++ b/nacl/signing.py
@@ -4,6 +4,7 @@ from __future__ import division
 from . import six
 
 from . import nacl
+from .encoding import encoder
 from .exceptions import CryptoError
 from .random import random
 
@@ -19,19 +20,26 @@ class SignedMessage(six.binary_type):
     A bytes subclass that holds a messaged that has been signed by a :class:`SigningKey`.
     """
 
+    @classmethod
+    def _from_parts(cls, signature, message, combined):
+        obj = cls(combined)
+        obj._signature = signature
+        obj._message = message
+        return obj
+
     @property
     def signature(self):
         """
         The signature contained within the :class:`SignedMessage`.
         """
-        return self[:nacl.lib.crypto_sign_BYTES]
+        return self._signature
 
     @property
     def message(self):
         """
         The message contained within the :class:`SignedMessage`.
         """
-        return self[nacl.lib.crypto_sign_BYTES:]
+        return self._message
 
 
 class VerifyKey(object):
@@ -42,14 +50,17 @@ class VerifyKey(object):
     :param key: [:class:`bytes`] Serialized Ed25519 public key
     """
 
-    def __init__(self, key):
+    def __init__(self, key, encoding="raw"):
+        # Decode the key
+        key = encoder[encoding].decode(key)
+
         if len(key) != nacl.lib.crypto_sign_PUBLICKEYBYTES:
             raise ValueError("The key must be exactly %s bytes long" %
                                 nacl.lib.crypto_sign_PUBLICKEYBYTES)
 
         self._key = key
 
-    def verify(self, smessage, signature=None):
+    def verify(self, smessage, signature=None, encoding="raw"):
         """
         Verifies the signature of a signed message, returning the message
         if it has not been tampered with else raising
@@ -66,6 +77,9 @@ class VerifyKey(object):
             #   them.
             smessage = signature + smessage
 
+        # Decode the signed message
+        smessage = encoder[encoding].decode(smessage)
+
         message = nacl.ffi.new("unsigned char[]", len(smessage))
         message_len = nacl.ffi.new("unsigned long long *")
 
@@ -93,7 +107,10 @@ class SigningKey(object):
         (i.e. public) key that corresponds with this signing key.
     """
 
-    def __init__(self, seed):
+    def __init__(self, seed, encoding="raw"):
+        # Decode the seed
+        seed = encoder[encoding].decode(seed)
+
         # Verify that our seed is the proper size
         seed_size = nacl.lib.crypto_sign_SECRETKEYBYTES // 2
         if len(seed) != seed_size:
@@ -120,9 +137,11 @@ class SigningKey(object):
 
         :rtype: :class:`~nacl.signing.SigningKey`
         """
-        return cls(random(nacl.lib.crypto_sign_SECRETKEYBYTES // 2))
+        return cls(random(nacl.lib.crypto_sign_SECRETKEYBYTES // 2),
+                    encoding="raw",
+                )
 
-    def sign(self, message):
+    def sign(self, message, encoding="raw"):
         """
         Sign a message using this key.
 
@@ -135,4 +154,10 @@ class SigningKey(object):
         if not nacl.lib.crypto_sign(sm, smlen, message, len(message), self._signing_key):
             raise CryptoError("Failed to sign the message")
 
-        return SignedMessage(nacl.ffi.buffer(sm, smlen[0])[:])
+        raw_signed = nacl.ffi.buffer(sm, smlen[0])[:]
+
+        signature = encoder[encoding].encode(raw_signed[:nacl.lib.crypto_sign_BYTES])
+        message = encoder[encoding].encode(raw_signed[nacl.lib.crypto_sign_BYTES:])
+        signed = encoder[encoding].encode(raw_signed)
+
+        return SignedMessage._from_parts(signature, message, signed)
diff --git a/tests/test_hash.py b/tests/test_hash.py
index 700c3bd041240d93d34158b6be9fa6a902cf1e1d..bc4ecea87ccad73f38f91c28e670453d9000114f 100644
--- a/tests/test_hash.py
+++ b/tests/test_hash.py
@@ -27,7 +27,7 @@ def test_sha256_hex(inp, expected):
     )
 ])
 def test_sha256_binary(inp, expected):
-    assert nacl.hash.sha256(inp, binary=True) == expected
+    assert nacl.hash.sha256(inp, encoding="raw") == expected
 
 
 @pytest.mark.parametrize(("inp", "expected"), [
@@ -55,4 +55,4 @@ def test_sha512_hex(inp, expected):
     )
 ])
 def test_sha512_binary(inp, expected):
-    assert nacl.hash.sha512(inp, binary=True) == expected
+    assert nacl.hash.sha512(inp, encoding="raw") == expected
diff --git a/tests/test_signing.py b/tests/test_signing.py
index fe57c970f15eb44e7fea66e00968578c9e259d84..3607c3fd166754c660f6a02f0a755e830c902656 100644
--- a/tests/test_signing.py
+++ b/tests/test_signing.py
@@ -45,12 +45,12 @@ class TestSigningKey:
                 for x in ed25519_known_answers()]
         )
     def test_message_signing(self, seed, message, signature, expected):
-        signing_key = nacl.signing.SigningKey(binascii.unhexlify(seed))
-        signed = signing_key.sign(binascii.unhexlify(message))
+        signing_key = nacl.signing.SigningKey(seed, encoding="hex")
+        signed = signing_key.sign(binascii.unhexlify(message), encoding="hex")
 
-        assert binascii.hexlify(signed) == expected
-        assert binascii.hexlify(signed.message) == message
-        assert binascii.hexlify(signed.signature) == signature
+        assert signed == expected
+        assert signed.message == message
+        assert signed.signature == signature
 
 
 class TestVerifyKey:
@@ -59,13 +59,10 @@ class TestVerifyKey:
         [(x["public_key"], x["signed"], x["message"], x["signature"]) for x in ed25519_known_answers()]
     )
     def test_valid_signed_message(self, public_key, signed, message, signature):
-        key = nacl.signing.VerifyKey(binascii.unhexlify(public_key))
-        signedb = binascii.unhexlify(signed)
-        messageb = binascii.unhexlify(message)
-        signatureb = binascii.unhexlify(signature)
+        key = nacl.signing.VerifyKey(public_key, encoding="hex")
 
-        assert binascii.hexlify(key.verify(signedb)) == message
-        assert binascii.hexlify(key.verify(messageb, signatureb)) == message
+        assert binascii.hexlify(key.verify(signed, encoding="hex")) == message
+        assert binascii.hexlify(key.verify(message, signature, encoding="hex")) == message
 
     def test_invalid_signed_message(self):
         skey = nacl.signing.SigningKey.generate()