commit
1fe623e02d
110
.gitignore
vendored
Normal file
110
.gitignore
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
**/Properties/launchSettings.json
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
21
LICENSE
21
LICENSE
@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Todd Palmer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
30
README.md
Normal file
30
README.md
Normal file
@ -0,0 +1,30 @@
|
||||
## Niceware for .NET
|
||||
A .NET port of [Niceware](https://github.com/diracdeltas/niceware) for generating random-yet-memorable passwords. Each word provides 16 bits of entropy, so a useful password requires at least 3 words.
|
||||
|
||||
Because the wordlist is of exactly size 2^16, Niceware is also useful for converting cryptographic keys and other sequences of random bytes into human-readable phrases. With Niceware, a 128-bit key is equivalent to an 8-word phrase.
|
||||
|
||||
* Free software: MIT license
|
||||
* Supports .NET Standard (core), .NET 4.6
|
||||
|
||||
## Usage
|
||||
|
||||
To Install:
|
||||
|
||||
Install via Nuget package manager:
|
||||
```
|
||||
PM> Install-Package niceware
|
||||
```
|
||||
|
||||
To generate an 8-byte passphrase:
|
||||
|
||||
``` c#
|
||||
|
||||
using niceware;
|
||||
|
||||
var passphrase = Niceware.GeneratePassphrase(8);
|
||||
|
||||
// result: ["unpeopling", "whipsawing", "sought", "rune"]
|
||||
```
|
||||
|
||||
## Credits
|
||||
Niceware for .NET is a port of [Niceware](https://github.com/diracdeltas/niceware) by [yan](https://diracdeltas.github.io/blog/about/)
|
94
src/niceware.tests/NicewareTests.cs
Normal file
94
src/niceware.tests/NicewareTests.cs
Normal file
@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Xunit;
|
||||
using niceware;
|
||||
|
||||
namespace niceware.tests
|
||||
{
|
||||
public class NicewareTests
|
||||
{
|
||||
[Theory]
|
||||
[MemberData(nameof(ToPassphraseData))]
|
||||
public void ToPassphrase(byte[] bytes, IEnumerable<string> expected)
|
||||
{
|
||||
var actual = bytes.ToPassphrase();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> ToPassphraseData()
|
||||
{
|
||||
yield return new object[] { new byte[0], new string[0] };
|
||||
yield return new object[] { new byte[] { 0, 0}, new [] { "a" } };
|
||||
yield return new object[] { new byte[] { 255, 255}, new [] { "zyzzyva" } };
|
||||
yield return new object[]
|
||||
{
|
||||
new byte[] { 0, 0, 17, 212, 12, 140, 90, 247, 46, 83, 254, 60, 54, 169, 255, 255 },
|
||||
new [] { "a", "bioengineering", "balloted", "gobbledegook", "creneled", "written", "depriving", "zyzzyva" }
|
||||
};
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(2, 1)]
|
||||
[InlineData(0, 0)]
|
||||
[InlineData(8, 4)]
|
||||
[InlineData(20, 10)]
|
||||
[InlineData(512, 256)]
|
||||
public void GeneratePassphrase(int length, int expectedWords)
|
||||
{
|
||||
var actual = Niceware.GeneratePassphrase(length);
|
||||
Assert.Equal(expectedWords, actual.Count);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1)]
|
||||
[InlineData(23)]
|
||||
public void GeneratePassphrase_OddBytes(int length)
|
||||
{
|
||||
var ex = Assert.Throws<ArgumentException>(() => Niceware.GeneratePassphrase(length));
|
||||
Assert.Equal("Only even-sized byte arrays are supported", ex.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1025)]
|
||||
[InlineData(-1)]
|
||||
public void GeneratePassphrase_OutOfRange(int length)
|
||||
{
|
||||
var ex = Assert.Throws<ArgumentException>(() => Niceware.GeneratePassphrase(length));
|
||||
Assert.Equal($"Size must be between 0 and {Niceware.MaxPassphraseSize} bytes", ex.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(PassphraseToBytesData))]
|
||||
public void PassphraseToBytes(IEnumerable<string> passphrase, byte[] expected)
|
||||
{
|
||||
var actual = passphrase.PassphraseToBytes();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> PassphraseToBytesData()
|
||||
{
|
||||
yield return new object[] { new [] { "A" }, new byte[] { 0, 0 } };
|
||||
yield return new object[] { new [] { "zyzzyva" }, new byte[] { 255, 255 } };
|
||||
yield return new object[]
|
||||
{
|
||||
new [] { "A", "bioengineering", "Balloted", "gobbledegooK", "cReneled", "wriTTen", "depriving", "zyzzyva" },
|
||||
new byte[] { 0, 0, 17, 212, 12, 140, 90, 247, 46, 83, 254, 60, 54, 169, 255, 255 }
|
||||
};
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PassphraseToBytes_NullOk()
|
||||
{
|
||||
var actual = ((string[])null).PassphraseToBytes();
|
||||
Assert.Equal(new byte[0], actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PassphraseToBytes_InvalidWord()
|
||||
{
|
||||
var ex = Assert.Throws<ArgumentException>(() => new [] { "You", "love", "ninetales" }.PassphraseToBytes());
|
||||
Assert.StartsWith("Invalid word", ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
14
src/niceware.tests/niceware.tests.csproj
Normal file
14
src/niceware.tests/niceware.tests.csproj
Normal file
@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
|
||||
<PackageReference Include="xunit" Version="2.2.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
|
||||
<ProjectReference Include="../niceware/niceware.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
8
src/niceware/AssemblyInfo.cs
Normal file
8
src/niceware/AssemblyInfo.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: AssemblyProduct("Niceware")]
|
||||
[assembly: AssemblyVersion("0.1.0.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.0.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.1.0.0")]
|
89
src/niceware/Niceware.cs
Normal file
89
src/niceware/Niceware.cs
Normal file
@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace niceware
|
||||
{
|
||||
public static partial class Niceware
|
||||
{
|
||||
private static Random _random = new Random((int)DateTime.Now.Ticks);
|
||||
|
||||
/// <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];
|
||||
_random.NextBytes(bytes);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
65556
src/niceware/Niceware.wordlist.cs
Normal file
65556
src/niceware/Niceware.wordlist.cs
Normal file
File diff suppressed because it is too large
Load Diff
27
src/niceware/niceware.csproj
Normal file
27
src/niceware/niceware.csproj
Normal file
@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard1.4;net45</TargetFrameworks>
|
||||
<DebugType>portable</DebugType>
|
||||
<AssemblyName>Niceware</AssemblyName>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
|
||||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
|
||||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
|
||||
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
|
||||
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
|
||||
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
|
||||
<GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
|
||||
|
||||
<PackageVersion>0.1.0.0</PackageVersion>
|
||||
<Title>Niceware for .NET</Title>
|
||||
<Authors>Todd Palmer</Authors>
|
||||
<Description>A library for generating random-yet-memorable passwords</Description>
|
||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
||||
<PackageTags>niceware passphrase</PackageTags>
|
||||
<PackageProjectUrl>https://github.com/trpalmer/dotnet-niceware</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/trpalmer/dotnet-niceware</RepositoryUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
Loading…
Reference in New Issue
Block a user