根據字元型別和密碼長度隨機生成密碼

gary-liu發表於2016-10-22

原因

初衷:我本來是想寫根據自己定義的一些資訊生成複雜度可自選的固定密碼,增強密碼的複雜性的同時,也更容易記住密碼,這樣密碼即使明文記錄在本地,沒有自己的加密演算法,也得不到最終真正的密碼。我看到網上有一些現成的工具以及chrome的外掛等,還是想自己試試。

不過看到一些自動生成隨機密碼的網站,一好奇就先有了這篇隨機生成密碼的文章。

目標

可以選擇數字,小寫字母,大寫字母,特殊符號,密碼長度,根據這些選擇生成隨機的密碼。

思路

思路1: 我的思路其實很簡單粗暴,密碼組成可以有數字,小寫字母,大寫字母,特殊符號4種選擇,所以可以選擇其中的1種,2種,3種,4種組成密碼,分別對應的組合方式有4種,6種,4種,1種,其實就是簡單的排列組合。然後根據選擇了幾種字元種類,就生成和為密碼長度的幾個隨機數,然後到相應的字元種類中隨機選擇幾個字元,把他們拼接在一起,最後打亂組成新密碼。

例如:選擇數字和小寫字母組成長度為 10 的隨機密碼,程式會生成和為 10 的兩個隨機數,假設兩個隨機數是 4 和 6,則會從 0-9 十個數字和 a-z 26小寫字母中中隨機的選擇 4 個數字和 6 個字母,然後把他們拼接在一起,最後打亂順序就得到最終的隨機密碼。

我的想法很簡單,如果有更好的方法,求告知,謝謝!

思路2: 另一種生成隨機密碼的方法,先拼裝所有可能組成密碼的字元型別,然後隨機選擇指定長度的n個字元,然後拿著這n字元校驗是否包含選擇了的字元型別的字元和是否不包含沒有選擇的字元型別的字元,這樣不斷重試,直到找到符合選擇的字元型別字串為止。這種方法可能重試的次數比較多,實現參考: https://github.com/lynchnf/password

思路1程式碼實現

package fun;

import java.util.*;

/**
 * Created by gary on 16/10/15.
 */
public class GeneratePassword {

    private static String number = "0123456789";
    private static String lowerChar = "abcdefghijklmnopqrstuvwxyz";
    private static String upperChar = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static String specialChar = "*$%!:;.,?&(-_)=#{[@]}";

    /**
     * 四種字元十五種組合方式隨機產生密碼
     * @param isNum
     * @param isLowerChar
     * @param isUpperChar
     * @param isSpecialChar
     * @param length
     * @return
     */
    private static String generPassword(boolean isNum, boolean isLowerChar, boolean isUpperChar, boolean isSpecialChar,
            int length) {
        String password = null;
        // 只選一種
        if (isNum && !(isLowerChar || isUpperChar || isSpecialChar))
            return genPwByNum(1, length, number);
        if (isLowerChar && !(isNum || isUpperChar || isSpecialChar))
            return genPwByNum(1, length, lowerChar);
        if (isUpperChar && !(isLowerChar || isNum || isSpecialChar))
            return genPwByNum(1, length, upperChar);
        if (isSpecialChar && !(isLowerChar || isUpperChar || isNum))
            return genPwByNum(1, length, specialChar);

        // 選擇了兩種
        if ((isNum && isLowerChar) && !(isUpperChar || isSpecialChar))
            return genPwByNum(2, length, number, lowerChar);
        if ((isNum && isUpperChar) && !(isLowerChar || isSpecialChar))
            return genPwByNum(2, length, number, upperChar);
        if ((isNum && isSpecialChar) && !(isLowerChar || isUpperChar))
            return genPwByNum(2, length, number, specialChar);
        if ((isLowerChar && isUpperChar) && !(isNum || isSpecialChar))
            return genPwByNum(2, length, lowerChar, upperChar);
        if ((isLowerChar && isSpecialChar) && !(isNum || isUpperChar))
            return genPwByNum(2, length, lowerChar, specialChar);
        if ((isUpperChar && isSpecialChar) && !(isNum || isLowerChar))
            return genPwByNum(2, length, upperChar, specialChar);

        // 選擇了三種
        if ((isNum && isLowerChar && isUpperChar) && !isSpecialChar)
            return genPwByNum(3, length, number, lowerChar, upperChar);
        if ((isNum && isLowerChar && isSpecialChar) && !isUpperChar)
            return genPwByNum(3, length, number, lowerChar, specialChar);
        if ((isNum && isUpperChar && isSpecialChar) && !isLowerChar)
            return genPwByNum(3, length, number, upperChar, specialChar);
        if ((isLowerChar && isUpperChar && isSpecialChar) && !isNum)
            return genPwByNum(3, length, lowerChar, upperChar, specialChar);

        // 四種都選
        if (isNum && isLowerChar && isUpperChar && isSpecialChar)
            return genPwByNum(4, length, number, lowerChar, upperChar, specialChar);

        return password;

    }

    /**
     * 根據選擇的字元型別生成密碼
     * @param num
     * @param length
     * @param keys
     * @return
     */
    public static String genPwByNum(int num, int length, String... keys) {
        StringBuilder stringBuilder = new StringBuilder();
        if (length < num) {
            return stringBuilder.append("length should be bigger than ").append(num - 1).toString();
        }
        int[] randArray = randArr(num, length);
        int i = 0;
        for (String str : keys)
            stringBuilder.append(collectStr(randArray[i++], str));

        return shuffleString(stringBuilder.toString());
    }

    /**
     * 產生和為length的num個隨機數
     * @param num
     * @param length
     * @return
     */
    public static int[] randArr(int num, int length) {
        Random random = new Random();
        int[] randArray = new int[num];
        int i = 0;
        if (num == 1) {
            randArray[i] = length;
        } else {
            while (num > 1) {
                int rand = random.nextInt(length - num + 1) + 1;
                randArray[i++] = rand;
                length -= rand;
                num--;
                if (num == 1) {
                    randArray[i] = length;
                }
            }
        }

        for (int m : randArray) {
            System.out.println(m);
        }

        return randArray;
    }

    /**
     * 隨機拼裝字元
     * @param length
     * @param sample
     * @return
     */
    public static String collectStr(int length, String sample) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < length; i++) {
            stringBuilder.append(sample.charAt((int) (Math.random() * sample.length())));
        }
        return stringBuilder.toString();
    }

    /**
     * 打亂字串
     * @param str
     * @return
     */
    public static String shuffleString(String str) {
        StringBuilder stringBuilder = new StringBuilder();
        List<String> list = Arrays.asList(str.split(""));
        Collections.shuffle(list);
        for (String s : list) {
            stringBuilder.append(s);
        }
        return stringBuilder.toString();
    }

    public static void main(String[] args) {
        String password = generPassword(true, true, true, true, 10);
        System.out.println(password);
        // randArr(4, 10);

    }
}

相關文章