From bd39a57c7cd681c45febecad430e60842341044b Mon Sep 17 00:00:00 2001 From: Martin Regen Date: Tue, 7 Jun 2016 16:17:09 +0200 Subject: [PATCH 1/2] Crypto improvements, get rid of windows.security and use using instead of dispose --- .../Certificates/DirectoryCertificateStore.cs | 16 +- Stack/Core/Security/Certificates/RsaUtils.cs | 252 +++++++-------- Stack/Core/Stack/Tcp/TcpChannel.Rsa.cs | 288 ++++++++---------- Stack/Core/Stack/Tcp/TcpChannel.Symmetric.cs | 92 +++--- Stack/Core/Stack/Tcp/TcpChannelToken.cs | 12 +- Stack/Core/Stack/Tcp/TcpServerChannel.cs | 1 - Stack/Core/project.json | 11 +- 7 files changed, 311 insertions(+), 361 deletions(-) diff --git a/Stack/Core/Security/Certificates/DirectoryCertificateStore.cs b/Stack/Core/Security/Certificates/DirectoryCertificateStore.cs index d30634e5e3..974cb931ab 100644 --- a/Stack/Core/Security/Certificates/DirectoryCertificateStore.cs +++ b/Stack/Core/Security/Certificates/DirectoryCertificateStore.cs @@ -426,15 +426,17 @@ public X509Certificate2 LoadPrivateKey(string thumbprint, string subjectName, st (password == null) ? String.Empty : password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.DefaultKeySet); - RSA rsa = certificate.GetRSAPrivateKey(); - if (rsa != null) + using (RSA rsa = certificate.GetRSAPrivateKey()) { - int inputBlockSize = rsa.KeySize / 8 - 42; - byte[] bytes1 = rsa.Encrypt(new byte[inputBlockSize], RSAEncryptionPadding.OaepSHA1); - byte[] bytes2 = rsa.Decrypt(bytes1, RSAEncryptionPadding.OaepSHA1); - if (bytes2 != null) + if (rsa != null) { - return certificate; + int inputBlockSize = rsa.KeySize / 8 - 42; + byte[] bytes1 = rsa.Encrypt(new byte[inputBlockSize], RSAEncryptionPadding.OaepSHA1); + byte[] bytes2 = rsa.Decrypt(bytes1, RSAEncryptionPadding.OaepSHA1); + if (bytes2 != null) + { + return certificate; + } } } } diff --git a/Stack/Core/Security/Certificates/RsaUtils.cs b/Stack/Core/Security/Certificates/RsaUtils.cs index 5469b8fabb..fb9b9e9f29 100644 --- a/Stack/Core/Security/Certificates/RsaUtils.cs +++ b/Stack/Core/Security/Certificates/RsaUtils.cs @@ -14,9 +14,6 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. using System.IO; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; -using Windows.Security.Cryptography; -using Windows.Security.Cryptography.Core; -using Windows.Storage.Streams; namespace Opc.Ua { @@ -31,20 +28,20 @@ public static class RsaUtils /// public static int GetPlainTextBlockSize(X509Certificate2 encryptingCertificate, bool useOaep) { - RSA rsa = encryptingCertificate.GetRSAPublicKey(); - - if (rsa != null) + using (RSA rsa = encryptingCertificate.GetRSAPublicKey()) { - if (useOaep) - { - return rsa.KeySize / 8 - 42; - } - else + if (rsa != null) { - return rsa.KeySize / 8 - 11; + if (useOaep) + { + return rsa.KeySize / 8 - 42; + } + else + { + return rsa.KeySize / 8 - 11; + } } } - return -1; } @@ -53,13 +50,13 @@ public static int GetPlainTextBlockSize(X509Certificate2 encryptingCertificate, /// public static int GetCipherTextBlockSize(X509Certificate2 encryptingCertificate, bool useOaep) { - RSA rsa = encryptingCertificate.GetRSAPublicKey(); - - if (rsa != null) + using (RSA rsa = encryptingCertificate.GetRSAPublicKey()) { - return rsa.KeySize / 8; + if (rsa != null) + { + return rsa.KeySize / 8; + } } - return -1; } @@ -68,14 +65,15 @@ public static int GetCipherTextBlockSize(X509Certificate2 encryptingCertificate, /// public static int RsaPkcs15Sha1_GetSignatureLength(X509Certificate2 signingCertificate) { - RSA rsa = signingCertificate.GetRSAPublicKey(); - - if (rsa == null) + using (RSA rsa = signingCertificate.GetRSAPublicKey()) { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); - } + if (rsa == null) + { + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); + } - return rsa.KeySize / 8; + return rsa.KeySize / 8; + } } /// @@ -86,27 +84,17 @@ public static byte[] RsaPkcs15Sha1_Sign( X509Certificate2 signingCertificate) { // extract the private key. - RSA rsa = signingCertificate.GetRSAPrivateKey(); - - if (rsa == null) + using (RSA rsa = signingCertificate.GetRSAPrivateKey()) { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); - } - - // compute the hash of message. - MemoryStream istrm = new MemoryStream(dataToSign.Array, dataToSign.Offset, dataToSign.Count, false); - // create the hmac. - HashAlgorithmProvider sha1Provider = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha1); - IBuffer buffer = CryptographicBuffer.CreateFromByteArray(istrm.ToArray()); - buffer = sha1Provider.HashData(buffer); - byte[] digest = new byte[buffer.Length]; - CryptographicBuffer.CopyToByteArray(buffer, out digest); - - istrm.Dispose(); + if (rsa == null) + { + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); + } - // create the signature. - return rsa.SignHash(digest, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + // create the signature. + return rsa.SignData(dataToSign.Array, dataToSign.Offset, dataToSign.Count, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + } } /// @@ -118,26 +106,17 @@ public static bool RsaPkcs15Sha1_Verify( X509Certificate2 signingCertificate) { // extract the private key. - RSA rsa = signingCertificate.GetRSAPublicKey(); - - if (rsa == null) + using (RSA rsa = signingCertificate.GetRSAPublicKey()) { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); - } - // compute the hash of message. - MemoryStream istrm = new MemoryStream(dataToVerify.Array, dataToVerify.Offset, dataToVerify.Count, false); - - HashAlgorithmProvider sha1Provider = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha1); - IBuffer buffer = CryptographicBuffer.CreateFromByteArray(istrm.ToArray()); - buffer = sha1Provider.HashData(buffer); - byte[] digest = new byte[buffer.Length]; - CryptographicBuffer.CopyToByteArray(buffer, out digest); - - istrm.Dispose(); + if (rsa == null) + { + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); + } - // verify signature. - return rsa.VerifyHash(digest, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + // verify signature. + return rsa.VerifyData(dataToVerify.Array, dataToVerify.Offset, dataToVerify.Count, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + } } /// @@ -181,54 +160,56 @@ public static ArraySegment Encrypt( ArraySegment outputBuffer) { // get the encrypting key. - RSA rsa = encryptingCertificate.GetRSAPublicKey(); - - if (rsa == null) - { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); - } - - int inputBlockSize = GetPlainTextBlockSize(encryptingCertificate, useOaep); - int outputBlockSize = rsa.KeySize / 8; - - // verify the input data is the correct block size. - if (dataToEncrypt.Count % inputBlockSize != 0) + using (RSA rsa = encryptingCertificate.GetRSAPublicKey()) { - Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToEncrypt.Count, inputBlockSize); - } - byte[] encryptedBuffer = outputBuffer.Array; - - MemoryStream ostrm = new MemoryStream( - encryptedBuffer, - outputBuffer.Offset, - outputBuffer.Count); + if (rsa == null) + { + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); + } - // encrypt body. - byte[] input = new byte[inputBlockSize]; + int inputBlockSize = GetPlainTextBlockSize(encryptingCertificate, useOaep); + int outputBlockSize = rsa.KeySize / 8; - for (int ii = dataToEncrypt.Offset; ii < dataToEncrypt.Offset + dataToEncrypt.Count; ii += inputBlockSize) - { - Array.Copy(dataToEncrypt.Array, ii, input, 0, input.Length); - if (useOaep == true) + // verify the input data is the correct block size. + if (dataToEncrypt.Count % inputBlockSize != 0) { - byte[] cipherText = rsa.Encrypt(input, RSAEncryptionPadding.OaepSHA1); - ostrm.Write(cipherText, 0, cipherText.Length); + Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToEncrypt.Count, inputBlockSize); } - else + + byte[] encryptedBuffer = outputBuffer.Array; + + using (MemoryStream ostrm = new MemoryStream( + encryptedBuffer, + outputBuffer.Offset, + outputBuffer.Count)) { - byte[] cipherText = rsa.Encrypt(input, RSAEncryptionPadding.Pkcs1); - ostrm.Write(cipherText, 0, cipherText.Length); - } - } - ostrm.Dispose(); + // encrypt body. + byte[] input = new byte[inputBlockSize]; + + for (int ii = dataToEncrypt.Offset; ii < dataToEncrypt.Offset + dataToEncrypt.Count; ii += inputBlockSize) + { + Array.Copy(dataToEncrypt.Array, ii, input, 0, input.Length); + if (useOaep == true) + { + byte[] cipherText = rsa.Encrypt(input, RSAEncryptionPadding.OaepSHA1); + ostrm.Write(cipherText, 0, cipherText.Length); + } + else + { + byte[] cipherText = rsa.Encrypt(input, RSAEncryptionPadding.Pkcs1); + ostrm.Write(cipherText, 0, cipherText.Length); + } + } + } - // return buffer - return new ArraySegment( - encryptedBuffer, - outputBuffer.Offset, - (dataToEncrypt.Count / inputBlockSize) * outputBlockSize); + // return buffer + return new ArraySegment( + encryptedBuffer, + outputBuffer.Offset, + (dataToEncrypt.Count / inputBlockSize) * outputBlockSize); + } } /// @@ -270,51 +251,52 @@ public static ArraySegment Decrypt( ArraySegment outputBuffer) { // get the encrypting key. - RSA rsa = encryptingCertificate.GetRSAPrivateKey(); - - if (rsa == null) + using (RSA rsa = encryptingCertificate.GetRSAPrivateKey()) { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); - } - - int inputBlockSize = rsa.KeySize / 8; - int outputBlockSize = GetPlainTextBlockSize(encryptingCertificate, useOaep); - - // verify the input data is the correct block size. - if (dataToDecrypt.Count % inputBlockSize != 0) - { - Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToDecrypt.Count, inputBlockSize); - } - - byte[] decryptedBuffer = outputBuffer.Array; - - MemoryStream ostrm = new MemoryStream( - decryptedBuffer, - outputBuffer.Offset, - outputBuffer.Count); + if (rsa == null) + { + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); + } - // decrypt body. - byte[] input = new byte[inputBlockSize]; + int inputBlockSize = rsa.KeySize / 8; + int outputBlockSize = GetPlainTextBlockSize(encryptingCertificate, useOaep); - for (int ii = dataToDecrypt.Offset; ii < dataToDecrypt.Offset + dataToDecrypt.Count; ii += inputBlockSize) - { - Array.Copy(dataToDecrypt.Array, ii, input, 0, input.Length); - if (useOaep == true) + // verify the input data is the correct block size. + if (dataToDecrypt.Count % inputBlockSize != 0) { - byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.OaepSHA1); - ostrm.Write(plainText, 0, plainText.Length); + Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToDecrypt.Count, inputBlockSize); } - else + + byte[] decryptedBuffer = outputBuffer.Array; + + using (MemoryStream ostrm = new MemoryStream( + decryptedBuffer, + outputBuffer.Offset, + outputBuffer.Count)) { - byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.Pkcs1); - ostrm.Write(plainText, 0, plainText.Length); - } - } - ostrm.Dispose(); + // decrypt body. + byte[] input = new byte[inputBlockSize]; + + for (int ii = dataToDecrypt.Offset; ii < dataToDecrypt.Offset + dataToDecrypt.Count; ii += inputBlockSize) + { + Array.Copy(dataToDecrypt.Array, ii, input, 0, input.Length); + if (useOaep == true) + { + byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.OaepSHA1); + ostrm.Write(plainText, 0, plainText.Length); + } + else + { + byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.Pkcs1); + ostrm.Write(plainText, 0, plainText.Length); + } + } + } - // return buffers. - return new ArraySegment(decryptedBuffer, outputBuffer.Offset, (dataToDecrypt.Count / inputBlockSize) * outputBlockSize); + // return buffers. + return new ArraySegment(decryptedBuffer, outputBuffer.Offset, (dataToDecrypt.Count / inputBlockSize) * outputBlockSize); + } } #endregion } diff --git a/Stack/Core/Stack/Tcp/TcpChannel.Rsa.cs b/Stack/Core/Stack/Tcp/TcpChannel.Rsa.cs index e41c7d2e58..3425cfadb9 100644 --- a/Stack/Core/Stack/Tcp/TcpChannel.Rsa.cs +++ b/Stack/Core/Stack/Tcp/TcpChannel.Rsa.cs @@ -15,9 +15,6 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. using System.IO; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; -using Windows.Security.Cryptography.Core; -using Windows.Security.Cryptography; -using Windows.Storage.Streams; namespace Opc.Ua.Bindings { @@ -31,35 +28,35 @@ public partial class TcpChannel /// protected static int Rsa_GetPlainTextBlockSize(X509Certificate2 encryptingCertificate, bool useOaep) { - RSA rsa = encryptingCertificate.GetRSAPublicKey(); - - if (rsa != null) + using (RSA rsa = encryptingCertificate.GetRSAPublicKey()) { - if (useOaep) - { - return rsa.KeySize/8 - 42; - } - else + if (rsa != null) { - return rsa.KeySize/8 - 11; + if (useOaep) + { + return rsa.KeySize / 8 - 42; + } + else + { + return rsa.KeySize / 8 - 11; + } } } - return -1; } - + /// /// Return the ciphertext block size for RSA OAEP encryption. /// protected static int Rsa_GetCipherTextBlockSize(X509Certificate2 encryptingCertificate, bool useOaep) { - RSA rsa = encryptingCertificate.GetRSAPublicKey(); - - if (rsa != null) + using (RSA rsa = encryptingCertificate.GetRSAPublicKey()) { - return rsa.KeySize/8; + if (rsa != null) + { + return rsa.KeySize / 8; + } } - return -1; } @@ -68,14 +65,15 @@ protected static int Rsa_GetCipherTextBlockSize(X509Certificate2 encryptingCerti /// private static int RsaPkcs15Sha1_GetSignatureLength(X509Certificate2 signingCertificate) { - RSA rsa = signingCertificate.GetRSAPublicKey(); - - if (rsa == null) + using (RSA rsa = signingCertificate.GetRSAPublicKey()) { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); - } + if (rsa == null) + { + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); + } - return rsa.KeySize/8; + return rsa.KeySize / 8; + } } /// @@ -86,34 +84,16 @@ private static byte[] RsaPkcs15Sha1_Sign( X509Certificate2 signingCertificate) { // extract the private key. - RSA rsa = null; - try + using (RSA rsa = signingCertificate.GetRSAPrivateKey()) { - rsa = signingCertificate.GetRSAPrivateKey(); - } - catch(Exception ex) - { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate: " + ex.Message); - } + if (rsa == null) + { + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); + } - 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.SHA1, RSASignaturePadding.Pkcs1); } - - // compute the hash of message. - MemoryStream istrm = new MemoryStream(dataToSign.Array, dataToSign.Offset, dataToSign.Count, false); - - HashAlgorithmProvider sha1Provider = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha1); - IBuffer buffer = CryptographicBuffer.CreateFromByteArray(istrm.ToArray()); - buffer = sha1Provider.HashData(buffer); - byte[] digest = new byte[buffer.Length]; - CryptographicBuffer.CopyToByteArray(buffer, out digest); - - istrm.Dispose(); - - // create the signature. - return rsa.SignHash(digest, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); } /// @@ -125,43 +105,31 @@ private static bool RsaPkcs15Sha1_Verify( X509Certificate2 signingCertificate) { // extract the public key. - RSA rsa = signingCertificate.GetRSAPublicKey(); - - if (rsa == null) + using (RSA rsa = signingCertificate.GetRSAPublicKey()) { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); - } - // compute the hash of message. - MemoryStream istrm = new MemoryStream(dataToVerify.Array, dataToVerify.Offset, dataToVerify.Count, false); - - HashAlgorithmProvider sha1Provider = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha1); - IBuffer buffer = CryptographicBuffer.CreateFromByteArray(istrm.ToArray()); - buffer = sha1Provider.HashData(buffer); - byte[] digest = new byte[buffer.Length]; - CryptographicBuffer.CopyToByteArray(buffer, out digest); - - istrm.Dispose(); - - // verify signature. - if (!rsa.VerifyHash(digest, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)) - { - string messageType = new UTF8Encoding().GetString(dataToVerify.Array, dataToVerify.Offset, 4); - int messageLength = BitConverter.ToInt32(dataToVerify.Array, dataToVerify.Offset+4); - string expectedDigest = Utils.ToHexString(digest); - string actualSignature = Utils.ToHexString(signature); - - Utils.Trace( - "Could not validate signature.\r\nCertificate={0}, MessageType={1}, Length={2}\r\nDigest={3}\r\nActualSignature={4}", - signingCertificate.Subject, - messageType, - messageLength, - expectedDigest, - actualSignature); + if (rsa == null) + { + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); + } - return false; + // verify signature. + if (!rsa.VerifyData(dataToVerify.Array, dataToVerify.Offset, dataToVerify.Count, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)) + { + string messageType = new UTF8Encoding().GetString(dataToVerify.Array, dataToVerify.Offset, 4); + int messageLength = BitConverter.ToInt32(dataToVerify.Array, dataToVerify.Offset + 4); + string actualSignature = Utils.ToHexString(signature); + + Utils.Trace( + "Could not validate signature.\r\nCertificate={0}, MessageType={1}, Length={2}\r\nActualSignature={3}", + signingCertificate.Subject, + messageType, + messageLength, + actualSignature); + + return false; + } } - return true; } @@ -175,52 +143,52 @@ private ArraySegment Rsa_Encrypt( bool useOaep) { // get the encrypting key. - RSA rsa = encryptingCertificate.GetRSAPublicKey(); - - if (rsa == null) - { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); - } - - int inputBlockSize = Rsa_GetPlainTextBlockSize(encryptingCertificate, useOaep); - int outputBlockSize = rsa.KeySize/8; - - // verify the input data is the correct block size. - if (dataToEncrypt.Count % inputBlockSize != 0) + using (RSA rsa = encryptingCertificate.GetRSAPublicKey()) { - Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToEncrypt.Count, inputBlockSize); - } - - byte[] encryptedBuffer = BufferManager.TakeBuffer(SendBufferSize, "Rsa_Encrypt"); - Array.Copy(headerToCopy.Array, headerToCopy.Offset, encryptedBuffer, 0, headerToCopy.Count); + if (rsa == null) + { + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); + } - MemoryStream ostrm = new MemoryStream( - encryptedBuffer, - headerToCopy.Count, - encryptedBuffer.Length - headerToCopy.Count); - - // encrypt body. - byte[] input = new byte[inputBlockSize]; + int inputBlockSize = Rsa_GetPlainTextBlockSize(encryptingCertificate, useOaep); + int outputBlockSize = rsa.KeySize / 8; - for (int ii = dataToEncrypt.Offset; ii < dataToEncrypt.Offset + dataToEncrypt.Count; ii += inputBlockSize) - { - Array.Copy(dataToEncrypt.Array, ii, input, 0, input.Length); - if (useOaep == true) + // verify the input data is the correct block size. + if (dataToEncrypt.Count % inputBlockSize != 0) { - byte[] cipherText = rsa.Encrypt(input, RSAEncryptionPadding.OaepSHA1); - ostrm.Write(cipherText, 0, cipherText.Length); + Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToEncrypt.Count, inputBlockSize); } - else + + byte[] encryptedBuffer = BufferManager.TakeBuffer(SendBufferSize, "Rsa_Encrypt"); + Array.Copy(headerToCopy.Array, headerToCopy.Offset, encryptedBuffer, 0, headerToCopy.Count); + + using (MemoryStream ostrm = new MemoryStream( + encryptedBuffer, + headerToCopy.Count, + encryptedBuffer.Length - headerToCopy.Count)) { - byte[] cipherText = rsa.Encrypt(input, RSAEncryptionPadding.Pkcs1); - ostrm.Write(cipherText, 0, cipherText.Length); + + // encrypt body. + byte[] input = new byte[inputBlockSize]; + + for (int ii = dataToEncrypt.Offset; ii < dataToEncrypt.Offset + dataToEncrypt.Count; ii += inputBlockSize) + { + Array.Copy(dataToEncrypt.Array, ii, input, 0, input.Length); + if (useOaep == true) + { + byte[] cipherText = rsa.Encrypt(input, RSAEncryptionPadding.OaepSHA1); + ostrm.Write(cipherText, 0, cipherText.Length); + } + else + { + byte[] cipherText = rsa.Encrypt(input, RSAEncryptionPadding.Pkcs1); + ostrm.Write(cipherText, 0, cipherText.Length); + } + } } + // return buffer + return new ArraySegment(encryptedBuffer, 0, (dataToEncrypt.Count / inputBlockSize) * outputBlockSize + headerToCopy.Count); } - - ostrm.Dispose(); - - // return buffer - return new ArraySegment(encryptedBuffer, 0, (dataToEncrypt.Count/inputBlockSize)*outputBlockSize + headerToCopy.Count); } /// @@ -233,52 +201,54 @@ private ArraySegment Rsa_Decrypt( bool useOaep) { // get the encrypting key. - RSA rsa = encryptingCertificate.GetRSAPrivateKey(); - - if (rsa == null) + using (RSA rsa = encryptingCertificate.GetRSAPrivateKey()) { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); - } - - int inputBlockSize = rsa.KeySize/8; - int outputBlockSize = Rsa_GetPlainTextBlockSize(encryptingCertificate, useOaep); - - // verify the input data is the correct block size. - if (dataToDecrypt.Count % inputBlockSize != 0) - { - Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToDecrypt.Count, inputBlockSize); - } - byte[] decryptedBuffer = BufferManager.TakeBuffer(SendBufferSize, "Rsa_Decrypt"); - Array.Copy(headerToCopy.Array, headerToCopy.Offset, decryptedBuffer, 0, headerToCopy.Count); - - MemoryStream ostrm = new MemoryStream( - decryptedBuffer, - headerToCopy.Count, - decryptedBuffer.Length - headerToCopy.Count); + if (rsa == null) + { + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); + } - // decrypt body. - byte[] input = new byte[inputBlockSize]; + int inputBlockSize = rsa.KeySize / 8; + int outputBlockSize = Rsa_GetPlainTextBlockSize(encryptingCertificate, useOaep); - for (int ii = dataToDecrypt.Offset; ii < dataToDecrypt.Offset + dataToDecrypt.Count; ii += inputBlockSize) - { - Array.Copy(dataToDecrypt.Array, ii, input, 0, input.Length); - if (useOaep == true) + // verify the input data is the correct block size. + if (dataToDecrypt.Count % inputBlockSize != 0) { - byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.OaepSHA1); - ostrm.Write(plainText, 0, plainText.Length); + Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToDecrypt.Count, inputBlockSize); } - else + + byte[] decryptedBuffer = BufferManager.TakeBuffer(SendBufferSize, "Rsa_Decrypt"); + Array.Copy(headerToCopy.Array, headerToCopy.Offset, decryptedBuffer, 0, headerToCopy.Count); + + using (MemoryStream ostrm = new MemoryStream( + decryptedBuffer, + headerToCopy.Count, + decryptedBuffer.Length - headerToCopy.Count)) { - byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.Pkcs1); - ostrm.Write(plainText, 0, plainText.Length); - } - } - ostrm.Dispose(); + // decrypt body. + byte[] input = new byte[inputBlockSize]; + + for (int ii = dataToDecrypt.Offset; ii < dataToDecrypt.Offset + dataToDecrypt.Count; ii += inputBlockSize) + { + Array.Copy(dataToDecrypt.Array, ii, input, 0, input.Length); + if (useOaep == true) + { + byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.OaepSHA1); + ostrm.Write(plainText, 0, plainText.Length); + } + else + { + byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.Pkcs1); + ostrm.Write(plainText, 0, plainText.Length); + } + } + } - // return buffers. - return new ArraySegment(decryptedBuffer, 0, (dataToDecrypt.Count/inputBlockSize)*outputBlockSize + headerToCopy.Count); - } + // return buffers. + return new ArraySegment(decryptedBuffer, 0, (dataToDecrypt.Count / inputBlockSize) * outputBlockSize + headerToCopy.Count); + } + } } } diff --git a/Stack/Core/Stack/Tcp/TcpChannel.Symmetric.cs b/Stack/Core/Stack/Tcp/TcpChannel.Symmetric.cs index 2a0a2a2c10..c3616d5818 100644 --- a/Stack/Core/Stack/Tcp/TcpChannel.Symmetric.cs +++ b/Stack/Core/Stack/Tcp/TcpChannel.Symmetric.cs @@ -13,9 +13,6 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. using System; using System.Text; using System.IO; -using Windows.Security.Cryptography.Core; -using Windows.Storage.Streams; -using Windows.Security.Cryptography; using System.Security.Cryptography; namespace Opc.Ua.Bindings @@ -151,21 +148,27 @@ protected void ComputeKeys(TcpChannelToken token) { case SecurityPolicies.Basic128Rsa15: case SecurityPolicies.Basic256: - { - // create encryptors. - SymmetricKeyAlgorithmProvider AesCbcProvider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbc); - - IBuffer buffer = CryptographicBuffer.CreateFromByteArray(token.ClientEncryptingKey); - token.ClientEncryptor = AesCbcProvider.CreateSymmetricKey(buffer); - - buffer = CryptographicBuffer.CreateFromByteArray(token.ServerEncryptingKey); - token.ServerEncryptor = AesCbcProvider.CreateSymmetricKey(buffer); - - // create HMACs. - token.ServerHmac = new HMACSHA1(token.ServerSigningKey); - token.ClientHmac = new HMACSHA1(token.ClientSigningKey); - break; - } + { + // create encryptors. + SymmetricAlgorithm AesCbcEncryptorProvider = Aes.Create(); + AesCbcEncryptorProvider.Mode = CipherMode.CBC; + AesCbcEncryptorProvider.Padding = PaddingMode.None; + AesCbcEncryptorProvider.Key = token.ClientEncryptingKey; + AesCbcEncryptorProvider.IV = token.ClientInitializationVector; + token.ClientEncryptor = AesCbcEncryptorProvider; + + SymmetricAlgorithm AesCbcDecryptorProvider = Aes.Create(); + AesCbcDecryptorProvider.Mode = CipherMode.CBC; + AesCbcDecryptorProvider.Padding = PaddingMode.None; + AesCbcDecryptorProvider.Key = token.ServerEncryptingKey; + AesCbcDecryptorProvider.IV = token.ServerInitializationVector; + token.ServerEncryptor = AesCbcDecryptorProvider; + + // create HMACs. + token.ServerHmac = new HMACSHA1(token.ServerSigningKey); + token.ClientHmac = new HMACSHA1(token.ClientSigningKey); + break; + } default: case SecurityPolicies.None: @@ -658,29 +661,27 @@ private static void SymmetricEncrypt( ArraySegment dataToEncrypt, bool useClientKeys) { - // get the encrypting key. - CryptographicKey encryptingKey = (useClientKeys)? token.ClientEncryptor : token.ServerEncryptor; - IBuffer IV = (useClientKeys) ? CryptographicBuffer.CreateFromByteArray(token.ClientInitializationVector) : CryptographicBuffer.CreateFromByteArray(token.ServerInitializationVector); + SymmetricAlgorithm encryptingKey = (useClientKeys)?token.ClientEncryptor:token.ServerEncryptor; if (encryptingKey == null) { throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Token missing symmetric key object."); } - SymmetricKeyAlgorithmProvider AesCbcProvider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbc); - if (dataToEncrypt.Count % AesCbcProvider.BlockLength != 0) + using (ICryptoTransform encryptor = encryptingKey.CreateEncryptor()) { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Input data is not an even number of encryption blocks."); - } + byte[] blockToEncrypt = dataToEncrypt.Array; - byte[] blockToEncrypt = new byte[dataToEncrypt.Count]; - Array.ConstrainedCopy(dataToEncrypt.Array, dataToEncrypt.Offset, blockToEncrypt, 0, dataToEncrypt.Count); + int start = dataToEncrypt.Offset; + int count = dataToEncrypt.Count; - IBuffer block = CryptographicBuffer.CreateFromByteArray(blockToEncrypt); - IBuffer encryptedBuffer = CryptographicEngine.Encrypt(encryptingKey, block, IV); - CryptographicBuffer.CopyToByteArray(encryptedBuffer, out blockToEncrypt); + if (count % encryptor.InputBlockSize != 0) + { + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Input data is not an even number of encryption blocks."); + } - Array.ConstrainedCopy(blockToEncrypt, 0, dataToEncrypt.Array, dataToEncrypt.Offset, dataToEncrypt.Count); + encryptor.TransformBlock(blockToEncrypt, start, count, blockToEncrypt, start); + } } /// @@ -691,29 +692,28 @@ private static void SymmetricDecrypt( ArraySegment dataToDecrypt, bool useClientKeys) { - // get the decrypting key. - CryptographicKey decryptingKey = (useClientKeys) ? token.ClientEncryptor : token.ServerEncryptor; - IBuffer IV = (useClientKeys) ? CryptographicBuffer.CreateFromByteArray(token.ClientInitializationVector) : CryptographicBuffer.CreateFromByteArray(token.ServerInitializationVector); + // get the encrypting key. + SymmetricAlgorithm encryptingKey = (useClientKeys)?token.ClientEncryptor:token.ServerEncryptor; - if (decryptingKey == null) + if (encryptingKey == null) { throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Token missing symmetric key object."); } - SymmetricKeyAlgorithmProvider AesCbcProvider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbc); - if (dataToDecrypt.Count % AesCbcProvider.BlockLength != 0) + using (ICryptoTransform decryptor = encryptingKey.CreateDecryptor()) { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Input data is not an even number of encryption blocks."); - } + byte[] blockToDecrypt = dataToDecrypt.Array; - byte[] blockToDecrypt = new byte[dataToDecrypt.Count]; - Array.ConstrainedCopy(dataToDecrypt.Array, dataToDecrypt.Offset, blockToDecrypt, 0, dataToDecrypt.Count); - - IBuffer block = CryptographicBuffer.CreateFromByteArray(blockToDecrypt); - IBuffer encryptedBuffer = CryptographicEngine.Decrypt(decryptingKey, block, IV); - CryptographicBuffer.CopyToByteArray(encryptedBuffer, out blockToDecrypt); + int start = dataToDecrypt.Offset; + int count = dataToDecrypt.Count; - Array.ConstrainedCopy(blockToDecrypt, 0, dataToDecrypt.Array, dataToDecrypt.Offset, dataToDecrypt.Count); + if (count % decryptor.InputBlockSize != 0) + { + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Input data is not an even number of encryption blocks."); + } + + decryptor.TransformBlock(blockToDecrypt, start, count, blockToDecrypt, start); + } } #endregion diff --git a/Stack/Core/Stack/Tcp/TcpChannelToken.cs b/Stack/Core/Stack/Tcp/TcpChannelToken.cs index fdccb5b3da..fae9f453ce 100644 --- a/Stack/Core/Stack/Tcp/TcpChannelToken.cs +++ b/Stack/Core/Stack/Tcp/TcpChannelToken.cs @@ -11,11 +11,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ using System; -using System.Collections.Generic; -using System.Text; using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; -using Windows.Security.Cryptography.Core; namespace Opc.Ua.Bindings { @@ -169,7 +165,7 @@ public byte[] ServerInitializationVector /// /// The SymmetricAlgorithm object used by the client to encrypt messages. /// - public CryptographicKey ClientEncryptor + public SymmetricAlgorithm ClientEncryptor { get { return m_clientEncryptor; } set { m_clientEncryptor = value; } @@ -178,7 +174,7 @@ public CryptographicKey ClientEncryptor /// /// The SymmetricAlgorithm object used by the server to encrypt messages. /// - public CryptographicKey ServerEncryptor + public SymmetricAlgorithm ServerEncryptor { get { return m_serverEncryptor; } set { m_serverEncryptor = value; } @@ -218,8 +214,8 @@ public HMAC ServerHmac private byte[] m_serverInitializationVector; private HMAC m_clientHmac; private HMAC m_serverHmac; - private CryptographicKey m_clientEncryptor; - private CryptographicKey m_serverEncryptor; + private SymmetricAlgorithm m_clientEncryptor; + private SymmetricAlgorithm m_serverEncryptor; #endregion } } diff --git a/Stack/Core/Stack/Tcp/TcpServerChannel.cs b/Stack/Core/Stack/Tcp/TcpServerChannel.cs index 8b7a255361..3dae74f1c4 100644 --- a/Stack/Core/Stack/Tcp/TcpServerChannel.cs +++ b/Stack/Core/Stack/Tcp/TcpServerChannel.cs @@ -16,7 +16,6 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. using System.IO; using System.Threading; using System.Security.Cryptography.X509Certificates; -using Windows.Networking.Sockets; using System.Threading.Tasks; using System.Net.Sockets; diff --git a/Stack/Core/project.json b/Stack/Core/project.json index 613de2d8e6..b6f18a741b 100644 --- a/Stack/Core/project.json +++ b/Stack/Core/project.json @@ -1,9 +1,10 @@ { - "dependencies": { - "Microsoft.NETCore.UniversalWindowsPlatform": "5.1.0", - "Newtonsoft.Json": "8.0.3", - "System.Security.Cryptography.X509Certificates": "4.0.0-beta-23516" - }, + "dependencies": { + "Microsoft.NETCore.UniversalWindowsPlatform": "5.1.0", + "Newtonsoft.Json": "8.0.3", + "System.Security.Cryptography.Algorithms": "4.0.0-beta-23516", + "System.Security.Cryptography.X509Certificates": "4.0.0-beta-23516" + }, "frameworks": { "uap10.0": {} }, From 3e0580e8418a63763cc883aaf745c7e5b4f6dec7 Mon Sep 17 00:00:00 2001 From: Martin Regen Date: Wed, 8 Jun 2016 16:06:18 +0200 Subject: [PATCH 2/2] fix a typo in decrypt --- Stack/Core/Stack/Tcp/TcpChannel.Symmetric.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Stack/Core/Stack/Tcp/TcpChannel.Symmetric.cs b/Stack/Core/Stack/Tcp/TcpChannel.Symmetric.cs index c3616d5818..e9f43ce2fc 100644 --- a/Stack/Core/Stack/Tcp/TcpChannel.Symmetric.cs +++ b/Stack/Core/Stack/Tcp/TcpChannel.Symmetric.cs @@ -693,14 +693,14 @@ private static void SymmetricDecrypt( bool useClientKeys) { // get the encrypting key. - SymmetricAlgorithm encryptingKey = (useClientKeys)?token.ClientEncryptor:token.ServerEncryptor; + SymmetricAlgorithm decryptingKey = (useClientKeys)?token.ClientEncryptor:token.ServerEncryptor; - if (encryptingKey == null) + if (decryptingKey == null) { throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Token missing symmetric key object."); } - using (ICryptoTransform decryptor = encryptingKey.CreateDecryptor()) + using (ICryptoTransform decryptor = decryptingKey.CreateDecryptor()) { byte[] blockToDecrypt = dataToDecrypt.Array;