Search code examples
hashinputstreamoutputstreamfileutils

Hamcrest. How to check byte array equals


There is needed to create application password for creation administrators without involving database. Administrators passwords, after creation, will be saved in database. There is problem to write byte[] and read the same value into/from file according to the following test methods.

Is it nice approach? What is wrong in the work with binary-data?

import org.apache.commons.io.FileUtils;
import org.junit.BeforeClass;
import org.junit.Test;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.io.*;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.Random;
import static org.junit.Assert.assertEquals;

public class Passwords {
static byte[] salt;
static byte[] password_hash;

private static final Random RANDOM = new SecureRandom();
private static final int ITERATIONS = 10000;
private static final int KEY_LENGTH = 256;

static String password_file ="C:\\Users\\hp\\IdeaProjects\\pp20_hotel_v1\\src\\main\\resources\\app_password_hash";
static String salt_file = "C:\\Users\\hp\\IdeaProjects\\pp20_hotel_v1\\src\\main\\resources\\salt_hash";

public static byte[] getNextSalt() {
    byte[] salt = new byte[16];
    RANDOM.nextBytes(salt);
    return salt;
}

private static void writeBinary(String path, byte[] arr){
    File file = new File(path);
    FileOutputStream fos = null;
    try {
        fos = new FileOutputStream(file);
        FileUtils.writeByteArrayToFile(file, arr);
        fos.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private static byte[] hash(char[] password, byte[] salt) {
    PBEKeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, KEY_LENGTH);
    Arrays.fill(password, Character.MIN_VALUE);
    try {
        SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        return skf.generateSecret(spec).getEncoded();
    } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
        throw new AssertionError("Error while hashing a password: " + e.getMessage(), e);
    } finally {
        spec.clearPassword();
    }
}

private static byte[] readBinary(String path){
    File file = new File(path);
    byte fileContent[] = null;
    try {
        fileContent = FileUtils.readFileToByteArray(file);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return fileContent;
}

@BeforeClass
public static void writeSaltAndPassword(){
    String password = "12345678";
    salt = getNextSalt();
    password_hash = hash(password.toCharArray(), salt);
    System.out.println("salt : "+salt);
    System.out.println("password_hash : "+password_hash);
    writeBinary(password_file, password_hash);
    writeBinary(salt_file, salt);
}

@Test
public void checkPassword(){
    byte[] actual_password_hash=readBinary(password_file);
    assertEquals(password_hash, actual_password_hash);
}

}


Solution

  • The problem was in this. Hamcrest does not check byte[] element by element. There was needed to write:

    for(int i=0; i<password_hash.length;i++){
            if(password_hash[i]!=actual_password_hash[i]){
                System.out.println(password_hash[i]!=actual_password_hash[i]);
                return;
            }
        }