Created
April 6, 2017 03:15
-
-
Save luuhq/9d88dab3af9be269f5159309e7bc60f5 to your computer and use it in GitHub Desktop.
HmacDataProtector
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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