diff options
author | Stephen Jennings <Stephen.G.Jennings@gmail.com> | 2011-11-06 21:24:34 -0800 |
---|---|---|
committer | Stephen Jennings <Stephen.G.Jennings@gmail.com> | 2011-11-11 20:46:13 -0800 |
commit | 2ae3bb5f3bbdedfe37f58445248cba658229d57e (patch) | |
tree | c9586e08d8a2eecef9769279f03eb1db861093ac | |
parent | 8acd1866c9974d68e24d1136cb9155db482ebcb3 (diff) | |
download | OATH.Net-2ae3bb5f3bbdedfe37f58445248cba658229d57e.zip OATH.Net-2ae3bb5f3bbdedfe37f58445248cba658229d57e.tar.gz OATH.Net-2ae3bb5f3bbdedfe37f58445248cba658229d57e.tar.bz2 |
Added Base32 utility class, can convert binary to base32.
-rw-r--r-- | OATH.Net.Test/Base32Tests.cs | 297 | ||||
-rw-r--r-- | OATH.Net.Test/KeyTests.cs | 32 | ||||
-rw-r--r-- | OATH.Net.Test/OATH.Net.Test.csproj | 1 | ||||
-rw-r--r-- | OATH.Net/Base32.cs | 118 | ||||
-rw-r--r-- | OATH.Net/CounterBasedOtpGenerator.cs | 2 | ||||
-rw-r--r-- | OATH.Net/Key.cs | 4 | ||||
-rw-r--r-- | OATH.Net/OATH.Net.csproj | 1 |
7 files changed, 440 insertions, 15 deletions
diff --git a/OATH.Net.Test/Base32Tests.cs b/OATH.Net.Test/Base32Tests.cs new file mode 100644 index 0000000..6f928af --- /dev/null +++ b/OATH.Net.Test/Base32Tests.cs @@ -0,0 +1,297 @@ +//------------------------------------------------------------------------------------ +// <copyright file="Base32Tests.cs" company="Stephen Jennings"> +// Copyright 2011 Stephen Jennings. Licensed under the Apache License, Version 2.0. +// </copyright> +//------------------------------------------------------------------------------------ + +namespace OathNet.Test +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using NUnit.Framework; + + public class Base32Tests + { + [Test] + public void ToBase32_10_bytes_1() + { + var binary = new byte[] + { + 0xDE, 0xAD, 0xBE, 0xEF, 0x48, + 0x65, 0x6C, 0x6C, 0x6F, 0x21 + }; + var expected = "32W3532IMVWGY3ZB"; + var actual = Base32.ToBase32(binary); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBase32_10_bytes_2() + { + var binary = new byte[] + { + 0x48, 0x65, 0x6C, 0x6C, 0x6F, + 0x21, 0xDE, 0xAD, 0xBE, 0xEF + }; + var expected = "JBSWY3DPEHPK3PXP"; + var actual = Base32.ToBase32(binary); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBase32_9_bytes_1() + { + var binary = new byte[] + { + 0xAD, 0xBE, 0xEF, 0x48, + 0x65, 0x6C, 0x6C, 0x6F, 0x21 + }; + var expected = "VW7O6SDFNRWG6II="; + var actual = Base32.ToBase32(binary); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBase32_9_bytes_2() + { + var binary = new byte[] + { + 0x65, 0x6C, 0x6C, 0x6F, + 0x21, 0xDE, 0xAD, 0xBE, 0xEF + }; + var expected = "MVWGY3ZB32W353Y="; + var actual = Base32.ToBase32(binary); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBase32_8_bytes_1() + { + var binary = new byte[] + { + 0xBE, 0xEF, 0x48, + 0x65, 0x6C, 0x6C, 0x6F, 0x21 + }; + var expected = "X3XUQZLMNRXSC==="; + var actual = Base32.ToBase32(binary); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBase32_8_bytes_2() + { + var binary = new byte[] + { + 0x6C, 0x6C, 0x6F, + 0x21, 0xDE, 0xAD, 0xBE, 0xEF + }; + var expected = "NRWG6IO6VW7O6==="; + var actual = Base32.ToBase32(binary); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBase32_7_bytes_1() + { + var binary = new byte[] + { + 0xEF, 0x48, + 0x65, 0x6C, 0x6C, 0x6F, 0x21 + }; + var expected = "55EGK3DMN4QQ===="; + var actual = Base32.ToBase32(binary); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBase32_7_bytes_2() + { + var binary = new byte[] + { + 0x6C, 0x6F, + 0x21, 0xDE, 0xAD, 0xBE, 0xEF + }; + var expected = "NRXSDXVNX3XQ===="; + var actual = Base32.ToBase32(binary); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBase32_6_bytes_1() + { + var binary = new byte[] + { + 0x48, + 0x65, 0x6C, 0x6C, 0x6F, 0x21 + }; + var expected = "JBSWY3DPEE======"; + var actual = Base32.ToBase32(binary); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBase32_6_bytes_2() + { + var binary = new byte[] + { + 0x6F, + 0x21, 0xDE, 0xAD, 0xBE, 0xEF + }; + var expected = "N4Q55LN654======"; + var actual = Base32.ToBase32(binary); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBinary_10_bytes_1() + { + var expected = new byte[] + { + 0xDE, 0xAD, 0xBE, 0xEF, 0x48, + 0x65, 0x6C, 0x6C, 0x6F, 0x21 + }; + var base32 = "32W3532IMVWGY3ZB"; + var actual = Base32.ToBinary(base32); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBinary_10_bytes_2() + { + var expected = new byte[] + { + 0x48, 0x65, 0x6C, 0x6C, 0x6F, + 0x21, 0xDE, 0xAD, 0xBE, 0xEF + }; + var base32 = "JBSWY3DPEHPK3PXP"; + var actual = Base32.ToBinary(base32); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBinary_9_bytes_1() + { + var expected = new byte[] + { + 0xAD, 0xBE, 0xEF, 0x48, + 0x65, 0x6C, 0x6C, 0x6F, 0x21 + }; + var base32 = "VW7O6SDFNRWG6II="; + var actual = Base32.ToBinary(base32); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBinary_9_bytes_2() + { + var expected = new byte[] + { + 0x65, 0x6C, 0x6C, 0x6F, + 0x21, 0xDE, 0xAD, 0xBE, 0xEF + }; + var base32 = "MVWGY3ZB32W353Y="; + var actual = Base32.ToBinary(base32); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBinary_8_bytes_1() + { + var expected = new byte[] + { + 0xBE, 0xEF, 0x48, + 0x65, 0x6C, 0x6C, 0x6F, 0x21 + }; + var base32 = "X3XUQZLMNRXSC==="; + var actual = Base32.ToBinary(base32); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBinary_8_bytes_2() + { + var expected = new byte[] + { + 0x6C, 0x6C, 0x6F, + 0x21, 0xDE, 0xAD, 0xBE, 0xEF + }; + var base32 = "NRWG6IO6VW7O6==="; + var actual = Base32.ToBinary(base32); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBinary_7_bytes_1() + { + var expected = new byte[] + { + 0xEF, 0x48, + 0x65, 0x6C, 0x6C, 0x6F, 0x21 + }; + var base32 = "55EGK3DMN4QQ===="; + var actual = Base32.ToBinary(base32); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBinary_7_bytes_2() + { + var expected = new byte[] + { + 0x6C, 0x6F, + 0x21, 0xDE, 0xAD, 0xBE, 0xEF + }; + var base32 = "NRXSDXVNX3XQ===="; + var actual = Base32.ToBinary(base32); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBinary_6_bytes_1() + { + var expected = new byte[] + { + 0x48, + 0x65, 0x6C, 0x6C, 0x6F, 0x21 + }; + var base32 = "JBSWY3DPEE======"; + var actual = Base32.ToBinary(base32); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void ToBinary_6_bytes_2() + { + var expected = new byte[] + { + 0x6F, + 0x21, 0xDE, 0xAD, 0xBE, 0xEF + }; + var base32 = "N4Q55LN654======"; + var actual = Base32.ToBinary(base32); + + Assert.AreEqual(expected, actual); + } + } +} diff --git a/OATH.Net.Test/KeyTests.cs b/OATH.Net.Test/KeyTests.cs index 1c9241c..7ddf93a 100644 --- a/OATH.Net.Test/KeyTests.cs +++ b/OATH.Net.Test/KeyTests.cs @@ -23,8 +23,9 @@ namespace OathNet.Test 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30 }; var key = new Key(keyData); + var actual = key.Binary; - Assert.AreEqual(keyData, key.Binary); + Assert.AreEqual(keyData, actual); } [Test] @@ -38,8 +39,9 @@ namespace OathNet.Test 0x31, 0x32 }; var key = new Key(keyData); + var actual = key.Binary; - Assert.AreEqual(keyData, key.Binary); + Assert.AreEqual(keyData, actual); } [Test] @@ -52,9 +54,10 @@ namespace OathNet.Test }; var key = new Key(keyData); - var base32 = "32W3532IMVWGY3ZB"; + var actual = key.Base32; + var expected = "32W3532IMVWGY3ZB"; - Assert.AreEqual(base32, key.Base32); + Assert.AreEqual(expected, actual); } [Test] @@ -67,9 +70,10 @@ namespace OathNet.Test }; var key = new Key(keyData); - var base32 = "JBSWY3DPEHPK3PXP"; + var actual = key.Base32; + var expected = "JBSWY3DPEHPK3PXP"; - Assert.AreEqual(base32, key.Base32); + Assert.AreEqual(expected, actual); } [Test] @@ -77,8 +81,9 @@ namespace OathNet.Test { var base32 = "32W3532IMVWGY3ZB"; var key = new Key(base32); + var actual = key.Base32; - Assert.AreEqual(base32, key.Base32); + Assert.AreEqual(base32, actual); } [Test] @@ -86,8 +91,9 @@ namespace OathNet.Test { var base32 = "JBSWY3DPEHPK3PXP"; var key = new Key(base32); + var actual = key.Base32; - Assert.AreEqual(base32, key.Base32); + Assert.AreEqual(base32, actual); } [Test] @@ -95,13 +101,14 @@ namespace OathNet.Test { var base32 = "32W3532IMVWGY3ZB"; var key = new Key(base32); - var binary = new byte[] + var actual = key.Binary; + var expected = new byte[] { 0xDE, 0xAD, 0xBE, 0xEF, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x21 }; - Assert.AreEqual(binary, key.Binary); + Assert.AreEqual(expected, actual); } [Test] @@ -109,13 +116,14 @@ namespace OathNet.Test { var base32 = "JBSWY3DPEHPK3PXP"; var key = new Key(base32); - var binary = new byte[] + var actual = key.Binary; + var expected = new byte[] { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x21, 0xDE, 0xAD, 0xBE, 0xEF }; - Assert.AreEqual(base32, key.Base32); + Assert.AreEqual(expected, actual); } } } diff --git a/OATH.Net.Test/OATH.Net.Test.csproj b/OATH.Net.Test/OATH.Net.Test.csproj index 5565426..5004614 100644 --- a/OATH.Net.Test/OATH.Net.Test.csproj +++ b/OATH.Net.Test/OATH.Net.Test.csproj @@ -55,6 +55,7 @@ <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> + <Compile Include="Base32Tests.cs" /> <Compile Include="KeyTests.cs" /> <Compile Include="MiscExtensionsTests.cs" /> <Compile Include="CounterBasedOtpGeneratorTests.cs" /> diff --git a/OATH.Net/Base32.cs b/OATH.Net/Base32.cs new file mode 100644 index 0000000..f7ef19f --- /dev/null +++ b/OATH.Net/Base32.cs @@ -0,0 +1,118 @@ +//------------------------------------------------------------------------------------ +// <copyright file="Base32.cs" company="Stephen Jennings"> +// Copyright 2011 Stephen Jennings. Licensed under the Apache License, Version 2.0. +// </copyright> +//------------------------------------------------------------------------------------ + +namespace OathNet +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + using System.Text; + + /// <summary> + /// Contains methods to convert to and from base-32 according to RFC 3548. + /// </summary> + public static class Base32 + { + private static readonly string[] Alphabet = new string[] + { + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", + "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", + "U", "V", "W", "X", "Y", "Z", "2", "3", "4", "5", + "6", "7" + }; + + private static readonly char Padding = '='; + + /// <summary> + /// Converts a byte array to a base-32 representation. + /// </summary> + /// <param name="data">The data to convert.</param> + /// <returns>A base-32 encoded string.</returns> + public static string ToBase32(byte[] data) + { + string result = String.Empty; + + var fullSegments = data.Length / 5; + var finalSegmentLength = data.Length % 5; + var segments = fullSegments + (finalSegmentLength == 0 ? 0 : 1); + + for (int i = 0; i < segments; i++) + { + var segment = data.Skip(i * 5).Take(5).ToArray(); + result = String.Concat(result, Base32.ConvertSegmentToBase32(segment)); + } + + return result; + } + + /// <summary> + /// Converts a base-32 encoded string to a byte array. + /// </summary> + /// <param name="base32">A base-32 encoded string.</param> + /// <returns>The data represented by the base-32 string.</returns> + public static byte[] ToBinary(string base32) + { + throw new NotImplementedException(); + } + + private static string ConvertSegmentToBase32(byte[] segment) + { + if (segment.Length == 0) + { + return String.Empty; + } + + if (segment.Length > 5) + { + throw new ArgumentException("Segment must be five bytes or fewer."); + } + + string result = String.Empty; + + int accumulator = 0; + int bitsRemaining = 5; + byte[] masks = new byte[] { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F }; + + foreach (var b in segment) + { + // Accumulate the bits remaining from the previous byte, if any + int bottomBitsInThisByte = 8 - bitsRemaining; + accumulator += (b >> bottomBitsInThisByte) & masks[Math.Min(bitsRemaining, 5)]; + + // Add the accumulated character to the result string + result = result + Alphabet[accumulator]; + + if (bottomBitsInThisByte >= 5) + { + bottomBitsInThisByte -= 5; + + // Set the accumulator to the next 5 bits in this byte + accumulator = (b >> bottomBitsInThisByte) & masks[5]; + + // Add the accumulated character to the result string + result = result + Alphabet[accumulator]; + } + + // Decide how many more bits we need to accumulate from the next byte + bitsRemaining = (5 - bottomBitsInThisByte) % 5; + + // Set the accumulator to the remaining bits in this byte + accumulator = (b & masks[bottomBitsInThisByte]) << bitsRemaining; + } + + if (bitsRemaining > 0) + { + // Capture the final accumulated value + result = result + Alphabet[accumulator]; + } + + result = result.PadRight(8, Padding); + + return result; + } + } +} diff --git a/OATH.Net/CounterBasedOtpGenerator.cs b/OATH.Net/CounterBasedOtpGenerator.cs index 70d5922..d876430 100644 --- a/OATH.Net/CounterBasedOtpGenerator.cs +++ b/OATH.Net/CounterBasedOtpGenerator.cs @@ -61,7 +61,7 @@ namespace OathNet /// Initializes a new instance of the CounterBasedOtpGenerator class. /// This is used when the client and server share a counter value. /// </summary> - /// <param name="secretKeyHex">The secret key represented as a sequence of hexadecimal digits.</param> + /// <param name="secretKey">The secret key.</param> /// <param name="otpLength">The number of digits in the OTP to generate.</param> public CounterBasedOtpGenerator(Key secretKey, int otpLength) : this(secretKey, otpLength, new SHA1HMACAlgorithm()) diff --git a/OATH.Net/Key.cs b/OATH.Net/Key.cs index e812e1d..66a98d7 100644 --- a/OATH.Net/Key.cs +++ b/OATH.Net/Key.cs @@ -40,7 +40,7 @@ namespace OathNet /// <param name="base32key">The key to initialize.</param> public Key(string base32key) { - throw new NotImplementedException(); + this.keyData = OathNet.Base32.ToBinary(base32key); } /// <summary> @@ -61,7 +61,7 @@ namespace OathNet { get { - throw new NotImplementedException(); + return OathNet.Base32.ToBase32(this.keyData); } } } diff --git a/OATH.Net/OATH.Net.csproj b/OATH.Net/OATH.Net.csproj index 155da01..f1d7dea 100644 --- a/OATH.Net/OATH.Net.csproj +++ b/OATH.Net/OATH.Net.csproj @@ -63,6 +63,7 @@ <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> + <Compile Include="Base32.cs" /> <Compile Include="Key.cs" /> <Compile Include="SHA512HMACAlgorithm.cs" /> <Compile Include="SHA256HMACAlgorithm.cs" /> |