Created
September 30, 2014 05:21
-
-
Save vegaasen/a0fb22974ec9a74f2410 to your computer and use it in GitHub Desktop.
Proposed implementation of (as-safe-as it-gets) passwords in java.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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