public override void ExportPrivateKey(PrivateKey pk, EncodingFormat fmt, Stream target)
        {
            var rsaPk = pk as CeRsaPrivateKey;

            if (rsaPk == null)
            {
                throw new NotSupportedException("unsupported private key type");
            }

            var cePk = new CERTENROLLLib.CX509PrivateKey();

            // MS_DEF_PROV
            //cePk.ProviderName = "Microsoft Base Cryptographic Provider";
            cePk.ProviderName = "Microsoft Enhanced Cryptographic Provider v1.0";

            // Don't store in the machine's local cert store and allow exporting of private key
            cePk.MachineContext = false;
            cePk.ExportPolicy   = CERTENROLLLib.X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_FLAG;



            cePk.Import(BCRYPT_PRIVATE_KEY_BLOB, rsaPk.Exported);

            if (fmt == EncodingFormat.PEM)
            {
                var pem = cePk.Export(BCRYPT_PRIVATE_KEY_BLOB,
                                      CERTENROLLLib.EncodingType.XCN_CRYPT_STRING_BASE64HEADER);
                var pemBytes = Encoding.UTF8.GetBytes(pem);
                target.Write(pemBytes, 0, pemBytes.Length);
            }
            else if (fmt == EncodingFormat.DER)
            {
                // TODO: Verify this is DER, not quite sure
                var der = cePk.Export(BCRYPT_PRIVATE_KEY_BLOB,
                                      CERTENROLLLib.EncodingType.XCN_CRYPT_STRING_BINARY);
                var derBytes = new byte[der.Length];
                for (int i = 0; i < derBytes.Length; ++i)
                {
                    derBytes[i] = (byte)der[i];
                }
                target.Write(derBytes, 0, derBytes.Length);
            }
            else
            {
                throw new NotSupportedException("unsupported encoding format");
            }
        }
        // From:
        //    http://blogs.interfacett.com/selecting-a-cryptographic-key-provider-in-windows-server-2012-ad-cs
        //    https://msdn.microsoft.com/en-us/library/windows/desktop/aa386983(v=vs.85).aspx
        //
        // Microsoft Base Smart Card Crypto Provider
        // Microsoft Enhanced Cryptographic Provider v1.0
        // ECDA_P256#Microsoft Smart Card Key Storage Provider
        // ECDA_P521#Microsoft Smart Card Key Storage Provider
        // RSA#Microsoft Software Key Storage Provider
        // Microsoft Base Cryptographic Provider v1.0
        // ECDA_P256#Microsoft Software Key Storage Provider
        // ECDA_P521#Microsoft Software Key Storage Provider
        // Microsoft Strong Cryptographic Provider
        // ECDA_P384#Microsoft Software Key Storage Provider
        // Microsoft Base DSS Cryptographic Provider
        // RSA#Microsoft Smart Card Key Storage Provider
        // DSA#Microsoft Software Key Storage Provider
        // ECDA_P384#Microsoft Smart Card Key Storage Provider


        public override PrivateKey GeneratePrivateKey(PrivateKeyParams pkp)
        {
            var rsaPkp = pkp as RsaPrivateKeyParams;
            var ecPkp  = pkp as EcPrivateKeyParams;

            var algId = new CERTENROLLLib.CObjectId();

            if (rsaPkp != null)
            {
                var oid = new System.Security.Cryptography.Oid("RSA");
                algId.InitializeFromValue(oid.Value);
            }
            else if (ecPkp != null)
            {
                throw new NotImplementedException("EC keys not implemented YET!");
            }
            else
            {
                throw new NotSupportedException("unsupported private key parameters type");
            }


            var cePk = new CERTENROLLLib.CX509PrivateKey();

            // MS_DEF_PROV
            //cePk.ProviderName = "Microsoft Base Cryptographic Provider";
            cePk.ProviderName = "Microsoft Enhanced Cryptographic Provider v1.0";

            //cePk.ProviderType = CERTENROLLLib.X509ProviderType.XCN_PROV_RSA_FULL;
            cePk.Algorithm = algId;
            cePk.KeySpec   = CERTENROLLLib.X509KeySpec.XCN_AT_KEYEXCHANGE;
            cePk.Length    = rsaPkp.NumBits;

            // Don't store in the machine's local cert store and allow exporting of private key
            cePk.MachineContext = false;
            cePk.ExportPolicy   = CERTENROLLLib.X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_FLAG;
            cePk.Create();

            var pk = new CeRsaPrivateKey(rsaPkp.NumBits, null, null)
            {
                Exported = cePk.Export(BCRYPT_PRIVATE_KEY_BLOB),
            };

            return(pk);
        }
        public override PrivateKey ImportPrivateKey <PK>(EncodingFormat fmt, Stream source)
        {
            if (typeof(PK) == typeof(RsaPrivateKey))
            {
                byte[] keyBytes;
                string encodedKey;
                CERTENROLLLib.EncodingType encodingType;

                using (var ms = new MemoryStream())
                {
                    source.CopyTo(ms);
                    keyBytes = ms.ToArray();
                }

                switch (fmt)
                {
                case EncodingFormat.PEM:
                    encodedKey   = Encoding.UTF8.GetString(keyBytes);
                    encodingType = CERTENROLLLib.EncodingType.XCN_CRYPT_STRING_ANY;
                    break;

                case EncodingFormat.DER:
                    var buff = new StringBuilder();
                    for (int i = 0; i < keyBytes.Length; ++i)
                    {
                        buff.Append((char)keyBytes[i]);
                    }
                    encodedKey   = buff.ToString();
                    encodingType = CERTENROLLLib.EncodingType.XCN_CRYPT_STRING_BINARY;
                    break;

                default:
                    throw new NotSupportedException("unsupported encoding format");
                }

                var cePk = new CERTENROLLLib.CX509PrivateKey();

                // MS_DEF_PROV
                //cePk.ProviderName = "Microsoft Base Cryptographic Provider";
                //cePk.ProviderName = "Microsoft Enhanced Cryptographic Provider v1.0";
                cePk.ProviderName = "Microsoft Strong Cryptographic Provider";

                // Don't store in the machine's local cert store and allow exporting of private key
                cePk.MachineContext = false;
                cePk.ExportPolicy   = CERTENROLLLib.X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_FLAG;


                cePk.Import(BCRYPT_PRIVATE_KEY_BLOB, encodedKey, encodingType);

                var pk = new CeRsaPrivateKey(cePk.Length, null, null)
                {
                    Exported = cePk.Export(BCRYPT_PRIVATE_KEY_BLOB),
                };

                return(pk);
            }
            else
            {
                throw new NotSupportedException("unsupported private key type");
            }
        }