[C#.NET] 使用 X509 數位電子簽章 加解密

[C#.NET] 使用 X509 數位電子簽章 加解密

上篇提到了使用X509的的憑證使用方式,請參考 [C#.NET] X509 數位電子簽章

這次便來進入主題加解密,要使用憑證來加解密,憑證必須要帶有私密金鑰,否則會無法解密,

PS.對於資安這塊實在完全不瞭解,憑證信任等等相關設定,我也不懂,問 方丈 也只是得到了些天書答案,完全不知道它講的天書是哪個章節,我只會拿憑證來加解密而已,若有憑證問題請找咱們家的 方丈

 

X509 是用RSA演算法來處理加解密的,所以邏輯完全跟之前的帖子一樣,請參考:

[C#.NET] 字串及檔案,利用 RSA 演算法加解密

[C#.NET] RSA的長度限制

 

重點是這句:var rsaCrypto = (RSACryptoServiceProvider)this.Certificate.PublicKey.Key;

還記得RSA的限制吧?所以一樣採用分段加密,加密邏輯如下:


{
    if (OriginalData == null) throw new ArgumentNullException("OriginalData");
    if (OriginalData.Length <= 0) throw new ArgumentOutOfRangeException("OriginalData");
    if (this.Certificate == null)
    {
        //使用預設憑證
        var defaultCert = RsaAndX509.Properties.Resources.artag_certnew;
        this.Certificate = new X509Certificate2(defaultCert, "pass@w0rd1");
    }
    var rsaCrypto = (RSACryptoServiceProvider)this.Certificate.PublicKey.Key;

    int bufferSize = (rsaCrypto.KeySize / 8) - 11;
    byte[] buffer = new byte[bufferSize];
    //分段加密
    using (MemoryStream input = new MemoryStream(OriginalData))
    using (MemoryStream ouput = new MemoryStream())
    {
        while (true)
        {
            int readLine = input.Read(buffer, 0, bufferSize);
            if (readLine <= 0)
            {
                break;
            }
            byte[] temp = new byte[readLine];
            Array.Copy(buffer, 0, temp, 0, readLine);
            byte[] encrypt = rsaCrypto.Encrypt(temp, false);
            ouput.Write(encrypt, 0, encrypt.Length);
        }
        return ouput.ToArray();
    }
}

 

解密,重點是這句:var rsaCrypto = (RSACryptoServiceProvider)this.Certificate.PrivateKey;


{
    if (EncryptDada == null) throw new ArgumentNullException("EncryptDada");
    if (EncryptDada.Length <= 0) throw new ArgumentOutOfRangeException("EncryptDada");

    if (this.Certificate == null)
    {
        //使用預設憑證
        var defaultCert = RsaAndX509.Properties.Resources.artag_certnew;
        this.Certificate = new X509Certificate2(defaultCert, "pass@w0rd1");
    }

    var rsaCrypto = (RSACryptoServiceProvider)this.Certificate.PrivateKey;

    int keySize = rsaCrypto.KeySize / 8;
    byte[] buffer = new byte[keySize];

    using (MemoryStream input = new MemoryStream(EncryptDada))
    using (MemoryStream output = new MemoryStream())
    {
        while (true)
        {
            int readLine = input.Read(buffer, 0, keySize);
            if (readLine <= 0)
            {
                break;
            }
            byte[] temp = new byte[readLine];
            Array.Copy(buffer, 0, temp, 0, readLine);
            byte[] decrypt = rsaCrypto.Decrypt(temp, false);
            output.Write(decrypt, 0, decrypt.Length);
        }
        return output.ToArray();
    }
}


 
完整範例如下:

{
    public class RsaCryptService
    {
        private Encoding _encoding = Encoding.UTF8;
 
        public Encoding Encoding
        {
            get { return _encoding; }
            set { _encoding = value; }
        }
 
        private X509ContentType _x509ContentType = X509ContentType.Cert;
 
        public X509ContentType X509ContentType
        {
            get { return _x509ContentType; }
            set { _x509ContentType = value; }
        }
 
        private StoreName _storeName = StoreName.My;
 
        public StoreName StoreName
        {
            get { return _storeName; }
            set { _storeName = value; }
        }
 
        private StoreLocation _locationr = StoreLocation.CurrentUser;
 
        public StoreLocation Location
        {
            get { return _locationr; }
            set { _locationr = value; }
        }
 
        private X509Certificate2 _certificate;
 
        public X509Certificate2 Certificate
        {
            get { return _certificate; }
            private set { _certificate = value; }
        }
 
        public X509Certificate2 CreateCertificate(string CertFile, string Password)
        {
            if (CertFile == null) throw new ArgumentNullException("CertFile");
            if (Password == null) throw new ArgumentNullException("Password");
            if (string.IsNullOrEmpty(Password))
            {
                this.Certificate = new X509Certificate2(CertFile);
            }
            else
            {
                this.Certificate = new X509Certificate2(CertFile, Password);
            }
 
            return this.Certificate;
        }
 
        public X509Certificate2 ImportCertificate(string CertFile, string Password)
        {
            if (CertFile == null) throw new ArgumentNullException("CertFile");
            if (Password == null) throw new ArgumentNullException("Password");
            var cert = this.CreateCertificate(CertFile, Password);
            if (cert == null) return null;
 
            X509Store store = new X509Store(this.StoreName, this.Location);
            store.Open(OpenFlags.ReadWrite);
            store.Add(cert);
            store.Close();
            return cert;
        }
 
        public bool ExportCertificate(string CertSubjectName, string ExportFile)
        {
            if (CertSubjectName == null) throw new ArgumentNullException("CertSubjectName");
            if (ExportFile == null) throw new ArgumentNullException("ExportFile");
            return ExportCertificate(CertSubjectName, null, ExportFile);
        }
 
        public bool ExportCertificate(string CertSubjectName, string Password, string ExportFile)
        {
            if (CertSubjectName == null) throw new ArgumentNullException("CertSubjectName");
            if (ExportFile == null) throw new ArgumentNullException("ExportFile");
            X509Store store = new X509Store(this.StoreName, this.Location);
            store.Open(OpenFlags.ReadOnly);
            FileStream fileStream = null;
            try
            {
                fileStream = new FileStream(ExportFile, FileMode.Create, FileAccess.Write);
                foreach (X509Certificate2 cert in store.Certificates)
                {
                    if (cert.Subject == CertSubjectName)
                    {
                        byte[] CertByte;
 
                        if (string.IsNullOrEmpty(Password))
                        {
                            CertByte = cert.Export(X509ContentType);
                        }
                        else
                        {
                            CertByte = cert.Export(X509ContentType, Password);
                        }
                        fileStream.Write(CertByte, 0, CertByte.Length);
                        return true;
                    }
                }
            }
            finally
            {
                if (fileStream != null) fileStream.Dispose();
                store.Close();
            }
            return false;
        }
 
        public void VerifyCertificate(X509Certificate2 Cert)
        {
            if (Cert == null) throw new ArgumentNullException("Ccert");
            X509Chain chain = new X509Chain();
 
            chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
            //RevocationStatusUnknown
            chain.Build(Cert);
 
            if (chain.ChainStatus.Length > 0)
            {
                StringBuilder builder = new StringBuilder();
                builder.AppendLine("憑證檢查錯誤:/r/n");
                foreach (X509ChainStatus status in chain.ChainStatus)
                {
                    builder.Append(string.Format("{0}={1}/r/n", status.Status, status.StatusInformation));
                }
 
                throw new ApplicationException(builder.ToString());
            }
            if (Cert.NotAfter <= DateTime.Now)
            {
                throw new ApplicationException(string.Format("憑証過期"));
            }
        }
 
        public byte[] Encryptor(byte[] OriginalData)
        {
            if (OriginalData == null) throw new ArgumentNullException("OriginalData");
            if (OriginalData.Length <= 0) throw new ArgumentOutOfRangeException("OriginalData");
            if (this.Certificate == null)
            {
                //使用資源檔裡的預設憑證
                var defaultCert = RsaAndX509.Properties.Resources.artag_certnew;
                this.Certificate = new X509Certificate2(defaultCert, "pass@w0rd1");
            }
            var rsaCrypto = (RSACryptoServiceProvider)this.Certificate.PublicKey.Key;
 
            int bufferSize = (rsaCrypto.KeySize / 8) - 11;
            byte[] buffer = new byte[bufferSize];
            //分段加密
            using (MemoryStream input = new MemoryStream(OriginalData))
            using (MemoryStream ouput = new MemoryStream())
            {
                while (true)
                {
                    int readLine = input.Read(buffer, 0, bufferSize);
                    if (readLine <= 0)
                    {
                        break;
                    }
                    byte[] temp = new byte[readLine];
                    Array.Copy(buffer, 0, temp, 0, readLine);
                    byte[] encrypt = rsaCrypto.Encrypt(temp, false);
                    ouput.Write(encrypt, 0, encrypt.Length);
                }
                return ouput.ToArray();
            }
        }
 
        public string EncryptString(string OriginalString)
        {
            if (OriginalString == null) throw new ArgumentNullException("OriginalString");
 
            var originalData = this.Encoding.GetBytes(OriginalString);
            var encryptData = this.Encryptor(originalData);
            var base64 = Convert.ToBase64String(encryptData);
            return base64;
        }
 
        public void EncryptFile(string OriginalFile, string EncrytpFile)
        {
            using (FileStream originalStream = new FileStream(OriginalFile, FileMode.Open, FileAccess.Read))
            using (FileStream encrytpStream = new FileStream(EncrytpFile, FileMode.Create, FileAccess.Write))
            {
                //加密
                var dataByteArray = new byte[originalStream.Length];
                originalStream.Read(dataByteArray, 0, dataByteArray.Length);
                var encryptData = this.Encryptor(dataByteArray);
                //寫檔
                encrytpStream.Write(encryptData, 0, encryptData.Length);
            }
        }
 
        public byte[] Decryptor(byte[] EncryptDada)
        {
            if (EncryptDada == null) throw new ArgumentNullException("EncryptDada");
            if (EncryptDada.Length <= 0) throw new ArgumentOutOfRangeException("EncryptDada");
 
            if (this.Certificate == null)
            {
                //使用資源檔裡的預設憑證
                var defaultCert = RsaAndX509.Properties.Resources.artag_certnew;
                this.Certificate = new X509Certificate2(defaultCert, "pass@w0rd1");
            }
 
            var rsaCrypto = (RSACryptoServiceProvider)this.Certificate.PrivateKey;
 
            int keySize = rsaCrypto.KeySize / 8;
            byte[] buffer = new byte[keySize];
 
            using (MemoryStream input = new MemoryStream(EncryptDada))
            using (MemoryStream output = new MemoryStream())
            {
                while (true)
                {
                    int readLine = input.Read(buffer, 0, keySize);
                    if (readLine <= 0)
                    {
                        break;
                    }
                    byte[] temp = new byte[readLine];
                    Array.Copy(buffer, 0, temp, 0, readLine);
                    byte[] decrypt = rsaCrypto.Decrypt(temp, false);
                    output.Write(decrypt, 0, decrypt.Length);
                }
                return output.ToArray();
            }
        }
 
        public string DecryptString(string EncryptString)
        {
            if (EncryptString == null) throw new ArgumentNullException("EncryptString");
            var encryptData = Convert.FromBase64String(EncryptString);
            var decryptData = this.Decryptor(encryptData);
            var decryptString = this.Encoding.GetString(decryptData);
            return decryptString;
        }
 
        public void DecryptFile(string EncrytpFile, string DecrytpFile)
        {
            if (EncrytpFile == null) throw new ArgumentNullException("EncrytpFile");
            if (DecrytpFile == null) throw new ArgumentNullException("DecrytpFile");
            using (FileStream encrytpStream = new FileStream(EncrytpFile, FileMode.Open, FileAccess.Read))
            using (FileStream decrytpStream = new FileStream(DecrytpFile, FileMode.Create, FileAccess.Write))
            {
                //解密
                var dataByteArray = new byte[encrytpStream.Length];
                encrytpStream.Read(dataByteArray, 0, dataByteArray.Length);
                var decryptData = this.Decryptor(dataByteArray);
                //寫檔
                decrytpStream.Write(decryptData, 0, decryptData.Length);
            }
        }
    }
}


 
字串加密單元測試:

        public void EncryptStringTest()
        {
            RsaCryptService target = new RsaCryptService();
            string OriginalString =
@"
你同事剛開完會走出來,你想知道結果如何?你的朋友願意幫你忙嗎?你的部屬是否對你做的新安排感到滿意?《看穿人心的問話術》教你透過五大技巧探知對方的真實感受,不論他們的口風有多緊!
技巧一:他願意幫忙嗎?請用「得寸進尺」法
研究顯示,在你想請某人幫你一個忙之前,先對他提出一個簡單容易達成的小小要求,在他幫忙之後,隨即給予感謝或表彰。事後你再提出原本要請他做的事情,或是尋求他更多的幫助,他就比較有可能會全盤接受。
佛德門和佛瑞賽(Freedman and Fraser)曾經提到一項實驗,他們將受訪住戶隨機分成兩組,他們直接向第一組住戶提出請求,要在他們在前院樹立一個大型的「小心駕駛」告示牌,結果只有百分之十七的人同意。至於第二組住戶,則先被要求在窗戶上貼一個三吋大小,上面寫著「當個安全駕駛人」的標示,幾乎所有的住戶都同意接受。幾週後,測試者再向第二組住戶提出請求,要他們跟第一組住戶一樣,在前院設置大型標示,最後竟有高達百分之七十六的住戶同意此項要求。
技巧二:他贊成還是反對?改問他心情好不好
想知道他的真實想法,可以問他不相干的問題。如果他的話中似乎隱含著好兆頭的跡象,那麼就表示他對此事看法樂觀。然而,若他說這件事似乎是負面結果的前兆,那麼就表示他的看法頗為悲觀。
例如,你的同事約翰最近在為一個新的秘密計畫爭取支援,剛剛開完相關會議走出來。他不能透露任何會議細節,以避免別人從他的神情中,窺探公司對其計畫的支持程度,他一直盡可能地維持面無表情的狀態。
";
            string expected = string.Empty;
            string actual;
            actual = target.EncryptString(OriginalString);
            Assert.AreNotEqual(expected, actual);
        }


 
字串解密單元測試:

        public void DecryptStringTest()
        {
            RsaCryptService target = new RsaCryptService();
            string EncryptString = "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";
            string expected =
@"
你同事剛開完會走出來,你想知道結果如何?你的朋友願意幫你忙嗎?你的部屬是否對你做的新安排感到滿意?《看穿人心的問話術》教你透過五大技巧探知對方的真實感受,不論他們的口風有多緊!
技巧一:他願意幫忙嗎?請用「得寸進尺」法
研究顯示,在你想請某人幫你一個忙之前,先對他提出一個簡單容易達成的小小要求,在他幫忙之後,隨即給予感謝或表彰。事後你再提出原本要請他做的事情,或是尋求他更多的幫助,他就比較有可能會全盤接受。
佛德門和佛瑞賽(Freedman and Fraser)曾經提到一項實驗,他們將受訪住戶隨機分成兩組,他們直接向第一組住戶提出請求,要在他們在前院樹立一個大型的「小心駕駛」告示牌,結果只有百分之十七的人同意。至於第二組住戶,則先被要求在窗戶上貼一個三吋大小,上面寫著「當個安全駕駛人」的標示,幾乎所有的住戶都同意接受。幾週後,測試者再向第二組住戶提出請求,要他們跟第一組住戶一樣,在前院設置大型標示,最後竟有高達百分之七十六的住戶同意此項要求。
技巧二:他贊成還是反對?改問他心情好不好
想知道他的真實想法,可以問他不相干的問題。如果他的話中似乎隱含著好兆頭的跡象,那麼就表示他對此事看法樂觀。然而,若他說這件事似乎是負面結果的前兆,那麼就表示他的看法頗為悲觀。
例如,你的同事約翰最近在為一個新的秘密計畫爭取支援,剛剛開完相關會議走出來。他不能透露任何會議細節,以避免別人從他的神情中,窺探公司對其計畫的支持程度,他一直盡可能地維持面無表情的狀態。
";
            string actual;
            actual = target.DecryptString(EncryptString);
            Assert.AreEqual(expected, actual);
        }


 
測試結果如下:
SNAGHTMLacb03c0

 

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo