mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Ludovic Poitou
08.04.2016 b63ceb54bb494700b27e493c7486be7641d4ac54
Added BCrypt unit test (port of the original JUnit tests to testNG).
1 files added
225 ■■■■■ changed files
opendj-server-legacy/src/test/java/org/opends/server/extensions/BCryptTest.java 225 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/extensions/BCryptTest.java
New file
@@ -0,0 +1,225 @@
/*
 * 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));
    }
}