Added additional Hasher implementations

- `BCRYPT`, `MD5`, `SHA1`, `SHA2`,
 - Also removed the support for bcrypt minor version y (i.e. $2y$) as it's not supported by our BCrypt implementation

Original commit: elastic/x-pack-elasticsearch@12cf024a59
This commit is contained in:
uboness 2014-10-17 14:33:22 -07:00
parent 1224454714
commit 836540455a
4 changed files with 113 additions and 13 deletions

View File

@ -9,6 +9,7 @@ import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.Crypt;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.digest.Md5Crypt;
import org.apache.commons.codec.digest.Sha2Crypt;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.common.os.OsUtils;
@ -34,9 +35,6 @@ public enum Hasher {
@Override
public boolean verify(SecuredString text, char[] hash) {
String hashStr = new String(hash);
if (hashStr.startsWith(BCRYPT_PREFIX_Y)) {
hashStr = BCRYPT_PREFIX + hashStr.substring(BCRYPT_PREFIX_Y.length());
}
if (hashStr.startsWith(BCRYPT_PREFIX)) {
return BCrypt.checkpw(text, hashStr);
}
@ -52,16 +50,94 @@ public enum Hasher {
String passwd64 = Base64.encodeBase64String(DigestUtils.sha1(textBytes));
return hashStr.substring(SHA1_PREFIX.length()).compareTo(passwd64) == 0;
}
if (hashStr.startsWith(SHA2_PREFIX_5) || hashStr.startsWith(SHA2_PREFIX_6)) {
return hashStr.compareTo(Sha2Crypt.sha256Crypt(textBytes, hashStr)) == 0;
}
return CRYPT_SUPPORTED ?
hashStr.compareTo(Crypt.crypt(textBytes, hashStr)) == 0 : // crypt algo
text.equals(hashStr); // plain text
hashStr.compareTo(Crypt.crypt(textBytes, hashStr)) == 0 : // crypt algo
text.equals(hashStr); // plain text
}
},
BCRYPT() {
@Override
public char[] hash(SecuredString text) {
String salt = org.elasticsearch.shield.authc.support.BCrypt.gensalt();
return BCrypt.hashpw(text, salt).toCharArray();
}
@Override
public boolean verify(SecuredString text, char[] hash) {
String hashStr = new String(hash);
if (!hashStr.startsWith(BCRYPT_PREFIX)) {
return false;
}
return BCrypt.checkpw(text, hashStr);
}
},
MD5() {
@Override
public char[] hash(SecuredString text) {
byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars());
return Md5Crypt.apr1Crypt(textBytes).toCharArray();
}
@Override
public boolean verify(SecuredString text, char[] hash) {
String hashStr = new String(hash);
if (!hashStr.startsWith(APR1_PREFIX)) {
return false;
}
byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars());
return hashStr.compareTo(Md5Crypt.apr1Crypt(textBytes, hashStr)) == 0;
}
},
SHA1() {
@Override
public char[] hash(SecuredString text) {
byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars());
String hash = Base64.encodeBase64String(DigestUtils.sha1(textBytes));
return (SHA1_PREFIX + hash).toCharArray();
}
@Override
public boolean verify(SecuredString text, char[] hash) {
String hashStr = new String(hash);
if (!hashStr.startsWith(SHA1_PREFIX)) {
return false;
}
byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars());
String passwd64 = Base64.encodeBase64String(DigestUtils.sha1(textBytes));
return hashStr.substring(SHA1_PREFIX.length()).compareTo(passwd64) == 0;
}
},
SHA2() {
@Override
public char[] hash(SecuredString text) {
byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars());
return Sha2Crypt.sha256Crypt(textBytes).toCharArray();
}
@Override
public boolean verify(SecuredString text, char[] hash) {
String hashStr = new String(hash);
if (hashStr.startsWith(SHA2_PREFIX_5) || hashStr.startsWith(SHA2_PREFIX_6)) {
byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars());
return hashStr.compareTo(Sha2Crypt.sha256Crypt(textBytes, hashStr)) == 0;
}
return false;
}
};
private static final String APR1_PREFIX = "$apr1$";
private static final String BCRYPT_PREFIX = "$2a$";
private static final String BCRYPT_PREFIX_Y = "$2y$";
private static final String SHA1_PREFIX = "{SHA}";
private static final String SHA2_PREFIX_5 = "$5$";
private static final String SHA2_PREFIX_6 = "$6$";
private static final String PLAIN_PREFIX = "{plain}";
static final boolean CRYPT_SUPPORTED = !OsUtils.WINDOWS;

View File

@ -48,7 +48,7 @@ public class FileUserPasswdStoreTests extends ElasticsearchTestCase {
assertThat(users, notNullValue());
assertThat(users.size(), is(6));
assertThat(users.get("bcrypt"), notNullValue());
assertThat(new String(users.get("bcrypt")), equalTo("$2y$05$zxnP0vdREMxnEpkLCDI2OuSaSk/QEKA2.A42iOpI6U2u.RLLOWm1e"));
assertThat(new String(users.get("bcrypt")), equalTo("$2a$05$zxnP0vdREMxnEpkLCDI2OuSaSk/QEKA2.A42iOpI6U2u.RLLOWm1e"));
assertThat(users.get("bcrypt10"), notNullValue());
assertThat(new String(users.get("bcrypt10")), equalTo("$2y$10$FMhmFjwU5.qxQ/BsEciS9OqcJVkFMgXMo4uH5CelOR1j4N9zIv67e"));
assertThat(users.get("md5"), notNullValue());

View File

@ -5,7 +5,6 @@
*/
package org.elasticsearch.shield.authc.support;
import org.elasticsearch.common.os.OsUtils;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.junit.Test;
@ -15,11 +14,11 @@ import org.junit.Test;
public class HasherTests extends ElasticsearchTestCase {
@Test
public void testHtpasswdToolGenerated() throws Exception {
public void testHtpasswd_ToolGenerated() throws Exception {
Hasher hasher = Hasher.HTPASSWD;
SecuredString passwd = SecuredStringTests.build("test123");
assertTrue(hasher.verify(passwd, "$2a$05$zxnP0vdREMxnEpkLCDI2OuSaSk/QEKA2.A42iOpI6U2u.RLLOWm1e".toCharArray()));
assertTrue(hasher.verify(passwd, "$2a$10$FMhmFjwU5.qxQ/BsEciS9OqcJVkFMgXMo4uH5CelOR1j4N9zIv67e".toCharArray()));
assertTrue(hasher.verify(passwd, "$2a$10$vNMk6GyVUU./7YSZB6BGPuozm921GVPw/Pdukzd09s.sL2rIWROU6".toCharArray()));
assertTrue(hasher.verify(passwd, "$apr1$R3DdqiAZ$aljIkaIVPSarmDMlJUBBP.".toCharArray()));
if (!Hasher.CRYPT_SUPPORTED) {
assertTrue(hasher.verify(passwd, "test123".toCharArray()));
@ -28,12 +27,37 @@ public class HasherTests extends ElasticsearchTestCase {
}
assertTrue(hasher.verify(passwd, "{plain}test123".toCharArray()));
assertTrue(hasher.verify(passwd, "{SHA}cojt0Pw//L6ToM8G41aOKFIWh7w=".toCharArray()));
assertTrue(hasher.verify(passwd, "$5$RsqcsPiF$51tIIXf6oZb3Awox6FWNhITVlM/aW3oa8uN2eptIf54".toCharArray()));
}
@Test
public void testHtpasswdSelfGenerated() throws Exception {
Hasher hasher = Hasher.HTPASSWD;
public void testHtpasswd_SelfGenerated() throws Exception {
testHasherSelfGenerated(Hasher.HTPASSWD);
}
@Test
public void testBcrypt_SelfGenerated() throws Exception {
testHasherSelfGenerated(Hasher.BCRYPT);
}
@Test
public void testMd5_SelfGenerated() throws Exception {
testHasherSelfGenerated(Hasher.MD5);
}
@Test
public void testSha1_SelfGenerated() throws Exception {
testHasherSelfGenerated(Hasher.SHA1);
}
@Test
public void testSha2_SelfGenerated() throws Exception {
testHasherSelfGenerated(Hasher.SHA2);
}
public void testHasherSelfGenerated(Hasher hasher) throws Exception {
SecuredString passwd = SecuredStringTests.build("test123");
assertTrue(hasher.verify(passwd, hasher.hash(passwd)));
}
}

View File

@ -1,4 +1,4 @@
bcrypt: $2y$05$zxnP0vdREMxnEpkLCDI2OuSaSk/QEKA2.A42iOpI6U2u.RLLOWm1e
bcrypt: $2a$05$zxnP0vdREMxnEpkLCDI2OuSaSk/QEKA2.A42iOpI6U2u.RLLOWm1e
md5: $apr1$R3DdqiAZ$aljIkaIVPSarmDMlJUBBP.
crypt: hsP1PYSLsEEvs
plain: {plain}test123