Commits

Devin Martin committed 622c0e6

Add the initial base32 implementation (copied from OtpSharp)

Comments (0)

Files changed (6)

+syntax: glob
+bin/*
+obj/*
+*.suo
+*.user
+*.orig
+TestResults
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Base32", "Base32\Base32.csproj", "{BA4DADF9-D647-46C1-86F6-8FF78C694166}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{BA4DADF9-D647-46C1-86F6-8FF78C694166}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BA4DADF9-D647-46C1-86F6-8FF78C694166}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BA4DADF9-D647-46C1-86F6-8FF78C694166}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BA4DADF9-D647-46C1-86F6-8FF78C694166}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
+using System;
+
+namespace Base32
+{
+    /// <summary>
+    /// Utility to deal with Base32 encoding and decoding
+    /// </summary>
+    /// <remarks>
+    /// http://tools.ietf.org/html/rfc4648
+    /// </remarks>
+    public static class Base32Encoder
+    {
+        /// <summary>
+        /// The number of bits in a base32 encoded character
+        /// </summary>
+        private const int encodedBitCount = 5;
+        /// <summary>
+        /// The number of bits in a byte
+        /// </summary>
+        private const int byteBitCount = 8;
+        /// <summary>
+        /// A string containing all of the base32 characters in order.
+        /// This allows a simple indexof or [index] to convert between
+        /// a numeric value and an encoded character and vice versa.
+        /// </summary>
+        private const string encodingChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+        /// <summary>
+        /// The rfc defines '=' as the padding character
+        /// </summary>
+        private const char paddingCharacter = '=';
+        /// <summary>
+        /// Takes a block of data and converts it to a base 32 encoded string
+        /// </summary>
+        /// <param name="data">Input data</param>
+        /// <returns>base 32 string</returns>
+        public static string Encode(byte[] data)
+        {
+            if (data == null)
+                throw new ArgumentNullException("data");
+
+            if (data.Length == 0)
+                throw new ArgumentException("data must not be empty");
+
+            // The output character count is calculated in 40 bit blocks.  That is because the least
+            // common blocks size for both binary (8 bit) and base 32 (5 bit) is 40.  Padding must be used
+            // to fill in the difference.
+            int outputCharacterCount = (int)Math.Ceiling(data.Length / (decimal)encodedBitCount) * byteBitCount;
+            char[] outputBuffer = new char[outputCharacterCount];
+
+            byte workingValue = 0;
+            short remainingBits = encodedBitCount;
+            int currentPosition = 0;
+
+            foreach (byte workingByte in data)
+            {
+                workingValue = (byte)(workingValue | (workingByte >> (byteBitCount - remainingBits)));
+                outputBuffer[currentPosition++] = encodingChars[workingValue];
+
+                if (remainingBits <= byteBitCount - encodedBitCount)
+                {
+                    workingValue = (byte)((workingByte >> (byteBitCount - encodedBitCount - remainingBits)) & 31);
+                    outputBuffer[currentPosition++] = encodingChars[workingValue];
+                    remainingBits += encodedBitCount;
+                }
+
+                remainingBits -= byteBitCount - encodedBitCount;
+                workingValue = (byte)((workingByte << remainingBits) & 31);
+            }
+
+            // if we didn't finish, write the last current working char
+            if (currentPosition != outputCharacterCount)
+                outputBuffer[currentPosition++] = encodingChars[workingValue];
+
+            // RFC 4648 specifies that padding up to the end of the next 40 bit block must be provided
+            // Since the outputCharacterCount does account for the paddingCharacters, fill it out
+            while (currentPosition < outputCharacterCount)
+            {
+                outputBuffer[currentPosition++] = paddingCharacter;
+            }
+
+            return new string(outputBuffer);
+        }
+
+        /// <summary>
+        /// Takes a base 32 encoded value and converts it back to binary data
+        /// </summary>
+        /// <param name="base32">Base 32 encoded string</param>
+        /// <returns>Binary data</returns>
+        public static byte[] Decode(string base32)
+        {
+            if (string.IsNullOrEmpty(base32))
+                throw new ArgumentNullException("base32");
+
+            var unpaddedBase32 = base32.ToUpperInvariant().TrimEnd(paddingCharacter);
+
+            foreach (var c in unpaddedBase32)
+            {
+                if (encodingChars.IndexOf(c) < 0)
+                    throw new ArgumentException("base32 contains illegal characters");
+            }
+
+            // we have already removed the padding so this will tell us how many actual bytes there should be
+            int outputByteCount = unpaddedBase32.Length * encodedBitCount / byteBitCount;
+            byte[] outputBuffer = new byte[outputByteCount];
+
+            byte workingByte = 0;
+            short bitsRemaining = byteBitCount;
+            int mask = 0;
+            int arrayIndex = 0;
+
+            foreach (char workingChar in unpaddedBase32)
+            {
+                int encodedCharacterNumericValue = encodingChars.IndexOf(workingChar);
+
+                if (bitsRemaining > encodedBitCount)
+                {
+                    mask = encodedCharacterNumericValue << (bitsRemaining - encodedBitCount);
+                    workingByte = (byte)(workingByte | mask);
+                    bitsRemaining -= encodedBitCount;
+                }
+                else
+                {
+                    mask = encodedCharacterNumericValue >> (encodedBitCount - bitsRemaining);
+                    workingByte = (byte)(workingByte | mask);
+                    outputBuffer[arrayIndex++] = workingByte;
+                    workingByte = (byte)(encodedCharacterNumericValue << (byteBitCount - encodedBitCount + bitsRemaining));
+                    bitsRemaining += byteBitCount - encodedBitCount;
+                }
+            }
+
+            return outputBuffer;
+        }
+    }
+}

Base32/Base32.csproj

+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{BA4DADF9-D647-46C1-86F6-8FF78C694166}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Base32</RootNamespace>
+    <AssemblyName>Base32</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Base32.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

Base32/Properties/AssemblyInfo.cs

+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Base32")]
+[assembly: AssemblyDescription("An implementation of RFC 4648 Base32")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Devin Martin")]
+[assembly: AssemblyProduct("Base32")]
+[assembly: AssemblyCopyright("Copyright © Devin Martin 2013")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("c7240dfc-1038-41c8-8e19-3f26eabdc56c")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+Copyright (C) 2012 Devin Martin
+
+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.
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.