Пример #1
0
        /// <summary>
        /// Lists the thumbprint value for each certificate in the specified store location which include "Key Encipherment" in its Key Usage extension
        /// </summary>
        /// <param name="Context">Store location from which to list certificate details (Either <see cref="X509Context.UserReadOnly"/> or <see cref="X509Context.SystemReadOnly"/>)</param>
        /// <param name="allowExpired">If set to True, expired certificates will be included in the output (Note that .NET will not perform cryptographic operations using a certificate which is not within its validity period)</param>
        /// <returns>A string expression listing all available certificate thumbprints and their expiration dates</returns>
        /// <example>
        /// <code>
        /// string availableCerts = <see cref="X509Utils"/>.<see cref="ListCerts"/>(<see cref="X509Context.UserReadOnly"/>);
        /// </code>
        /// </example>
        public static string ListCerts(X509Context Context = null, bool allowExpired = false)
        {
            if (Context == null)
            {
                Context = X509Context.UserReadOnly;
            }

            string output     = "Key Encipherment Certificates found:\r\n\r\n";
            bool   firstAdded = false;

            X509Store store = new X509Store(Context.Location);

            store.Open(OpenFlags.ReadOnly);
            foreach (X509Certificate2 cert in store.Certificates)
            {
                if (X509CryptoAgent.IsUsable(cert, allowExpired))
                {
                    firstAdded = true;
                    output    += cert.Subject + "\t" +
                                 string.Format("Expires {0}", cert.NotAfter.ToShortDateString()) + "\t" +
                                 cert.Thumbprint + "\r\n";
                }
            }

            if (!firstAdded)
            {
                output += "None.\r\n";
            }

            return(output);
        }
Пример #2
0
 /// <summary>
 /// Encrypts the specified plaintext expression
 /// </summary>
 /// <param name="thumbprint">The thumbprint of the certificate to use for encryption</param>
 /// <param name="plaintext">The plaintext expression to encrypt</param>
 /// <param name="Context">The certificate store where the encryption certificate resides</param>
 /// <param name="verbose">True enables verbose logging</param>
 /// <returns></returns>
 /// <example>
 /// <code>
 /// string thumbprint = @"ccdc673c40ebb2a433300c0c8a2ba6f443da5688";
 /// <see cref="X509Context"/> certStore = <see cref="X509Context"/>.<see cref="X509Context.UserReadOnly"/>;
 /// string plaintext = @"Please encrypt this";
 /// string ciphertext = <see cref="X509Utils"/>.EncryptText(thumbprint, plaintext, certStore);
 /// </code>
 /// </example>
 public static string EncryptText(string thumbprint, string plaintext, X509Context Context, bool verbose = false)
 {
     using (X509CryptoAgent cryptoAgent = new X509CryptoAgent(FormatThumbprint(thumbprint), Context))
     {
         return(cryptoAgent.EncryptText(plaintext));
     }
 }
Пример #3
0
        /// <summary>
        /// Decrypts the specified Base64-encoded ciphertext expression
        /// </summary>
        /// <param name="ciphertext">The Base64-encoded ciphertext expression to be decrypted</param>
        /// <returns>A recovered plaintext string</returns>
        public string DecryptText(string ciphertext)
        {
            string plaintext = string.Empty;

            using (X509CryptoAgent Agent = new X509CryptoAgent(Thumbprint, Context))
            {
                plaintext = Agent.DecryptText(ciphertext);
            }
            return(plaintext);
        }
Пример #4
0
        /// <summary>
        /// Decrypts the specified encrypted file
        /// </summary>
        /// <param name="thumbprint">The thumbprint of the certificate corresponding to the public key used to encrypt the file</param>
        /// <param name="ciphertextFilePath">The fully-qualified path of the encrypted file</param>
        /// <param name="plaintextFilePath">The fully-qualified path in which to write the decrypted file</param>
        /// <param name="Context">The certificate store where the encryption certificate resides</param>
        /// <param name="verbose">True enables verbose logging</param>
        /// <returns>True or false depending upon whether the file decryption succeeded</returns>
        /// <example>
        /// <code>
        /// string thumbprint = @"ccdc673c40ebb2a433300c0c8a2ba6f443da5688";
        /// <see cref="X509Context"/> certStore = <see cref="X509Context"/>.<see cref="X509Context.UserReadOnly"/>;
        /// string encryptedFilePath = @"C:\Data\accounts.csv.ctx";
        /// bool success = <see cref="X509Utils"/>.DecryptFile(thumbprint, encryptedFilePath, certStore);
        /// </code>
        /// </example>
        public static bool DecryptFile(string thumbprint, string ciphertextFilePath, string plaintextFilePath, X509Context Context, bool verbose = false)
        {
            CheckForFile(ciphertextFilePath);

            File.Delete(plaintextFilePath);

            using (X509CryptoAgent cryptoAgent = new X509CryptoAgent(FormatThumbprint(thumbprint), Context))
            {
                cryptoAgent.DecryptFile(ciphertextFilePath, plaintextFilePath);
            }

            return(File.Exists(plaintextFilePath));
        }
Пример #5
0
        /// <summary>
        /// This constructor is intended to create a new X509Alias pointing to the specified encryption certificate
        /// </summary>
        /// <param name="Name">The desired identifier for the alias</param>
        /// <param name="Thumbprint">The SHA1 thumbprint of the certificate to be used for cryptographic operations. Must exist in the specified Context</param>
        /// <param name="Context">The context in which to create the alias</param>
        /// <param name="complainIfExists">If set to true, an exception is thrown if an existing alias identifier is specified for "Name"</param>
        public X509Alias(string Name, string Thumbprint, X509Context Context, bool complainIfExists)
            : this(Context)
        {
            this.Name       = Name;
            this.Thumbprint = Thumbprint;

            LoadIfExists(complainIfExists);

            if (!X509CryptoAgent.CertificateExists(Thumbprint, Context))
            {
                throw new X509CryptoCertificateNotFoundException(Thumbprint, Context);
            }
        }
Пример #6
0
 internal string Reveal(X509Alias Alias)
 {
     try
     {
         using (X509CryptoAgent Agent = new X509CryptoAgent(Alias))
         {
             return(Agent.DecryptText(Value));
         }
     }
     catch (Exception ex)
     {
         throw new X509CryptoException($"Could not decrypt secret named \"{Key}\" in Alias \"{Alias.Name}\"", ex);
     }
 }
Пример #7
0
        /// <summary>
        /// Recovers the specified encrypted file
        /// </summary>
        /// <param name="inFile">The path to the encrypted file to be recovered. Path must exist</param>
        /// <param name="outFile">The path in which to write the recovered plaintext file</param>
        /// <param name="wipeTimesToWrite">Performs n-pass forensic wipe of the disk sectors where the input file was stored.</param>
        public void DecryptFile(string inFile, string outFile, int wipeTimesToWrite = 0)
        {
            using (X509CryptoAgent Agent = new X509CryptoAgent(this))
            {
                Agent.DecryptFile(inFile, outFile);
            }

            if (!File.Exists(outFile))
            {
                throw new X509CryptoException($"Unable to decrypt the file \"{inFile}\". The plaintext file \"{outFile}\" could not be created.");
            }

            if (wipeTimesToWrite > 0)
            {
                X509Utils.WipeFile(inFile, wipeTimesToWrite);
            }
        }
Пример #8
0
        internal X509Secret(X509Alias Alias, string key, string value)
        {
            string cipherText;

            try
            {
                Key = key;

                using (X509CryptoAgent Agent = new X509CryptoAgent(Alias))
                {
                    cipherText = Agent.EncryptText(value);
                }
                Value = cipherText;
            }
            catch (Exception ex)
            {
                throw new X509CryptoException($"Could not encrypt new secret named \"{key}\" in alias \"{Alias.Name}\"", ex);
            }
        }
Пример #9
0
        /// <summary>
        /// Re-encrypts a ciphertext expression using a different certificate
        /// </summary>
        /// <param name="oldThumbprint">The thumbprint of the old certificate used for prior encryption</param>
        /// <param name="newThumbprint">The thumbprint of the new certificate to be used for re-encryption</param>
        /// <param name="ciphertext">The ciphertext expression to be re-encrypted</param>
        /// <param name="OldContext">(Optional) The X509Context where the old encryption certificate resides (Default: <see cref="X509Context"/>.<see cref="X509Context.UserReadOnly"/>)</param>
        /// <param name="NewContext">(Optional) The X509Context where the new encryption certificate resides (Default: <see cref="X509Context"/>.<see cref="X509Context.UserReadOnly"/>)</param>
        /// <param name="verbose">(Optional) True enables verbose logging (Default: false)</param>
        /// <returns>The text expression re-encrypted using the new certificate</returns>
        /// <example>
        /// <code>
        /// string oldThumbprint = @"ccdc673c40ebb2a433300c0c8a2ba6f443da5688";
        /// string newThumbprint = @"0e7e327aab74e47a702c02d90c659da1115b29f7";
        /// string ciphertext = File.ReadAllText(@"C:\data\connectionString.txt");
        /// string updatedCiphertext = <see cref="X509Utils"/>.ReEncryptText(oldThumbprint, newThumbprint, ciphertext);
        /// File.WriteAllText(@"C:\data\connectionString.txt", updatedCiphertext);
        /// </code>
        /// </example>
        public static string ReEncryptText(string oldThumbprint, string newThumbprint, string ciphertext, X509Context OldContext = null, X509Context NewContext = null, bool verbose = false)
        {
            if (OldContext == null)
            {
                OldContext = X509Context.UserReadOnly;
            }
            if (NewContext == null)
            {
                NewContext = X509Context.UserReadOnly;
            }

            using (X509CryptoAgent oldAgent = new X509CryptoAgent(FormatThumbprint(oldThumbprint), OldContext))
            {
                using (X509CryptoAgent newAgent = new X509CryptoAgent(FormatThumbprint(newThumbprint), NewContext))
                {
                    return(newAgent.EncryptText(oldAgent.DecryptText(ciphertext)));
                }
            }
        }
Пример #10
0
        /// <summary>
        /// Installs an encryption certificate and associated key pair in the specified X509Context
        /// </summary>
        /// <param name="infile">The PKCS#12 (usually with a .pfx or .p12 extension) containing the bundled certificate and key pair</param>
        /// <param name="PfxPassword">The password to unlock the PKCS#12 file</param>
        /// <param name="Context">The X509Context in which to place the certificate and key pair</param>
        /// <returns></returns>
        public static string InstallCert(string infile, SecureString PfxPassword, X509Context Context)
        {
            bool certInstalled = false;
            X509Certificate2Collection certCol = new X509Certificate2Collection();
            X509Store keyChain;
            string    thumbprint = string.Empty;

            try
            {
                certCol.Import(infile, PfxPassword.Plaintext(), X509KeyStorageFlags.PersistKeySet);
                keyChain = new X509Store(StoreName.My, Context.Location);
                keyChain.Open(OpenFlags.ReadWrite);

                foreach (X509Certificate2 cert in certCol)
                {
                    if (X509CryptoAgent.IsUsable(cert, Constants.ProbeMode))
                    {
                        keyChain.Add(cert);
                        if (Context.Index == X509Context.Indexer.SystemFull || Context.Index == X509Context.Indexer.SystemReadOnly)
                        {
                            AddIISKeyAccess(cert.Thumbprint);
                        }
                        certInstalled = true;
                        thumbprint    = cert.Thumbprint;
                        break;
                    }
                }
                if (!certInstalled)
                {
                    throw new X509CryptoException($"The PKCS#12 file {Path.GetFileName(infile).InQuotes()} did not contain a valid encryption certificate");
                }
                else
                {
                    return(thumbprint);
                }
            }
            finally
            {
                certCol  = null;
                keyChain = null;
            }
        }
Пример #11
0
        /// <summary>
        /// Encrypts the specified file
        /// </summary>
        /// <param name="thumbprint">The thumbprint of the certificate to use for encryption</param>
        /// <param name="plaintextFilePath">The fully-qualified path of the plaintext file (can be text or binary)</param>
        /// <param name="Context">(Optional) The certificate store where the encryption certificate resides (Default: <see cref="X509Context"/>.<see cref="X509Context.UserReadOnly"/>)</param>
        /// <param name="ciphertextFilePath">(Optional) The fully-qualified path in which to write the encrypted file (If not specified, the plaintext file path is appended with a ".ctx" extension)</param>
        /// <param name="verbose">(Optional) True enables verbose logging</param>
        /// <returns></returns>
        /// <example>
        /// <code>
        /// string thumbprint = @"ccdc673c40ebb2a433300c0c8a2ba6f443da5688";
        /// <see cref="X509Context"/> certStore = <see cref="X509Context"/>.<see cref="X509Context.UserReadOnly"/>
        /// string plaintextFilePath = @"C:\Data\accounts.csv";
        /// string ciphertextFilePath =
        /// bool success = <see cref="X509Utils"/>.EncryptFile(thumbprint, plaintextFilePath, certStore);
        /// </code>
        /// </example>
        public static bool EncryptFile(string thumbprint, string plaintextFilePath, X509Context Context = null, string ciphertextFilePath = "", bool verbose = false)
        {
            CheckForFile(plaintextFilePath);

            if (Context == null)
            {
                Context = X509Context.UserReadOnly;
            }

            if (string.IsNullOrEmpty(ciphertextFilePath))
            {
                ciphertextFilePath = plaintextFilePath + CRYPTO_ENCRYPTED_FILE_EXT;
            }
            File.Delete(ciphertextFilePath);

            using (X509CryptoAgent cryptoAgent = new X509CryptoAgent(FormatThumbprint(thumbprint), Context))
            {
                cryptoAgent.EncryptFile(plaintextFilePath, ciphertextFilePath);
            }

            return(File.Exists(ciphertextFilePath));
        }
Пример #12
0
        /// <summary>
        /// Updates this X509Alias to use a new encryption certificate and key pair. The old certificate and key pair must still be available to perform this operation.
        /// </summary>
        /// <param name="newThumbprint">The SHA1 thumbprint of the new encryption certificate. The certificate and associated key pair must exist and be available in the specified X509Context</param>
        /// <param name="newContext">The X509Context where the new encryption certificate and key pair is located</param>
        public void ReEncrypt(string newThumbprint, X509Context newContext = null)
        {
            if (newContext == null)
            {
                newContext = Context;
            }

            newThumbprint = newThumbprint.RemoveNonHexChars();
            if (!X509CryptoAgent.CertificateExists(newThumbprint, newContext))
            {
                throw new X509CryptoException($"A valid encryption certificate with thumbprint {newThumbprint} was not found in the {Context.Name} context");
            }

            foreach (X509Secret secret in Secrets)
            {
                secret.ReEncrypt(this, newThumbprint, newContext);
            }

            Thumbprint = newThumbprint;
            Context    = newContext;
            Commit();
        }
Пример #13
0
        internal static Dictionary <string, X509Certificate2> GetAll(X509Context Context)
        {
            Dictionary <string, X509Certificate2> Aliases   = new Dictionary <string, X509Certificate2>();
            X509Certificate2Collection            CertStore = GetCertificates(Context);

            X509Alias CurrentAlias;

            foreach (string aliasName in Context.GetAliasNames())
            {
                CurrentAlias = new X509Alias(aliasName, Context);
                if (X509CryptoAgent.CertificateExists(CurrentAlias.Thumbprint, Context))
                {
                    foreach (X509Certificate2 Cert in CertStore)
                    {
                        if (Cert.Thumbprint.Matches(CurrentAlias.Thumbprint))
                        {
                            Aliases.Add(aliasName, Cert);
                            break;
                        }
                    }
                }
            }
            return(Aliases);
        }
Пример #14
0
        /// <summary>
        /// Re-encrypts an encrypted file using a different encryption certificate
        /// </summary>
        /// <param name="oldThumbprint">The thumbprint of the old certificate used for prior encryption</param>
        /// <param name="newThumbprint">The thumbprint of the new certificate to be used for re-encryption</param>
        /// <param name="ciphertextFilePath">The fully-qualified path to the ciphertext file to be re-encrypted</param>
        /// <param name="OldContext">(Optional) The certificate store where the old encryption certificate resides (Default: <see cref="X509Context"/>.<see cref="X509Context.UserReadOnly"/>)</param>
        /// <param name="NewContext">(Optional) The certificate store where the new encryption certificate resides (Default: <see cref="X509Context"/>.<see cref="X509Context.UserReadOnly"/>)</param>
        /// <param name="verbose">(Optional) True enables verbose logging (Default: false)</param>
        /// <example>
        /// <code>
        /// string oldThumbprint = @"ccdc673c40ebb2a433300c0c8a2ba6f443da5688";
        /// string newThumbprint = @"0e7e327aab74e47a702c02d90c659da1115b29f7";
        /// string encryptedFilePath = @"C:\data\accounts.csv.ctx";
        /// <see cref="X509Utils"/>.ReEncryptFile"(oldThumbprint, newThumbprint, encryptedFilePath);
        /// </code>
        /// </example>
        public static void ReEncryptFile(string oldThumbprint, string newThumbprint, string ciphertextFilePath, X509Context OldContext = null, X509Context NewContext = null, bool verbose = false)
        {
            CheckForFile(ciphertextFilePath);

            if (OldContext == null)
            {
                OldContext = X509Context.UserReadOnly;
            }
            if (NewContext == null)
            {
                NewContext = X509Context.UserReadOnly;
            }

            byte[] hashOrig,
            hashCopy;

            string tmpCopy;

            hashOrig = Hash(ciphertextFilePath);
            tmpCopy  = string.Format(@"{0}\cryptotmp_{1}", Path.GetDirectoryName(ciphertextFilePath), Rnd(6));
            File.Copy(ciphertextFilePath, tmpCopy);
            hashCopy = Hash(tmpCopy);

            if (hashOrig.SequenceEqual(hashCopy))
            {
                File.Delete(ciphertextFilePath);
            }
            else
            {
                try { File.Delete(tmpCopy); } catch { }
                throw new Exception(string.Format("Could not back up original file \"{0}\"", ciphertextFilePath));
            }

            try
            {
                using (X509CryptoAgent oldAgent = new X509CryptoAgent(oldThumbprint.RemoveNonHexChars(), OldContext))
                {
                    byte[] data = oldAgent.DecryptFileToByteArray(tmpCopy);

                    using (X509CryptoAgent newAgent = new X509CryptoAgent(newThumbprint.RemoveNonHexChars(), NewContext))
                    {
                        newAgent.EncryptFileFromByteArray(data, ciphertextFilePath);
                    }
                }

                if (!File.Exists(ciphertextFilePath))
                {
                    throw new FileNotFoundException($"\"{ciphertextFilePath}\": File not found after cryptographic operation. Restoring original");
                }
            }
            catch (Exception ex)
            {
                if (File.Exists(ciphertextFilePath))
                {
                    if (!Hash(ciphertextFilePath).SequenceEqual(hashCopy))
                    {
                        File.Delete(ciphertextFilePath);
                        File.Copy(tmpCopy, ciphertextFilePath);
                    }
                }
                else
                {
                    File.Copy(tmpCopy, ciphertextFilePath);
                }

                throw ex;
            }
        }
Пример #15
0
 /// <summary>
 /// Re-encrypts the specified ciphertext expression using a different X509CryptoAgent
 /// </summary>
 /// <param name="ciphertext">the ciphertext expression to be re-encrypted</param>
 /// <param name="newAgent">the X509CryptoAgent to be used to perform re-encryption</param>
 /// <returns></returns>
 public string ReEncryptText(string ciphertext, X509CryptoAgent newAgent)
 {
     return(newAgent.EncryptText(DecryptText(ciphertext)));
 }
Пример #16
0
 /// <summary>
 /// Exports the encryption certificate contained in this alias to a Base64-encoded text file. The private key is not exported.
 /// </summary>
 /// <param name="path">The fully-qualified path where the export file should be written</param>
 public void ExportCert(string path)
 {
     X509CryptoAgent.ExportCert(Thumbprint, Context, path);
 }