.net C#使用私鑰sign公鑰驗證 驗證JWS signature data

回顧:項目數據安全需要,對數據使用私鑰簽名,公鑰驗證。'RSA-SHA256'加密方式。

1.   讀取證書有兩種方法,第一種是直接把.pfx 安裝到server裏直接然後code裏直接讀取,第二種是直接根據證書物理物理路徑和密碼直接讀取證書信息。推薦第一種會速度更快一些。 第一種,從server讀取證書,可以根據subject名字,也可以導入時設置friendly name,查找該證書,然後一定要在管理key的屬性中給iis_iusrs讀取操作權限。不然private key 沒有權限讀取,會有error. 

        public string SignatureFormatter(string privateKeyPath, string SignatureData, string certPassword)
        {                                              //第一種                                                                                       //第二種

            X509Certificate2 c3 = DataCertificate.GetCertificateFromStore("證書subject");//new X509Certificate2(privateKeyPath, certPassword, X509KeyStorageFlags.Exportable);

            string keyPrivate3 = c3.PrivateKey.ToXmlString(true);
            byte[] signData = System.Text.Encoding.UTF8.GetBytes(SignatureData); 
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
            RSA.FromXmlString(keyPrivate3);
            byte[] inArray = RSA.SignData(signData, CryptoConfig.MapNameToOID("SHA256"));
            return Convert.ToBase64String(inArray);
        }

 public static X509Certificate2 GetCertificateFromStore(string subjectName)
            {
                subjectName = "CN=" + subjectName;
                X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
                store.Open(OpenFlags.ReadOnly);
                X509Certificate2Collection storecollection = (X509Certificate2Collection)store.Certificates;
                foreach (X509Certificate2 x509 in storecollection)
                {
                    if (x509.Subject.StartsWith(subjectName))
                    {
                        return x509;
                    }
                }
                store.Close();
                store = null;
                storecollection = null;
                return null;
            }

2. 證書導入server.

 在運行中輸入,mmc, 到證書管理控制檯,工具欄file->add/remove snap-in->選擇證書 本地電腦賬戶。然後導入pfx 或者 cert 證書。

 



3.驗證簽名。從第一步生成的signature,使用public key進行驗證。我試了這兩種方法都成功的。 parametersStr 是做sign之前的數據。就是元數據與signature進行比對。如果驗證成功就會返回true。

                //byte[] DeFormaterSingature = Convert.FromBase64String(signature);
                //X509Certificate2 c3 = DataCertificate.GetCertificateFromStore("證書subject")
                //verify signature method 1 
                //RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
                //var publicKey = c3.PublicKey.Key.ToXmlString(false);
                //RSA.FromXmlString(publicKey);
                //RSAParameters rasPara = RSA.ExportParameters(true);
                //var test1 = RSA.VerifyData(Encoding.Unicode.GetBytes(parametersStr), "SHA256", DeFormaterSingature);

                // verify signature method 2
                //var key = (RSACryptoServiceProvider)c3.PublicKey.Key;
                //var test2 = key.VerifyData(System.Text.Encoding.Unicode.GetBytes(parametersStr), CryptoConfig.MapNameToOID("SHA256"), DeFormaterSingature);


4. 驗證JWS signature. 因爲項目傳回來的是jws(json web signature)格式的數據。https://tools.ietf.org/html/rfc7515 這是介紹可以瞭解。

格式像這樣,分三段,第一部分是頭,是加密類型,第二部分是json數據,第三部分是返回的signature的。我們需要用第三方給的公鑰進行驗證。當然不驗證也是可以拿到數據,但是爲了安全你選擇吧。

     eyJhbGciOiJFUzI1NiJ9
     .
     eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt
     cGxlLmNvbS9pc19yb290Ijp0cnVlfQ
     .
     DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSA
     pmWQxfKTUJqPP3-Kg6NU1Q

這是我的decode 代碼,token 是待解密的jws數據, keyPath是public key 證書的物理路徑。 第二部分的數據,可以直接decode 拿到json數據.

public string Decode(string token, string keyPath, bool verify = true)
        {
            string[] parts = token.Split('.');
            string header = parts[0];
            string content = parts[1];
            var jwtSignature = parts[2];
            string headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));
            string bodyJson= Encoding.UTF8.GetString(Base64UrlDecode(content));
            JObject bodyData = JObject.Parse(bodyJson);
            if (verify)
            {
                var publicCert = new X509Certificate2(keyPath);
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                rsa.FromXmlString(publicCert.PublicKey.Key.ToXmlString(false));
                SHA256 sha256 = SHA256.Create();
                byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(header + '.' + content));
                RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
                rsaDeformatter.SetHashAlgorithm("SHA256");
                if (!rsaDeformatter.VerifySignature(hash, Base64UrlDecode(jwtSignature)))
                    throw new ApplicationException(string.Format("exception - Invalid signature"));
            }
            return bodyData .ToString();
        }


如果遇到server error, 類似RSACryptoServiceProvider 不允許操作,可以設置下面 enable使用。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章