90 lines
3.4 KiB
C#
90 lines
3.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace niceware
|
|
{
|
|
public static partial class Niceware
|
|
{
|
|
/// <summary>Maximum number of bytes for a passphrase</summary>
|
|
public const int MaxPassphraseSize = 1024;
|
|
|
|
/// <summary>Convert an array of bytes into a passphrase</summary>
|
|
/// <param name="bytes">Bytes to convert</param>
|
|
/// <returns>A passphrase</returns>
|
|
/// <remarks>Must be a even size array of bytes</remarks>
|
|
public static List<string> ToPassphrase(this byte[] bytes)
|
|
{
|
|
if (bytes.Length % 2 == 1)
|
|
{
|
|
throw new ArgumentException("Only even-sized byte arrays are supported");
|
|
}
|
|
|
|
var result = new List<string>();
|
|
for (var i = 0; i < bytes.Length; i = i + 2)
|
|
{
|
|
result.Add(WordList[bytes[i] * 256 + bytes[i + 1]]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>Generates a random passphrase with the specified number of bytes</summary>
|
|
/// <param name="size">Number of random bytes to use.</param>
|
|
/// <returns>A passphrase</returns>
|
|
/// <remarks>Size must be an even number</remarks>
|
|
public static List<string> GeneratePassphrase(int size)
|
|
{
|
|
return Generate(size).Item1;
|
|
}
|
|
|
|
/// <summary>Generates random bytes corresponding passphrase with the specified number of bytes</summary>
|
|
/// <param name="size">Number of random bytes to use.</param>
|
|
/// <returns>Tuple of the passphrase and generated bytes</returns>
|
|
/// <remarks>Size must be an even number and less than <see cref="MaxPassphraseSize" /></remarks>
|
|
public static Tuple<List<string>, byte[]> Generate(int size)
|
|
{
|
|
if (size < 0 || size > MaxPassphraseSize)
|
|
{
|
|
throw new ArgumentException($"Size must be between 0 and {MaxPassphraseSize} bytes");
|
|
}
|
|
|
|
var bytes = new Byte[size];
|
|
var rng = System.Security.Cryptography.RandomNumberGenerator.Create();
|
|
rng.GetBytes(bytes);
|
|
rng.Dispose();
|
|
return new Tuple<List<string>, byte[]>(bytes.ToPassphrase(), bytes);
|
|
}
|
|
|
|
/// <summary>Converts a phrase back into the original byte array</summary>
|
|
/// <param name="passphrase">Passphrase</param>
|
|
/// <returns>Array of bytes</returns>
|
|
/// <remarks>Throws an ArgumentException if a word is not in the list</remarks>
|
|
public static byte[] PassphraseToBytes(this IEnumerable<string> passphrase)
|
|
{
|
|
if (passphrase == null)
|
|
{
|
|
return new byte[0];
|
|
}
|
|
|
|
var result = new byte[passphrase.Count() * 2];
|
|
for (int i = 0; i < passphrase.Count(); i++)
|
|
{
|
|
int wordIndex = -1;
|
|
var word = passphrase.ElementAtOrDefault(i)?.ToLower();
|
|
if (word != null)
|
|
{
|
|
wordIndex = WordList.IndexOf(word);
|
|
}
|
|
|
|
if (wordIndex == -1)
|
|
{
|
|
throw new ArgumentException($"Invalid word {word}");
|
|
}
|
|
result[2 * i] = (byte)Math.Floor(wordIndex / 256d);
|
|
result[2 * i + 1] = (byte)(wordIndex % 256);
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
}
|