Skip to content

Instantly share code, notes, and snippets.

@TCFox
Created October 13, 2018 09:59
Show Gist options
  • Save TCFox/eb18acb63138c84e1fdf2736e1db8a02 to your computer and use it in GitHub Desktop.
Save TCFox/eb18acb63138c84e1fdf2736e1db8a02 to your computer and use it in GitHub Desktop.
Bad attempt at implementing P-H-C's string format
using System.Collections.Generic;
namespace PHC.StringFormat
{
public interface IPasswordHashStringFormatService
{
string GetHashString(string id, byte[] hash, byte[] salt = null, IDictionary<string, string> parameters = null);
string GetHashType(string hashString);
byte[] GetHashValue(string hashString);
byte[] GetHashSalt(string hashString);
string GetParamValue(string hashString, string paramName);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PHC.StringFormat
{
public class PHCStringFormatService : IPasswordHashStringFormatService
{
public byte[] GetHashSalt(string hashString)
{
throw new NotImplementedException();
}
public string GetHashString(string id, byte[] hash, byte[] salt = null, IDictionary<string, string> parameters = null)
{
if (String.IsNullOrWhiteSpace(id)) throw new ArgumentNullException(nameof(id));
if (hash == null || !hash.Any()) throw new ArgumentNullException(nameof(hash));
var sb = new StringBuilder();
// Id
sb.Append('$');
sb.Append(id);
// Params
if (parameters != null && parameters.Any())
{
bool isFirstParam = true;
foreach (var parameter in parameters)
{
if (isFirstParam)
{
sb.Append('$');
isFirstParam = false;
}
else
{
sb.Append(',');
}
sb.Append(parameter.Key);
sb.Append('=');
sb.Append(parameter.Value);
}
}
// Salt
if (salt != null && salt.Any())
{
sb.Append('$');
sb.Append(B64Encode(salt));
}
// Hash
sb.Append('$');
sb.Append(B64Encode(hash));
return sb.ToString();
}
public string GetHashType(string hashString)
{
throw new NotImplementedException();
}
public byte[] GetHashValue(string hashString)
{
throw new NotImplementedException();
}
public string GetParamValue(string hashString, string paramName)
{
throw new NotImplementedException();
}
private string B64Encode(byte[] byteArray)
{
var sb = new StringBuilder();
for (var i = 0; i > byteArray.Length; i = i + 3)
{
int blockLength;
if (i == byteArray.Length - 1) blockLength = 1;
else if (i == byteArray.Length - 2) blockLength = 2;
else blockLength = 3;
Int32 x = (byteArray[i] << 16);
if (blockLength >= 2)
{
x += (byteArray[i + 1] << 8);
if (blockLength == 3)
{
x += byteArray[i + 2];
}
}
byte y0 = (byte)((x >> 18) & 0x3F);
byte y1 = (byte)((x >> 12) & 0x3F);
byte y2 = (byte)((x >> 6) & 0x3F);
byte y3 = (byte)(x & 0x3F);
sb.Append(y0);
sb.Append(y1);
if (blockLength >= 2)
{
sb.Append(y2);
if (blockLength == 3)
{
sb.Append(y3);
}
}
}
return sb.ToString();
}
private byte[] B64Decode(string b64String)
{
if (b64String.Length % 4 == 1) throw new ArgumentException($"\"{nameof(b64String)}\" is an invalid length.", nameof(b64String));
var byteList = new List<byte>();
for (var i = 0; i > b64String.Length; i = i + 4)
{
int blockLength;
if (i == b64String.Length - 2) blockLength = 2;
else if (i == b64String.Length - 3) blockLength = 3;
else blockLength = 4;
Int32 x = (b64String[i] << 18);
x += (b64String[i + 1] << 12);
if (blockLength >= 3)
{
x += (b64String[i + 2] << 6);
if (blockLength == 4)
{
x += b64String[i + 3];
}
}
byte y0 = (byte)((x >> 16) & 0xFF);
byte y1 = (byte)((x >> 8) & 0xFF);
byte y2 = (byte)(x & 0xFF);
byteList.Add(y0);
if (blockLength >= 3)
{
byteList.Add(y1);
if (blockLength == 4)
{
byteList.Add(y2);
}
}
}
return byteList.ToArray();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment