/** * Create a copy of the byte array. If this instance is read-only, * the copy will not be read-only. * @return A copy of the byte array. * @throws IllegalStateException If the byte array has been disposed */ public GuardedByteArray copy() { checkNotDisposed(); byte [] encryptedBytes2 = new byte[_encryptedBytes.length]; System.arraycopy(_encryptedBytes, 0, encryptedBytes2, 0, _encryptedBytes.length); GuardedByteArray rv = new GuardedByteArray(); rv._encryptedBytes = encryptedBytes2; return rv; }
/** * Decrypts the value of a {@link GuardedByteArray}. * * @param guardedByteArray the guarded byte array value. * @return the clear byte array value. * @since 1.4 */ public static byte[] decrypt(GuardedByteArray guardedByteArray) { byte[][] clearByte = new byte[1][]; guardedByteArray.access((clearBytes) -> { clearByte[0] = clearBytes; }); return clearByte[0]; } }
/** * Initializes the GuardedByteArray from the given clear text bytes. * * Caller is responsible for zeroing out the array of bytes after the call. * * @param clearBytes * The clear-text bytes */ public GuardedByteArray(byte[] clearBytes) { encryptBytes(clearBytes); }
value = new GuardedString(values.get(0).toString().toCharArray()); } else if (GuardedByteArray.class.equals(propertySchemaClass)) { value = new GuardedByteArray((byte[]) values.get(0)); } else if (Character.class.equals(propertySchemaClass) || Character.TYPE.equals(propertySchemaClass)) { value = values.get(0) == null || values.get(0).toString().isEmpty()
@Test public void testRange() { for (int i = -128; i < 128; i++) { final byte expected = (byte) i; GuardedByteArray bytes = new GuardedByteArray(new byte[] { (byte) i }); bytes.access((byte[] clearBytes) -> { byte v = clearBytes[0]; assertEquals(v, expected); }); } }
@Test public void testDispose() { GuardedByteArray str = new GuardedByteArray(new byte[] { 0x00, 0x01, 0x02 }); str.dispose(); try { decryptToBytes(str); str.isReadOnly(); fail("expected exception"); } catch (IllegalStateException e) { str.appendByte((byte) 0x03); fail("expected exception"); } catch (IllegalStateException e) { str.copy(); fail("expected exception"); } catch (IllegalStateException e) { str.verifyBase64SHA1Hash("foo"); fail("expected exception"); } catch (IllegalStateException e) {
@Test public void testReadOnly() { GuardedByteArray bytes = new GuardedByteArray(new byte[] { 0x00, 0x01, 0x02 }); assertFalse(bytes.isReadOnly()); bytes.makeReadOnly(); assertTrue(bytes.isReadOnly()); assertTrue(Arrays.equals(new byte[] { 0x00, 0x01, 0x02 }, decryptToBytes(bytes))); try { bytes.appendByte((byte) 0x03); fail("expected exception"); } catch (IllegalStateException e) { /* ignore */ } bytes = bytes.copy(); assertTrue(Arrays.equals(new byte[] { 0x00, 0x01, 0x02 }, decryptToBytes(bytes))); bytes.appendByte((byte) 0x03); assertTrue(Arrays.equals(new byte[] { 0x00, 0x01, 0x02, 0x03 }, decryptToBytes(bytes))); }
/** * Appends a single clear-text byte to the secure byte array. * The in-memory data will be decrypted, the byte will be * appended, and then it will be re-encrypted. * @param b The byte to append. * @throws IllegalStateException If the byte array is read-only * @throws IllegalStateException If the byte array has been disposed */ public void appendByte(byte b) { checkNotDisposed(); checkWriteable(); byte[] clearBytes = null; byte[] clearBytes2 = null; try { clearBytes = decryptBytes(); clearBytes2 = new byte[clearBytes.length+1]; System.arraycopy(clearBytes, 0, clearBytes2, 0, clearBytes.length); clearBytes2[clearBytes2.length-1] = b; encryptBytes(clearBytes2); } finally { SecurityUtil.clear(clearBytes); SecurityUtil.clear(clearBytes2); } }
@Test public void testEquals() { GuardedByteArray bytes1 = new GuardedByteArray(); GuardedByteArray bytes2 = new GuardedByteArray(); assertEquals(bytes1, bytes2); bytes2.appendByte((byte) 0x03); assertFalse(bytes1.equals(bytes2)); bytes1.appendByte((byte) 0x03); assertEquals(bytes1, bytes2); }
@Test public void testBasics() { GuardedByteArray bytes = new GuardedByteArray(new byte[] { 0x00, 0x01, 0x02 }); assertTrue(Arrays.equals(decryptToBytes(bytes), new byte[] { 0x00, 0x01, 0x02 })); assertTrue(Arrays.equals(new byte[] { 0x00, 0x01, 0x02 }, decryptToBytes(bytes))); bytes.appendByte((byte) 0x03); assertTrue(Arrays.equals(new byte[] { 0x00, 0x01, 0x02, 0x03 }, decryptToBytes(bytes))); assertFalse(bytes.verifyBase64SHA1Hash( SecurityUtil.computeBase64SHA1Hash(new byte[] { 0x00, 0x01, 0x02 }))); assertTrue(bytes.verifyBase64SHA1Hash( SecurityUtil.computeBase64SHA1Hash(new byte[] { 0x00, 0x01, 0x02, 0x03 }))); }
/** * Provides access to the clear-text value of the byte array in a controlled fashion. * The clear-text bytes will only be available for the duration of the call * and automatically zeroed out following the call. * * <p> * <b>NOTE:</b> Callers are encouraged to use {@link #verifyBase64SHA1Hash(String)} * where possible if the intended use is merely to verify the contents of * the byte array match an expected hash value. * @param accessor Accessor callback. * @throws IllegalStateException If the byte array has been disposed */ public void access(Accessor accessor) { checkNotDisposed(); byte[] clearBytes = null; try { clearBytes = decryptBytes(); accessor.access(clearBytes); } finally { SecurityUtil.clear(clearBytes); } }
/** * Returns true if this byte array has been marked read-only. * * @return true if this byte array has been marked read-only * @throws IllegalStateException * If the byte array has been disposed */ public boolean isReadOnly() { checkNotDisposed(); return readOnly; }
private byte[] decryptBytes() { Encryptor encryptor = getEncryptor(); return encryptor.decrypt(encryptedBytes); }
@Override public Object deserialize(final ObjectDecoder decoder) { byte[] encryptedBytes = null; byte[] clearBytes = null; try { encryptedBytes = decoder.readByteArrayContents(); clearBytes = EncryptorFactory.getInstance().getDefaultEncryptor().decrypt(encryptedBytes); return new GuardedByteArray(clearBytes); } finally { SecurityUtil.clear(encryptedBytes); SecurityUtil.clear(clearBytes); } }
/** * Appends a single clear-text byte to the secure byte array. * * The in-memory data will be decrypted, the byte will be appended, and then * it will be re-encrypted. * * @param b * The byte to append. * @throws IllegalStateException * If the byte array is read-only * @throws IllegalStateException * If the byte array has been disposed */ public void appendByte(byte b) { checkNotDisposed(); checkWriteable(); byte[] clearBytes = null; byte[] clearBytes2 = null; try { clearBytes = decryptBytes(); clearBytes2 = new byte[clearBytes.length + 1]; System.arraycopy(clearBytes, 0, clearBytes2, 0, clearBytes.length); clearBytes2[clearBytes2.length - 1] = b; encryptBytes(clearBytes2); } finally { SecurityUtil.clear(clearBytes); SecurityUtil.clear(clearBytes2); } }
/** * Provides access to the clear-text value of the byte array in a controlled * fashion. * * The clear-text bytes will only be available for the duration of the call * and automatically zeroed out following the call. * <p> * <b>NOTE:</b> Callers are encouraged to use * {@link #verifyBase64SHA1Hash(String)} where possible if the intended use * is merely to verify the contents of the byte array match an expected hash * value. * * @param accessor * Accessor callback. * @throws IllegalStateException * If the byte array has been disposed */ public void access(Accessor accessor) { checkNotDisposed(); byte[] clearBytes = null; try { clearBytes = decryptBytes(); accessor.access(clearBytes); } finally { SecurityUtil.clear(clearBytes); } }
/** * Mark this byte array as read-only. * * @throws IllegalStateException * If the byte array has been disposed */ public void makeReadOnly() { checkNotDisposed(); readOnly = true; }
private byte [] decryptBytes() { Encryptor encryptor = getEncryptor(); return encryptor.decrypt(_encryptedBytes); }
@Override public Object deserialize(final ObjectDecoder decoder) { byte[] encryptedBytes = null; byte[] clearBytes = null; try { encryptedBytes = decoder.readByteArrayContents(); clearBytes = EncryptorFactory.getInstance().getDefaultEncryptor().decrypt(encryptedBytes); return new GuardedByteArray(clearBytes); } finally { SecurityUtil.clear(encryptedBytes); SecurityUtil.clear(clearBytes); } }
/** * Create a copy of the byte array. * * If this instance is read-only, the copy will not be read-only. * * @return A copy of the byte array. * @throws IllegalStateException * If the byte array has been disposed */ public GuardedByteArray copy() { checkNotDisposed(); byte[] encryptedBytes2 = new byte[encryptedBytes.length]; System.arraycopy(encryptedBytes, 0, encryptedBytes2, 0, encryptedBytes.length); GuardedByteArray rv = new GuardedByteArray(); rv.encryptedBytes = encryptedBytes2; return rv; }