How do I generate a SALT in Java for Salted-Hash?

后端 未结 4 2193
星月不相逢
星月不相逢 2020-11-29 17:09

I\'ve been looking around and the closest answer is : How to generate a random alpha-numeric string?

I want to follow this workflow according to this CrackStation tut

4条回答
  •  粉色の甜心
    2020-11-29 17:28

    Another version using SHA-3, I am using bouncycastle:

    The interface:

    public interface IPasswords {
    
        /**
         * Generates a random salt.
         *
         * @return a byte array with a 64 byte length salt.
         */
        byte[] getSalt64();
    
        /**
         * Generates a random salt
         *
         * @return a byte array with a 32 byte length salt.
         */
        byte[] getSalt32();
    
        /**
         * Generates a new salt, minimum must be 32 bytes long, 64 bytes even better.
         *
         * @param size the size of the salt
         * @return a random salt.
         */
        byte[] getSalt(final int size);
    
        /**
         * Generates a new hashed password
         *
         * @param password to be hashed
         * @param salt the randomly generated salt
         * @return a hashed password
         */
        byte[] hash(final String password, final byte[] salt);
    
        /**
         * Expected password
         *
         * @param password to be verified
         * @param salt the generated salt (coming from database)
         * @param hash the generated hash (coming from database)
         * @return true if password matches, false otherwise
         */
        boolean isExpectedPassword(final String password, final byte[] salt, final byte[] hash);
    
        /**
         * Generates a random password
         *
         * @param length desired password length
         * @return a random password
         */
        String generateRandomPassword(final int length);
    }
    

    The implementation:

    import org.apache.commons.lang3.ArrayUtils;
    import org.apache.commons.lang3.Validate;
    import org.apache.log4j.Logger;
    import org.bouncycastle.jcajce.provider.digest.SHA3;
    
    import java.io.Serializable;
    import java.io.UnsupportedEncodingException;
    import java.security.SecureRandom;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Random;
    
    public final class Passwords implements IPasswords, Serializable {
    
        /*serialVersionUID*/
        private static final long serialVersionUID = 8036397974428641579L;
        private static final Logger LOGGER = Logger.getLogger(Passwords.class);
        private static final Random RANDOM = new SecureRandom();
        private static final int DEFAULT_SIZE = 64;
        private static final char[] symbols;
    
        static {
                final StringBuilder tmp = new StringBuilder();
                for (char ch = '0'; ch <= '9'; ++ch) {
                        tmp.append(ch);
                }
                for (char ch = 'a'; ch <= 'z'; ++ch) {
                        tmp.append(ch);
                }
                symbols = tmp.toString().toCharArray();
        }
    
        @Override public byte[] getSalt64() {
                return getSalt(DEFAULT_SIZE);
        }
    
        @Override public byte[] getSalt32() {
                return getSalt(32);
        }
    
        @Override public byte[] getSalt(int size) {
                final byte[] salt;
                if (size < 32) {
                        final String message = String.format("Size < 32, using default of: %d", DEFAULT_SIZE);
                        LOGGER.warn(message);
                        salt = new byte[DEFAULT_SIZE];
                } else {
                        salt = new byte[size];
                }
                RANDOM.nextBytes(salt);
                return salt;
        }
    
        @Override public byte[] hash(String password, byte[] salt) {
    
                Validate.notNull(password, "Password must not be null");
                Validate.notNull(salt, "Salt must not be null");
    
                try {
                        final byte[] passwordBytes = password.getBytes("UTF-8");
                        final byte[] all = ArrayUtils.addAll(passwordBytes, salt);
                        SHA3.DigestSHA3 md = new SHA3.Digest512();
                        md.update(all);
                        return md.digest();
                } catch (UnsupportedEncodingException e) {
                        final String message = String
                                .format("Caught UnsupportedEncodingException e: <%s>", e.getMessage());
                        LOGGER.error(message);
                }
                return new byte[0];
        }
    
        @Override public boolean isExpectedPassword(final String password, final byte[] salt, final byte[] hash) {
    
                Validate.notNull(password, "Password must not be null");
                Validate.notNull(salt, "Salt must not be null");
                Validate.notNull(hash, "Hash must not be null");
    
                try {
                        final byte[] passwordBytes = password.getBytes("UTF-8");
                        final byte[] all = ArrayUtils.addAll(passwordBytes, salt);
    
                        SHA3.DigestSHA3 md = new SHA3.Digest512();
                        md.update(all);
                        final byte[] digest = md.digest();
                        return Arrays.equals(digest, hash);
                }catch(UnsupportedEncodingException e){
                        final String message =
                                String.format("Caught UnsupportedEncodingException e: <%s>", e.getMessage());
                        LOGGER.error(message);
                }
                return false;
    
    
        }
    
        @Override public String generateRandomPassword(final int length) {
    
                if (length < 1) {
                        throw new IllegalArgumentException("length must be greater than 0");
                }
    
                final char[] buf = new char[length];
                for (int idx = 0; idx < buf.length; ++idx) {
                        buf[idx] = symbols[RANDOM.nextInt(symbols.length)];
                }
                return shuffle(new String(buf));
        }
    
    
        private String shuffle(final String input){
                final List characters = new ArrayList();
                for(char c:input.toCharArray()){
                        characters.add(c);
                }
                final StringBuilder output = new StringBuilder(input.length());
                while(characters.size()!=0){
                        int randPicker = (int)(Math.random()*characters.size());
                        output.append(characters.remove(randPicker));
                }
                return output.toString();
        }
    }
    

    The test cases:

    public class PasswordsTest {
    
        private static final Logger LOGGER = Logger.getLogger(PasswordsTest.class);
    
        @Before
        public void setup(){
                BasicConfigurator.configure();
        }
    
        @Test
        public void testGeSalt() throws Exception {
    
                IPasswords passwords = new Passwords();
                final byte[] bytes = passwords.getSalt(0);
                int arrayLength = bytes.length;
    
                assertThat("Expected length is", arrayLength, is(64));
        }
    
        @Test
        public void testGeSalt32() throws Exception {
                IPasswords passwords = new Passwords();
                final byte[] bytes = passwords.getSalt32();
                int arrayLength = bytes.length;
                assertThat("Expected length is", arrayLength, is(32));
        }
    
        @Test
        public void testGeSalt64() throws Exception {
                IPasswords passwords = new Passwords();
                final byte[] bytes = passwords.getSalt64();
                int arrayLength = bytes.length;
                assertThat("Expected length is", arrayLength, is(64));
        }
    
        @Test
        public void testHash() throws Exception {
                IPasswords passwords = new Passwords();
                final byte[] hash = passwords.hash("holacomoestas", passwords.getSalt64());
                assertThat("Array is not null", hash, Matchers.notNullValue());
        }
    
    
        @Test
        public void testSHA3() throws UnsupportedEncodingException {
                SHA3.DigestSHA3 md = new SHA3.Digest256();
                md.update("holasa".getBytes("UTF-8"));
                final byte[] digest = md.digest();
                 assertThat("expected digest is:",digest,Matchers.notNullValue());
        }
    
        @Test
        public void testIsExpectedPasswordIncorrect() throws Exception {
    
                String password = "givemebeer";
                IPasswords passwords = new Passwords();
    
                final byte[] salt64 = passwords.getSalt64();
                final byte[] hash = passwords.hash(password, salt64);
                //The salt and the hash go to database.
    
                final boolean isPasswordCorrect = passwords.isExpectedPassword("jfjdsjfsd", salt64, hash);
    
                assertThat("Password is not correct", isPasswordCorrect, is(false));
    
        }
    
        @Test
        public void testIsExpectedPasswordCorrect() throws Exception {
                String password = "givemebeer";
                IPasswords passwords = new Passwords();
                final byte[] salt64 = passwords.getSalt64();
                final byte[] hash = passwords.hash(password, salt64);
                //The salt and the hash go to database.
                final boolean isPasswordCorrect = passwords.isExpectedPassword("givemebeer", salt64, hash);
                assertThat("Password is correct", isPasswordCorrect, is(true));
        }
    
        @Test
        public void testGenerateRandomPassword() throws Exception {
                IPasswords passwords = new Passwords();
                final String randomPassword = passwords.generateRandomPassword(10);
                LOGGER.info(randomPassword);
                assertThat("Random password is not null", randomPassword, Matchers.notNullValue());
        }
    }
    

    pom.xml (only dependencies):

    
        
            junit
            junit
            4.12
            test
        
        
            org.testng
            testng
            6.1.1
            test
        
    
        
            org.hamcrest
            hamcrest-all
            1.3
            test
        
    
        
            log4j
            log4j
            1.2.17
        
    
        
            org.bouncycastle
            bcprov-jdk15on
            1.51
            jar
        
    
    
        
            org.apache.commons
            commons-lang3
            3.3.2
        
    
    
    
    

提交回复
热议问题