„Alfanumeryczny” skrót - A-Z, 0-9
Szukam funkcji, która wygeneruje „alfanumeryczny skrót”. Biorąc pod uwagę łańcuch źródłowy, tworzy określony wynikowy ciąg znaków, który może zawierać dowolną literę a-z lub cyfrę 0-9 i nie można go poddać inżynierii wstecznej w celu utworzenia źródła. Będzie to używane do generowania haseł dla systemu opartego na tajnych danych, więc idealne są ciągi znaków od 8 do 12 znaków, a idealny byłby również bezpieczny hash.
Myślę, że mogę użyć normalnego skrótu bitowego, złożyć XOR do 64 bitów (jeśli używam na przykład SHA256), a następnie wziąć wynik 5 bitów na raz (wytwarzając liczbę 0-31) i sprawdzić kod postaci, który ma zostać użyty w indeksowanej kolekcji uporządkowanej. Jest 26 liter i 10 cyfr, co oznacza, że muszę zostawić kilka (prawdopodobnie usuwając znaki, które mogłyby zostać pomylone z innymi, jeśli są napisane ręcznie). 64 bity, 5 bitów na raz, wytworzy 12-znakowy łańcuch z 4 bitami pozostałymi.
Martwię się jednak o dwie rzeczy: po pierwsze, wprowadzenie błędu poprzez przyjęcie liczby bitów innej niż 2; a po drugie, co zrobić z resztkami. Czy używam ich jako takich, które wiedzą, że będzie tylko 16 możliwości, czy zostawiam je wyłączone (i tracę dane, ewentualnie wprowadzając uprzedzenia), czy też mam jeszcze jeden bit, aby utworzyć 13-znakowy ciąg (i gdzie powinien być ostatni bit pochodzić z)?
EDYTOWAĆ: Oto moje aktualne uderzenie; pobiera liczbę bajtów (jak tablica bajtów generowana przez większość algorytmów mieszających) i zwraca ciąg znaków:
/// <summary>
/// Converts an IEnumerable of bytes to a string representation which can have any lowercase letter a-z except for l, o, q and z, and any digit 0-9.
/// Uses 5 bits of the byte array at a time to generate numbers from 0 to 31, which are then translated to letters or numbers.
/// </summary>
/// <param name="toConvert">the byte array to convert.</param>
/// <returns>A string containing the alphanumeric case-insensitive representation of the bytes in the array.</returns>
public static string ToInsensitiveAlphaNumericString(this IEnumerable<byte> toConvert)
{
var chars = new[]
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'p', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
};
var enumerator = toConvert.GetEnumerator();
enumerator.MoveNext();
int buffer = enumerator.Current;
short bufferLength = 8;
const int valueLength = 5;
var builder = new StringBuilder();
while (true)
{
var value = buffer >> (bufferLength - valueLength);
builder.Append(chars[value]);
buffer = buffer - (value << (bufferLength - valueLength));
bufferLength -= valueLength;
if(bufferLength < valueLength )
{
if (enumerator.MoveNext())
{
buffer = (buffer << 8) + enumerator.Current;
bufferLength += 8;
}
else
{
//here's the main question; to include, or not to include?
if (bufferLength > 0)
builder.Append(chars[buffer]);
break;
}
}
}
return builder.ToString();
}