| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright (c) 2006 Damien Miller <djm@mindrot.org> |
| | | * Portions Copyright 2016 ForgeRock AS |
| | | * |
| | | * Permission to use, copy, modify, and distribute this software for any |
| | | * purpose with or without fee is hereby granted, provided that the above |
| | | * copyright notice and this permission notice appear in all copies. |
| | | * |
| | | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| | | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| | | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| | | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| | | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| | | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| | | * |
| | | */ |
| | | |
| | | package org.opends.server.extensions; |
| | | |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import static org.testng.Assert.*; |
| | | |
| | | public class BCryptTest extends ExtensionsTestCase { |
| | | |
| | | /** |
| | | * Retrieves a set of passwords, salt and expected hashed passwords for tests. |
| | | */ |
| | | @DataProvider(name = "PasswordsAndHash") |
| | | public Object[][] getPasswordsAndHash() { |
| | | return new Object[][]{ |
| | | { "", "$2a$06$DCq7YPn5Rq63x1Lad4cll.", |
| | | "$2a$06$DCq7YPn5Rq63x1Lad4cll.TV4S6ytwfsfvkgY8jIucDrjc8deX1s." }, |
| | | { "", "$2a$08$HqWuK6/Ng6sg9gQzbLrgb.", |
| | | "$2a$08$HqWuK6/Ng6sg9gQzbLrgb.Tl.ZHfXLhvt/SgVyWhQqgqcZ7ZuUtye" }, |
| | | { "", "$2a$10$k1wbIrmNyFAPwPVPSVa/ze", |
| | | "$2a$10$k1wbIrmNyFAPwPVPSVa/zecw2BCEnBwVS2GbrmgzxFUOqW9dk4TCW" }, |
| | | { "", "$2a$12$k42ZFHFWqBp3vWli.nIn8u", |
| | | "$2a$12$k42ZFHFWqBp3vWli.nIn8uYyIkbvYRvodzbfbK18SSsY.CsIQPlxO" }, |
| | | { "a", "$2a$06$m0CrhHm10qJ3lXRY.5zDGO", |
| | | "$2a$06$m0CrhHm10qJ3lXRY.5zDGO3rS2KdeeWLuGmsfGlMfOxih58VYVfxe" }, |
| | | { "a", "$2a$08$cfcvVd2aQ8CMvoMpP2EBfe", |
| | | "$2a$08$cfcvVd2aQ8CMvoMpP2EBfeodLEkkFJ9umNEfPD18.hUF62qqlC/V." }, |
| | | { "a", "$2a$10$k87L/MF28Q673VKh8/cPi.", |
| | | "$2a$10$k87L/MF28Q673VKh8/cPi.SUl7MU/rWuSiIDDFayrKk/1tBsSQu4u" }, |
| | | { "a", "$2a$12$8NJH3LsPrANStV6XtBakCe", |
| | | "$2a$12$8NJH3LsPrANStV6XtBakCez0cKHXVxmvxIlcz785vxAIZrihHZpeS" }, |
| | | { "abc", "$2a$06$If6bvum7DFjUnE9p2uDeDu", |
| | | "$2a$06$If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0i" }, |
| | | { "abc", "$2a$08$Ro0CUfOqk6cXEKf3dyaM7O", |
| | | "$2a$08$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm" }, |
| | | { "abc", "$2a$10$WvvTPHKwdBJ3uk0Z37EMR.", |
| | | "$2a$10$WvvTPHKwdBJ3uk0Z37EMR.hLA2W6N9AEBhEgrAOljy2Ae5MtaSIUi" }, |
| | | { "abc", "$2a$12$EXRkfkdmXn2gzds2SSitu.", |
| | | "$2a$12$EXRkfkdmXn2gzds2SSitu.MW9.gAVqa9eLS1//RYtYCmB1eLHg.9q" }, |
| | | { "abcdefghijklmnopqrstuvwxyz", "$2a$06$.rCVZVOThsIa97pEDOxvGu", |
| | | "$2a$06$.rCVZVOThsIa97pEDOxvGuRRgzG64bvtJ0938xuqzv18d3ZpQhstC" }, |
| | | { "abcdefghijklmnopqrstuvwxyz", "$2a$08$aTsUwsyowQuzRrDqFflhge", |
| | | "$2a$08$aTsUwsyowQuzRrDqFflhgekJ8d9/7Z3GV3UcgvzQW3J5zMyrTvlz." }, |
| | | { "abcdefghijklmnopqrstuvwxyz", "$2a$10$fVH8e28OQRj9tqiDXs1e1u", |
| | | "$2a$10$fVH8e28OQRj9tqiDXs1e1uxpsjN0c7II7YPKXua2NAKYvM6iQk7dq" }, |
| | | { "abcdefghijklmnopqrstuvwxyz", "$2a$12$D4G5f18o7aMMfwasBL7Gpu", |
| | | "$2a$12$D4G5f18o7aMMfwasBL7GpuQWuP3pkrZrOAnqP.bmezbMng.QwJ/pG" }, |
| | | { "~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2a$06$fPIsBO8qRqkjj273rfaOI.", |
| | | "$2a$06$fPIsBO8qRqkjj273rfaOI.HtSV9jLDpTbZn782DC6/t7qT67P6FfO" }, |
| | | { "~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2a$08$Eq2r4G/76Wv39MzSX262hu", |
| | | "$2a$08$Eq2r4G/76Wv39MzSX262huzPz612MZiYHVUJe/OcOql2jo4.9UxTW" }, |
| | | { "~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2a$10$LgfYWkbzEvQ4JakH7rOvHe", |
| | | "$2a$10$LgfYWkbzEvQ4JakH7rOvHe0y8pHKF9OaFgwUZ2q7W2FFZmZzJYlfS" }, |
| | | { "~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2a$12$WApznUOJfkEGSmYRfnkrPO", |
| | | "$2a$12$WApznUOJfkEGSmYRfnkrPOr466oFDCaj4b6HY3EXGvfxm43seyhgC" } |
| | | }; |
| | | } |
| | | |
| | | /** |
| | | * Retrieves a set of passwords for tests. |
| | | */ |
| | | @DataProvider(name = "Passwords") |
| | | public Object[][] getPasswords() { |
| | | return new Object[][]{ |
| | | {""}, |
| | | {"a"}, |
| | | {"abc"}, |
| | | {"abcdefghijklmnopqrstuvwxyz"}, |
| | | {"~!@#$%^&*() ~!@#$%^&*()PNBFRD"} |
| | | }; |
| | | } |
| | | |
| | | /** |
| | | * Retrieves a pair of password and hashed passwords that don't match |
| | | */ |
| | | @DataProvider(name = "BadPasswords") |
| | | public Object[][] getBadPasswords() { |
| | | return new Object[][]{ |
| | | { "", "$2a$06$m0CrhHm10qJ3lXRY.5zDGO3rS2KdeeWLuGmsfGlMfOxih58VYVfxe" }, |
| | | { "a", "$2a$06$If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0i" }, |
| | | { "abc", "$2a$06$.rCVZVOThsIa97pEDOxvGuRRgzG64bvtJ0938xuqzv18d3ZpQhstC" }, |
| | | { "abcdefghijklmnopqrstuvwxyz", "$2a$06$fPIsBO8qRqkjj273rfaOI.HtSV9jLDpTbZn782DC6/t7qT67P6FfO" }, |
| | | { "~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2a$06$DCq7YPn5Rq63x1Lad4cll.TV4S6ytwfsfvkgY8jIucDrjc8deX1s." } |
| | | }; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Test for BCrypt.hashpw(String, String). |
| | | * |
| | | * @param plain The plain text password. |
| | | * @param salt The salt to use when hashing the password. |
| | | * @param expected The expected hashed password. |
| | | * |
| | | */ |
| | | @Test(dataProvider = "PasswordsAndHash") |
| | | public void hashpw(String plain, String salt, String expected) { |
| | | String hashed = BCrypt.hashpw(plain, salt); |
| | | assertEquals(hashed, expected); |
| | | } |
| | | |
| | | /** |
| | | * Test for the BCrypt.hashpw(byte[], String) method. |
| | | * |
| | | * @param plain The plain text password. |
| | | * @param salt The salt to use when hashing the password. |
| | | * @param expected The expected hashed password. |
| | | * |
| | | */ |
| | | @Test(dataProvider = "PasswordsAndHash") |
| | | public void hashpwBytes(String plain, String salt, String expected) { |
| | | String hashed = BCrypt.hashpw(plain.getBytes(), salt); |
| | | assertEquals(hashed, expected); |
| | | } |
| | | |
| | | /** |
| | | * Test for the BCrypt.genSalt(int) method, with a cost varying from 4 to 12. |
| | | * |
| | | * @param plain The plain text password. |
| | | * |
| | | */ |
| | | @Test(dataProvider = "Passwords") |
| | | public void genSaltInt(String plain) { |
| | | for (int i = 4; i <= 12; i++){ |
| | | String salt = BCrypt.gensalt(i); |
| | | String hashed1 = BCrypt.hashpw(plain, salt); |
| | | String hashed2 = BCrypt.hashpw(plain, hashed1); |
| | | assertEquals(hashed1, hashed2); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Tests the BCrypt.genSalt method with default cost |
| | | * |
| | | * @param plain The plain text password. |
| | | * |
| | | */ |
| | | @Test(dataProvider = "Passwords") |
| | | public void genSalt(String plain) { |
| | | String salt = BCrypt.gensalt(); |
| | | String hashed1 = BCrypt.hashpw(plain, salt); |
| | | String hashed2 = BCrypt.hashpw(plain, hashed1); |
| | | assertEquals(hashed1, hashed2); |
| | | } |
| | | |
| | | /** |
| | | * Test for the BCrypt.checkpw(String, String) method. |
| | | * |
| | | * @param plain The plain text password. |
| | | * @param salt The salt to use when hashing the password. |
| | | * @param expected The expected hashed password. |
| | | * |
| | | */ |
| | | @Test(dataProvider = "PasswordsAndHash") |
| | | public void checkPw(String plain, String salt, String expected) { |
| | | assertTrue(BCrypt.checkpw(plain, expected)); |
| | | } |
| | | |
| | | /** |
| | | * Test for the BCrypt.checkpw(String, String) method, expecting failures. |
| | | * |
| | | * @param plain The plain text password. |
| | | * @param hashedValue A hashed password that doesn't match the plain text password. |
| | | * |
| | | */ |
| | | @Test(dataProvider = "BadPasswords") |
| | | public void checkPw_Failure(String plain, String hashedValue) { |
| | | assertFalse(BCrypt.checkpw(plain, hashedValue)); |
| | | } |
| | | |
| | | /** |
| | | * Test for correct hashing of non-US-ASCII passwords. |
| | | */ |
| | | @Test |
| | | public void testInternationalChars() { |
| | | String pw1 = "\u2605\u2605\u2605\u2605\u2605\u2605\u2605\u2605"; |
| | | String pw2 = "????????"; |
| | | |
| | | String h1 = BCrypt.hashpw(pw1, BCrypt.gensalt()); |
| | | assertFalse(BCrypt.checkpw(pw2, h1)); |
| | | |
| | | String h2 = BCrypt.hashpw(pw2, BCrypt.gensalt()); |
| | | assertFalse(BCrypt.checkpw(pw1, h2)); |
| | | } |
| | | } |