org.elasticsearch.common.settings.SecureString Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elasticsearch Show documentation
Show all versions of elasticsearch Show documentation
Elasticsearch subproject :server
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.common.settings;
import java.io.Closeable;
import java.util.Arrays;
import java.util.Objects;
/**
* A String implementations which allows clearing the underlying char array.
*/
public final class SecureString implements CharSequence, Closeable {
private char[] chars;
/**
* Constructs a new SecureString which controls the passed in char array.
*
* Note: When this instance is closed, the array will be zeroed out.
*/
public SecureString(char[] chars) {
this.chars = Objects.requireNonNull(chars);
}
/**
* Constructs a new SecureString from an existing String.
*
* NOTE: This is not actually secure, since the provided String cannot be deallocated, but
* this constructor allows for easy compatibility between new and old apis.
*
* @deprecated Only use for compatibility between deprecated string settings and new secure strings
*/
@Deprecated
public SecureString(String s) {
this(s.toCharArray());
}
/** Constant time equality to avoid potential timing attacks. */
@Override
public synchronized boolean equals(Object o) {
ensureNotClosed();
if (this == o) return true;
if (o == null || o instanceof CharSequence == false) return false;
CharSequence that = (CharSequence) o;
if (chars.length != that.length()) {
return false;
}
int equals = 0;
for (int i = 0; i < chars.length; i++) {
equals |= chars[i] ^ that.charAt(i);
}
return equals == 0;
}
@Override
public synchronized int hashCode() {
return Arrays.hashCode(chars);
}
@Override
public synchronized int length() {
ensureNotClosed();
return chars.length;
}
@Override
public synchronized char charAt(int index) {
ensureNotClosed();
return chars[index];
}
@Override
public SecureString subSequence(int start, int end) {
throw new UnsupportedOperationException("Cannot get subsequence of SecureString");
}
/**
* Convert to a {@link String}. This should only be used with APIs that do not take {@link CharSequence}.
*/
@Override
public synchronized String toString() {
return new String(chars);
}
/**
* Closes the string by clearing the underlying char array.
*/
@Override
public synchronized void close() {
if (chars != null) {
Arrays.fill(chars, '\0');
chars = null;
}
}
/**
* Returns a new copy of this object that is backed by its own char array. Closing the new instance has no effect on the instance it
* was created from. This is useful for APIs which accept a char array and you want to be safe about the API potentially modifying the
* char array. For example:
*
*
* try (SecureString copy = secureString.clone()) {
* // pass thee char[] to a external API
* PasswordAuthentication auth = new PasswordAuthentication(username, copy.getChars());
* ...
* }
*
*/
@Override
public synchronized SecureString clone() {
ensureNotClosed();
return new SecureString(Arrays.copyOf(chars, chars.length));
}
/**
* Returns the underlying char[]. This is a dangerous operation as the array may be modified while it is being used by other threads
* or a consumer may modify the values in the array. For safety, it is preferable to use {@link #clone()} and pass its chars to the
* consumer when the chars are needed multiple times.
*/
public synchronized char[] getChars() {
ensureNotClosed();
return chars;
}
/** Throw an exception if this string has been closed, indicating something is trying to access the data after being closed. */
private void ensureNotClosed() {
if (chars == null) {
throw new IllegalStateException("SecureString has already been closed");
}
}
}