java - मैं नमकीन-हैश के लिए जावा में एक एसएएलटी कैसे उत्पन्न करूं?




security encryption (2)

मैं चारों ओर देख रहा हूं और निकटतम उत्तर है: यादृच्छिक अल्फा-न्यूमेरिक स्ट्रिंग कैसे उत्पन्न करें?

मैं इस क्रैकस्टेशन ट्यूटोरियल के अनुसार इस वर्कफ़्लो का पालन करना चाहता हूं:

पासवर्ड स्टोर करने के लिए

  1. एक सीएसपीआरएनजी का उपयोग कर एक लंबे यादृच्छिक नमक उत्पन्न करें।

  2. नमक को पासवर्ड में तैयार करें और इसे मानक क्रिप्टोग्राफ़िक हैश फ़ंक्शन जैसे SHA256 के साथ हैश करें।

  3. उपयोगकर्ता के डेटाबेस रिकॉर्ड में नमक और हैश दोनों को बचाएं।

पासवर्ड सत्यापित करने के लिए

  1. डेटाबेस से उपयोगकर्ता के नमक और हैश को पुनः प्राप्त करें।

  2. नमक को दिए गए पासवर्ड पर तैयार करें और हैश फ़ंक्शन का उपयोग करके इसे हश करें।

  3. डेटाबेस से हैश के साथ दिए गए पासवर्ड के हैश की तुलना करें। यदि वे मेल खाते हैं, तो पासवर्ड सही है। अन्यथा, पासवर्ड गलत है।

मुझे नहीं पता कि एसएएलटी कैसे उत्पन्न करें। मैंने पाया कि संदेशडिगेट का उपयोग करके हैश कैसे उत्पन्न करें। मैंने SecureRandom का उपयोग करने की कोशिश की लेकिन अगलीबाइट विधि गड़बड़ कोड उत्पन्न करती है।

संपादित करें: मुझे नहीं पता कि कौन सा जवाब चुनना है, वे मेरे लिए बहुत जटिल हैं, मैंने jBCrypt का उपयोग करने का निर्णय लिया है; jBCript का उपयोग करना आसान है, दृश्यों के पीछे सभी जटिल सामान करता है। इसलिए मैं समुदाय को सर्वोत्तम उत्तर के लिए वोट दूंगा।


SHA-3 का उपयोग करने वाला एक और संस्करण, मैं बाउंसीकैसल का उपयोग कर रहा हूं:

अंतरपटल:

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);
}

कार्यान्वयन:

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<Character> characters = new ArrayList<Character>();
            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();
    }
}

परीक्षण के मामले:

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 (केवल निर्भरता):

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.testng</groupId>
        <artifactId>testng</artifactId>
        <version>6.1.1</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.hamcrest</groupId>
        <artifactId>hamcrest-all</artifactId>
        <version>1.3</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>

    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk15on</artifactId>
        <version>1.51</version>
        <type>jar</type>
    </dependency>


    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.3.2</version>
    </dependency>


</dependencies>

आप इस बारे में सही थे कि आप कैसे नमक उत्पन्न करना चाहते हैं यानी इसके अलावा कुछ भी यादृच्छिक संख्या नहीं है। इस विशेष मामले के लिए यह आपके सिस्टम को संभावित शब्दकोश हमलों से सुरक्षित रखेगा। अब, दूसरी समस्या के लिए आप क्या कर सकते हैं यूटीएफ -8 एन्कोडिंग का उपयोग करने के बजाय आप बेस 64 का उपयोग करना चाह सकते हैं। यहां, हैश उत्पन्न करने के लिए एक नमूना है। मैं बेस 64 एन्कोडिंग करने के लिए अपाचे कॉमन कोडेक्स का उपयोग कर रहा हूं, आप स्वयं में से एक का चयन कर सकते हैं

public byte[] generateSalt() {
        SecureRandom random = new SecureRandom();
        byte bytes[] = new byte[20];
        random.nextBytes(bytes);
        return bytes;
    }

public String bytetoString(byte[] input) {
        return org.apache.commons.codec.binary.Base64.encodeBase64String(input);
    }

public byte[] getHashWithSalt(String input, HashingTechqniue technique, byte[] salt) throws NoSuchAlgorithmException {
        MessageDigest digest = MessageDigest.getInstance(technique.value);
        digest.reset();
        digest.update(salt);
        byte[] hashedBytes = digest.digest(stringToByte(input));
        return hashedBytes;
    }
public byte[] stringToByte(String input) {
        if (Base64.isBase64(input)) {
            return Base64.decodeBase64(input);

        } else {
            return Base64.encodeBase64(input.getBytes());
        }
    }

OWASP से सीधे पासवर्ड हैशिंग में मानक अभ्यास का कुछ अतिरिक्त संदर्भ यहां दिया गया है





salt