Skip to content

Instantly share code, notes, and snippets.

@jechtom
Created July 8, 2015 09:09
Show Gist options
  • Save jechtom/cde72caeebb215115171 to your computer and use it in GitHub Desktop.
Save jechtom/cde72caeebb215115171 to your computer and use it in GitHub Desktop.
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Services
{
public class HMAC
{
/// <remarks>
/// To generate new key:
// byte[] tokenData = new byte[64];
// new RNGCryptoServiceProvider().GetBytes(tokenData);
// string key = string.Join(", ", tokenData);
// </remarks>
private byte[] hmacKey64bytes = new byte[] { .................... };
public T DeserializeAndValidate<T>(string text) where T : class
{
if (string.IsNullOrWhiteSpace(text))
return null;
// deserialize
byte[] input;
try
{
// decode
input = Convert.FromBase64String(text);
using (MemoryStream inputStream = new MemoryStream(input))
{
int hashSize;
using (System.Security.Cryptography.HMAC hmac = CreateProvider())
{
// read hash
hashSize = (hmac.HashSize / 8);
byte[] hash = new byte[hashSize];
inputStream.Read(hash, 0, hash.Length);
// verify hash
byte[] hashCurrent = hmac.ComputeHash(inputStream);
// compare hash
for (int i = 0; i < hashCurrent.Length; i++)
{
if (hash[i] != hashCurrent[i])
return null; // invalid hash
}
}
// move position after hash
inputStream.Position = hashSize;
// hash is valid - try to deserialize object
using (var bsonReader = new BsonReader(inputStream))
{
T result = new JsonSerializer().Deserialize<T>(bsonReader);
return result;
}
}
}
catch
{
// invalid format
return null;
}
}
public string SerializeAndSign<T>(T value) where T : class
{
if (value == null)
throw new ArgumentNullException("value");
// serialize
byte[] input;
using (MemoryStream inputStream = new MemoryStream())
{
// serialize to input stream
using (var bsonWriter = new BsonWriter(inputStream))
{
new JsonSerializer().Serialize(bsonWriter, value);
}
input = inputStream.ToArray();
}
// sign
using (MemoryStream outputStream = new MemoryStream())
{
// compute hash
byte[] hash;
using (System.Security.Cryptography.HMAC hmac = CreateProvider())
{
hash = hmac.ComputeHash(input);
}
// write hash stream
outputStream.Write(hash, 0, hash.Length);
// and write input stream
outputStream.Write(input, 0, input.Length);
// serialize to Base64
var result = Convert.ToBase64String(outputStream.ToArray());
return result;
}
}
private System.Security.Cryptography.HMAC CreateProvider()
{
return new System.Security.Cryptography.HMACSHA256(hmacKey64bytes);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment