Neste post será criado um código em C# para geração de senha randômica e cumprindo os níveis de complexidade estabelecidos.
No Windows geralmente o nível de complexidade exigido é:
- Não conter partes significativas do nome da conta do usuário ou o nome todo
- Ter pelo menos seis caracteres de comprimento
- Conter caracteres de três das quatro categorias a seguir:
- Caracteres maiúsculos do inglês (A-Z)
- Caracteres minúsculos do inglês (a-z)
- 10 dígitos básicos (0-9)
- Caracteres não-alfabéticos (por exemplo, !, $, #, %)
Desta forma criei um código para cumprir todos estes requisitos.
A base de geração de alguns dados foi a tabela ASCII (conforma imagem abaixo). Da tabela foram utilizados os caracteres A-Z, a-z, 0-9 e alguns caracteres especiais. Porém no código eles aparecem como os seus decimais.
Como referência temos os itens:
[sourcecode language="csharp"]
using System;
using System.Collections.Generic;
using System.Text;
[/sourcecode]
A Classe é:
[sourcecode language="csharp"]
public class PasswordGenerator
{
//Caracteres especiais utilizados
private String[] Special = new String[] { "@", "#", "$", "!", "%", "-", "_" };
//Requisitos mínimos de senha
private Boolean useLowerCase;
private Boolean useUpperCase;
private Boolean useDigits;
private Boolean useSpecial;
public Boolean UseLowerCase { get { return useLowerCase; } set { useLowerCase = value; } }
public Boolean UseUpperCase { get { return useUpperCase; } set { useUpperCase = value; } }
public Boolean UseDigits { get { return useDigits; } set { useDigits = value; } }
public Boolean UseSpecial { get { return useSpecial; } set { useSpecial = value; } }
public PasswordGenerator() : this(true, true, true, true) { }
public PasswordGenerator(Boolean UseLowerCase, Boolean UseUpperCase, Boolean UseDigits, Boolean UseSpecial)
{
this.useLowerCase = UseLowerCase;
this.useUpperCase = UseUpperCase;
this.useDigits = UseDigits;
this.useSpecial = UseSpecial;
if ((!this.useLowerCase) && (!this.useUpperCase) && (!this.useDigits) && (!this.useSpecial))
this.useLowerCase = true;
}
public String Generate(Int32 Length)
{
String passwd = "";
Int32 uppper = 0;
Int32 lower = 0;
Int32 digits = 0;
Int32 special = 0;
Random rnd = new Random();
while(passwd.Length < Length)
{
Int32 i = rnd.Next(1, 4);
Int32 i2 = 0;
//Regras de checagem de requisitos
while (i != i2)
{
switch (i)
{
case 1:
if (!useDigits){
i++;
break;
}
else if (digits > 0)
{
if ((useUpperCase) && (uppper == 0))
i = i2 = 2;
else if ((useLowerCase) && (lower == 0))
i = i2 = 3;
else if ((useSpecial) && (special == 0))
i = i2 = 4;
else
i2 = i;
}
else
{
i2 = i;
}
break;
case 2:
if (!useUpperCase)
{
i++;
break;
}
else if (uppper > 0)
{
if ((useDigits) && (digits == 0))
i = i2 = 1;
else if ((useLowerCase) && (lower == 0))
i = i2 = 3;
else if ((useSpecial) && (special == 0))
i = i2 = 4;
else
i2 = i;
}
else
{
i2 = i;
}
break;
case 3:
if (!useLowerCase)
{
i++;
break;
}
else if (lower > 0)
{
if ((useDigits) && (digits == 0))
i = i2 = 1;
else if ((useUpperCase) && (uppper == 0))
i = i2 = 2;
else if ((useSpecial) && (special == 0))
i = i2 = 4;
else
i2 = i;
}
else
{
i2 = i;
}
break;
case 4:
if (!useSpecial)
{
i++;
break;
}
else if (special > 0)
{
if ((useDigits) && (digits == 0))
i = i2 = 1;
else if ((useUpperCase) && (uppper == 0))
i = i2 = 2;
else if ((useLowerCase) && (lower == 0))
i = i2 = 3;
else
i2 = i;
}
else
{
i2 = i;
}
break;
}
}
String newItem = "";
switch (i2)
{
case 1:
newItem = ((char)(rnd.Next(48, 57))).ToString();
digits++;
break;
case 2:
newItem = ((char)(rnd.Next(65, 90))).ToString();
uppper++;
break;
case 3:
newItem = ((char)(rnd.Next(97, 122))).ToString();
lower++;
break;
case 4:
newItem = Special[rnd.Next(0, Special.Length - 1)];
special++;
break;
}
//Randomiza a posição dos caracteres
if (passwd.Length > 0)
{
System.Threading.Thread.Sleep(1);
Int32 pos = rnd.Next(0, passwd.Length - 1);
passwd = passwd.Insert(pos, newItem);
}
else
{
passwd = newItem;
}
//Slep necessário para que o 'rnd.Next' traga valores diferentes
System.Threading.Thread.Sleep(5);
}
return passwd;
}
}
[/sourcecode]
Para a utilização da classe temos este exemplo com um loop gerando 10 senhas diferentes com 16 caracteres cada.
[sourcecode language="csharp"]
PasswordGenerator gen = new PasswordGenerator();
for (Int32 i = 0; i < 10; i++)
{
Console.WriteLine(gen.Generate(16));
}
[/sourcecode]
Segue abaixo o aplicativo completo para download