Skip to content

Instantly share code, notes, and snippets.

@vegaasen
Created September 30, 2014 05:21
Show Gist options
  • Select an option

  • Save vegaasen/a0fb22974ec9a74f2410 to your computer and use it in GitHub Desktop.

Select an option

Save vegaasen/a0fb22974ec9a74f2410 to your computer and use it in GitHub Desktop.
Proposed implementation of (as-safe-as it-gets) passwords in java.
import java.util.Objects;
/**
* Password-class which is as safe as it gets in Java. Try to avoid using the "toString", "fromString"-methods due to
* memory allocations and gc-troubles (in regards to the actual removal of the password within RAM etc.
*
* @author <a href="mailto:[email protected]">Vegard Aasen</a>
*/
public final class Password implements CharSequence, Comparable<Password> {
private char[] password;
private int hash;
public Password() {
password = new char[0];
}
public Password(final char[] password) {
copyFrom(password);
}
public Password(final Password password) {
copyFrom(password.password);
}
public Password(final String password) {
copyFrom(password.toCharArray());
}
public void clear() {
if (password == null) {
return;
}
for (int q = password.length - 1; q >= 0; q--) {
password[q] = 0;
}
password = null;
hash = 0;
}
public boolean contains(final char[] chars) {
assertHasValue();
if (chars == null) {
return false;
}
for (int q = 0; q <= password.length - chars.length; q++) {
boolean match = false;
for (int w = 0; w < chars.length; w++) {
final char c = password[q + w];
if (chars[w] != c) {
break;
} else if (w == chars.length - 1) {
match = true;
}
}
if (match) {
return true;
}
}
return false;
}
public boolean contains(final Password other) {
return contains(other.password);
}
public boolean contains(final String s) {
return contains(s.toCharArray());
}
public String toUnsafeString() {
return new String(password);
}
@Override
protected void finalize()
throws Throwable {
clear();
super.finalize();
}
@Override
public int hashCode() {
return Objects.hash(password, hash);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final Password other = (Password) obj;
return Objects.equals(this.password, other.password) && Objects.equals(this.hash, other.hash);
}
@Override
public int length() {
assertHasValue();
return password.length;
}
@Override
public char charAt(final int index) {
return password[index];
}
@Override
public CharSequence subSequence(final int start, final int end) {
assertHasValue();
final Password ret = new Password();
ret.copyFrom(password, start, end);
return ret;
}
@Override
public String toString() {
throw new RuntimeException("toString not supported for Password. Use toUnsafeString if you really want to do this.");
}
@Override
public int compareTo(final Password other) {
assertHasValue();
other.assertHasValue();
final int len1 = password.length;
final int len2 = other.password.length;
int n = Math.min(len1, len2);
int q = 0;
while (n-- != 0) {
final char c1 = password[q];
final char c2 = other.password[q];
if (c1 != c2) {
return c1 - c2;
}
++q;
}
return len1 - len2;
}
private void assertHasValue() {
if (password == null) {
throw new RuntimeException("Password doesn't contain a value. cleared?");
}
}
private void copyFrom(final char[] chars, final int start, final int end) {
clear();
if (chars == null) {
password = null;
return;
}
password = new char[chars.length];
System.arraycopy(chars, start, password, 0, end - start);
}
private void copyFrom(final char[] chars) {
copyFrom(chars, 0, chars.length);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment