C#逐渐生成唯一的安全随机字符串

时间:2018-06-18 07:19:49

标签: c# random unique

我想随机生成唯一且安全的字符串,我想随着时间的推移而做。我想为我的使用选择尽可能短的长度(足够大,以便随机尝试失败并且有很好的机会)。我也希望这个过程很快。使用以下代码并测试它的唯一性,重复发生的时间比我预期的要快。我不确定是否有任何问题。

P.S。:使用池生成数字是否安全?

P.P.S:我不想在字母表中添加' - '和'_'。是否值得删除它?

string Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
string Random(int length,string alphabet)
    {
        StringBuilder result = new StringBuilder();
        using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
        {
            for (int i = 0; i < length; i++)
            {
                byte[] buffer = new byte[sizeof(uint)];
                rng.GetBytes(buffer);
                uint num = BitConverter.ToUInt32(buffer, 0);
                result.Append(alphabet[(int)(num % (uint)alphabet.Length)]);
            }
        }

        return result.ToString();
    }

1 个答案:

答案 0 :(得分:0)

通常,在Alphabet中,每个字符都有6位“信息”(有64个字符)。所以长度= 10的字符串有60位信息。对于sq {(2 ^ 60)之后的birthday paradox,即2 ^ 30,你应该有0.5次碰撞的可能性(50%)。 2 ^ 30相当大,但如果字符数较少,那么碰撞就会发生得更早。

请注意,可以在代码中进行可能的优化(预先分配StringBuilder的“正确”长度)并且存在错误:

public const string BaseAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";

public static string Random(int length, string alphabet = BaseAlphabet)
{
    StringBuilder result = new StringBuilder(length);
    uint maxValue = (uint)((((ulong)uint.MaxValue) + 1) / (uint)alphabet.Length * (uint)alphabet.Length);

    using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
    {
        for (int i = 0; i < length; i++)
        {
            uint num;

            do
            {
                byte[] buffer = new byte[sizeof(uint)];
                rng.GetBytes(buffer);
                num = BitConverter.ToUInt32(buffer, 0);
            }
            while (num >= maxValue);

            result.Append(alphabet[(int)(num % (uint)alphabet.Length)]);
        }
    }

    return result.ToString();
}

在您编写的代码中,某些字符可能比其他字符更可能。这是因为if {uint.MaxValue + 1)(由rng生成的整个可能数字范围)不能被alphabet.Length完全整除,那么alphabet末尾的字符可能比var container; class LandingPage extends React.Component { constructor(props) { super(props); } listTaskLists = () => { console.log(window.gapi.client.tasks); window.gapi.client.tasks.tasklists.list({ 'maxResults': 10 }).then(function(response) { var l = ''; var taskLists = response.result.items; if (taskLists && taskLists.length > 0) { for (var i = 0; i < taskLists.length; i++) { var taskList = taskLists[i]; console.log(taskList.title); } } else { console.log("TNo Tasks") } }); } componentDidMount() { container = this; console.log("hg"); console.log(window.gapi.client.tasks); // window.gapi.client.tasks.tasklists.list({ // 'maxResults': 10 // }).then(function(response) { // // appendPre('Task Lists:'); // var l = ''; // var taskLists = response.result.items; // if (taskLists && taskLists.length > 0) { // for (var i = 0; i < taskLists.length; i++) { // var taskList = taskLists[i]; // console.log(taskList.title); // } // } else { // console.log("TNo Tasks") // } // }); } render () { return ( <div id = "LandingPageMain" style = {{height: '414px'}}> <Grid container wrap="nowrap" spacing={40} alignContent="center" justify ="center" alignItems="center" direction="column"> <Grid item> <img style={{width: '80px', height: '80px'}} src={Icon}/> </Grid> <Grid item> <Typography variant="display1" align="center" component="h3"> TASKS </Typography> </Grid> <Grid item> <Link to={{ pathname: "/TasksPage", state: { listId: 'MTI1NzMwMjIzNjgxNDAwMDExMjM6MDow'} }}> <Button variant="contained">TasksPage</Button> </Link> </Grid> <Grid item> <Link to = "/ListsPage"> <Button variant="contained">ListsPage</Button> </Link> </Grid> <Grid item> <Button variant="contained" onClick={this.listTaskLists}>Test</Button> </Grid> </Grid> </div> ); } } 更不可能。开头的人物。