我的密码生成功能效率低下吗?

时间:2013-05-04 09:19:44

标签: javascript function random passwords

我有这个javascript密码生成功能。现在,我要丢弃与所选规格不匹配的密码。例如,如果密码不包含数字,我会丢弃它并生成一个新的跳跃,其中一个将包含一个数字。然而,这似乎不是高效的表演老虎机,至少对我而言不是。

是否有更好的方法在生成的密码中实施特定字符的强制?

此外,我计划添加以便密码可以强制包含特殊字符。如果我以当前的方式执行此操作,我将需要一些正则表达式来检查密码是否包含特殊字符,如果不是这样的话(对我而言似乎并不高效)。

function generatePassword(length, charset, nosimilar) {
    // default parameters
    length = (typeof length === "undefined") ? 8 : length;
    charset = (typeof charset === "undefined") ? 'abcdefghjknpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ123456789' : charset;
    nosimilar = (typeof similar === "undefined") ? true : nosimilar;

    var gen;
    retVal = "";
    for (var i = 0, n = charset.length; i < length; ++i) {
        gen = charset.charAt(Math.floor(Math.random() * n))
        if ( (retVal.charAt( retVal.length-1 ) == gen) && (nosimilar)) {
            retVal = retVal.substring(0, retVal.length - 1)
            retVal += charset.charAt(Math.floor(Math.random() * n))
            console.log('Generated character same as the last one. Trunkated and regenerated.');
        }
        retVal += gen;
    }

    // if charset contains numbers make sure we get atleast one number
    if ( (retVal.match(/\d+/g) == null) && (charset.match(/\d+/g) != null)) {
    console.log('Password generated but no numbers found. Regenerating.');
    generatePassword(length, charset, nosimilar);
    }

    return retVal;
}

if ($("#chLetters").prop('checked')) charset += 'abcdefghjknpqrstuvwxyz';
if ($("#chNumbers").prop('checked')) charset += '123456789';
if ($("#chMixedCase").prop('checked')) charset += 'ABCDEFGHJKLMNPQRSTUVWXYZ';
if ($("#chSpecial").prop('checked')) charset += '!@$%&?+*-_';

$("#passgen").text(generatePassword($("#maxLength").val(), charset, $("#chNoSimilar").prop('checked')));

3 个答案:

答案 0 :(得分:1)

如果您的密码长度为n个字符,并且要求它至少包含一个字母,一个数字和一个特殊字符,则表示每个密码的字符数为1到n-2。例如(简化):

function generatePassword( length ) {
    var letters = 'abcdefghjknpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ',
        special = '{}()#%&',
        characters = [],
        amountOfLetters = Math.floor( Math.random() * ( length - 2 ) ) + 1,
        amountOfNumbers = Math.floor( Math.random() * ( length - 1 - amountOfLetters ) ) + 1,
        amountOfSpecial = length - ( amountOfLetters + amountOfNumbers );

    // pick letters
    for (var i = 0, n = letters.length; i < amountOfLetters; ++i) {
        characters.push( letters.charAt( Math.floor( Math.random() * n ) ) );
    }

    // pick numbers
    for ( i = 0; i < amountOfNumbers; ++i) {
        characters.push( ''+( Math.floor( Math.random() * 9 ) + 1 ) );
    }

    // pick special characters
    for ( i = 0, n = special.length; i < amountOfSpecial; ++i) {
        characters.push( special.charAt( Math.floor( Math.random() * n ) ) );
    }

    // sort the array and concatenate elements into a string
    return characters.sort( function( a, b ) {
        return Math.random() - 0.5;
    } ).join( '' );
}

演示:http://jsfiddle.net/gGwyM/

该功能选择1到n-2个字母,然后是1到n-L-1个数字(其中L是字母数量),其余为特殊字符。这可以保证密码至少包含每个组中的一个字符。

(请注意,你应该使用比我这里更好的函数来随机化数组,参见例如How to randomize (shuffle) a JavaScript array?

答案 1 :(得分:0)

你可以使用这样的东西。使用此方法可以创建多个密钥集,并且通过使用简单的选项属性,您可以将这些密钥集切换进出密码生成,同时设置长度甚至选择生成十六进制密码。

function isObject(value) {
  return Object.prototype.toString.call(value) === '[object Object]';
}

function assign(target, source) {
  for (var prop in source) {
    if (source.hasOwnProperty(prop)) {
      target[prop] = source[prop];
    }
  }

  return target;
}

function shuffle(obj) {
  var i = obj.length;
  var rnd, tmp;

  while (i) {
    rnd = Math.floor(Math.random() * i);
    i -= 1;
    tmp = obj[i];
    obj[i] = obj[rnd];
    obj[rnd] = tmp;
  }

  return obj;
}

function generatePassword(options) {
  var opts = isObject(options) ? assign({}, options) : {};
  var keyspace = '';
  if (opts.hex) {
    keyspace = '0123456789abcdef';
    if (opts.uppercase) {
      keyspace = keyspace.toUpperCase();
    }
  } else {
    if (opts.alpha) {
      keyspace += 'abcdefghijklmnopqrstuvwxyz';
    }

    if (opts.uppercase) {
      keyspace += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    }

    if (opts.numeric) {
      keyspace += '0123456789';
    }

    if (opts.punctuation) {
      keyspace += "`!\"?$?%^&*()_-+={[}]:;@'~#|\\<,>.?/";
    }
  }

  if (keyspace.length - 1 < 0) {
    return '';
  }

  opts.size = opts.size >>> 0 || 16;
  if (opts.size < 5) {
    opts.size = 5;
  } else if (opts.size > 100) {
    opts.size = 100;
  }

  return shuffle(keyspace.split('')).join('').slice(0, opts.size);
}

var password = generatePassword({
  alpha: true,
  uppercase: true,
  numeric: true,
  punctuation: true
});

console.log(password);

其他选项是十六进制生成长度的大小

您可以修改它以获取您想要使用的特殊字符串。

更新:这是一个更复杂的示例,它强制执行各种类型的所选字符,其工作方式与上述简单示例类似。

function isObject(value) {
  return Object.prototype.toString.call(value) === '[object Object]';
}

function assign(target, source) {
  for (var prop in source) {
    if (source.hasOwnProperty(prop)) {
      target[prop] = source[prop];
    }
  }

  return target;
}

function shuffle(obj) {
  var i = obj.length;
  var rnd, tmp;

  while (i) {
    rnd = Math.floor(Math.random() * i);
    i -= 1;
    tmp = obj[i];
    obj[i] = obj[rnd];
    obj[rnd] = tmp;
  }

  return obj;
}

function getXChars(string, number) {
  var str = typeof string === 'string' ? string : '';
  var num = typeof number === 'number' && number > 0 ? number : 0;
  var array = [];
  var i = str.length;
  var rnd;

  while (i && array.length < num) {
    rnd = Math.floor(Math.random() * i);
    i -= 1;
    array.push(str.charAt(rnd));
  }

  return array;
}

function generatePassword(opts) {
  var opts = isObject(opts) ? assign({}, opts) : {};
  var keyspace = '';
  var result = [];
  var i = 0;
  var tmp;

  if (typeof opts.hex === 'number' && opts.hex > 0) {
    i += opts.hex;
    keyspace = '0123456789abcdef';
    if (opts.uppercase === true) {
      keyspace = keyspace.toUpperCase();
    }

    result = result.concat(getXChars(keyspace, opts.hex));
  } else {
    if (typeof opts.alpha === 'number' && opts.alpha > 0) {
      i += opts.alpha;
      tmp = 'abcdefghijklmnopqrstuvwxyz';
      keyspace += tmp;
      result = result.concat(getXChars(tmp, opts.alpha));
    }

    if (typeof opts.uppercase === 'number' && opts.uppercase > 0) {
      i += opts.uppercase;
      tmp = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
      keyspace += tmp;
      result = result.concat(getXChars(tmp, opts.uppercase));
    }

    if (typeof opts.numeric === 'number' && opts.numeric > 0) {
      i += opts.numeric;
      tmp = '0123456789';
      keyspace += tmp;
      result = result.concat(getXChars(tmp, opts.numeric));
    }

    if (typeof opts.punctuation === 'number' && opts.punctuation > 0) {
      i += opts.punctuation;
      tmp = "`!\"?$?%^&*()_-+={[}]:;@'~#|\\<,>.?/";
      keyspace += tmp;
      result = result.concat(getXChars(tmp, opts.punctuation));
    }
  }

  if (keyspace.length === 0) {
    return keyspace;
  }

  opts.size = opts.size >>> 0 || 16;
  if (opts.size < 5) {
    opts.size = 5;
  } else if (opts.size > 100) {
    opts.size = 100;
  }

  result = result.concat(getXChars(keyspace, opts.size - i));

  return shuffle(result).join('');
}

var password = generatePassword({
  alpha: 1,
  uppercase: 1,
  numeric: 1,
  punctuation: 1
});

console.log(password);

更新:正如此处所承诺的那样,Math.random可能会替代。如果window.crypto.getRandomValues可用,那么它将使用它,否则它将回退到Math.random。

function random() {
  if (window.crypto && typeof window.crypto.getRandomValues === 'function') {
    console.log('Using crypto');
    var array = new Uint32Array(1);
    window.crypto.getRandomValues(array);
    return array[0] / (Math.pow(2, 32) + 1);
  }

  console.log('Using random');
  return Math.random();
}

console.log(random());

答案 2 :(得分:0)

我认为您需要根据数组的要求从不同的数组中选择字符。这是我的解决方案:

var alphas = "abcdefghjknpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
var specials = "!#$%&/()=`";
var numbers = "1234567890";

var requiredSpecials = 1;
var requiredNumbers = 2;

function pickRandom(str, count){
    var remaining = str;
    var result = "";
    while (remaining.length > 0 && count > 0){
        // pick random char from remaining
        var char = remaining.charAt(Math.floor(Math.random() *remaining.length));

        // remove char from remaining. (Just replace with empty string)
        remaining = remaining.replace(char, "");

        // add char to result
        result += char;

        // decrement count
        count -= 1;
    }

    return result;
}

function shuffleString(str){
    var arr = str.split(''); // Convert to array
    arr.sort(function(){ // Sort by random
        return 0.5-Math.random()
    })
    return arr.join(''); // Join back to string
}

function generate(length){
    var specialCount = requiredSpecials;
    var numberCount = requiredNumbers;
    var alphaCount = length - specialCount - numberCount;

    var tmp = pickRandom(alphas, alphaCount) + pickRandom(specials, specialCount) + pickRandom(numbers, numberCount);

    // Shuffle and return
    return shuffleString(tmp);
}

alert(generate(9))

您也可以在jsFiddle

进行游戏