// Path: commons-base/commons-crypto/src/main/java/ch/ge/ve/commons/crypto/SensitiveDataCryptoUtils.java
// public static String generateStrongPasswordHash(char[] password) {
//     int iterations = config.getIterations();
//     byte[] salt = SaltUtils.generateSalt(SALT_SIZE_BYTES * 8);
// 
//     try {
//         SecretKeyFactory skf = SecretKeyFactory.getInstance(config.getPbkdf2Algorithm());
//         PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterations, 64 * 8);
//         SecretKey secretKey = skf.generateSecret(keySpec);
// 
//         return String.format("%d:%s:%s", iterations, DatatypeConverter.printHexBinary(salt), DatatypeConverter.printHexBinary(secretKey.getEncoded()));
//     } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
//         throw new CryptoOperationRuntimeException("cannot generate strong password hash", e);
//     }
// }
// 
// Path: commons-base/commons-crypto/src/main/java/ch/ge/ve/commons/crypto/SensitiveDataCryptoUtils.java
// public static boolean validateStrongPasswordHash(char[] passwd, String storedHash) {
//     String[] parts = storedHash.split(":");
//     if (parts.length != 3) {
//         return false;
//     }
// 
//     int iterations = Integer.parseInt(parts[0]);
//     byte[] salt = fromHex(parts[1]);
//     byte[] hash = fromHex(parts[2]);
// 
//     try {
//         PBEKeySpec keySpec = new PBEKeySpec(passwd, salt, iterations, hash.length * 8);
//         SecretKeyFactory skf = SecretKeyFactory.getInstance(config.getPbkdf2Algorithm());
//         byte[] testHash = skf.generateSecret(keySpec).getEncoded();
//         return constantTimeArrayCompare(hash, testHash);
//     } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
//         throw new CryptoOperationRuntimeException("cannot validate strong password hash", e);
//     }
// }


import java.util.concurrent.TimeUnit;
import static ch.ge.ve.commons.crypto.SensitiveDataCryptoUtils.generateStrongPasswordHash;
import static ch.ge.ve.commons.crypto.SensitiveDataCryptoUtils.validateStrongPasswordHash;
import com.google.common.base.Joiner;
import com.google.common.base.Stopwatch;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.BeforeClass;
import org.junit.Test;
import java.math.BigInteger;
import java.security.Security;
/*
 * -
 * #%L
 * Common crypto utilities
 * %%
 * Copyright (C) 2016 République et Canton de Genève
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * #L%
 */

package ch.ge.ve.commons.crypto;




/**
 * This test suit aims at stress testing the {@link SensitiveDataCryptoUtils} utility class.
 */
public class SensitiveDataCryptoUtilsST {
    @BeforeClass
    public static void init() {
        Security.addProvider(new BouncyCastleProvider());
        SensitiveDataCryptoUtils.configure(new TestSensitiveDataCryptoUtilsConfiguration());
    }

    /**
     * Runs several times the {@link SensitiveDataCryptoUtils#validateStrongPasswordHash} method and logs the
     * average execution time to identify a potential timing attack. This verification is manual, nothing is checked in
     * this test case.
     */
    @Test
    public void analyzePotentialTimingAttacksOnPasswordHashVerification() {
        char[] passwd = "A random te$ting p#s$w0rd!!!".toCharArray();
        String passwordHash = generateStrongPasswordHash(passwd);

        int runs = 100;

        System.out.printf("%-25s | %15s | %s (%d runs)%n", "Test", "average (ms)", "total", runs);

        Stopwatch validPasswordChecking = Stopwatch.createStarted();
        for (int i = 0; i < runs; i++) {
// Path: commons-base/commons-crypto/src/main/java/ch/ge/ve/commons/crypto/SensitiveDataCryptoUtils.java
// public static String generateStrongPasswordHash(char[] password) {
//     int iterations = config.getIterations();
//     byte[] salt = SaltUtils.generateSalt(SALT_SIZE_BYTES * 8);
// 
//     try {
//         SecretKeyFactory skf = SecretKeyFactory.getInstance(config.getPbkdf2Algorithm());
//         PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterations, 64 * 8);
//         SecretKey secretKey = skf.generateSecret(keySpec);
// 
//         return String.format("%d:%s:%s", iterations, DatatypeConverter.printHexBinary(salt), DatatypeConverter.printHexBinary(secretKey.getEncoded()));
//     } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
//         throw new CryptoOperationRuntimeException("cannot generate strong password hash", e);
//     }
// }
// 
// Path: commons-base/commons-crypto/src/main/java/ch/ge/ve/commons/crypto/SensitiveDataCryptoUtils.java
// public static boolean validateStrongPasswordHash(char[] passwd, String storedHash) {
//     String[] parts = storedHash.split(":");
//     if (parts.length != 3) {
//         return false;
//     }
// 
//     int iterations = Integer.parseInt(parts[0]);
//     byte[] salt = fromHex(parts[1]);
//     byte[] hash = fromHex(parts[2]);
// 
//     try {
//         PBEKeySpec keySpec = new PBEKeySpec(passwd, salt, iterations, hash.length * 8);
//         SecretKeyFactory skf = SecretKeyFactory.getInstance(config.getPbkdf2Algorithm());
//         byte[] testHash = skf.generateSecret(keySpec).getEncoded();
//         return constantTimeArrayCompare(hash, testHash);
//     } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
//         throw new CryptoOperationRuntimeException("cannot validate strong password hash", e);
//     }
// }


// Path: commons-base/commons-crypto/src/test/java/ch/ge/ve/commons/crypto/SensitiveDataCryptoUtilsST.java
import java.util.concurrent.TimeUnit;
import static ch.ge.ve.commons.crypto.SensitiveDataCryptoUtils.generateStrongPasswordHash;
import static ch.ge.ve.commons.crypto.SensitiveDataCryptoUtils.validateStrongPasswordHash;
import com.google.common.base.Joiner;
import com.google.common.base.Stopwatch;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.BeforeClass;
import org.junit.Test;
import java.math.BigInteger;
import java.security.Security;

/*
 * -
 * #%L
 * Common crypto utilities
 * %%
 * Copyright (C) 2016 République et Canton de Genève
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * #L%
 */

package ch.ge.ve.commons.crypto;




/**
 * This test suit aims at stress testing the {@link SensitiveDataCryptoUtils} utility class.
 */
public class SensitiveDataCryptoUtilsST {
    @BeforeClass
    public static void init() {
        Security.addProvider(new BouncyCastleProvider());
        SensitiveDataCryptoUtils.configure(new TestSensitiveDataCryptoUtilsConfiguration());
    }

    /**
     * Runs several times the {@link SensitiveDataCryptoUtils#validateStrongPasswordHash} method and logs the
     * average execution time to identify a potential timing attack. This verification is manual, nothing is checked in
     * this test case.
     */
    @Test
    public void analyzePotentialTimingAttacksOnPasswordHashVerification() {
        char[] passwd = "A random te$ting p#s$w0rd!!!".toCharArray();
        String passwordHash = generateStrongPasswordHash(passwd);

        int runs = 100;

        System.out.printf("%-25s | %15s | %s (%d runs)%n", "Test", "average (ms)", "total", runs);

        Stopwatch validPasswordChecking = Stopwatch.createStarted();
        for (int i = 0; i < runs; i++) {
            validateStrongPasswordHash(passwd, passwordHash);