Skip to content

Instantly share code, notes, and snippets.

@luuhq
Created April 6, 2017 03:15
Show Gist options
  • Save luuhq/9d88dab3af9be269f5159309e7bc60f5 to your computer and use it in GitHub Desktop.
Save luuhq/9d88dab3af9be269f5159309e7bc60f5 to your computer and use it in GitHub Desktop.
HmacDataProtector
using System;
using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNetCore.DataProtection;
namespace Home.Web
{
internal sealed class HmacDataProtector : IDataProtector
{
private const int HmacSize = 32; // for SHA256
private byte[] HmacSalt;
public HmacDataProtector(string salt)
: this(Encoding.UTF8.GetBytes(salt))
{
}
public HmacDataProtector(byte[] salt)
{
if (salt == null || salt.Length == 0)
{
throw new ArgumentNullException(nameof(salt));
}
HmacSalt = salt;
}
public IDataProtector CreateProtector(string purpose)
{
return this;
}
public byte[] Protect(byte[] plaintext)
{
if (plaintext == null || plaintext.Length == 0)
{
return plaintext;
}
var hmac = CalculateHmac(plaintext);
System.Diagnostics.Debug.Assert(hmac.Length == HmacSize);
var bytes = new byte[plaintext.Length + hmac.Length];
Array.Copy(plaintext, bytes, plaintext.Length);
Array.Copy(hmac, 0, bytes, plaintext.Length, hmac.Length);
return bytes;
}
public byte[] Unprotect(byte[] protectedData)
{
if (protectedData == null || protectedData.Length == 0)
{
return protectedData;
}
if (protectedData.Length <= HmacSize)
{
throw new CryptographicException();
}
var plaintext = new byte[protectedData.Length - HmacSize];
var expectedHmac = new byte[HmacSize];
Array.Copy(protectedData, plaintext, plaintext.Length);
Array.Copy(protectedData, plaintext.Length, expectedHmac, 0, expectedHmac.Length);
var realHmac = CalculateHmac(plaintext);
if (realHmac.Length != expectedHmac.Length)
{
throw new CryptographicException();
}
for (int i = 0; i < realHmac.Length; i++)
{
if (realHmac[i] != expectedHmac[i])
{
throw new CryptographicException();
}
}
return plaintext;
}
private byte[] CalculateHmac(byte[] plainText)
{
using (var sha = SHA256.Create())
{
var hash = sha.ComputeHash(plainText);
var bytes = new byte[hash.Length + HmacSalt.Length];
Array.Copy(hash, 0, bytes, destinationIndex: 0, length: hash.Length);
Array.Copy(HmacSalt, 0, bytes, destinationIndex: hash.Length, length: HmacSalt.Length);
return sha.ComputeHash(bytes);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment