private static unsafe TstInfo Decode(byte[] rawData)
        {
            var really = new byte[rawData.Length];

            fixed(byte *pbData = rawData)
            {
                var decodedPtr = IntPtr.Zero;
                var cbStruct   = 0;

                try
                {
                    if (!Rfc3161TimestampWin32.CryptDecodeObjectEx(
                            Rfc3161TimestampWin32.CryptEncodingTypes.X509_ASN_ENCODING,
                            Rfc3161TimestampWin32.TIMESTAMP_INFO,
                            (IntPtr)pbData,
                            rawData.Length,
                            Rfc3161TimestampWin32.CryptDecodeObjectFlags.CRYPT_DECODE_ALLOC_FLAG |
                            Rfc3161TimestampWin32.CryptDecodeObjectFlags.CRYPT_DECODE_NOCOPY_FLAG |
                            Rfc3161TimestampWin32.CryptDecodeObjectFlags.CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG,
                            IntPtr.Zero,
                            (IntPtr)(&decodedPtr),
                            ref cbStruct))
                    {
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                    }

                    var tstInfo = ReadTstInfo(decodedPtr);

                    //fixed (byte* pbReally = really)
                    {
                        uint cbReally        = 0;
                        var  letThemEncodeIt = IntPtr.Zero;

                        if (!Rfc3161TimestampWin32.CryptEncodeObjectEx(
                                Rfc3161TimestampWin32.CryptEncodingTypes.X509_ASN_ENCODING,
                                Rfc3161TimestampWin32.TIMESTAMP_INFO,
                                decodedPtr,
                                Rfc3161TimestampWin32.CryptEncodeObjectFlags.CRYPT_ENCODE_ALLOC_FLAG,
                                IntPtr.Zero,
                                (IntPtr)(&letThemEncodeIt),
                                ref cbReally))
                        {
                            throw new CryptographicException(Marshal.GetLastWin32Error());
                        }

                        really = new byte[cbReally];
                        Marshal.Copy(letThemEncodeIt, really, 0, (int)cbReally);
                    }

                    return(tstInfo);
                }
                finally
                {
                    if (decodedPtr != IntPtr.Zero)
                    {
                        Rfc3161TimestampWin32.LocalFree(decodedPtr);
                    }
                }
            }
        }
        private static unsafe byte[] Encode(TstInfo tstInfo)
        {
            var algOid = tstInfo.HashAlgorithmId.Value;

            var policyOidBytes           = new byte[tstInfo.PolicyId.Length + 1];
            var algOidBytes              = new byte[algOid.Length + 1];
            var serialNumberBigEndian    = tstInfo.SerialNumber;
            var serialNumberLittleEndian = new byte[serialNumberBigEndian.Length];

            for (var i = 0; i < serialNumberLittleEndian.Length; i++)
            {
                serialNumberLittleEndian[i] = serialNumberBigEndian[serialNumberBigEndian.Length - i - 1];
            }

            var filetime = tstInfo.Timestamp.ToFileTime();

            fixed(byte *pbPolicyOid = policyOidBytes)
            fixed(char *pszPolicyOid    = tstInfo.PolicyId)
            fixed(byte *pbHashedMessage = tstInfo.HashedMessage)
            fixed(byte *pbSerialNumber  = serialNumberLittleEndian)
            fixed(char *pszAlgOid       = algOid)
            fixed(byte *pbAlgOid        = algOidBytes)
            fixed(byte *pbNonce         = tstInfo.Nonce)
            fixed(byte *pbTsaName       = tstInfo.TsaName)
            {
                Encoding.ASCII.GetBytes(pszPolicyOid, tstInfo.PolicyId.Length, pbPolicyOid, policyOidBytes.Length);
                Encoding.ASCII.GetBytes(pszAlgOid, algOid.Length, pbAlgOid, algOidBytes.Length);

                var info = new Rfc3161TimestampWin32.CRYPT_TIMESTAMP_INFO
                {
                    dwVersion      = tstInfo.Version,
                    pszTSAPolicyId = (IntPtr)pbPolicyOid,
                    fOrdering      = tstInfo.IsOrdering,
                };

                var accuracy = default(Rfc3161TimestampWin32.CRYPT_TIMESTAMP_ACCURACY);

                info.HashAlgorithm.pszOid = (IntPtr)pbAlgOid;
                info.HashedMessage.cbData = (uint)tstInfo.HashedMessage.Length;
                info.HashedMessage.pbData = (IntPtr)pbHashedMessage;
                info.SerialNumber.cbData  = (uint)serialNumberLittleEndian.Length;
                info.SerialNumber.pbData  = (IntPtr)pbSerialNumber;

                info.ftTime.dwLowDateTime  = (int)(filetime & 0xFFFFFFFF);
                info.ftTime.dwHighDateTime = (int)(filetime >> 32);

                if (tstInfo.AccuracyInMicroseconds.HasValue)
                {
                    var val = tstInfo.AccuracyInMicroseconds.Value;
                    val = Math.DivRem(val, 1000, out var rem);
                    accuracy.dwMicros = (int)rem;
                    val = Math.DivRem(val, 1000, out rem);
                    accuracy.dwMillis = (int)rem;

                    if (val > int.MaxValue)
                    {
                        Debug.Fail($"accuracy value {tstInfo.AccuracyInMicroseconds.Value} had seconds component {val}, which should have been stopped");
                        throw new CryptographicException();
                    }

                    accuracy.dwSeconds = (int)val;
                    info.pvAccuracy    = (IntPtr)(&accuracy);
                }

                if (tstInfo.Nonce != null)
                {
                    info.Nonce.cbData = (uint)tstInfo.Nonce.Length;
                    info.Nonce.pbData = (IntPtr)pbNonce;
                }

                if (tstInfo.TsaName != null)
                {
                    info.Tsa.cbData = (uint)tstInfo.TsaName.Length;
                    info.Tsa.pbData = (IntPtr)pbTsaName;
                }

                if (tstInfo.Extensions != null)
                {
                    throw new NotImplementedException();
                }

                var  encodedDataPtr = IntPtr.Zero;
                uint cbEncoded      = 0;

                try
                {
                    if (!Rfc3161TimestampWin32.CryptEncodeObjectEx(
                            Rfc3161TimestampWin32.CryptEncodingTypes.X509_ASN_ENCODING,
                            Rfc3161TimestampWin32.TIMESTAMP_INFO,
                            (IntPtr)(&info),
                            Rfc3161TimestampWin32.CryptEncodeObjectFlags.CRYPT_ENCODE_ALLOC_FLAG,
                            IntPtr.Zero,
                            (IntPtr)(&encodedDataPtr),
                            ref cbEncoded))
                    {
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                    }

                    var encoded = new byte[cbEncoded];
                    Marshal.Copy(encodedDataPtr, encoded, 0, (int)cbEncoded);
                    return(encoded);
                }
                finally
                {
                    if (encodedDataPtr != IntPtr.Zero)
                    {
                        Rfc3161TimestampWin32.LocalFree(encodedDataPtr);
                    }
                }
            }
        }
        private static unsafe byte[] Encode(DataType data)
        {
            IntPtr algorithmOidPtr = IntPtr.Zero;
            IntPtr policyOidPtr    = IntPtr.Zero;
            IntPtr encodedDataPtr  = IntPtr.Zero;

            try
            {
                algorithmOidPtr = Marshal.StringToHGlobalAnsi(data._hashAlgorithm.Value);
                policyOidPtr    = Marshal.StringToHGlobalAnsi(data._requestedPolicyId?.Value);

                Rfc3161TimestampWin32.CRYPT_TIMESTAMP_REQUEST request = new Rfc3161TimestampWin32.CRYPT_TIMESTAMP_REQUEST
                {
                    dwVersion      = data._version,
                    fCertReq       = data._requestSignerCertificate,
                    pszTSAPolicyId = policyOidPtr,
                };

                request.HashAlgorithm.pszOid = algorithmOidPtr;
                request.HashedMessage.cbData = (uint)data._hash.Length;
                request.Nonce.cbData         = (uint)(data._nonce?.Length ?? 0);

                fixed(byte *hashPtr = data._hash)
                fixed(byte *noncePtr = data._nonce)
                {
                    request.HashedMessage.pbData = (IntPtr)hashPtr;
                    request.Nonce.pbData         = (IntPtr)noncePtr;

                    uint cbEncoded = 0;

                    if (!Rfc3161TimestampWin32.CryptEncodeObjectEx(
                            Rfc3161TimestampWin32.CryptEncodingTypes.X509_ASN_ENCODING,
                            Rfc3161TimestampWin32.TIMESTAMP_REQUEST,
                            (IntPtr)(&request),
                            Rfc3161TimestampWin32.CryptEncodeObjectFlags.CRYPT_ENCODE_ALLOC_FLAG,
                            IntPtr.Zero,
                            (IntPtr)(&encodedDataPtr),
                            ref cbEncoded))
                    {
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                    }

                    byte[] encoded = new byte[cbEncoded];
                    Marshal.Copy(encodedDataPtr, encoded, 0, (int)cbEncoded);
                    return(encoded);
                }
            }
            finally
            {
                if (algorithmOidPtr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(algorithmOidPtr);
                }

                if (policyOidPtr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(policyOidPtr);
                }

                if (encodedDataPtr != IntPtr.Zero)
                    Rfc3161TimestampWin32.LocalFree(encodedDataPtr); }
            }