Skip to content

Instantly share code, notes, and snippets.

@benlesh
Created August 15, 2012 15:09
Show Gist options
  • Save benlesh/3360908 to your computer and use it in GitHub Desktop.
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
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);
}
}
}
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