using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Collections.Specialized;
private static readonly byte[] FinalBlock = new byte[0];
private static readonly byte[] NullByte = new byte[1];
private readonly Func<byte[], byte[]> _signHash;
private readonly HashAlgorithm _hashAlg;
private readonly AsymmetricAlgorithm _cryptoAlg;
public static void Main()
byte[] FinalBlock = new byte[0];
byte[] NullByte = new byte[1];
HashAlgorithm _hashAlg = HashAlgorithm.Create(HashAlgorithmName.SHA256.Name);
var url = "https://service.auth.xboxlive.com/service/authenticate";
var requestUri = new Uri(url);
var pathAndQuery = requestUri.GetComponents(UriComponents.PathAndQuery, UriFormat.SafeUnescaped);
Console.WriteLine($"pathAndQuery: {pathAndQuery}");
var signingContext = new SigningContext();
signingContext.SignVersion(4);
signingContext.SignTimestamp(130401704106544335L);
signingContext.SignElement("POST".ToUpperInvariant());
signingContext.SignElement(pathAndQuery);
var headers = new NameValueCollection();
signingContext.SignElement(headers["Authorization"] ?? string.Empty);
var fCreationTime = System.DateTime.FromFileTime(130401704106544335L);
var signature = CreateSignatureHeader(signingContext.GetSignature(), 4, 130401704106544335L);
Console.WriteLine($"Final signature header: {fCreationTime}");
public static string CreateSignatureHeader(byte[] signature, int version, long timestamp)
var bytes1 = BitConverter.GetBytes(version);
var bytes2 = BitConverter.GetBytes(timestamp);
if (BitConverter.IsLittleEndian)
Array.Reverse((Array)bytes1);
Array.Reverse((Array)bytes2);
var inArray = new byte[signature.Length + bytes1.Length + bytes2.Length];
Buffer.BlockCopy(bytes1, 0, inArray, 0, bytes1.Length);
Buffer.BlockCopy(bytes2, 0, inArray, bytes1.Length, bytes2.Length);
Buffer.BlockCopy(signature, 0, inArray, bytes1.Length + bytes2.Length, signature.Length);
Console.WriteLine($"version: {byteArrayToString(bytes1)}");
Console.WriteLine($"timestamp: {byteArrayToString(bytes2)}");
return Convert.ToBase64String(inArray);
private static string byteArrayToString(byte[] data){
var sBuilder = new StringBuilder();
for (int i = 0; i < data.Length; i++)
sBuilder.Append(data[i].ToString("x2"));
return sBuilder.ToString();
public class XstsRequest {
public string RelyingParty { get; set; }
public class SigningContext
private static readonly byte[] FinalBlock = new byte[0];
private static readonly byte[] NullByte = new byte[1];
private readonly Func<byte[], byte[]> _signHash;
private readonly HashAlgorithm _hashAlg;
private readonly AsymmetricAlgorithm _cryptoAlg;
private readonly ECDsa ecdsa;
private const string CertPem = @"-----BEGIN CERTIFICATE-----
MIIB4DCCAYWgAwIBAgIUB3BSK19+3lolhm1mgjtlhKNgEVIwCgYIKoZIzj0EAwIw
RTELMAkGA1UEBhMCRlIxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMjAzMTgxMDM0NTFaFw0yMzAzMTMx
MDM0NTFaMEUxCzAJBgNVBAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwWTATBgcqhkjOPQIBBggqhkjO
PQMBBwNCAARvWRDpMRgmg4Z0+YFbl/YqGKm5OyW/HcxhbnZ7ri3hP2634jwGLKgh
fLK0aUtnnGZCLu7yzu3Ahp9ReISaMoqKo1MwUTAdBgNVHQ4EFgQUJk1UUvYLc5Is
O4bBiIsaioiBFPUwHwYDVR0jBBgwFoAUJk1UUvYLc5IsO4bBiIsaioiBFPUwDwYD
VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNJADBGAiEAkr75umdg8IUdXtrfljTD
ArcQTBUgzJpaNbHZnGU7J6ICIQCA7SEigtq1bteLBMkAx6K95v2AGwzMU19JDxcP
-----END CERTIFICATE-----";
private const string EccPem = @"-----BEGIN EC PRIVATE KEY-----
MHcCAQEEILFFsR5KbKIcBp7cEBJzIm8ZxPvTQMTvhVhFtLT6ZJi+oAoGCCqGSM49
AwEHoUQDQgAEb1kQ6TEYJoOGdPmBW5f2KhipuTslvx3MYW52e64t4T9ut+I8Biyo
IXyytGlLZ5xmQi7u8s7twIafUXiEmjKKig==
-----END EC PRIVATE KEY-----";
var cert = X509Certificate2.CreateFromPem(CertPem, EccPem);
var eccAlg = ECDsa.Create();
eccAlg.ImportFromPem(EccPem);
HashAlgorithmName hashAlgName = HashAlgorithmName.SHA256;
_hashAlg = HashAlgorithm.Create(hashAlgName.Name);
_signHash = eccAlg.SignHash;
public void AddBytes(byte[] buffer, int index, int count)
_hashAlg.TransformBlock(buffer, index, count, null, 0);
public void AddNullByte()
_hashAlg.TransformBlock(NullByte, 0, 1, null, 0);
public void SignVersion(int version)
var bytes = BitConverter.GetBytes(version);
if (BitConverter.IsLittleEndian)
Array.Reverse((Array)bytes);
AddBytes(bytes, 0, bytes.Length);
public void SignTimestamp(long timestamp)
var bytes = BitConverter.GetBytes(timestamp);
if (BitConverter.IsLittleEndian)
Array.Reverse((Array)bytes);
AddBytes(bytes, 0, bytes.Length);
public void SignElement(string element)
var bytes = Encoding.ASCII.GetBytes(element);
AddBytes(bytes, 0, bytes.Length);
public byte[] GetSignature()
_hashAlg.TransformFinalBlock(FinalBlock, 0, 0);
Console.WriteLine($"GetSignature signature Hash => {byteArrayToString(_hashAlg.Hash)}" );
return _signHash(_hashAlg.Hash);
GC.SuppressFinalize(this);
private void Dispose(bool disposing)
private static string byteArrayToString(byte[] data){
var sBuilder = new StringBuilder();
for (int i = 0; i < data.Length; i++)
sBuilder.Append(data[i].ToString("x2"));
return sBuilder.ToString();