diff --git a/WORKSPACE b/WORKSPACE
index c0781b0c2f29e182f95225cece20171232709ff8..a669286b18839954ea3251fc63d0e1c67bca6b5c 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -116,3 +116,9 @@ maven_jar(
     artifact = "com.google.truth:truth:jar:0.32",
     sha1 = "e996fb4b41dad04365112786796c945f909cfdf7",
 )
+
+maven_jar(
+    name = "com_google_errorprone_error_prone_annotations",
+    artifact = "com.google.errorprone:error_prone_annotations:2.0.19",
+    sha1 = "c3754a0bdd545b00ddc26884f9e7624f8b6a14de",
+)
\ No newline at end of file
diff --git a/java/src/main/java/com/google/cloud/crypto/tink/BUILD b/java/src/main/java/com/google/cloud/crypto/tink/BUILD
index 260b02672982f4bcaae0a88f485b36b938729cff..26dc66d8eb357d368921cf880d5532cfeb0cdd0a 100644
--- a/java/src/main/java/com/google/cloud/crypto/tink/BUILD
+++ b/java/src/main/java/com/google/cloud/crypto/tink/BUILD
@@ -72,6 +72,7 @@ java_library(
         "//java/src/main/java/com/google/cloud/crypto/tink/subtle",
         "//proto:common_java_proto",
         "//proto:tink_java_proto",
+        "@com_google_errorprone_error_prone_annotations//jar",
         "@com_google_protobuf_java//:protobuf_java",
     ],
 )
@@ -84,6 +85,7 @@ java_library(
         "//java/src/main/java/com/google/cloud/crypto/tink/subtle",
         "//proto:common_java_proto_lite",
         "//proto:tink_java_proto_lite",
+        "@com_google_errorprone_error_prone_annotations//jar",
         "@com_google_protobuf_java//:protobuf_java",
     ],
 )
diff --git a/java/src/main/java/com/google/cloud/crypto/tink/KeysetHandle.java b/java/src/main/java/com/google/cloud/crypto/tink/KeysetHandle.java
index 93ff9dc8a55de9c1536de74a33953f625ca6331a..6e7a528431a5a9e1b23f81629b29825c3dad5a19 100644
--- a/java/src/main/java/com/google/cloud/crypto/tink/KeysetHandle.java
+++ b/java/src/main/java/com/google/cloud/crypto/tink/KeysetHandle.java
@@ -18,11 +18,14 @@ package com.google.cloud.crypto.tink;
 
 import com.google.cloud.crypto.tink.TinkProto.Keyset;
 import com.google.cloud.crypto.tink.TinkProto.KeysetInfo;
+import com.google.cloud.crypto.tink.subtle.ImmutableByteArray;
+import com.google.errorprone.annotations.Immutable;
 
 /**
  * KeysetHandle provides abstracted access to Keysets, to limit the exposure
  * of actual protocol buffers that hold sensitive key material.
  */
+@Immutable
 public final class KeysetHandle {
   /**
    * The {@code Keyset}.
@@ -32,7 +35,7 @@ public final class KeysetHandle {
   /**
    * {@code Keyset} encrypted with some key.
    */
-  private final byte[] encryptedKeyset;
+  private final ImmutableByteArray encryptedKeyset;
 
   /**
    * This constructor is package-private. To get a new instance, users have to use one of
@@ -51,7 +54,7 @@ public final class KeysetHandle {
    */
   KeysetHandle(Keyset keyset, final byte[] encryptedKeyset) {
     this.keyset = keyset;
-    this.encryptedKeyset = encryptedKeyset;
+    this.encryptedKeyset = ImmutableByteArray.of(encryptedKeyset);
   }
 
   /**
@@ -72,7 +75,11 @@ public final class KeysetHandle {
    * @return the actual keyset data.
    */
   public byte[] getEncryptedKeyset() {
-    return encryptedKeyset;
+    if (encryptedKeyset == null) {
+      return null;
+    } else {
+      return encryptedKeyset.getBytes();
+    }
   }
 
   /**
diff --git a/java/src/main/java/com/google/cloud/crypto/tink/PrimitiveSet.java b/java/src/main/java/com/google/cloud/crypto/tink/PrimitiveSet.java
index 5cd93b79a1488c55f6be345505764b80ffe3d9ae..9f79df3126335e73abc91c09d634c4f5685caced 100644
--- a/java/src/main/java/com/google/cloud/crypto/tink/PrimitiveSet.java
+++ b/java/src/main/java/com/google/cloud/crypto/tink/PrimitiveSet.java
@@ -18,6 +18,8 @@ package com.google.cloud.crypto.tink;
 
 import com.google.cloud.crypto.tink.TinkProto.KeyStatusType;
 import com.google.cloud.crypto.tink.TinkProto.Keyset;
+import com.google.cloud.crypto.tink.subtle.ImmutableByteArray;
+import com.google.errorprone.annotations.Immutable;
 import java.nio.charset.Charset;
 import java.security.GeneralSecurityException;
 import java.util.ArrayList;
@@ -35,7 +37,7 @@ import java.util.concurrent.ConcurrentMap;
  * PrimitiveSet is an auxiliary class used for supporting key rotation: primitives in a set
  * correspond to keys in a keyset.  Users will usually work with primitive instances,
  * which essentially wrap primitive sets.  For example an instance of an Aead-primitive
- * for a given keyset holds a set of Aead-primitivies corresponding to the keys in the keyset,
+ * for a given keyset holds a set of Aead-primitives corresponding to the keys in the keyset,
  * and uses the set members to do the actual crypto operations: to encrypt data the primary
  * Aead-primitive from the set is used, and upon decryption the ciphertext's prefix
  * determines the id of the primitive from the set. <p>
@@ -48,18 +50,19 @@ public final class PrimitiveSet<P> {
    * A single entry in the set. In addition to the actual primitive it holds also
    * some extra information about the primitive.
    */
+  @Immutable(containerOf={"P"})
   public class Entry<P> {
     // The actual primitive.
     private final P primitive;
     // Identifies the primitive within the set.
     // It is the ciphertext prefix of the correponding key.
-    private final byte[] identifier;
+    private final ImmutableByteArray identifier;
     // The status of the key represented by the primitive.
     private final KeyStatusType status;
 
     public Entry(P primitive, final byte[] identifier, KeyStatusType status) {
       this.primitive = primitive;
-      this.identifier = identifier;
+      this.identifier = ImmutableByteArray.of(identifier);
       this.status = status;
     }
     public P getPrimitive() {
@@ -69,7 +72,11 @@ public final class PrimitiveSet<P> {
       return status;
     }
     public final byte[] getIdentifier() {
-      return identifier;
+      if (identifier == null) {
+        return null;
+      } else {
+        return identifier.getBytes();
+      }
     }
   }
 
diff --git a/java/src/main/java/com/google/cloud/crypto/tink/subtle/BUILD b/java/src/main/java/com/google/cloud/crypto/tink/subtle/BUILD
index a30b2d59a3ed651fad0b0ae90c2c15fc0922e337..a353263a72e3f6dfba3b12ffb1ae0daa6e38e723 100644
--- a/java/src/main/java/com/google/cloud/crypto/tink/subtle/BUILD
+++ b/java/src/main/java/com/google/cloud/crypto/tink/subtle/BUILD
@@ -19,10 +19,14 @@ java_library(
         "EcUtil.java",
         "EngineFactory.java",
         "EngineWrapper.java",
+        "ImmutableByteArray.java",
         "Random.java",
         "SubtleUtil.java",
     ],
     javacopts = JAVACOPTS,
+    deps = [
+        "@com_google_errorprone_error_prone_annotations//jar",
+    ],
 )
 
 # aead subtle
@@ -121,6 +125,7 @@ java_library(
     deps = [
         ":subtle",
         "//java/src/main/java/com/google/cloud/crypto/tink:primitives",
+        "@com_google_errorprone_error_prone_annotations//jar",
     ],
 )
 
@@ -166,6 +171,7 @@ java_library(
         ":subtle",
         ":x25519",
         "//java/src/main/java/com/google/cloud/crypto/tink:primitives",
+        "@com_google_errorprone_error_prone_annotations//jar",
     ],
 )
 
diff --git a/java/src/main/java/com/google/cloud/crypto/tink/subtle/EciesHkdfSenderKem.java b/java/src/main/java/com/google/cloud/crypto/tink/subtle/EciesHkdfSenderKem.java
index 9a70f70e021d9e18f00d4e69dc5de85e143f8d96..24a63c7fbcb0003e22c6975ca74caffa8303a003 100644
--- a/java/src/main/java/com/google/cloud/crypto/tink/subtle/EciesHkdfSenderKem.java
+++ b/java/src/main/java/com/google/cloud/crypto/tink/subtle/EciesHkdfSenderKem.java
@@ -16,6 +16,7 @@
 
 package com.google.cloud.crypto.tink.subtle;
 
+import com.google.errorprone.annotations.Immutable;
 import java.security.GeneralSecurityException;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
@@ -34,18 +35,27 @@ public final class EciesHkdfSenderKem {
   /**
    * A container for key parts generated by the KEM.
    */
+  @Immutable
   public static final class KemKey {
-    private byte[] kemBytes;
-    private byte[] symmetricKey;
+    private final ImmutableByteArray kemBytes;
+    private final ImmutableByteArray symmetricKey;
     public KemKey(final byte[] kemBytes, final byte[] symmetricKey) {
-      this.kemBytes = kemBytes;
-      this.symmetricKey = symmetricKey;
+      this.kemBytes = ImmutableByteArray.of(kemBytes);
+      this.symmetricKey = ImmutableByteArray.of(symmetricKey);
     }
     public byte[] getKemBytes() {
-      return kemBytes;
+      if (kemBytes == null) {
+        return null;
+      } else {
+        return kemBytes.getBytes();
+      }
     }
     public byte[] getSymmetricKey() {
-      return symmetricKey;
+      if (symmetricKey == null) {
+        return null;
+      } else {
+        return symmetricKey.getBytes();
+      }
     }
   }
 
diff --git a/java/src/main/java/com/google/cloud/crypto/tink/subtle/Ed25519Verify.java b/java/src/main/java/com/google/cloud/crypto/tink/subtle/Ed25519Verify.java
index 348d1f71fa0d0d26dad1c15bada96c1d11a5a29a..f7f0d3ac411a5aff62507be9a0b0088e4334c280 100644
--- a/java/src/main/java/com/google/cloud/crypto/tink/subtle/Ed25519Verify.java
+++ b/java/src/main/java/com/google/cloud/crypto/tink/subtle/Ed25519Verify.java
@@ -19,6 +19,7 @@ package com.google.cloud.crypto.tink.subtle;
 import static com.google.cloud.crypto.tink.subtle.Curve25519.FIELD_LEN;
 
 import com.google.cloud.crypto.tink.PublicKeyVerify;
+import com.google.errorprone.annotations.Immutable;
 import java.security.GeneralSecurityException;
 import java.security.SignatureException;
 
@@ -36,12 +37,13 @@ import java.security.SignatureException;
  *   // all the rest of security exceptions.
  * }
  */
+@Immutable
 public class Ed25519Verify implements PublicKeyVerify {
 
   public static final int PUBLIC_KEY_LEN = FIELD_LEN;
   public static final int SIGNATURE_LEN = FIELD_LEN * 2;
 
-  private final byte[] publicKey;
+  private final ImmutableByteArray publicKey;
 
   public Ed25519Verify(final byte[] publicKey)
       throws GeneralSecurityException {
@@ -49,7 +51,7 @@ public class Ed25519Verify implements PublicKeyVerify {
       throw new IllegalArgumentException(
           String.format("Given public key's length is not %s.", PUBLIC_KEY_LEN));
     }
-    this.publicKey = publicKey;
+    this.publicKey = ImmutableByteArray.of(publicKey);
   }
 
   @Override
@@ -61,7 +63,7 @@ public class Ed25519Verify implements PublicKeyVerify {
     if (((signature[SIGNATURE_LEN - 1] & 0xff) & 224) != 0) {
       throw new IllegalArgumentException("Given signature's 3 most significant bits must be 0.");
     }
-    if (!Ed25519.verify(data, signature, publicKey)) {
+    if (!Ed25519.verify(data, signature, publicKey.getBytes())) {
       throw new SignatureException("Signature check failed.");
     }
   }
diff --git a/java/src/main/java/com/google/cloud/crypto/tink/subtle/ImmutableByteArray.java b/java/src/main/java/com/google/cloud/crypto/tink/subtle/ImmutableByteArray.java
new file mode 100644
index 0000000000000000000000000000000000000000..26241fa389d7e61a8ffc4f1d1956727eb220a243
--- /dev/null
+++ b/java/src/main/java/com/google/cloud/crypto/tink/subtle/ImmutableByteArray.java
@@ -0,0 +1,74 @@
+// Copyright 2017 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.cloud.crypto.tink.subtle;
+
+import com.google.errorprone.annotations.Immutable;
+
+/**
+ * Immutable Wrapper around a byte array.
+ *
+ * <p>Wrap a bytearray so it prevents callers from modifying its contents. It does this by making a
+ * copy upon initialization, and also makes a copy if the underlying bytes are requested.
+ */
+@Immutable
+@SuppressWarnings("Immutable")
+public final class ImmutableByteArray {
+
+  /**
+   * @param data the byte array to be wrapped.
+   * @return an immutable wrapper around the provided bytes.
+   */
+  public static ImmutableByteArray of(final byte[] data) {
+    if (data == null) {
+      return null;
+    } else {
+      return of(data, 0, data.length);
+    }
+  }
+
+  /**
+   * Wrap an immutable byte array over a slice of a bytearray
+   *
+   * @param data the byte array to be wrapped.
+   * @param start the starting index of the slice
+   * @param len the length of the slice. start + len must be less than the length of the array.
+   * @return an immutable wrapper around the bytes in the slice from {@code start} to
+   *    {@code start + len}
+   */
+  public static ImmutableByteArray of(final byte[] data, final int start, final int len) {
+    return new ImmutableByteArray(data, start, len);
+  }
+
+  /** @return a copy of the bytes wrapped by this object. */
+  public byte[] getBytes() {
+    byte[] result = new byte[data.length];
+    System.arraycopy(data, 0, result, 0, data.length);
+    return result;
+  }
+
+  /** @return the length of the bytes wrapped by this object. */
+  public int getLength() {
+    return data.length;
+  }
+
+  private ImmutableByteArray(final byte[] buf, final int start, final int len) {
+    data = new byte[len];
+    System.arraycopy(buf, start, data, 0, len);
+  }
+
+  private final byte[] data;
+}
diff --git a/java/src/test/java/com/google/cloud/crypto/tink/subtle/ImmutableByteArrayTest.java b/java/src/test/java/com/google/cloud/crypto/tink/subtle/ImmutableByteArrayTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ed8364416b274166714f4c1e5971b10aa88cffb
--- /dev/null
+++ b/java/src/test/java/com/google/cloud/crypto/tink/subtle/ImmutableByteArrayTest.java
@@ -0,0 +1,40 @@
+// Copyright 2017 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.google.cloud.crypto.tink.subtle;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for ImmutableByteArray */
+@RunWith(JUnit4.class)
+public class ImmutableByteArrayTest {
+
+  @Test
+  public void checkWrap() {
+    byte[] initial = new byte[] {(byte) 1};
+    ImmutableByteArray ba = ImmutableByteArray.of(initial);
+    byte[] result = ba.getBytes();
+    assertNotSame(result, initial);
+    assertArrayEquals(result, initial);
+    assertEquals(ba.getLength(), initial.length);
+  }
+}
diff --git a/pom.xml b/pom.xml
index 75192cefb0657cadaddd371eaacc5dc1738f513c..42fe9d72ac8be79be592c156a0896baa7a8feb7f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -74,6 +74,7 @@
     <os-maven-plugin.version>1.2.0.Final</os-maven-plugin.version>
 
     <!-- library versions -->
+    <error-prone-annotations.version>2.0.19</error-prone-annotations.version>
     <google-api-client.version>1.22.0</google-api-client.version>
     <google-api-services-cloudkms.version>v1-rev9-1.22.0</google-api-services-cloudkms.version>
     <gson.version>2.8.0</gson.version>
@@ -122,6 +123,12 @@
         <version>${protobuf.version}</version>
       </dependency>
 
+      <dependency>
+        <groupId>com.google.errorprone</groupId>
+        <artifactId>error_prone_annotations</artifactId>
+        <version>${error-prone-annotations.version}</version>
+      </dependency>
+
       <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
@@ -170,6 +177,11 @@
       <artifactId>protobuf-java</artifactId>
     </dependency>
 
+    <dependency>
+      <groupId>com.google.errorprone</groupId>
+      <artifactId>error_prone_annotations</artifactId>
+    </dependency>
+
     <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>