Created
August 15, 2012 15:09
-
-
Save benlesh/3360908 to your computer and use it in GitHub Desktop.
A basic digitally signed token in C#. More info at: http://www.benlesh.com/2012/08/creating-digitally-signed-security.html
This file contains 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
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
TokenTesting(); | |
} | |
private static void TokenTesting() | |
{ | |
// create a private key to use in our tests. | |
var privateKey = GetPrivateKey(); | |
// create a token and token string to test with. | |
var token = new Token("testdata", DateTime.Now.AddMinutes(1)); | |
var tokenString = token.GetTokenString(privateKey); | |
//try getting the token from the token string. | |
var token2 = Token.FromTokenString(tokenString, privateKey); | |
if (token2 != null) | |
{ | |
Console.WriteLine("Valid token!"); | |
Console.WriteLine("Token Value: {0}", token2.Value); | |
} | |
//try tampering with the token string (this is a corny way to do it, but whatever) | |
tokenString = "blah" + tokenString; | |
var token3 = Token.FromTokenString(tokenString, privateKey); | |
if (token3 == null) | |
{ | |
Console.WriteLine("Invalid token string!"); | |
} | |
//try an expired token | |
var token4 = new Token("this is expired", DateTime.Now.AddDays(-1)); | |
var expiredTokenString = token4.GetTokenString(privateKey); | |
var token5 = Token.FromTokenString(expiredTokenString, privateKey); | |
if (token5 == null) | |
{ | |
Console.WriteLine("This token is expired, silly."); | |
} | |
Console.ReadKey(); | |
} | |
private static string GetPrivateKey() | |
{ | |
using (var rsa = new RSACryptoServiceProvider()) | |
{ | |
return rsa.ToXmlString(true); | |
} | |
} | |
} |
This file contains 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
class Token | |
{ | |
public readonly string Value; | |
public readonly DateTime Expires; | |
public readonly byte[] Data; | |
public byte[] Signature { private set; get; } | |
public Token(string value, DateTime expires) | |
{ | |
Value = value; | |
Expires = expires; | |
using (var ms = new MemoryStream()) | |
using (var writer = new BinaryWriter(ms)) | |
{ | |
writer.Write(Expires.Ticks); | |
writer.Write(Value); | |
Data = ms.ToArray(); | |
} | |
} | |
private void Sign(string privateKey) | |
{ | |
using (var rsa = new RSACryptoServiceProvider()) | |
using (var sha1 = new SHA1CryptoServiceProvider()) | |
{ | |
rsa.FromXmlString(privateKey); | |
Signature = rsa.SignData(Data, sha1); | |
} | |
} | |
public string GetTokenString(string privateKey) | |
{ | |
if (Signature == null) | |
{ | |
Sign(privateKey); | |
} | |
return Convert.ToBase64String(Data.Concat(Signature).ToArray()); | |
} | |
public static Token FromTokenString(string tokenString, string key) | |
{ | |
var buffer = Convert.FromBase64String(tokenString); | |
var data = buffer.Take(buffer.Length - 128).ToArray(); | |
var sig = buffer.Skip(data.Length).Take(128).ToArray(); | |
using (var rsa = new RSACryptoServiceProvider()) | |
using (var sha1 = new SHA1CryptoServiceProvider()) | |
{ | |
rsa.FromXmlString(key); | |
if (rsa.VerifyData(data, sha1, sig)) | |
{ | |
using (var ms = new MemoryStream(data)) | |
using (var reader = new BinaryReader(ms)) | |
{ | |
var ticks = reader.ReadInt64(); | |
var value = reader.ReadString(); | |
var expires = new DateTime(ticks); | |
if (expires > DateTime.Now) | |
{ | |
return new Token(value, expires); | |
} | |
} | |
} | |
} | |
return null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment