/// <summary> /// Signs the data using the SecurityPolicyUri and returns the signature. /// </summary> public static SignatureData Sign(X509Certificate2 certificate, string securityPolicyUri, byte[] dataToSign) { SignatureData signatureData = new SignatureData(); // check if nothing to do. if (dataToSign == null) { return(signatureData); } // nothing more to do if no encryption. if (String.IsNullOrEmpty(securityPolicyUri)) { return(signatureData); } // sign data. switch (securityPolicyUri) { case SecurityPolicies.Basic256: case SecurityPolicies.Basic128Rsa15: { signatureData.Algorithm = SecurityAlgorithms.RsaSha1; signatureData.Signature = RsaUtils.RsaPkcs15Sha1_Sign(new ArraySegment <byte>(dataToSign), certificate); break; } case SecurityPolicies.None: { signatureData.Algorithm = null; signatureData.Signature = null; break; } default: { throw ServiceResultException.Create( StatusCodes.BadSecurityPolicyRejected, "Unsupported security policy: {0}", securityPolicyUri); } } return(signatureData); }
/// <summary> /// Decrypts the data using RSA encryption. /// </summary> internal static byte[] Decrypt( ArraySegment <byte> dataToDecrypt, X509Certificate2 encryptingCertificate, Padding padding) { RSA rsa = null; try { rsa = encryptingCertificate.GetRSAPrivateKey(); if (rsa == null) { throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); } int plainTextSize = dataToDecrypt.Count / GetCipherTextBlockSize(rsa, padding); plainTextSize *= GetPlainTextBlockSize(encryptingCertificate, padding); byte[] buffer = new byte[plainTextSize]; ArraySegment <byte> plainText = Decrypt(dataToDecrypt, rsa, padding, new ArraySegment <byte>(buffer)); System.Diagnostics.Debug.Assert(plainText.Count == buffer.Length); // decode length. int length = 0; length += (((int)plainText.Array[plainText.Offset + 0])); length += (((int)plainText.Array[plainText.Offset + 1]) << 8); length += (((int)plainText.Array[plainText.Offset + 2]) << 16); length += (((int)plainText.Array[plainText.Offset + 3]) << 24); if (length > (plainText.Count - plainText.Offset - 4)) { throw ServiceResultException.Create(StatusCodes.BadEndOfStream, "Could not decrypt data. Invalid total length."); } byte[] decryptedData = new byte[length]; Array.Copy(plainText.Array, plainText.Offset + 4, decryptedData, 0, length); return(decryptedData); } finally { RsaUtils.RSADispose(rsa); } }
/// <summary> /// Returns the length of a RSA PKCS#1 v1.5 signature of a digest. /// </summary> internal static int GetSignatureLength(X509Certificate2 signingCertificate) { RSA rsa = null; try { rsa = signingCertificate.GetRSAPublicKey(); if (rsa == null) { throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); } return(rsa.KeySize / 8); } finally { RsaUtils.RSADispose(rsa); } }
/// <summary> /// Encrypts the data using RSA encryption. /// </summary> internal static byte[] Encrypt( byte[] dataToEncrypt, X509Certificate2 encryptingCertificate, Padding padding) { RSA rsa = null; try { rsa = encryptingCertificate.GetRSAPublicKey(); if (rsa == null) { throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); } int plaintextBlockSize = GetPlainTextBlockSize(rsa, padding); int blockCount = ((dataToEncrypt.Length + 4) / plaintextBlockSize) + 1; int plainTextSize = blockCount * plaintextBlockSize; int cipherTextSize = blockCount * GetCipherTextBlockSize(rsa, padding); byte[] plainText = new byte[plainTextSize]; // encode length. plainText[0] = (byte)((0x000000FF & dataToEncrypt.Length)); plainText[1] = (byte)((0x0000FF00 & dataToEncrypt.Length) >> 8); plainText[2] = (byte)((0x00FF0000 & dataToEncrypt.Length) >> 16); plainText[3] = (byte)((0xFF000000 & dataToEncrypt.Length) >> 24); // copy data. Array.Copy(dataToEncrypt, 0, plainText, 4, dataToEncrypt.Length); byte[] buffer = new byte[cipherTextSize]; ArraySegment <byte> cipherText = Encrypt(new ArraySegment <byte>(plainText), rsa, padding, new ArraySegment <byte>(buffer)); System.Diagnostics.Debug.Assert(cipherText.Count == buffer.Length); return(buffer); } finally { RsaUtils.RSADispose(rsa); } }
/// <summary> /// Computes an RSA/SHA256 PKCS#1 v1.5 signature. /// </summary> public static byte[] RsaPkcs15Sha256_Sign( ArraySegment <byte> dataToSign, X509Certificate2 signingCertificate) { RSA rsa = null; try { // extract the private key. rsa = signingCertificate.GetRSAPrivateKey(); if (rsa == null) { throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); } // create the signature. return(rsa.SignData(dataToSign.Array, dataToSign.Offset, dataToSign.Count, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)); } finally { RsaUtils.RSADispose(rsa); } }
/// <summary> /// Verifies an RSA/SHA1 PKCS#1 v1.5 signature. /// </summary> public static bool RsaPkcs15Sha1_Verify( ArraySegment <byte> dataToVerify, byte[] signature, X509Certificate2 signingCertificate) { RSA rsa = null; try { // extract the public key. rsa = signingCertificate.GetRSAPublicKey(); if (rsa == null) { throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); } // verify signature. return(rsa.VerifyData(dataToVerify.Array, dataToVerify.Offset, dataToVerify.Count, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)); } finally { RsaUtils.RSADispose(rsa); } }
/// <summary> /// Verifies the signature using the SecurityPolicyUri and return true if valid. /// </summary> public static bool Verify(X509Certificate2 certificate, string securityPolicyUri, byte[] dataToVerify, SignatureData signature) { // check if nothing to do. if (signature == null) { return(true); } // nothing more to do if no encryption. if (String.IsNullOrEmpty(securityPolicyUri)) { return(true); } // decrypt data. switch (securityPolicyUri) { case SecurityPolicies.Basic256: case SecurityPolicies.Basic128Rsa15: { if (signature.Algorithm == SecurityAlgorithms.RsaSha1) { return(RsaUtils.Rsa_Verify(new ArraySegment <byte>(dataToVerify), signature.Signature, certificate, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)); } throw ServiceResultException.Create( StatusCodes.BadSecurityChecksFailed, "Unexpected signature algorithm for Basic256/Basic128Rsa15: {0}\n" + "Expected signature algorithm: {1}", signature.Algorithm, SecurityAlgorithms.RsaSha1); } case SecurityPolicies.Aes128_Sha256_RsaOaep: case SecurityPolicies.Basic256Sha256: { if (signature.Algorithm == SecurityAlgorithms.RsaSha256) { return(RsaUtils.Rsa_Verify(new ArraySegment <byte>(dataToVerify), signature.Signature, certificate, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)); } throw ServiceResultException.Create( StatusCodes.BadSecurityChecksFailed, "Unexpected signature algorithm for Basic256Sha256/Aes128_Sha256_RsaOaep: {0}\n" + "Expected signature algorithm: {1}", signature.Algorithm, SecurityAlgorithms.RsaSha256); } case SecurityPolicies.Aes256_Sha256_RsaPss: { if (signature.Algorithm == SecurityAlgorithms.RsaPssSha256) { return(RsaUtils.Rsa_Verify(new ArraySegment <byte>(dataToVerify), signature.Signature, certificate, HashAlgorithmName.SHA256, RSASignaturePadding.Pss)); } throw ServiceResultException.Create( StatusCodes.BadSecurityChecksFailed, "Unexpected signature algorithm for Aes256_Sha256_RsaPss: {0}\n" + "Expected signature algorithm : {1}", signature.Algorithm, SecurityAlgorithms.RsaPssSha256); } // always accept signatures if security is not used. case SecurityPolicies.None: { return(true); } default: { throw ServiceResultException.Create( StatusCodes.BadSecurityPolicyRejected, "Unsupported security policy: {0}", securityPolicyUri); } } throw ServiceResultException.Create( StatusCodes.BadSecurityChecksFailed, "Unexpected security policy Uri: {0}", securityPolicyUri); }
/// <summary> /// Decrypts the CipherText using the SecurityPolicyUri and returns the PlainTetx. /// </summary> public static byte[] Decrypt(X509Certificate2 certificate, string securityPolicyUri, EncryptedData dataToDecrypt) { // check if nothing to do. if (dataToDecrypt == null) { return(null); } // nothing more to do if no encryption. if (String.IsNullOrEmpty(securityPolicyUri)) { return(dataToDecrypt.Data); } // decrypt data. switch (securityPolicyUri) { case SecurityPolicies.Basic256: case SecurityPolicies.Basic256Sha256: case SecurityPolicies.Aes128_Sha256_RsaOaep: { if (dataToDecrypt.Algorithm == SecurityAlgorithms.RsaOaep) { return(RsaUtils.Decrypt(new ArraySegment <byte>(dataToDecrypt.Data), certificate, RsaUtils.Padding.OaepSHA1)); } break; } case SecurityPolicies.Basic128Rsa15: { if (dataToDecrypt.Algorithm == SecurityAlgorithms.Rsa15) { return(RsaUtils.Decrypt(new ArraySegment <byte>(dataToDecrypt.Data), certificate, RsaUtils.Padding.Pkcs1)); } break; } case SecurityPolicies.Aes256_Sha256_RsaPss: { if (dataToDecrypt.Algorithm == SecurityAlgorithms.RsaOaepSha256) { return(RsaUtils.Decrypt(new ArraySegment <byte>(dataToDecrypt.Data), certificate, RsaUtils.Padding.OaepSHA256)); } break; } case SecurityPolicies.None: { if (String.IsNullOrEmpty(dataToDecrypt.Algorithm)) { return(dataToDecrypt.Data); } break; } default: { throw ServiceResultException.Create( StatusCodes.BadSecurityPolicyRejected, "Unsupported security policy: {0}", securityPolicyUri); } } throw ServiceResultException.Create( StatusCodes.BadIdentityTokenInvalid, "Unexpected encryption algorithm : {0}", dataToDecrypt.Algorithm); }
/// <summary> /// Encrypts the text using the SecurityPolicyUri and returns the result. /// </summary> public static EncryptedData Encrypt(X509Certificate2 certificate, string securityPolicyUri, byte[] plainText) { EncryptedData encryptedData = new EncryptedData(); encryptedData.Algorithm = null; encryptedData.Data = plainText; // check if nothing to do. if (plainText == null) { return(encryptedData); } // nothing more to do if no encryption. if (String.IsNullOrEmpty(securityPolicyUri)) { return(encryptedData); } // encrypt data. switch (securityPolicyUri) { case SecurityPolicies.Basic256: case SecurityPolicies.Basic256Sha256: case SecurityPolicies.Aes128_Sha256_RsaOaep: { encryptedData.Algorithm = SecurityAlgorithms.RsaOaep; encryptedData.Data = RsaUtils.Encrypt(plainText, certificate, RsaUtils.Padding.OaepSHA1); break; } case SecurityPolicies.Basic128Rsa15: { encryptedData.Algorithm = SecurityAlgorithms.Rsa15; encryptedData.Data = RsaUtils.Encrypt(plainText, certificate, RsaUtils.Padding.Pkcs1); break; } case SecurityPolicies.Aes256_Sha256_RsaPss: { encryptedData.Algorithm = SecurityAlgorithms.RsaOaepSha256; encryptedData.Data = RsaUtils.Encrypt(plainText, certificate, RsaUtils.Padding.OaepSHA256); break; } case SecurityPolicies.None: { break; } default: { throw ServiceResultException.Create( StatusCodes.BadSecurityPolicyRejected, "Unsupported security policy: {0}", securityPolicyUri); } } return(encryptedData); }
/// <summary> /// Loads the private key from a PFX file in the certificate store. /// </summary> public X509Certificate2 LoadPrivateKey(string thumbprint, string subjectName, string password) { if (m_certificateSubdir == null || !m_certificateSubdir.Exists) { return(null); } if (string.IsNullOrEmpty(thumbprint) && string.IsNullOrEmpty(subjectName)) { return(null); } foreach (FileInfo file in m_certificateSubdir.GetFiles("*.der")) { try { X509Certificate2 certificate = new X509Certificate2(file.FullName); if (!String.IsNullOrEmpty(thumbprint)) { if (!string.Equals(certificate.Thumbprint, thumbprint, StringComparison.CurrentCultureIgnoreCase)) { continue; } } if (!String.IsNullOrEmpty(subjectName)) { if (!Utils.CompareDistinguishedName(subjectName, certificate.Subject)) { if (subjectName.Contains("=") || !certificate.Subject.Contains("CN=" + subjectName)) { continue; } } } string fileRoot = file.Name.Substring(0, file.Name.Length - file.Extension.Length); StringBuilder filePath = new StringBuilder(); filePath.Append(m_privateKeySubdir.FullName); filePath.Append(Path.DirectorySeparatorChar); filePath.Append(fileRoot); FileInfo privateKeyFile = new FileInfo(filePath.ToString() + ".pfx"); RSA rsa = null; try { certificate = new X509Certificate2( privateKeyFile.FullName, (password == null) ? String.Empty : password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.UserKeySet); rsa = certificate.GetRSAPrivateKey(); } catch (Exception) { certificate = new X509Certificate2( privateKeyFile.FullName, (password == null) ? String.Empty : password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet); rsa = certificate.GetRSAPrivateKey(); } if (rsa != null) { int inputBlockSize = RsaUtils.GetPlainTextBlockSize(rsa, true); byte[] bytes1 = rsa.Encrypt(new byte[inputBlockSize], RSAEncryptionPadding.OaepSHA1); byte[] bytes2 = rsa.Decrypt(bytes1, RSAEncryptionPadding.OaepSHA1); if (bytes2 != null) { // Utils.Trace(1, "RSA: {0}", certificate.Thumbprint); return(certificate); } } } catch (Exception e) { Utils.Trace(e, "Could not load private key for certificate " + subjectName); } } return(null); }