diff --git a/app/src/main/java/com/futo/polycentric/core/Models.kt b/app/src/main/java/com/futo/polycentric/core/Models.kt
index 5edf9319f351fe9c0b5c42a7aab6f9b36a7c2a0d..58c96ea782ce84f869385634ccc3c96026234809 100644
--- a/app/src/main/java/com/futo/polycentric/core/Models.kt
+++ b/app/src/main/java/com/futo/polycentric/core/Models.kt
@@ -1,5 +1,6 @@
 package com.futo.polycentric.core
 
+import com.futo.polycentric.core.serializers.ByteArraySerializer
 import com.google.protobuf.ByteString
 import com.google.protobuf.InvalidProtocolBufferException
 import kotlinx.serialization.Serializable
@@ -40,7 +41,8 @@ enum class ClaimType(val value: String) {
 }
 
 class Blob(val mime: String, val content: ByteArray) { }
-class Digest(val digestType: Long, val digest: ByteArray) {
+@Serializable
+class Digest(val digestType: Long, @Serializable(with = ByteArraySerializer::class) val digest: ByteArray) {
     init {
         if (digestType != 1L) {
             throw IllegalArgumentException("unknown digest type")
@@ -87,6 +89,7 @@ fun ByteArray.hash(): Digest {
     return Digest(1L, digest)
 }
 
+@Serializable
 data class Pointer(
     val system: PublicKey,
     val process: Process,
@@ -184,7 +187,7 @@ data class Opinion(val data: ByteArray) {
 }
 
 @Serializable
-data class PublicKey(val keyType: Long, val key: ByteArray) {
+data class PublicKey(val keyType: Long, @Serializable(with = ByteArraySerializer::class) val key: ByteArray) {
     init {
         if (keyType != 1L) {
             throw IllegalArgumentException("unknown key type")
@@ -286,7 +289,8 @@ class PrivateKey(val keyType: Long, val key: ByteArray) {
     }
 }
 
-class Process(val process: ByteArray) {
+@Serializable
+class Process(@Serializable(with = ByteArraySerializer::class) val process: ByteArray) {
     init {
         if (process.size != 16) {
             throw IllegalArgumentException("incorrect process size")
diff --git a/app/src/main/java/com/futo/polycentric/core/SystemState.kt b/app/src/main/java/com/futo/polycentric/core/SystemState.kt
index b0a453fff20045cd8e20b38fb428291f970cacc2..129f1d3f2c841f8793fa9476cc3df468cbc3e85a 100644
--- a/app/src/main/java/com/futo/polycentric/core/SystemState.kt
+++ b/app/src/main/java/com/futo/polycentric/core/SystemState.kt
@@ -1,7 +1,9 @@
 package com.futo.polycentric.core
 
+import kotlinx.serialization.Serializable
 import userpackage.Protocol
 
+@Serializable
 class SystemState(
     val servers: Array<String>,
     val processes: Array<Process>,
diff --git a/app/src/main/java/com/futo/polycentric/core/Utility.kt b/app/src/main/java/com/futo/polycentric/core/Utility.kt
index 93ccc2a81b5602cb2aff04a70cab99d263e71187..e9895b37485bde78d6e4aa49a3fd01897af558e5 100644
--- a/app/src/main/java/com/futo/polycentric/core/Utility.kt
+++ b/app/src/main/java/com/futo/polycentric/core/Utility.kt
@@ -1,6 +1,8 @@
 package com.futo.polycentric.core
 
 import android.util.Base64
+import com.futo.polycentric.core.serializers.ClaimSerializer
+import kotlinx.serialization.Serializable
 import userpackage.Protocol
 import userpackage.Protocol.Claim
 import userpackage.Protocol.URLInfoSystemLink
@@ -29,8 +31,8 @@ fun String.base64ToByteArray(): ByteArray {
     return Base64.decode(this, Base64.NO_PADDING or Base64.NO_WRAP)
 }
 
-
-data class OwnedClaim(val system: PublicKey, val claim: Claim);
+@Serializable
+data class OwnedClaim(val system: PublicKey, @Serializable(with = ClaimSerializer::class) val claim: Claim);
 fun List<SignedEvent>.getValidClaims(): List<OwnedClaim> {
     val validClaims = arrayListOf<OwnedClaim>();
 
diff --git a/app/src/main/java/com/futo/polycentric/core/serializers/ByteArraySerializer.kt b/app/src/main/java/com/futo/polycentric/core/serializers/ByteArraySerializer.kt
new file mode 100644
index 0000000000000000000000000000000000000000..dfa040cb433f3e3e8708fd3fa55b77316ce429d2
--- /dev/null
+++ b/app/src/main/java/com/futo/polycentric/core/serializers/ByteArraySerializer.kt
@@ -0,0 +1,25 @@
+package com.futo.polycentric.core.serializers
+
+import com.futo.polycentric.core.base64UrlToByteArray
+import com.futo.polycentric.core.toBase64Url
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.descriptors.PrimitiveKind
+import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+import userpackage.Protocol
+
+object ByteArraySerializer : KSerializer<ByteArray> {
+    override val descriptor: SerialDescriptor =
+        PrimitiveSerialDescriptor("com.futo.polycentric.core.serializers.ByteArray", PrimitiveKind.STRING)
+
+    override fun serialize(encoder: Encoder, value: ByteArray) {
+        encoder.encodeString(value.toBase64Url())
+    }
+
+    override fun deserialize(decoder: Decoder): ByteArray {
+        val string = decoder.decodeString()
+        return string.base64UrlToByteArray()
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/polycentric/core/serializers/ClaimSerializer.kt b/app/src/main/java/com/futo/polycentric/core/serializers/ClaimSerializer.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9b411d8dc623f1912087f23c8915f1bf33db48a0
--- /dev/null
+++ b/app/src/main/java/com/futo/polycentric/core/serializers/ClaimSerializer.kt
@@ -0,0 +1,23 @@
+package com.futo.polycentric.core.serializers
+
+import com.futo.polycentric.core.base64UrlToByteArray
+import com.futo.polycentric.core.toBase64Url
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.descriptors.PrimitiveKind
+import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+import userpackage.Protocol
+
+class ClaimSerializer : KSerializer<Protocol.Claim> {
+    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Claim", PrimitiveKind.STRING)
+
+    override fun serialize(encoder: Encoder, value: Protocol.Claim) {
+        encoder.encodeString(value.toByteArray().toBase64Url())
+    }
+    override fun deserialize(decoder: Decoder): Protocol.Claim {
+        val value = decoder.decodeString();
+        return Protocol.Claim.parseFrom(value.base64UrlToByteArray());
+    }
+}
\ No newline at end of file