├── .gitignore ├── LICENSE ├── LibUA.sln ├── NET Core ├── LibUA.Benchmarks │ ├── LibUA.Benchmarks.csproj │ ├── NodeIds.cs │ └── Program.cs ├── LibUA.Tests │ ├── Framework │ │ ├── TestClient.cs │ │ ├── TestClientFixture.cs │ │ └── TestServerFixture.cs │ ├── LibUA.Tests.csproj │ ├── NodeId_Tests.cs │ └── TestServerClient.cs ├── LibUA │ ├── AddressSpace.cs │ ├── Application.cs │ ├── Client.cs │ ├── Coding.cs │ ├── LibUA.csproj │ ├── MemoryBuffer.cs │ ├── MemoryBufferExtensions.cs │ ├── NetDispatcher.cs │ ├── Security.cs │ ├── Server.cs │ ├── Types.cs │ └── ValueTypes │ │ ├── EUInformation.cs │ │ └── OpcRange.cs ├── TestClient │ ├── Program.cs │ └── TestClient.csproj └── TestServer │ ├── Program.cs │ └── TestServer.csproj ├── NET └── LibUA │ ├── AddressSpace.cs │ ├── Application.cs │ ├── Client.cs │ ├── Coding.cs │ ├── LibUA.csproj │ ├── MemoryBuffer.cs │ ├── MemoryBufferExtensions.cs │ ├── NetDispatcher.cs │ ├── Security.Cryptography │ ├── AesCng.cs │ ├── AuthenticatedAes.cs │ ├── AuthenticatedAesCng.cs │ ├── AuthenticatedSymmetricAlgorithm.cs │ ├── BCryptAuthenticatedSymmetricAlgorithm.cs │ ├── BCryptAuthenticatedSymmetricCryptoTransform.cs │ ├── BCryptHMAC.cs │ ├── BCryptNative.cs │ ├── BCryptPBKDF2.cs │ ├── BCryptSymmetricAlgorithm.cs │ ├── BCryptSymmetricCryptoTransform.cs │ ├── BlockPaddingMethod.cs │ ├── CapiNative.cs │ ├── CngAlgorithm2.cs │ ├── CngChainingMode.cs │ ├── CngKeyExtensionMethods.cs │ ├── CngProvider2.cs │ ├── CngProviderCollection.cs │ ├── CngProviderExtensionMethods.cs │ ├── CryptoConfig2.cs │ ├── GlobalSuppressions.cs │ ├── HMACSHA256Cng.cs │ ├── HMACSHA384Cng.cs │ ├── HMACSHA512Cng.cs │ ├── IAuthenticatedCryptoTransform.cs │ ├── ICngAlgorithm.cs │ ├── ICngAsymmetricAlgorithm.cs │ ├── ICngSymmetricAlgorithm.cs │ ├── ICryptoTransform2.cs │ ├── NCryptNative.cs │ ├── Oid2.cs │ ├── RNGCng.cs │ ├── RSACng.cs │ ├── RSAPKCS1SHA256SignatureDescription.cs │ ├── TripleDESCng.cs │ ├── Win32Native.cs │ ├── X509Certificates │ │ ├── SafeCertContextHandle.cs │ │ ├── X509AlternateName.cs │ │ ├── X509AlternateNameBlob.cs │ │ ├── X509AlternateNameIPAddress.cs │ │ ├── X509AlternateNameOther.cs │ │ ├── X509AlternateNameString.cs │ │ ├── X509Certificate2ExtensionMethods.cs │ │ ├── X509CertificateCreationParameters.cs │ │ ├── X509CertificateExtensionMethods.cs │ │ └── X509Native.cs │ └── Xml │ │ ├── EncryptedXmlExtensionMethods.cs │ │ ├── TransformFactory.cs │ │ ├── XmlDsigNodeList.cs │ │ └── XmlDsigXPathWithNamespacesTransform.cs │ ├── Security.cs │ ├── Server.cs │ ├── Types.cs │ └── packages.config └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio coding add-ins. 3 | 4 | # Visual Studio user-specific files 5 | *.suo 6 | *.user 7 | 8 | # Build results 9 | [Bb]in/ 10 | [Oo]bj/ 11 | 12 | # Visual Studio 2015/2017 cache/options directory 13 | .vs/ 14 | 15 | # ReSharper is a .NET coding add-in 16 | _ReSharper*/ 17 | *.[Rr]e[Ss]harper 18 | *.DotSettings.user 19 | 20 | # CodeRush is a .NET coding add-in 21 | .cr/ 22 | 23 | # Package cache can be rebuilt 24 | packages 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2015-present Nauful Shaikh, QuantenSystems LLC 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LibUA.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.10.34607.79 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NET Core", "NET Core", "{6F1B9BE5-B2AB-4794-A642-AA0FA74DFF2E}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibUA", "NET Core\LibUA\LibUA.csproj", "{84BC6739-52AC-482B-BF45-3D3EBD754D4B}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestServer", "NET Core\TestServer\TestServer.csproj", "{62DE01CE-6B65-46AE-B338-DC2D21F98EAA}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestClient", "NET Core\TestClient\TestClient.csproj", "{809924A5-E31A-465D-9E1F-BD1AA1F63340}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NET", "NET", "{B5D51E19-F3EC-4193-BADC-E7F1862D5FFF}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibUA", "NET\LibUA\LibUA.csproj", "{A02727B5-BA44-4B42-A75F-B35E295DBAF0}" 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibUA.Tests", "NET Core\LibUA.Tests\LibUA.Tests.csproj", "{14422ED0-3219-4816-961B-00E5BC4EC757}" 19 | EndProject 20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibUA.Benchmarks", "NET Core\LibUA.Benchmarks\LibUA.Benchmarks.csproj", "{89681A86-9667-4A67-8D92-A5847E6D19FC}" 21 | EndProject 22 | Global 23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 24 | Debug|Any CPU = Debug|Any CPU 25 | Release|Any CPU = Release|Any CPU 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {84BC6739-52AC-482B-BF45-3D3EBD754D4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {84BC6739-52AC-482B-BF45-3D3EBD754D4B}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {84BC6739-52AC-482B-BF45-3D3EBD754D4B}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {84BC6739-52AC-482B-BF45-3D3EBD754D4B}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {62DE01CE-6B65-46AE-B338-DC2D21F98EAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {62DE01CE-6B65-46AE-B338-DC2D21F98EAA}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {62DE01CE-6B65-46AE-B338-DC2D21F98EAA}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {62DE01CE-6B65-46AE-B338-DC2D21F98EAA}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {809924A5-E31A-465D-9E1F-BD1AA1F63340}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {809924A5-E31A-465D-9E1F-BD1AA1F63340}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {809924A5-E31A-465D-9E1F-BD1AA1F63340}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {809924A5-E31A-465D-9E1F-BD1AA1F63340}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {A02727B5-BA44-4B42-A75F-B35E295DBAF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {A02727B5-BA44-4B42-A75F-B35E295DBAF0}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {A02727B5-BA44-4B42-A75F-B35E295DBAF0}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {A02727B5-BA44-4B42-A75F-B35E295DBAF0}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {14422ED0-3219-4816-961B-00E5BC4EC757}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {14422ED0-3219-4816-961B-00E5BC4EC757}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {14422ED0-3219-4816-961B-00E5BC4EC757}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {14422ED0-3219-4816-961B-00E5BC4EC757}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {89681A86-9667-4A67-8D92-A5847E6D19FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {89681A86-9667-4A67-8D92-A5847E6D19FC}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {89681A86-9667-4A67-8D92-A5847E6D19FC}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {89681A86-9667-4A67-8D92-A5847E6D19FC}.Release|Any CPU.Build.0 = Release|Any CPU 52 | EndGlobalSection 53 | GlobalSection(SolutionProperties) = preSolution 54 | HideSolutionNode = FALSE 55 | EndGlobalSection 56 | GlobalSection(NestedProjects) = preSolution 57 | {84BC6739-52AC-482B-BF45-3D3EBD754D4B} = {6F1B9BE5-B2AB-4794-A642-AA0FA74DFF2E} 58 | {62DE01CE-6B65-46AE-B338-DC2D21F98EAA} = {6F1B9BE5-B2AB-4794-A642-AA0FA74DFF2E} 59 | {809924A5-E31A-465D-9E1F-BD1AA1F63340} = {6F1B9BE5-B2AB-4794-A642-AA0FA74DFF2E} 60 | {A02727B5-BA44-4B42-A75F-B35E295DBAF0} = {B5D51E19-F3EC-4193-BADC-E7F1862D5FFF} 61 | {14422ED0-3219-4816-961B-00E5BC4EC757} = {6F1B9BE5-B2AB-4794-A642-AA0FA74DFF2E} 62 | {89681A86-9667-4A67-8D92-A5847E6D19FC} = {6F1B9BE5-B2AB-4794-A642-AA0FA74DFF2E} 63 | EndGlobalSection 64 | GlobalSection(ExtensibilityGlobals) = postSolution 65 | SolutionGuid = {03381D17-B1F1-48B8-9F30-97F101AEA4AD} 66 | EndGlobalSection 67 | EndGlobal 68 | -------------------------------------------------------------------------------- /NET Core/LibUA.Benchmarks/LibUA.Benchmarks.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | pdbonly 9 | true 10 | True 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /NET Core/LibUA.Benchmarks/NodeIds.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using LibUA.Core; 3 | 4 | namespace LibUA.Benchmarks 5 | { 6 | [MarkdownExporter] 7 | [MemoryDiagnoser(false)] 8 | public class NodeId_Benchmarks 9 | { 10 | public readonly static NodeId[] NullNodes = 11 | [ 12 | new NodeId(0,0), 13 | new NodeId(0, null, NodeIdNetType.String), 14 | new NodeId(0, string.Empty), 15 | new NodeId(0, null, NodeIdNetType.Guid), 16 | new NodeId(0, Guid.Empty.ToByteArray(), NodeIdNetType.Guid), 17 | new NodeId(0, null, NodeIdNetType.ByteString), 18 | new NodeId(0, [], NodeIdNetType.ByteString) 19 | ]; 20 | 21 | public readonly static NodeId[] NumericNodes = 22 | [ 23 | new NodeId(2, 1), 24 | new NodeId(2, 100), 25 | new NodeId(2, 200), 26 | new NodeId(2, 300), 27 | new NodeId(2, 400), 28 | new NodeId(2, 500), 29 | new NodeId(2, 600), 30 | new NodeId(2, 700), 31 | new NodeId(2, 800), 32 | new NodeId(2, 900), 33 | new NodeId(2, 1000), 34 | ]; 35 | 36 | public readonly static NodeId[] StringNodes = 37 | [ 38 | new NodeId(2, "Test String 1"), 39 | new NodeId(2, "Test String 2"), 40 | new NodeId(2, "Test String 3"), 41 | new NodeId(2, "Test String 4"), 42 | new NodeId(2, "Test String 5"), 43 | new NodeId(2, "Test String 6"), 44 | new NodeId(2, "Test String 7"), 45 | new NodeId(2, "Test String 8"), 46 | new NodeId(2, "Test String 9"), 47 | new NodeId(2, "Test String 10"), 48 | ]; 49 | 50 | public readonly static NodeId[] GuidNodes = 51 | [ 52 | new NodeId(2, new Guid().ToByteArray(), NodeIdNetType.Guid), 53 | new NodeId(2, new Guid().ToByteArray(), NodeIdNetType.Guid), 54 | new NodeId(2, new Guid().ToByteArray(), NodeIdNetType.Guid), 55 | new NodeId(2, new Guid().ToByteArray(), NodeIdNetType.Guid), 56 | new NodeId(2, new Guid().ToByteArray(), NodeIdNetType.Guid), 57 | new NodeId(2, new Guid().ToByteArray(), NodeIdNetType.Guid), 58 | new NodeId(2, new Guid().ToByteArray(), NodeIdNetType.Guid), 59 | new NodeId(2, new Guid().ToByteArray(), NodeIdNetType.Guid), 60 | new NodeId(2, new Guid().ToByteArray(), NodeIdNetType.Guid), 61 | new NodeId(2, new Guid().ToByteArray(), NodeIdNetType.Guid), 62 | ]; 63 | 64 | public readonly static NodeId[] ByteStringNodes = 65 | [ 66 | new NodeId(2, new byte[] { 0, 1, 2, 3 }, NodeIdNetType.Guid), 67 | new NodeId(2, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, NodeIdNetType.Guid), 68 | new NodeId(2, new byte[] { 2, 1, 2, 3 }, NodeIdNetType.Guid), 69 | new NodeId(2, new byte[] { 0, 3, 2, 3 }, NodeIdNetType.Guid), 70 | new NodeId(2, new byte[] { 0, 1, 2, 1 }, NodeIdNetType.Guid), 71 | new NodeId(2, new byte[] { 0, 6, 2, 3, 7, 5, 6, 4, 255 }, NodeIdNetType.Guid), 72 | new NodeId(2, new byte[] { 0, 1, 8, 3 }, NodeIdNetType.Guid), 73 | new NodeId(2, new byte[] { 0, 9, 2, 3 }, NodeIdNetType.Guid), 74 | new NodeId(2, new byte[] { 0, 1, 2, 0, 1, 5, 6, 7 }, NodeIdNetType.Guid), 75 | ]; 76 | 77 | public readonly static NodeId[] Nodes = 78 | [ 79 | .. NullNodes, 80 | .. StringNodes, 81 | .. GuidNodes, 82 | .. ByteStringNodes 83 | ]; 84 | 85 | public static readonly string[] TryParseData = [.. Enumerable.Range(0,1_000_000).Select(i => $"ns=2;i={i}")]; 86 | 87 | [Benchmark] 88 | public void NodeIdEquivalency() 89 | { 90 | for(int i = 0; i < Nodes.Length; i++) 91 | { 92 | for(int j = 0; j < Nodes.Length; j++) 93 | { 94 | _ = Nodes[i].Equals(Nodes[j]); 95 | } 96 | } 97 | } 98 | 99 | [Benchmark] 100 | public void NodeIdAllocations() 101 | { 102 | NodeId[] nodes = new NodeId[1_000_000]; 103 | for (int i = 0; i < 1_000_000; i++) 104 | { 105 | nodes[i] = new NodeId(0, 0); 106 | } 107 | } 108 | 109 | [Benchmark] 110 | public void NodeId_TryParse_Integer() 111 | { 112 | foreach (var i in TryParseData) 113 | { 114 | var node = NodeId.TryParse(i); 115 | } 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /NET Core/LibUA.Benchmarks/Program.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Running; 2 | 3 | internal class Program 4 | { 5 | private static void Main(string[] args) 6 | { 7 | var summary = BenchmarkRunner.Run(typeof(Program).Assembly); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /NET Core/LibUA.Tests/Framework/TestClient.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Cryptography.X509Certificates; 2 | using System.Security.Cryptography; 3 | using LibUA.Core; 4 | 5 | namespace LibUA.Tests 6 | { 7 | public class TestClient : Client, IDisposable 8 | { 9 | private X509Certificate2? appCertificate = null; 10 | private RSA? cryptPrivateKey = null; 11 | public override X509Certificate2? ApplicationCertificate 12 | { 13 | get { return appCertificate; } 14 | } 15 | 16 | public override RSA? ApplicationPrivateKey 17 | { 18 | get { return cryptPrivateKey; } 19 | } 20 | 21 | public TestClient(string Target, int Port, int Timeout) : base(Target, Port, Timeout) 22 | { 23 | LoadCertificateAndPrivateKey(); 24 | } 25 | 26 | public new void Dispose() 27 | { 28 | base.Dispose(); 29 | GC.SuppressFinalize(this); 30 | } 31 | 32 | private void LoadCertificateAndPrivateKey() 33 | { 34 | try 35 | { 36 | // Try to load existing (public key) and associated private key 37 | appCertificate = new X509Certificate2("ClientCert.der"); 38 | cryptPrivateKey = RSA.Create(); 39 | cryptPrivateKey.KeySize = 2048; 40 | 41 | var rsaPrivParams = UASecurity.ImportRSAPrivateKey(File.ReadAllText("ClientKey.pem")); 42 | cryptPrivateKey.ImportParameters(rsaPrivParams); 43 | } 44 | catch 45 | { 46 | // Make a new certificate (public key) and associated private key 47 | var dn = new X500DistinguishedName("CN=Client certificate;OU=Demo organization", 48 | X500DistinguishedNameFlags.UseSemicolons); 49 | SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder(); 50 | sanBuilder.AddUri(new Uri("urn:DemoApplication")); 51 | 52 | using RSA rsa = RSA.Create(4096); 53 | var request = new CertificateRequest(dn, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); 54 | 55 | request.CertificateExtensions.Add(sanBuilder.Build()); 56 | request.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false)); 57 | request.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(request.PublicKey, false)); 58 | 59 | request.CertificateExtensions.Add(new X509KeyUsageExtension( 60 | X509KeyUsageFlags.DigitalSignature | 61 | X509KeyUsageFlags.NonRepudiation | 62 | X509KeyUsageFlags.DataEncipherment | 63 | X509KeyUsageFlags.KeyEncipherment, false)); 64 | 65 | request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension( 66 | [ 67 | new Oid("1.3.6.1.5.5.7.3.8"), 68 | new Oid("1.3.6.1.5.5.7.3.1"), 69 | new Oid("1.3.6.1.5.5.7.3.2"), 70 | new Oid("1.3.6.1.5.5.7.3.3"), 71 | new Oid("1.3.6.1.5.5.7.3.4"), 72 | new Oid("1.3.6.1.5.5.7.3.8"), 73 | new Oid("1.3.6.1.5.5.7.3.9"), 74 | ], true)); 75 | 76 | var certificate = request.CreateSelfSigned(new DateTimeOffset(DateTime.UtcNow.AddDays(-1)), 77 | new DateTimeOffset(DateTime.UtcNow.AddDays(3650))); 78 | 79 | appCertificate = new X509Certificate2(certificate.Export(X509ContentType.Pfx, ""), 80 | "", X509KeyStorageFlags.DefaultKeySet); 81 | 82 | var certPrivateParams = rsa.ExportParameters(true); 83 | File.WriteAllText("ClientCert.der", UASecurity.ExportPEM(appCertificate)); 84 | File.WriteAllText("ClientKey.pem", UASecurity.ExportRSAPrivateKey(certPrivateParams)); 85 | 86 | cryptPrivateKey = RSA.Create(); 87 | cryptPrivateKey.KeySize = 2048; 88 | cryptPrivateKey.ImportParameters(certPrivateParams); 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /NET Core/LibUA.Tests/Framework/TestClientFixture.cs: -------------------------------------------------------------------------------- 1 | namespace LibUA.Tests 2 | { 3 | public class TestClientFixture : IDisposable 4 | { 5 | public TestClient client; 6 | 7 | public TestClientFixture() 8 | { 9 | client = new TestClient(TestServerFixture.HostName, TestServerFixture.PortNumber, 100); 10 | } 11 | 12 | public void Dispose() 13 | { 14 | client?.Disconnect(); 15 | client?.Dispose(); 16 | GC.SuppressFinalize(this); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /NET Core/LibUA.Tests/LibUA.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | false 8 | true 9 | 10 | 11 | 12 | 13 | all 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | 16 | 17 | 18 | 19 | all 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /NET Core/LibUA.Tests/NodeId_Tests.cs: -------------------------------------------------------------------------------- 1 | using LibUA.Core; 2 | 3 | namespace LibUA.Tests 4 | { 5 | public class NodeId_Tests 6 | { 7 | // OPC 10000-3: Address Space Model 8 | // 8.2.4 Identifier value 9 | // A canonical null NodeId has an IdType equal to Numeric, a NamespaceIndex equal to 0 and an 10 | // Identifier equal to 0. 11 | // 12 | // In addition to the canonical null NodeId the alternative values defined in Table 23 shall be 13 | // considered a null NodeId. 14 | // IdType NamespaceIndex Null Value 15 | // String 0 A null or Empty String("") 16 | // Guid 0 A Guid initialised with zeros(e.g. 00000000-0000-0000-0000-000000) 17 | // Opaque 0 A null or Empty ByteString 18 | [Fact] 19 | public void NodeId_NullEquivalence() 20 | { 21 | NodeId nullNumeric = new NodeId(0, 0); 22 | NodeId nullString = new NodeId(0, null); 23 | NodeId emptyString = new NodeId(0, string.Empty); 24 | NodeId nullGuid = new NodeId(0, null, NodeIdNetType.Guid); 25 | NodeId emptyGuid = new NodeId(0, new Guid().ToByteArray(), NodeIdNetType.Guid); 26 | NodeId nullBytes = new NodeId(0, null, NodeIdNetType.ByteString); 27 | NodeId emptyBytes = new NodeId(0, new byte[0], NodeIdNetType.ByteString); 28 | 29 | Assert.Equal(nullNumeric, nullNumeric); 30 | Assert.Equal(nullNumeric, nullString); 31 | Assert.Equal(nullNumeric, emptyString); 32 | Assert.Equal(nullNumeric, nullGuid); 33 | Assert.Equal(nullNumeric, emptyGuid); 34 | Assert.Equal(nullNumeric, nullBytes); 35 | Assert.Equal(nullNumeric, emptyBytes); 36 | } 37 | 38 | [Fact] 39 | public void NodeId_NumericEquivalence() 40 | { 41 | Assert.Equal(new NodeId(2, 100), new NodeId(2, 100)); 42 | } 43 | 44 | [Fact] 45 | public void NodeId_NumericNamespaceNonEquivalence() 46 | { 47 | Assert.NotEqual(new NodeId(2, 100), new NodeId(3, 100)); 48 | } 49 | 50 | [Fact] 51 | public void NodeId_NumericValueNonEquivalence() 52 | { 53 | Assert.NotEqual(new NodeId(2, 100), new NodeId(2, 101)); 54 | } 55 | 56 | [Fact] 57 | public void NodeId_StringEquivalence() 58 | { 59 | Assert.Equal(new NodeId(2, "Test String"), new NodeId(2, "Test String")); 60 | } 61 | 62 | [Fact] 63 | public void NodeId_StringNamespaceNonEquivalence() 64 | { 65 | Assert.NotEqual(new NodeId(2, "Test String"), new NodeId(3, "Test String")); 66 | } 67 | 68 | [Fact] 69 | public void NodeId_StringValueNonEquivalence() 70 | { 71 | Assert.NotEqual(new NodeId(2, "Test String"), new NodeId(2, "Test String2")); 72 | } 73 | 74 | [Fact] 75 | public void NodeId_GuidEquivalence() 76 | { 77 | var guid = new Guid(); 78 | var guid2 = new Guid(guid.ToByteArray()); 79 | Assert.Equal(new NodeId(2, guid.ToByteArray(), NodeIdNetType.Guid), new NodeId(2, guid2.ToByteArray(), NodeIdNetType.Guid)); 80 | } 81 | 82 | [Fact] 83 | public void NodeId_GuidNamespaceNonEquivalence() 84 | { 85 | var guid = new Guid(); 86 | var guid2 = new Guid(guid.ToByteArray()); 87 | Assert.NotEqual(new NodeId(2, guid.ToByteArray(), NodeIdNetType.Guid), new NodeId(3, guid2.ToByteArray(), NodeIdNetType.Guid)); 88 | } 89 | 90 | [Fact] 91 | public void NodeId_GuidValueNonEquivalence() 92 | { 93 | var byteArray1 = Enumerable.Range(0, 16).Select(x => (byte)x).ToArray(); 94 | var byteArray2 = Enumerable.Range(1, 16).Select(x => (byte)x).ToArray(); 95 | var guid1 = new Guid(byteArray1); 96 | var guid2 = new Guid(byteArray2); 97 | Assert.NotEqual(new NodeId(2, guid1.ToByteArray(), NodeIdNetType.Guid), new NodeId(2, guid2.ToByteArray(), NodeIdNetType.Guid)); 98 | } 99 | 100 | [Fact] 101 | public void NodeId_OpaqueEquivalence() 102 | { 103 | Assert.Equal(new NodeId(2, [0, 1, 2, 3, 4], NodeIdNetType.ByteString), new NodeId(2, [0, 1, 2, 3, 4], NodeIdNetType.ByteString)); 104 | } 105 | 106 | [Fact] 107 | public void NodeId_OpaqueNamespaceNonEquivalence() 108 | { 109 | Assert.NotEqual(new NodeId(2, [0, 1, 2, 3, 4], NodeIdNetType.ByteString), new NodeId(3, [0, 1, 2, 3, 4], NodeIdNetType.ByteString)); 110 | } 111 | 112 | [Fact] 113 | public void NodeId_OpaqueValueNonEquivalence() 114 | { 115 | Assert.NotEqual(new NodeId(2, [0, 1, 2, 3, 4], NodeIdNetType.ByteString), new NodeId(2, [0, 1, 2, 3, 5], NodeIdNetType.ByteString)); 116 | } 117 | 118 | [Fact] 119 | public void NodeId_TryParse_Numeric() 120 | { 121 | var nodeId = NodeId.TryParse("ns=2;i=100"); 122 | Assert.NotNull(nodeId); 123 | Assert.Equal(2, nodeId.NamespaceIndex); 124 | Assert.Equal(100u, nodeId.NumericIdentifier); 125 | Assert.Equal(NodeIdNetType.Numeric, nodeId.IdType); 126 | } 127 | 128 | [Fact] 129 | public void NodeId_TryParse_String() 130 | { 131 | var nodeId = NodeId.TryParse("ns=2;s=TestString"); 132 | Assert.NotNull(nodeId); 133 | Assert.Equal(2, nodeId.NamespaceIndex); 134 | Assert.Equal("TestString", nodeId.StringIdentifier); 135 | Assert.Equal(NodeIdNetType.String, nodeId.IdType); 136 | } 137 | 138 | [Fact] 139 | public void NodeId_TryParse_OpaqueBase64() 140 | { 141 | var nodeId = NodeId.TryParse("ns=2;b=VEVTVHRlc3RURVNU"); 142 | Assert.NotNull(nodeId); 143 | Assert.Equal("ns=2;b=VEVTVHRlc3RURVNU", nodeId.ToString()); 144 | Assert.Equal(2, nodeId.NamespaceIndex); 145 | Assert.Equal(Convert.FromBase64String("VEVTVHRlc3RURVNU"), nodeId.ByteStringIdentifier); 146 | Assert.Equal(NodeIdNetType.ByteString, nodeId.IdType); 147 | } 148 | 149 | [Fact] 150 | public void NodeId_TryParse_Guid() 151 | { 152 | var guid = Guid.NewGuid(); 153 | var nodeId = NodeId.TryParse($"ns=2;g={guid}"); 154 | Assert.NotNull(nodeId); 155 | Assert.Equal($"ns=2;g={guid}", nodeId.ToString()); 156 | Assert.Equal(2, nodeId.NamespaceIndex); 157 | Assert.Equal(guid.ToByteArray(), nodeId.ByteStringIdentifier); 158 | Assert.Equal(NodeIdNetType.Guid, nodeId.IdType); 159 | } 160 | 161 | [Fact] 162 | public void NodeId_TryParse_DefaultNamespace() 163 | { 164 | var guid = Guid.NewGuid(); 165 | var nodeId = NodeId.TryParse($"g={guid}"); 166 | var expected = new NodeId(0, guid); 167 | Assert.NotNull(nodeId); 168 | Assert.Equal(expected, nodeId); 169 | } 170 | 171 | [Fact] 172 | public void NodeId_ToString_DefaultNamespace() 173 | { 174 | var guid = Guid.NewGuid(); 175 | var nodeId = new NodeId(0, guid); 176 | Assert.Equal($"g={guid}", nodeId.ToString()); 177 | } 178 | 179 | [Fact] 180 | public void NodeId_TryParse_OpcExamples() 181 | { 182 | var nodeIdA = NodeId.TryParse("i=13"); 183 | Assert.NotNull(nodeIdA); 184 | Assert.Equal(NodeIdNetType.Numeric, nodeIdA.IdType); 185 | Assert.Equal(0u, nodeIdA.NamespaceIndex); 186 | Assert.Equal(13u, nodeIdA.NumericIdentifier); 187 | 188 | var nodeIdB = NodeId.TryParse("ns=10;i=12345"); 189 | Assert.NotNull(nodeIdB); 190 | Assert.Equal(NodeIdNetType.Numeric, nodeIdB.IdType); 191 | Assert.Equal(10u, nodeIdB.NamespaceIndex); 192 | Assert.Equal(12345u, nodeIdB.NumericIdentifier); 193 | 194 | // TODO: Support nsu= format for NodeId 195 | //var nodeIdC = NodeId.TryParse("nsu=http://widgets.com/schemas/hello;s=水 World"); 196 | //Assert.NotNull(nodeIdC); 197 | //Assert.Equal(NodeIdNetType.String, nodeIdC.IdType); 198 | //Assert.Equal(10u, nodeIdC.NamespaceIndex); 199 | //Assert.Equal("水 World", nodeIdC.StringIdentifier); 200 | 201 | var nodeIdD = NodeId.TryParse("g=09087e75-8e5e-499b-954f-f2a9603db28a"); 202 | Assert.NotNull(nodeIdD); 203 | Assert.Equal(NodeIdNetType.Guid, nodeIdD.IdType); 204 | Assert.Equal(0u, nodeIdD.NamespaceIndex); 205 | Assert.Equal(new Guid("09087e75-8e5e-499b-954f-f2a9603db28a").ToByteArray(), nodeIdD.ByteStringIdentifier); 206 | 207 | // TODO: Support nsu= format for NodeId 208 | //var nodeIdE = NodeId.TryParse("nsu=tag:acme.com,2023:schemas:data#off%3B;b=M/RbKBsRVkePCePcx24oRA=="); 209 | //Assert.NotNull(nodeIdE); 210 | //Assert.Equal(NodeIdNetType.ByteString, nodeIdE.IdType); 211 | //Assert.Equal(10u, nodeIdE.NamespaceIndex); 212 | //Assert.Equal(Convert.FromBase64String("M/RbKBsRVkePCePcx24oRA=="), nodeIdE.ByteStringIdentifier); 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /NET Core/LibUA.Tests/TestServerClient.cs: -------------------------------------------------------------------------------- 1 | using LibUA.Core; 2 | 3 | namespace LibUA.Tests 4 | { 5 | [Collection(nameof(TestServerFixture))] 6 | public class TestServerClient : IDisposable 7 | { 8 | readonly TestClient client; 9 | 10 | public TestServerClient() 11 | { 12 | client = new TestClient(TestServerFixture.HostName, TestServerFixture.PortNumber, 100); 13 | 14 | Assert.Equal(StatusCode.Good, client.Connect()); 15 | Assert.Equal(StatusCode.Good, client.OpenSecureChannel(MessageSecurityMode.None, SecurityPolicy.None, null)); 16 | } 17 | 18 | public void Dispose() 19 | { 20 | Assert.Equal(StatusCode.Good, client.Disconnect()); 21 | 22 | client?.Dispose(); 23 | GC.SuppressFinalize(this); 24 | } 25 | 26 | [Fact] 27 | public void TestServerClient_ValidateApplicationDescriptions() 28 | { 29 | Assert.Equal(StatusCode.Good, client.FindServers(out ApplicationDescription[] appDescs, null)); 30 | Assert.NotEmpty(appDescs); 31 | } 32 | 33 | [Fact] 34 | public void TestServerClient_ValidateUnfilteredEndpointDescriptions() 35 | { 36 | Assert.Equal(StatusCode.Good, client.GetEndpoints(out EndpointDescription[] endpointDescs, null)); 37 | Assert.NotEmpty(endpointDescs); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /NET Core/LibUA/LibUA.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | nauful-$(AssemblyName)-core 6 | True 7 | https://github.com/nauful/libua 8 | (c) Nauful Shaikh, QuantenSystems LLC 2015-(now) 9 | Open-source OPC UA client and server library for .NET Core. 10 | LibUA Core 11 | git 12 | https://github.com/nauful/libua 13 | 1.0.33 14 | README.md 15 | LICENSE 16 | 17 | 18 | 19 | true 20 | 21 | 22 | 23 | true 24 | 25 | 26 | 27 | 28 | True 29 | \ 30 | 31 | 32 | True 33 | \ 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /NET Core/LibUA/ValueTypes/EUInformation.cs: -------------------------------------------------------------------------------- 1 | using LibUA.Core; 2 | 3 | namespace LibUA.ValueTypes; 4 | 5 | public class EUInformation 6 | { 7 | public string NameSpaceUri { get; set; } = "http://www.opcfoundation.org/UA/units/un/cefact"; 8 | public int UnitId { get; set; } = -1; 9 | public LocalizedText DisplayName { get; set; } = new(""); 10 | public LocalizedText Description { get; set; } = new(""); 11 | } 12 | 13 | public static class EUInformationExtensions 14 | { 15 | public static int CodingSize(this MemoryBuffer mem, EUInformation dv) 16 | { 17 | int sum = 0; 18 | 19 | sum += Coding.CodingSizeUAString(dv.NameSpaceUri); 20 | sum += Coding.CodingSize(dv.UnitId); 21 | sum += Coding.CodingSize(dv.DisplayName); 22 | sum += Coding.CodingSize(dv.Description); 23 | 24 | return sum; 25 | } 26 | 27 | public static bool Encode(this MemoryBuffer mem, EUInformation item) 28 | { 29 | if (!mem.EncodeUAString(item.NameSpaceUri)) { return false; } 30 | if (!mem.Encode(item.UnitId)) { return false; } 31 | if (!mem.Encode(item.DisplayName)) { return false; } 32 | if (!mem.Encode(item.Description)) { return false; } 33 | 34 | return true; 35 | } 36 | 37 | public static bool Decode(this MemoryBuffer mem, out EUInformation wv) 38 | { 39 | wv = null; 40 | 41 | if (!mem.DecodeUAString(out string namespaceUri)) { return false; } 42 | if (!mem.Decode(out int unitId)) { return false; } 43 | if (!mem.Decode(out LocalizedText displayName)) { return false; } 44 | if (!mem.Decode(out LocalizedText description)) { return false; } 45 | 46 | try 47 | { 48 | wv = new EUInformation() 49 | { 50 | NameSpaceUri = namespaceUri, 51 | UnitId = unitId, 52 | DisplayName = displayName, 53 | Description = description 54 | }; 55 | } 56 | catch 57 | { 58 | return false; 59 | } 60 | 61 | return true; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /NET Core/LibUA/ValueTypes/OpcRange.cs: -------------------------------------------------------------------------------- 1 | using LibUA.Core; 2 | 3 | namespace LibUA.ValueTypes; 4 | 5 | public class OpcRange 6 | { 7 | public double High { get; set; } 8 | public double Low { get; set; } 9 | } 10 | 11 | public static class RangeExtensions 12 | { 13 | public static int CodingSize(this MemoryBuffer mem, OpcRange dv) 14 | { 15 | int sum = 0; 16 | 17 | sum += Coding.CodingSize(dv.Low); 18 | sum += Coding.CodingSize(dv.High); 19 | 20 | return sum; 21 | } 22 | 23 | public static bool Encode(this MemoryBuffer mem, OpcRange item) 24 | { 25 | if (!mem.Encode(item.Low)) { return false; } 26 | if (!mem.Encode(item.High)) { return false; } 27 | 28 | return true; 29 | } 30 | 31 | public static bool Decode(this MemoryBuffer mem, out OpcRange wv) 32 | { 33 | wv = null; 34 | 35 | if (!mem.Decode(out double low)) { return false; } 36 | if (!mem.Decode(out double high)) { return false; } 37 | 38 | try 39 | { 40 | wv = new OpcRange() 41 | { 42 | High = high, 43 | Low = low 44 | }; 45 | } 46 | catch 47 | { 48 | return false; 49 | } 50 | 51 | return true; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /NET Core/TestClient/TestClient.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /NET Core/TestServer/TestServer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /NET/LibUA/LibUA.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {A02727B5-BA44-4B42-A75F-B35E295DBAF0} 8 | Library 9 | Properties 10 | LibUA 11 | LibUA 12 | v4.8 13 | 512 14 | true 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | true 26 | false 27 | 28 | 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | true 36 | false 37 | 38 | 39 | 40 | ..\..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.8.0.2\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll 41 | 42 | 43 | ..\..\packages\Microsoft.Extensions.Logging.Abstractions.8.0.3\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll 44 | 45 | 46 | 47 | ..\..\packages\System.Buffers.4.6.0\lib\net462\System.Buffers.dll 48 | 49 | 50 | 51 | ..\..\packages\System.Memory.4.6.0\lib\net462\System.Memory.dll 52 | 53 | 54 | 55 | ..\..\packages\System.Numerics.Vectors.4.6.0\lib\net462\System.Numerics.Vectors.dll 56 | 57 | 58 | ..\..\packages\System.Runtime.CompilerServices.Unsafe.6.1.0\lib\net462\System.Runtime.CompilerServices.Unsafe.dll 59 | 60 | 61 | 62 | ..\..\packages\System.Threading.Tasks.Extensions.4.6.0\lib\net462\System.Threading.Tasks.Extensions.dll 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/AesCng.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Security.Cryptography; 5 | 6 | namespace LibUA.Security.Cryptography 7 | { 8 | /// 9 | /// 10 | /// The AesCng class provides a wrapper for the CNG implementation of the AES algorithm. It 11 | /// provides the same interface as the other AES implementations shipped with the .NET Framework, 12 | /// including and . 13 | /// 14 | /// 15 | /// AesCng uses the BCrypt layer of CNG to do its work, and requires Windows Vista and the .NET 16 | /// Framework 3.5. 17 | /// 18 | /// 19 | /// Since most of the AesCng APIs are inherited from the base class, see the 20 | /// documentation for Aes for a complete API description. 21 | /// 22 | /// 23 | public sealed class AesCng : Aes, ICngSymmetricAlgorithm 24 | { 25 | private readonly BCryptSymmetricAlgorithm m_symmetricAlgorithm; 26 | 27 | /// 28 | /// Constructs an AesCng object. The default settings for this object are: 29 | /// 30 | /// Algorithm provider - Microsoft Primitive Algorithm Provider 31 | /// Block size - 128 bits 32 | /// Feedback size - 8 bits 33 | /// Key size - 256 bits 34 | /// Cipher mode - CipherMode.CBC 35 | /// Padding mode - PaddingMode.PKCS7 36 | /// 37 | /// 38 | public AesCng() : this(CngProvider2.MicrosoftPrimitiveAlgorithmProvider) 39 | { 40 | } 41 | 42 | /// 43 | /// Constructs an AesCng object using the specified algorithm provider. The default settings for 44 | /// this object are: 45 | /// 46 | /// Algorithm provider - Microsoft Primitive Algorithm Provider 47 | /// Block size - 128 bits 48 | /// Feedback size - 8 bits 49 | /// Key size - 256 bits 50 | /// Cipher mode - CipherMode.CBC 51 | /// Padding mode - PaddingMode.PKCS7 52 | /// 53 | /// 54 | /// if is null 55 | /// algorithm provider to use for AES computation 56 | public AesCng(CngProvider algorithmProvider) 57 | { 58 | if (algorithmProvider == null) 59 | throw new ArgumentNullException("algorithmProvider"); 60 | 61 | m_symmetricAlgorithm = new BCryptSymmetricAlgorithm(new CngAlgorithm(BCryptNative.AlgorithmName.Aes), 62 | algorithmProvider, 63 | LegalBlockSizesValue, 64 | LegalKeySizesValue) 65 | { 66 | // Propigate the default properties from the Aes class to the implementation algorithm. 67 | BlockSize = BlockSizeValue, 68 | KeySize = KeySizeValue, 69 | Mode = ModeValue, 70 | Padding = PaddingValue 71 | }; 72 | } 73 | 74 | protected override void Dispose(bool disposing) 75 | { 76 | try 77 | { 78 | if (disposing && m_symmetricAlgorithm != null) 79 | { 80 | (m_symmetricAlgorithm as IDisposable).Dispose(); 81 | } 82 | } 83 | finally 84 | { 85 | base.Dispose(disposing); 86 | } 87 | } 88 | 89 | // 90 | // Forwarded APIs 91 | // 92 | 93 | public override int BlockSize 94 | { 95 | get { return m_symmetricAlgorithm.BlockSize; } 96 | set { m_symmetricAlgorithm.BlockSize = value; } 97 | } 98 | 99 | public CngChainingMode CngMode 100 | { 101 | get { return m_symmetricAlgorithm.CngMode; } 102 | set { m_symmetricAlgorithm.CngMode = value; } 103 | } 104 | 105 | public override int FeedbackSize 106 | { 107 | get { return m_symmetricAlgorithm.FeedbackSize; } 108 | set { m_symmetricAlgorithm.FeedbackSize = value; } 109 | } 110 | 111 | public override byte[] IV 112 | { 113 | get { return m_symmetricAlgorithm.IV; } 114 | set { m_symmetricAlgorithm.IV = value; } 115 | } 116 | 117 | public override byte[] Key 118 | { 119 | get { return m_symmetricAlgorithm.Key; } 120 | set { m_symmetricAlgorithm.Key = value; } 121 | } 122 | 123 | public override int KeySize 124 | { 125 | get { return m_symmetricAlgorithm.KeySize; } 126 | set { m_symmetricAlgorithm.KeySize = value; } 127 | } 128 | 129 | public override KeySizes[] LegalBlockSizes 130 | { 131 | get { return m_symmetricAlgorithm.LegalBlockSizes; } 132 | } 133 | 134 | public override KeySizes[] LegalKeySizes 135 | { 136 | get { return m_symmetricAlgorithm.LegalBlockSizes; } 137 | } 138 | 139 | /// 140 | /// Gets or sets the cipher mode to use during encryption or decryption. Supported modes are: 141 | /// 142 | /// CipherMode.CBC 143 | /// CipherMode.ECB 144 | /// CipherMode.CFB 145 | /// 146 | /// 147 | public override CipherMode Mode 148 | { 149 | get { return m_symmetricAlgorithm.Mode; } 150 | set { m_symmetricAlgorithm.Mode = value; } 151 | } 152 | 153 | public override PaddingMode Padding 154 | { 155 | get { return m_symmetricAlgorithm.Padding; } 156 | set { m_symmetricAlgorithm.Padding = value; } 157 | } 158 | 159 | public CngProvider Provider 160 | { 161 | get { return m_symmetricAlgorithm.Provider; } 162 | } 163 | 164 | public override ICryptoTransform CreateDecryptor() 165 | { 166 | return m_symmetricAlgorithm.CreateDecryptor(); 167 | } 168 | 169 | public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV) 170 | { 171 | return m_symmetricAlgorithm.CreateDecryptor(rgbKey, rgbIV); 172 | } 173 | 174 | public override ICryptoTransform CreateEncryptor() 175 | { 176 | return m_symmetricAlgorithm.CreateEncryptor(); 177 | } 178 | 179 | public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV) 180 | { 181 | return m_symmetricAlgorithm.CreateEncryptor(rgbKey, rgbIV); 182 | } 183 | 184 | public override void GenerateIV() 185 | { 186 | m_symmetricAlgorithm.GenerateIV(); 187 | } 188 | 189 | public override void GenerateKey() 190 | { 191 | m_symmetricAlgorithm.GenerateKey(); 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/AuthenticatedAes.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Security.Cryptography; 5 | 6 | namespace LibUA.Security.Cryptography 7 | { 8 | /// 9 | /// The AuthenticatedAes abstract base class forms the base class for concrete implementations of 10 | /// authenticated AES algorithms. For instance, AES with CCM or GCM chaining modes provides 11 | /// authentication, and therefore derive from AuthenticatedAes. 12 | /// 13 | public abstract class AuthenticatedAes : AuthenticatedSymmetricAlgorithm 14 | { 15 | private static readonly KeySizes[] s_legalBlockSizes = { new KeySizes(128, 128, 0) }; 16 | private static readonly KeySizes[] s_legalKeySizes = { new KeySizes(128, 256, 64) }; 17 | 18 | protected AuthenticatedAes() 19 | { 20 | LegalBlockSizesValue = s_legalBlockSizes; 21 | LegalKeySizesValue = s_legalKeySizes; 22 | 23 | BlockSizeValue = 128; 24 | KeySizeValue = 256; 25 | } 26 | 27 | /// 28 | /// Creates an instance of the default AuthenticatedAes registered in . 29 | /// By default, this is the algorithm. 30 | /// 31 | public static new AuthenticatedAes Create() 32 | { 33 | return Create(typeof(AuthenticatedAes).Name); 34 | } 35 | 36 | /// 37 | /// Create an instance of the specified AuthenticatedAes type. If the type cannot be found in 38 | /// , Create returns null. 39 | /// 40 | /// name of the authenticated symmetric algorithm to create 41 | /// if is null 42 | public static new AuthenticatedAes Create(string algorithm) 43 | { 44 | if (algorithm == null) 45 | throw new ArgumentNullException("algorithm"); 46 | 47 | return CryptoConfig2.CreateFromName(algorithm) as AuthenticatedAes; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/BCryptAuthenticatedSymmetricAlgorithm.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Diagnostics; 5 | using System.Security; 6 | using System.Security.Cryptography; 7 | 8 | namespace LibUA.Security.Cryptography 9 | { 10 | /// 11 | /// Generic implementation of an authenticated symmetric algorithm which is provided by the BCrypt 12 | /// layer of CNG. Concrete AuthenticatedSymmetricAlgorithm classes should contain an instance of this 13 | /// type and delegate all of their work to that object. 14 | /// 15 | /// Most of the real encryption work occurs in the BCryptAuthenticatedCryptoTransform class. (see 16 | /// code:code:Microsoft.Security.Cryptography.BCryptAuthenticatedSymmetricCryptoTransform). 17 | /// 18 | internal sealed class BCryptAuthenticatedSymmetricAlgorithm : AuthenticatedSymmetricAlgorithm, ICngSymmetricAlgorithm 19 | { 20 | private readonly CngAlgorithm m_algorithm; 21 | private CngChainingMode m_chainingMode; 22 | private readonly CngProvider m_implementation; 23 | 24 | [SecurityCritical] 25 | [SecuritySafeCritical] 26 | internal BCryptAuthenticatedSymmetricAlgorithm(CngAlgorithm algorithm, 27 | CngProvider implementation, 28 | KeySizes[] legalBlockSizes, 29 | KeySizes[] legalKeySizes) 30 | { 31 | Debug.Assert(algorithm != null, "algorithm != null"); 32 | Debug.Assert(implementation != null, "implementation != null"); 33 | Debug.Assert(legalBlockSizes != null, "legalBlockSizes != null"); 34 | Debug.Assert(legalKeySizes != null, "legalKeySizes != null"); 35 | 36 | m_algorithm = algorithm; 37 | m_implementation = implementation; 38 | m_chainingMode = CngChainingMode.Gcm; 39 | 40 | LegalBlockSizesValue = legalBlockSizes; 41 | LegalKeySizesValue = legalKeySizes; 42 | 43 | // Create a temporary algorithm handle so that we can query it for some properties - such as the 44 | // block and tag sizes. 45 | using (SafeBCryptAlgorithmHandle algorithmHandle = SetupAlgorithm()) 46 | { 47 | // Get block size in bits 48 | BlockSize = BCryptNative.GetInt32Property(algorithmHandle, BCryptNative.ObjectPropertyName.BlockLength) * 8; 49 | 50 | UpdateLegalTagSizes(algorithmHandle); 51 | } 52 | } 53 | 54 | /// 55 | /// Determine if the current mode supports calculating the authenticated cipher across multiple 56 | /// transform calls, or must the entire cipher be calculated at once. 57 | /// 58 | public bool ChainingSupported 59 | { 60 | get 61 | { 62 | // Currently only CCM does not support chaining. 63 | return m_chainingMode != CngChainingMode.Ccm; 64 | } 65 | } 66 | 67 | /// 68 | /// Chaining mode to use for chaining in the authenticated algorithm. This value should be one 69 | /// of the CNG modes that is an authenticated chaining mode such as CCM or GCM. 70 | /// 71 | public CngChainingMode CngMode 72 | { 73 | get { return m_chainingMode; } 74 | 75 | set 76 | { 77 | if (value == null) 78 | throw new ArgumentNullException("value"); 79 | 80 | // Updating the chaining mode requires doing other work, such as figuring out the new set of 81 | // legal tag sizes. If we're just setting to the same value we already were in, then don't 82 | // bother changing the value. 83 | if (m_chainingMode != value) 84 | { 85 | // Don't do a direct check for GCM or CCM since we want to allow expansion to future 86 | // authenticated chaining modes. 87 | m_chainingMode = value; 88 | 89 | // Legal tag sizes vary with chaining mode, so we need to update them when we update the 90 | // chaining mode. Preserve the existing tag in case it's still legal in the new mode. 91 | byte[] tag = Tag; 92 | try 93 | { 94 | UpdateLegalTagSizes(); 95 | 96 | // If the old tag is still of a legal tag size, restore it as the new tag now. 97 | if (ValidTagSize(tag.Length * 8)) 98 | { 99 | Tag = tag; 100 | } 101 | } 102 | finally 103 | { 104 | Array.Clear(tag, 0, tag.Length); 105 | } 106 | } 107 | } 108 | } 109 | 110 | /// 111 | /// Algorithm provider which is implementing the authenticated transform 112 | /// 113 | public CngProvider Provider 114 | { 115 | get { return m_implementation; } 116 | } 117 | 118 | [SecurityCritical] 119 | [SecuritySafeCritical] 120 | public override IAuthenticatedCryptoTransform CreateAuthenticatedEncryptor(byte[] rgbKey, 121 | byte[] rgbIV, 122 | byte[] rgbAuthenticatedData) 123 | { 124 | return new BCryptAuthenticatedSymmetricCryptoTransform(SetupAlgorithm(), 125 | rgbKey, 126 | rgbIV, 127 | rgbAuthenticatedData, 128 | ChainingSupported, 129 | TagSize); 130 | } 131 | 132 | [SecurityCritical] 133 | [SecuritySafeCritical] 134 | public override ICryptoTransform CreateDecryptor(byte[] rgbKey, 135 | byte[] rgbIV, 136 | byte[] rgbAuthenticatedData, 137 | byte[] rgbTag) 138 | { 139 | if (rgbKey == null) 140 | throw new ArgumentNullException("rgbKey"); 141 | if (rgbTag == null) 142 | throw new ArgumentNullException("rgbTag"); 143 | 144 | return new BCryptAuthenticatedSymmetricCryptoTransform(SetupAlgorithm(), 145 | rgbKey, 146 | rgbIV, 147 | rgbAuthenticatedData, 148 | rgbTag, 149 | ChainingSupported); 150 | } 151 | 152 | /// 153 | /// Build an algorithm handle setup according to the parameters of this AES object 154 | /// 155 | [SecurityCritical] 156 | private SafeBCryptAlgorithmHandle SetupAlgorithm() 157 | { 158 | // Open the algorithm handle 159 | SafeBCryptAlgorithmHandle algorithm = 160 | BCryptNative.OpenAlgorithm(m_algorithm.Algorithm, m_implementation.Provider); 161 | 162 | // Set the chaining mode 163 | BCryptNative.SetStringProperty(algorithm, 164 | BCryptNative.ObjectPropertyName.ChainingMode, 165 | m_chainingMode.ChainingMode); 166 | 167 | return algorithm; 168 | } 169 | 170 | public override void GenerateIV() 171 | { 172 | // Both GCM and CCM work well with 12 byte nonces, so use that by default. 173 | IVValue = RNGCng.GenerateKey(12); 174 | } 175 | 176 | public override void GenerateKey() 177 | { 178 | KeyValue = RNGCng.GenerateKey(KeySizeValue / 8); 179 | } 180 | 181 | /// 182 | /// Update the legal tag sizes for this algorithm 183 | /// 184 | [SecurityCritical] 185 | [SecuritySafeCritical] 186 | private void UpdateLegalTagSizes() 187 | { 188 | using (SafeBCryptAlgorithmHandle algorithm = SetupAlgorithm()) 189 | { 190 | UpdateLegalTagSizes(algorithm); 191 | } 192 | } 193 | 194 | /// 195 | /// Update the legal tag sizes for this algortithm from an already opened algorithm handle 196 | /// 197 | [SecurityCritical] 198 | private void UpdateLegalTagSizes(SafeBCryptAlgorithmHandle algorithm) 199 | { 200 | Debug.Assert(algorithm != null, "algorithm != null"); 201 | Debug.Assert(!algorithm.IsClosed && !algorithm.IsInvalid, "!algorithm.IsClosed && !algorithm.IsInvalid"); 202 | 203 | // Get the authentication tag length structure. 204 | BCryptNative.BCRYPT_KEY_LENGTHS_STRUCT tagLengths = 205 | BCryptNative.GetValueTypeProperty( 206 | algorithm, 207 | BCryptNative.ObjectPropertyName.AuthTagLength); 208 | 209 | // BCrypt returns the tag sizes in bytes, convert them to bits for the LegalTagSizes property 210 | LegalTagSizesValue = new KeySizes[] 211 | { 212 | new KeySizes(tagLengths.dwMinLength * 8, tagLengths.dwMaxLength * 8, tagLengths.dwIncrement * 8) 213 | }; 214 | 215 | // By default, generate the maximum authentication tag length possible for this algorithm 216 | TagSize = tagLengths.dwMaxLength * 8; 217 | } 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/BCryptHMAC.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Diagnostics; 5 | using System.Globalization; 6 | using System.Security; 7 | using System.Security.Cryptography; 8 | 9 | namespace LibUA.Security.Cryptography 10 | { 11 | /// 12 | /// Generic implementation of HMAC which is implemented by the BCrypt layer of Cng. Concrete HMAC 13 | /// classes should contain an instance of the BCryptHMAC type and delegate their work to that object. 14 | /// 15 | internal sealed class BCryptHMAC : HMAC, ICngAlgorithm 16 | { 17 | private readonly SafeBCryptAlgorithmHandle m_algorithm; 18 | private SafeBCryptHashHandle m_hash; 19 | private readonly CngProvider m_implementation; 20 | 21 | [SecurityCritical] 22 | [SecuritySafeCritical] 23 | internal BCryptHMAC(CngAlgorithm algorithm, 24 | CngProvider algorithmProvider, 25 | string hashName, 26 | int blockSize, 27 | byte[] key) 28 | { 29 | Debug.Assert(algorithm != null, "algorithm != null"); 30 | Debug.Assert(algorithmProvider != null, "algorithmProvider != null"); 31 | Debug.Assert(!String.IsNullOrEmpty(hashName), "!String.IsNullOrEmpty(hashName)"); 32 | Debug.Assert(blockSize > 0, "blockSize > 0"); 33 | Debug.Assert(key != null, "key != null"); 34 | 35 | BlockSizeValue = blockSize; 36 | 37 | // We set the HashName up to be the CNG version of the hash, since the base type will instantiate 38 | // the algorithm, and the CNG versions have different FIPS characteristics than the standard implementations. 39 | HashName = String.Format(CultureInfo.InvariantCulture, 40 | "System.Security.Cryptography.{0}Cng, {1}", 41 | hashName, 42 | typeof(SHA256Cng).Assembly.FullName); 43 | 44 | m_implementation = algorithmProvider; 45 | 46 | m_algorithm = BCryptNative.OpenAlgorithm(algorithm.Algorithm, 47 | algorithmProvider.Provider, 48 | BCryptNative.AlgorithmProviderOptions.HmacAlgorithm); 49 | 50 | // Resetting the key will call Initialize for us, and get us setup with a hash handle, 51 | // so we don't need to create the hash handle ourselves 52 | Key = key; 53 | 54 | HashSizeValue = BCryptNative.GetInt32Property(m_hash, BCryptNative.HashPropertyName.HashLength) * 8; 55 | } 56 | 57 | public override bool CanReuseTransform 58 | { 59 | get { return true; } 60 | } 61 | 62 | public override bool CanTransformMultipleBlocks 63 | { 64 | get { return true; } 65 | } 66 | 67 | public override byte[] Key 68 | { 69 | set 70 | { 71 | // HMAC's Key setter will ensure that we're in a valid state to change the key 72 | base.Key = value; 73 | 74 | // Changing the key value requires us to create a new hash handle, so we need to reset 75 | Initialize(); 76 | } 77 | } 78 | 79 | public CngProvider Provider 80 | { 81 | get { return m_implementation; } 82 | } 83 | 84 | [SecurityCritical] 85 | [SecuritySafeCritical] 86 | protected override void Dispose(bool disposing) 87 | { 88 | try 89 | { 90 | if (disposing) 91 | { 92 | m_hash?.Dispose(); 93 | 94 | m_algorithm?.Dispose(); 95 | } 96 | } 97 | finally 98 | { 99 | base.Dispose(disposing); 100 | } 101 | } 102 | 103 | protected override void HashCore(byte[] rgb, int ib, int cb) 104 | { 105 | HashCoreImpl(rgb, ib, cb); 106 | } 107 | 108 | [SecurityCritical] 109 | [SecuritySafeCritical] 110 | internal void HashCoreImpl(byte[] rgb, int ib, int cb) 111 | { 112 | if (rgb == null) 113 | throw new ArgumentNullException("rgb"); 114 | if (ib < 0 || ib > rgb.Length - cb) 115 | throw new ArgumentOutOfRangeException("ib"); 116 | if (cb < 0 || cb > rgb.Length) 117 | throw new ArgumentOutOfRangeException("cb"); 118 | 119 | // Tell the base class that resetting the key is no longer allowed 120 | State = 1; 121 | 122 | byte[] data = new byte[cb]; 123 | Buffer.BlockCopy(rgb, ib, data, 0, data.Length); 124 | BCryptNative.HashData(m_hash, data); 125 | } 126 | 127 | protected override byte[] HashFinal() 128 | { 129 | return HashFinalImpl(); 130 | } 131 | 132 | [SecurityCritical] 133 | [SecuritySafeCritical] 134 | internal byte[] HashFinalImpl() 135 | { 136 | return BCryptNative.FinishHash(m_hash); 137 | } 138 | 139 | [SecurityCritical] 140 | [SecuritySafeCritical] 141 | public override void Initialize() 142 | { 143 | Debug.Assert(m_algorithm != null, "m_algorithm != null"); 144 | 145 | base.Initialize(); 146 | 147 | // If we have a previously used hash handle, we can clean it up now 148 | m_hash?.Dispose(); 149 | 150 | m_hash = BCryptNative.CreateHash(m_algorithm, KeyValue); 151 | 152 | // We're allowed to reset the key at this point 153 | State = 0; 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/BCryptPBKDF2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Globalization; 4 | using System.Security; 5 | using System.Security.Cryptography; 6 | 7 | namespace LibUA.Security.Cryptography 8 | { 9 | 10 | /// 11 | /// Set of hash algorithms that can be used with PBKDF2. 12 | /// Choosing, e.g., SHA-256, with compute PBKDF2 with HMAC-SHA256 as 13 | /// a PRF. 14 | /// 15 | public static class PBKDF2HashAlgorithm 16 | { 17 | public const string SHA1 = BCryptNative.AlgorithmName.Sha1; 18 | public const string SHA256 = BCryptNative.AlgorithmName.Sha256; 19 | public const string SHA384 = BCryptNative.AlgorithmName.Sha384; 20 | public const string SHA512 = BCryptNative.AlgorithmName.Sha512; 21 | 22 | public static bool ValidateHashName(string name) 23 | { 24 | if (name != SHA1 && 25 | name != SHA256 && 26 | name != SHA384 && 27 | name != SHA512) 28 | { 29 | return false; 30 | } 31 | return true; 32 | } 33 | } 34 | 35 | /// 36 | /// Class containing the API for PBKDF2, a wrapper of the CNG/bcrypt.dll implementation. 37 | /// 38 | public static class BCryptPBKDF2 39 | { 40 | /// 41 | /// Compute the PBKDF2 function on the given inputs using the CNG implementation in the BCryptKeyDerivation API. 42 | /// 43 | /// The hash function to use, must be one of the strings in . 44 | /// The password, as a byte array (i.e., without a string termination character). 45 | /// The salt, a cryptographically random value. Should be 16-bytes or longer. 46 | /// The number of iterations of PBKDF2 to apply. 47 | /// The digest of the password (also sometimes called derived key). The length of the digest 48 | /// will be equal to the length of the chosen hash function output. 49 | /// 50 | /// See http://msdn.microsoft.com/en-us/library/windows/desktop/hh448506 for a description 51 | /// of the wrapped function. Larger values of cIterations will cause the function to use more 52 | /// CPU time, and will also increase the workfactor for an attacker in a brute-force attack. 53 | /// 54 | public static byte[] ComputeHash(string hashName, byte[] password, byte[] salt, Int64 cIterations) 55 | { 56 | if (cIterations < 1) 57 | throw new ArgumentException("Iteration count must be greater than zero.", "cIterations"); 58 | if (salt == null) 59 | throw new ArgumentException("Salt must be non-null", "salt"); 60 | if (password == null) 61 | throw new ArgumentException("Password must be non-null", "password"); 62 | 63 | if (!PBKDF2HashAlgorithm.ValidateHashName(hashName)) 64 | throw new ArgumentException("Invalid hash name for PBKDF2"); 65 | double vers = Environment.OSVersion.Version.Major + Environment.OSVersion.Version.Minor * 0.1; 66 | 67 | 68 | byte[] digest; 69 | if (vers > 6.1) 70 | { 71 | // The BCryptKeyDerivation API is only supported on Win8/Server 2012 and above 72 | digest = BCryptNative.PBKDF2BCryptKeyDerivation(hashName, password, salt, (UInt64)cIterations); 73 | } 74 | else 75 | { 76 | // Fall back to BCryptDeriveKeyPBKDF2, which is roughly 2x slower on systems without the KeyDerivation API 77 | digest = BCryptNative.PBKDF2BCryptDeriveKeyPBKDF2(hashName, password, salt, (UInt64)cIterations); 78 | } 79 | 80 | return digest; 81 | } 82 | 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/BCryptSymmetricAlgorithm.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Diagnostics; 5 | using System.Security; 6 | using System.Security.Cryptography; 7 | 8 | namespace LibUA.Security.Cryptography 9 | { 10 | /// 11 | /// Generic implementation of a symmetric algorithm which is provided by the BCrypt layer of CNG. 12 | /// Concrete SymmetricAlgorithm classes should contain an instance of this type and delegate all of 13 | /// their work to that object. 14 | /// 15 | /// Most of the real encryption work occurs in the BCryptSymmetricCryptoTransform class. (see 16 | /// code:code:Microsoft.Security.Cryptography.BCryptSymmetricCryptoTransform). 17 | /// 18 | internal sealed class BCryptSymmetricAlgorithm : SymmetricAlgorithm, ICngSymmetricAlgorithm 19 | { 20 | private readonly CngAlgorithm m_algorithm; 21 | private readonly CngProvider m_algorithmProvider; 22 | private CngChainingMode m_chainingMode; 23 | 24 | internal BCryptSymmetricAlgorithm(CngAlgorithm algorithm, 25 | CngProvider algorithmProvider, 26 | KeySizes[] legalBlockSizes, 27 | KeySizes[] legalkeySizes) 28 | { 29 | Debug.Assert(algorithm != null, "algorithm != null"); 30 | Debug.Assert(algorithmProvider != null, "algorithmProvider != null"); 31 | Debug.Assert(legalBlockSizes != null, "legalBlockSizes != null"); 32 | Debug.Assert(legalkeySizes != null, "legalKeySizes != null"); 33 | 34 | m_algorithm = algorithm; 35 | m_algorithmProvider = algorithmProvider; 36 | 37 | LegalBlockSizesValue = legalBlockSizes; 38 | LegalKeySizesValue = legalkeySizes; 39 | } 40 | 41 | /// 42 | /// Setup a BCrypt algorithm with our current parameters 43 | /// 44 | [SecurityCritical] 45 | [SecuritySafeCritical] 46 | private SafeBCryptAlgorithmHandle SetupAlgorithm() 47 | { 48 | SafeBCryptAlgorithmHandle algorithmHandle = BCryptNative.OpenAlgorithm(m_algorithm.Algorithm, m_algorithmProvider.Provider); 49 | 50 | // If we've selected a different block size than the default, set that now 51 | if (BlockSize / 8 != BCryptNative.GetInt32Property(algorithmHandle, BCryptNative.ObjectPropertyName.BlockLength)) 52 | { 53 | BCryptNative.SetInt32Property(algorithmHandle, BCryptNative.ObjectPropertyName.BlockLength, BlockSize / 8); 54 | } 55 | 56 | BCryptNative.SetStringProperty(algorithmHandle, BCryptNative.ObjectPropertyName.ChainingMode, m_chainingMode.ChainingMode); 57 | 58 | return algorithmHandle; 59 | } 60 | 61 | // 62 | // ICngSymmetricAlgorithm implementation 63 | // 64 | 65 | public CngChainingMode CngMode 66 | { 67 | get { return m_chainingMode; } 68 | 69 | set 70 | { 71 | if (value == null) 72 | throw new ArgumentNullException("value"); 73 | 74 | m_chainingMode = value; 75 | } 76 | } 77 | 78 | public override CipherMode Mode 79 | { 80 | get 81 | { 82 | return BCryptNative.MapChainingMode(m_chainingMode.ChainingMode); 83 | } 84 | 85 | set 86 | { 87 | m_chainingMode = new CngChainingMode(BCryptNative.MapChainingMode(value)); 88 | } 89 | } 90 | 91 | public CngProvider Provider 92 | { 93 | get { return m_algorithmProvider; } 94 | } 95 | 96 | // 97 | // SymmetricAlgorithm abstract method implementations 98 | // 99 | 100 | [SecurityCritical] 101 | [SecuritySafeCritical] 102 | public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV) 103 | { 104 | if (rgbKey == null) 105 | throw new ArgumentNullException("rgbKey"); 106 | 107 | return new BCryptSymmetricCryptoTransform(SetupAlgorithm(), rgbKey, rgbIV, Padding, false); 108 | } 109 | 110 | [SecurityCritical] 111 | [SecuritySafeCritical] 112 | public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV) 113 | { 114 | if (rgbKey == null) 115 | throw new ArgumentNullException("rgbKey"); 116 | 117 | return new BCryptSymmetricCryptoTransform(SetupAlgorithm(), rgbKey, rgbIV, Padding, true); 118 | } 119 | 120 | public override void GenerateIV() 121 | { 122 | IVValue = RNGCng.GenerateKey(BlockSizeValue / 8); 123 | } 124 | 125 | public override void GenerateKey() 126 | { 127 | KeyValue = RNGCng.GenerateKey(KeySizeValue / 8); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/CngAlgorithm2.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Security.Cryptography; 5 | 6 | namespace LibUA.Security.Cryptography 7 | { 8 | /// 9 | /// The CngAlgorithm2 class provides additional objects to suppliment the 10 | /// ones found on the standard type. 11 | /// 12 | public static class CngAlgorithm2 13 | { 14 | private static CngAlgorithm s_aes; 15 | private static CngAlgorithm s_rsa; 16 | 17 | /// 18 | /// CngAlgorithm for the AES symmetric algorithm 19 | /// 20 | public static CngAlgorithm Aes 21 | { 22 | get 23 | { 24 | if (s_aes == null) 25 | { 26 | s_aes = new CngAlgorithm(BCryptNative.AlgorithmName.Aes); 27 | } 28 | 29 | return s_aes; 30 | } 31 | } 32 | 33 | /// 34 | /// CngAlgorithm for the RSA asymmetric algorithm 35 | /// 36 | public static CngAlgorithm Rsa 37 | { 38 | get 39 | { 40 | if (s_rsa == null) 41 | { 42 | s_rsa = new CngAlgorithm(BCryptNative.AlgorithmName.Rsa); 43 | } 44 | 45 | return s_rsa; 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/CngChainingMode.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Security.Cryptography; 5 | 6 | namespace LibUA.Security.Cryptography 7 | { 8 | /// 9 | /// The CngChainingMode class provides a pseudo-enumeration similar to 10 | /// which provides an enumeration over chaining modes that CNG supports. Several of the enumeration 11 | /// values are the CNG equivalents of the framework enumeration. 12 | /// 13 | [Serializable] 14 | public sealed class CngChainingMode : IEquatable 15 | { 16 | private static CngChainingMode s_cbc; 17 | private static CngChainingMode s_ccm; 18 | private static CngChainingMode s_cfb; 19 | private static CngChainingMode s_ecb; 20 | private static CngChainingMode s_gcm; 21 | 22 | private readonly string m_chainingMode; 23 | 24 | /// 25 | /// Creates a new CngChainingMode for the chaining mode string. This constructor should generally 26 | /// not be used, and instead the built in values for the standard chaining modes should be 27 | /// preferred. 28 | /// 29 | /// chaining mode to create a CngChainingMode object for 30 | /// if is empty 31 | /// if is null 32 | public CngChainingMode(string chainingMode) 33 | { 34 | if (chainingMode == null) 35 | throw new ArgumentNullException("chainingMode"); 36 | if (chainingMode.Length == 0) 37 | throw new ArgumentException("InvalidChainingModeName", "chainingMode"); 38 | 39 | m_chainingMode = chainingMode; 40 | } 41 | 42 | /// 43 | /// Get the string which represents this chaining mode to CNG 44 | /// 45 | public string ChainingMode 46 | { 47 | get { return m_chainingMode; } 48 | } 49 | 50 | public static bool operator ==(CngChainingMode left, CngChainingMode right) 51 | { 52 | if (Object.ReferenceEquals(left, null)) 53 | { 54 | return Object.ReferenceEquals(right, null); 55 | } 56 | 57 | return left.Equals(right); 58 | } 59 | 60 | public static bool operator !=(CngChainingMode left, CngChainingMode right) 61 | { 62 | if (Object.ReferenceEquals(left, null)) 63 | { 64 | return !Object.ReferenceEquals(right, null); 65 | } 66 | 67 | return !left.Equals(right); 68 | } 69 | 70 | public override bool Equals(object obj) 71 | { 72 | return Equals(obj as CngChainingMode); 73 | } 74 | 75 | public bool Equals(CngChainingMode other) 76 | { 77 | if (Object.ReferenceEquals(other, null)) 78 | { 79 | return false; 80 | } 81 | 82 | return m_chainingMode.Equals(other.ChainingMode); 83 | } 84 | 85 | public override int GetHashCode() 86 | { 87 | return m_chainingMode.GetHashCode(); 88 | } 89 | 90 | public override string ToString() 91 | { 92 | return m_chainingMode; 93 | } 94 | 95 | // 96 | // Well known chaining modes 97 | // 98 | 99 | /// 100 | /// Gets a CngChainingMode object for the cipher block chaining mode. This is equivalent to 101 | /// CipherMode.Cbc in the managed enumeration. 102 | /// 103 | public static CngChainingMode Cbc 104 | { 105 | get 106 | { 107 | if (s_cbc == null) 108 | { 109 | s_cbc = new CngChainingMode(BCryptNative.ChainingMode.Cbc); 110 | } 111 | 112 | return s_cbc; 113 | } 114 | } 115 | 116 | /// 117 | /// Gets a CngChainingMode object for the counter with cipher block chaining MAC authenticated 118 | /// chaining mode. 119 | /// 120 | public static CngChainingMode Ccm 121 | { 122 | get 123 | { 124 | if (s_ccm == null) 125 | { 126 | s_ccm = new CngChainingMode(BCryptNative.ChainingMode.Ccm); 127 | } 128 | 129 | return s_ccm; 130 | } 131 | } 132 | 133 | /// 134 | /// Gets a CngChainingMode object for the cipher feedback mode. This is equivalent to 135 | /// CipherMode.Cfb in the managed enumeration. 136 | /// 137 | public static CngChainingMode Cfb 138 | { 139 | get 140 | { 141 | if (s_cfb == null) 142 | { 143 | s_cfb = new CngChainingMode(BCryptNative.ChainingMode.Cfb); 144 | } 145 | 146 | return s_cfb; 147 | } 148 | } 149 | 150 | /// 151 | /// Gets a CngChainingMode object for the electronic codebook mode. This is equivalent to 152 | /// CipherMode.Ecb in the managed enumeration. 153 | /// 154 | public static CngChainingMode Ecb 155 | { 156 | get 157 | { 158 | if (s_ecb == null) 159 | { 160 | s_ecb = new CngChainingMode(BCryptNative.ChainingMode.Ecb); 161 | } 162 | 163 | return s_ecb; 164 | } 165 | } 166 | 167 | /// 168 | /// Gets a CngChainingMode object for the counter with Galois/counter mode authenticated chaining 169 | /// mode. 170 | /// 171 | public static CngChainingMode Gcm 172 | { 173 | get 174 | { 175 | if (s_gcm == null) 176 | { 177 | s_gcm = new CngChainingMode(BCryptNative.ChainingMode.Gcm); 178 | } 179 | 180 | return s_gcm; 181 | } 182 | } 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/CngKeyExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Runtime.CompilerServices; 6 | using System.Security; 7 | using System.Security.Cryptography; 8 | using System.Security.Cryptography.X509Certificates; 9 | using System.Security.Permissions; 10 | using Microsoft.Win32.SafeHandles; 11 | using LibUA.Security.Cryptography.X509Certificates; 12 | 13 | namespace LibUA.Security.Cryptography 14 | { 15 | /// 16 | /// 17 | /// The CngKeyExtensionMethods class provides several extension methods for the 18 | /// . This type is in the Security.Cryptography namespace (not the 19 | /// System.Security.Cryptography namespace), so in order to use these extension methods, you will 20 | /// need to make sure you include this namespace as well as a reference to 21 | /// Security.Cryptography.dll. 22 | /// 23 | /// 24 | /// CngKey uses the NCrypt layer of CNG, and requires Windows Vista and the .NET Framework 3.5. 25 | /// 26 | /// 27 | public static class CngKeyExtensionMethods 28 | { 29 | /// 30 | /// 31 | /// CreateSelfSignedCertificate creates a new self signed certificate issued to the specified 32 | /// subject. The certificate will contain the key used to create the self signed certificate. 33 | /// Since the certificate needs to be signed, the CngKey used must be usable for signing, which 34 | /// means it must also contain a private key. If there is no private key, the operation will fail 35 | /// with a CryptographicException indicating that "The key does not exist." 36 | /// 37 | /// 38 | /// This overload creates a certificate which does take ownership of the underlying key - which 39 | /// means that the input CngKey will be disposed before this method exits and should no longer 40 | /// be used by the caller. 41 | /// 42 | /// 43 | /// key to wrap in a self signed certificate 44 | /// the name of hte subject the self-signed certificate will be issued to 45 | /// if is null 46 | /// if the certificate cannot be created 47 | public static X509Certificate2 CreateSelfSignedCertificate(this CngKey key, 48 | X500DistinguishedName subjectName) 49 | { 50 | X509CertificateCreationParameters creationParameters = new X509CertificateCreationParameters(subjectName) 51 | { 52 | TakeOwnershipOfKey = true 53 | }; 54 | return CreateSelfSignedCertificate(key, creationParameters); 55 | } 56 | 57 | /// 58 | /// 59 | /// CreateSelfSignedCertificate creates a new self signed certificate issued to the specified 60 | /// subject. The certificate will contain the key used to create the self signed certificate. 61 | /// Since the certificate needs to be signed, the CngKey used must be usable for signing, which 62 | /// means it must also contain a private key. If there is no private key, the operation will fail 63 | /// with a CryptographicException indicating that "The key does not exist." 64 | /// 65 | /// 66 | /// If have TakeOwnershipOfKey set to true, the certificate 67 | /// generated will own the key and the input CngKey will be disposed to ensure that the caller 68 | /// doesn't accidentally use it beyond its lifetime (which is now controlled by the certificate 69 | /// object). 70 | /// 71 | /// 72 | /// Conversely, if TakeOwnershipOfKey is set to false, the API requires full trust to use, and 73 | /// also requires that the caller ensure that the generated certificate does not outlive the 74 | /// input CngKey object. 75 | /// 76 | /// 77 | /// key to wrap in a self signed certificate 78 | /// parameters to customize the self-signed certificate 79 | /// if is null 80 | /// if the certificate cannot be created 81 | /// 82 | /// This API requries full trust if specifies TakeOwnershipOfKey 83 | /// to be false. 84 | /// 85 | [SecurityCritical] 86 | [SecuritySafeCritical] 87 | public static X509Certificate2 CreateSelfSignedCertificate(this CngKey key, 88 | X509Certificates.X509CertificateCreationParameters creationParameters) 89 | { 90 | if (creationParameters == null) 91 | throw new ArgumentNullException("creationParameters"); 92 | 93 | // If we are not being asked to hand ownership of the key over to the certificate, then we need 94 | // ensure that we are running in a trusted context as we have no way to ensure that the caller 95 | // will not force the key to be cleaned up and then continue to use the dangling handle left in 96 | // the certificate. 97 | if (!creationParameters.TakeOwnershipOfKey) 98 | { 99 | new PermissionSet(PermissionState.Unrestricted).Demand(); 100 | } 101 | 102 | using (SafeCertContextHandle selfSignedCertHandle = 103 | X509Native.CreateSelfSignedCertificate(key, 104 | creationParameters.TakeOwnershipOfKey, 105 | creationParameters.SubjectName.RawData, 106 | creationParameters.CertificateCreationOptions, 107 | X509Native.MapCertificateSignatureAlgorithm(creationParameters.SignatureAlgorithm), 108 | creationParameters.StartTime, 109 | creationParameters.EndTime, 110 | creationParameters.ExtensionsNoDemand)) 111 | { 112 | // We need to get the raw handle out of the safe handle because X509Certificate2 only 113 | // exposes an IntPtr constructor. To do that we'll temporarially bump the ref count on 114 | // the handle. 115 | // 116 | // X509Certificate2 will duplicate the handle value in the .ctor, so once we've created 117 | // the certificate object, we can safely drop the ref count and dispose of our handle. 118 | X509Certificate2 certificate = null; 119 | bool addedRef = false; 120 | RuntimeHelpers.PrepareConstrainedRegions(); 121 | try 122 | { 123 | selfSignedCertHandle.DangerousAddRef(ref addedRef); 124 | certificate = new X509Certificate2(selfSignedCertHandle.DangerousGetHandle()); 125 | } 126 | finally 127 | { 128 | if (addedRef) 129 | { 130 | selfSignedCertHandle.DangerousRelease(); 131 | } 132 | } 133 | 134 | // If we passed ownership of the key to the certificate, than destroy the key 135 | // now so that we don't continue to use it beyond the liftime of the cert. 136 | if (creationParameters.TakeOwnershipOfKey) 137 | { 138 | key.Dispose(); 139 | } 140 | 141 | return certificate; 142 | } 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/CngProvider2.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Security.Cryptography; 5 | 6 | namespace LibUA.Security.Cryptography 7 | { 8 | /// 9 | /// The CngProvider2 class provides additional objects to suppliment the 10 | /// ones found on the standard type. 11 | /// 12 | public static class CngProvider2 13 | { 14 | private static CngProvider s_primitiveAlgorithmProvider; 15 | 16 | /// 17 | /// Get a CngProvider for the Microsoft Primitive algorithm provider 18 | /// 19 | public static CngProvider MicrosoftPrimitiveAlgorithmProvider 20 | { 21 | get 22 | { 23 | if (s_primitiveAlgorithmProvider == null) 24 | { 25 | s_primitiveAlgorithmProvider = new CngProvider(BCryptNative.ProviderName.MicrosoftPrimitiveProvider); 26 | } 27 | 28 | return s_primitiveAlgorithmProvider; 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/CngProviderCollection.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | using System.Diagnostics; 7 | using System.Runtime.InteropServices; 8 | using System.Security.Cryptography; 9 | 10 | namespace LibUA.Security.Cryptography 11 | { 12 | /// 13 | /// 14 | /// The CngProviderCollection class implements an enumerator over the installed CNG providers on 15 | /// the machine. The enumerator specifically lists the NCrypt key storage providers, and does not 16 | /// work with the BCrypt layer of CNG. 17 | /// 18 | /// 19 | /// CngProviderCollection uses the NCrypt layer of CNG to do its work, and requires Windows Vista 20 | /// and the .NET Framework 3.5. 21 | /// 22 | /// 23 | public sealed class CngProviderCollection : IEnumerable 24 | { 25 | /// 26 | /// Get an enumerator containing a for each of the installed NCrypt 27 | /// key storage providers on the current machine. 28 | /// 29 | public IEnumerator GetEnumerator() 30 | { 31 | foreach (NCryptNative.NCryptProviderName providerName in NCryptNative.EnumerateStorageProviders()) 32 | { 33 | yield return new CngProvider(providerName.pszName); 34 | } 35 | } 36 | 37 | /// 38 | /// Get an enumerator containing a for each of the installed NCrypt 39 | /// key storage providers on the current machine. 40 | /// 41 | IEnumerator IEnumerable.GetEnumerator() 42 | { 43 | return GetEnumerator(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/CngProviderExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics.CodeAnalysis; 6 | using System.Linq; 7 | using System.Security; 8 | using System.Security.Permissions; 9 | using System.Security.Cryptography; 10 | using Microsoft.Win32.SafeHandles; 11 | 12 | namespace LibUA.Security.Cryptography 13 | { 14 | /// 15 | /// 16 | /// The CngProviderExtensionMethods type provides several extension methods for the 17 | /// class. This type is in the Security.Cryptography namespace (not 18 | /// the System.Security.Cryptography namespace), so in order to use these extension methods, you 19 | /// will need to make sure you include this namespace as well as a reference to 20 | /// Security.Cryptography.dll 21 | /// 22 | /// 23 | /// CngProvider uses the NCrypt layer of CNG, and requires Windows Vista and the .NET Framework 24 | /// 3.5. 25 | /// 26 | /// 27 | public static class CngProviderExtensionMethods 28 | { 29 | /// 30 | /// GetKeys provides an enumerator over all of the keys that are stored in the key storage 31 | /// provider. 32 | /// 33 | public static IEnumerable GetKeys(this CngProvider provider) 34 | { 35 | foreach (CngKey machineKey in GetKeys(provider, CngKeyOpenOptions.MachineKey)) 36 | { 37 | yield return machineKey; 38 | } 39 | 40 | foreach (CngKey userKey in GetKeys(provider, CngKeyOpenOptions.UserKey)) 41 | { 42 | yield return userKey; 43 | } 44 | } 45 | 46 | /// 47 | /// GetKeys provides an enumerator over all of the keys that are stored in the key storage 48 | /// provider. This overload of GetKeys allows you to enumerate over only the user keys in the 49 | /// KSP or only the machine keys. 50 | /// 51 | /// CngProvider to enumerate the keys of 52 | /// options to use when opening the CNG keys 53 | [SecurityCritical] 54 | [SecuritySafeCritical] 55 | public static IEnumerable GetKeys(this CngProvider provider, CngKeyOpenOptions openOptions) 56 | { 57 | using (SafeNCryptProviderHandle providerHandle = provider.OpenProvider()) 58 | { 59 | NCryptNative.NCryptKeyName[] keyNames = NCryptNative.EnumerateKeys(providerHandle, openOptions); 60 | CngKey[] keys = new CngKey[keyNames.Length]; 61 | 62 | for (int i = 0; i < keys.Length; ++i) 63 | { 64 | keys[i] = CngKey.Open(keyNames[i].pszName, provider); 65 | } 66 | 67 | return keys; 68 | } 69 | } 70 | 71 | /// 72 | /// GetKeys provides an enumerator over all of the keys that are stored in the key storage 73 | /// provider. This overload of GetKeys allows you to enumerate over only the user keys in the KSP 74 | /// or only the machine keys. It also allows you to return only keys that are usable with a 75 | /// specified algorithm. 76 | /// 77 | /// CngProvider to enumerate the keys of 78 | /// options to use when opening the CNG keys 79 | /// algorithm that the returned keys should support 80 | /// if is null 81 | public static IEnumerable GetKeys(this CngProvider provider, 82 | CngKeyOpenOptions openOptions, 83 | CngAlgorithm algorithm) 84 | { 85 | if (algorithm == null) 86 | throw new ArgumentNullException("algorithm"); 87 | 88 | return from key in provider.GetKeys(openOptions) 89 | where key.Algorithm == algorithm 90 | select key; 91 | } 92 | 93 | /// 94 | /// GetSupportedAlgorithms provides an enumerator over all of the algorithms that the NCrypt 95 | /// provider supports. 96 | /// 97 | public static IEnumerable GetSupportedAlgorithms(this CngProvider provider) 98 | { 99 | return GetSupportedAlgorithms(provider, NCryptAlgorithmOperations.AsymmetricEncryption | 100 | NCryptAlgorithmOperations.Cipher | 101 | NCryptAlgorithmOperations.Hash | 102 | NCryptAlgorithmOperations.RandomNumberGeneration | 103 | NCryptAlgorithmOperations.SecretAgreement | 104 | NCryptAlgorithmOperations.Signature); 105 | } 106 | 107 | /// 108 | /// GetSupportedAlgorithms provides an enumerator over all of the algorithms that the NCrypt 109 | /// provider supports. Each of the returned algortihms will support at least one of the 110 | /// cryptographic operations specified by the operations parameter. 111 | /// 112 | /// CngProvider to enumerate the supported algorithms of 113 | /// operations that the returned algorithms should support 114 | [SecurityCritical] 115 | [SecuritySafeCritical] 116 | public static IEnumerable GetSupportedAlgorithms(this CngProvider provider, 117 | NCryptAlgorithmOperations operations) 118 | { 119 | using (SafeNCryptProviderHandle providerHandle = provider.OpenProvider()) 120 | { 121 | NCryptNative.NCryptAlgorithmName[] algorithmNames = NCryptNative.EnumerateAlgorithms(providerHandle, operations); 122 | CngAlgorithm[] algorithms = new CngAlgorithm[algorithmNames.Length]; 123 | 124 | for (int i = 0; i < algorithmNames.Length; ++i) 125 | { 126 | algorithms[i] = new CngAlgorithm(algorithmNames[i].pszName); 127 | } 128 | 129 | return algorithms; 130 | } 131 | } 132 | 133 | /// 134 | /// Gets a SafeHandle for the NCrypt provider. This handle can be used for P/Invoking to other 135 | /// APIs which expect an NCRYPT_PROV_HANDLE parameter. 136 | /// 137 | /// 138 | /// SecurityPermission/UnmanagedCode is required of the immediate caller to this API 139 | /// 140 | [SecurityCritical] 141 | [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] 142 | public static SafeNCryptProviderHandle OpenProvider(this CngProvider provider) 143 | { 144 | return NCryptNative.OpenKeyStorageProvider(provider.Provider); 145 | } 146 | } 147 | } -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | // This file is used by Code Analysis to maintain SuppressMessage 4 | // attributes that are applied to this project. 5 | // Project-level suppressions either have no target or are given 6 | // a specific target and scoped to a namespace, type, member, etc. 7 | // 8 | // To add a suppression to this file, right-click the message in the 9 | // Error List, point to "Suppress Message(s)", and click 10 | // "In Project Suppression File". 11 | // You do not need to add suppressions to this file manually. 12 | 13 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames")] 14 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "Security.Cryptography.Xml", Justification = "The types in this namespace map to the framework's System.Security.Cryptography.Xml namespace")] 15 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/HMACSHA256Cng.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Security.Cryptography; 6 | 7 | namespace LibUA.Security.Cryptography 8 | { 9 | /// 10 | /// 11 | /// The HMACSHA256Cng class provides a wrapper for the CNG implementation of the HMAC SHA256 12 | /// algorithm. It provides the same interface as the other HMAC implementations shipped with the 13 | /// .NET Framework, including 14 | /// 15 | /// 16 | /// HMACSHA256Cng uses the BCrypt layer of CNG to do its work, and requires Windows Vista and the 17 | /// .NET Framework 3.5. 18 | /// 19 | /// 20 | /// Since most of the HMACSHA256Cng APIs are inherited from the base class, 21 | /// please see the MSDN documentation for HMAC for a complete description. 22 | /// 23 | /// 24 | public sealed class HMACSHA256Cng : HMAC, ICngAlgorithm 25 | { 26 | private const int BlockSize = 64; 27 | 28 | private readonly BCryptHMAC m_hmac; 29 | 30 | /// 31 | /// Constructs a HMACSHA256Cng object with a randomly generated key, which will use the Microsoft 32 | /// PrimitiveAlgorithm Provider to do its work. 33 | /// 34 | public HMACSHA256Cng() : this(RNGCng.GenerateKey(BlockSize)) 35 | { 36 | } 37 | 38 | /// 39 | /// Constructs a HMACSHA256Cng object using the given key, which will use the Microsoft 40 | /// Primitive Algorithm Provider to do its work. 41 | /// 42 | /// key to use when calculating the HMAC 43 | /// if is null 44 | public HMACSHA256Cng(byte[] key) : this(key, CngProvider2.MicrosoftPrimitiveAlgorithmProvider) 45 | { 46 | } 47 | 48 | /// 49 | /// Constructs a HMACSHA256Cng object using the given key, which will calculate the HMAC using the 50 | /// given algorithm provider and key. 51 | /// 52 | /// key to use when calculating the HMAC 53 | /// algorithm provider to calculate the HMAC in 54 | /// 55 | /// if or are null 56 | /// 57 | public HMACSHA256Cng(byte[] key, CngProvider algorithmProvider) 58 | { 59 | if (key == null) 60 | throw new ArgumentNullException("key"); 61 | if (algorithmProvider == null) 62 | throw new ArgumentNullException("algorithmProvider"); 63 | 64 | m_hmac = new BCryptHMAC(CngAlgorithm.Sha256, algorithmProvider, "SHA256", BlockSize, key); 65 | HashName = m_hmac.HashName; 66 | } 67 | 68 | protected override void Dispose(bool disposing) 69 | { 70 | try 71 | { 72 | if (disposing) 73 | { 74 | if (m_hmac != null) 75 | { 76 | (m_hmac as IDisposable).Dispose(); 77 | } 78 | } 79 | } 80 | finally 81 | { 82 | base.Dispose(disposing); 83 | } 84 | } 85 | 86 | // 87 | // Forwarded APIs 88 | // 89 | 90 | public override bool CanReuseTransform 91 | { 92 | get { return m_hmac.CanReuseTransform; } 93 | } 94 | 95 | public override bool CanTransformMultipleBlocks 96 | { 97 | get { return m_hmac.CanTransformMultipleBlocks; } 98 | } 99 | 100 | public override byte[] Hash 101 | { 102 | get { return m_hmac.Hash; } 103 | } 104 | 105 | public override int HashSize 106 | { 107 | get { return m_hmac.HashSize; } 108 | } 109 | 110 | public override int InputBlockSize 111 | { 112 | get { return m_hmac.InputBlockSize; } 113 | } 114 | 115 | public override byte[] Key 116 | { 117 | get { return m_hmac.Key; } 118 | set { m_hmac.Key = value; } 119 | } 120 | 121 | public override int OutputBlockSize 122 | { 123 | get { return m_hmac.OutputBlockSize; } 124 | } 125 | 126 | public CngProvider Provider 127 | { 128 | get { return m_hmac.Provider; } 129 | } 130 | 131 | protected override void HashCore(byte[] rgb, int ib, int cb) 132 | { 133 | m_hmac.HashCoreImpl(rgb, ib, cb); 134 | } 135 | 136 | protected override byte[] HashFinal() 137 | { 138 | return m_hmac.HashFinalImpl(); 139 | } 140 | 141 | public override void Initialize() 142 | { 143 | m_hmac.Initialize(); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/HMACSHA384Cng.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Security.Cryptography; 6 | 7 | namespace LibUA.Security.Cryptography 8 | { 9 | /// 10 | /// 11 | /// The HMACSHA384Cng class provides a wrapper for the CNG implementation of the HMAC SHA384 12 | /// algorithm. It provides the same interface as the other HMAC implementations shipped with the 13 | /// .NET Framework, including 14 | /// 15 | /// 16 | /// HMACSHA384Cng uses the BCrypt layer of CNG to do its work, and requires Windows Vista and the 17 | /// .NET Framework 3.5. 18 | /// 19 | /// 20 | /// Since most of the HMACSHA384Cng APIs are inherited from the base class, 21 | /// please see the MSDN documentation for HMAC for a complete description. 22 | /// 23 | /// 24 | public sealed class HMACSHA384Cng : HMAC, ICngAlgorithm 25 | { 26 | private const int BlockSize = 128; 27 | 28 | private readonly BCryptHMAC m_hmac; 29 | 30 | /// 31 | /// Constructs a HMACSHA384Cng object with a randomly generated key, which will use the Microsoft 32 | /// PrimitiveAlgorithm Provider to do its work. 33 | /// 34 | public HMACSHA384Cng() : this(RNGCng.GenerateKey(BlockSize)) 35 | { 36 | } 37 | 38 | /// 39 | /// Constructs a HMACSHA384Cng object using the given key, which will use the Microsoft 40 | /// Primitive Algorithm Provider to do its work. 41 | /// 42 | /// key to use when calculating the HMAC 43 | /// if is null 44 | public HMACSHA384Cng(byte[] key) : this(key, CngProvider2.MicrosoftPrimitiveAlgorithmProvider) 45 | { 46 | } 47 | 48 | /// 49 | /// Constructs a HMACSHA384Cng object using the given key, which will calculate the HMAC using the 50 | /// given algorithm provider and key. 51 | /// 52 | /// key to use when calculating the HMAC 53 | /// algorithm provider to calculate the HMAC in 54 | /// 55 | /// if or are null 56 | /// 57 | public HMACSHA384Cng(byte[] key, CngProvider algorithmProvider) 58 | { 59 | if (key == null) 60 | throw new ArgumentNullException("key"); 61 | if (algorithmProvider == null) 62 | throw new ArgumentNullException("algorithmProvider"); 63 | 64 | m_hmac = new BCryptHMAC(CngAlgorithm.Sha384, algorithmProvider, "SHA384", BlockSize, key); 65 | HashName = m_hmac.HashName; 66 | } 67 | 68 | protected override void Dispose(bool disposing) 69 | { 70 | try 71 | { 72 | if (disposing) 73 | { 74 | if (m_hmac != null) 75 | { 76 | (m_hmac as IDisposable).Dispose(); 77 | } 78 | } 79 | } 80 | finally 81 | { 82 | base.Dispose(disposing); 83 | } 84 | } 85 | 86 | // 87 | // Forwarded APIs 88 | // 89 | 90 | public override bool CanReuseTransform 91 | { 92 | get { return m_hmac.CanReuseTransform; } 93 | } 94 | 95 | public override bool CanTransformMultipleBlocks 96 | { 97 | get { return m_hmac.CanTransformMultipleBlocks; } 98 | } 99 | 100 | public override byte[] Hash 101 | { 102 | get { return m_hmac.Hash; } 103 | } 104 | 105 | public override int HashSize 106 | { 107 | get { return m_hmac.HashSize; } 108 | } 109 | 110 | public override int InputBlockSize 111 | { 112 | get { return m_hmac.InputBlockSize; } 113 | } 114 | 115 | public override byte[] Key 116 | { 117 | get { return m_hmac.Key; } 118 | set { m_hmac.Key = value; } 119 | } 120 | 121 | public override int OutputBlockSize 122 | { 123 | get { return m_hmac.OutputBlockSize; } 124 | } 125 | 126 | public CngProvider Provider 127 | { 128 | get { return m_hmac.Provider; } 129 | } 130 | 131 | protected override void HashCore(byte[] rgb, int ib, int cb) 132 | { 133 | m_hmac.HashCoreImpl(rgb, ib, cb); 134 | } 135 | 136 | protected override byte[] HashFinal() 137 | { 138 | return m_hmac.HashFinalImpl(); 139 | } 140 | 141 | public override void Initialize() 142 | { 143 | m_hmac.Initialize(); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/HMACSHA512Cng.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Security.Cryptography; 6 | 7 | namespace LibUA.Security.Cryptography 8 | { 9 | /// 10 | /// 11 | /// The HMACSHA512Cng class provides a wrapper for the CNG implementation of the HMAC SHA512 12 | /// algorithm. It provides the same interface as the other HMAC implementations shipped with the 13 | /// .NET Framework, including 14 | /// 15 | /// 16 | /// HMACSHA512Cng uses the BCrypt layer of CNG to do its work, and requires Windows Vista and the 17 | /// .NET Framework 3.5. 18 | /// 19 | /// 20 | /// Since most of the HMACSHA512Cng APIs are inherited from the base class, 21 | /// please see the MSDN documentation for HMAC for a complete description. 22 | /// 23 | /// 24 | public sealed class HMACSHA512Cng : HMAC, ICngAlgorithm 25 | { 26 | private const int BlockSize = 128; 27 | 28 | private readonly BCryptHMAC m_hmac; 29 | 30 | /// 31 | /// Constructs a HMACSHA512Cng object with a randomly generated key, which will use the Microsoft 32 | /// PrimitiveAlgorithm Provider to do its work. 33 | /// 34 | public HMACSHA512Cng() : this(RNGCng.GenerateKey(BlockSize)) 35 | { 36 | } 37 | 38 | /// 39 | /// Constructs a HMACSHA512Cng object using the given key, which will use the Microsoft 40 | /// Primitive Algorithm Provider to do its work. 41 | /// 42 | /// key to use when calculating the HMAC 43 | /// if is null 44 | public HMACSHA512Cng(byte[] key) : this(key, CngProvider2.MicrosoftPrimitiveAlgorithmProvider) 45 | { 46 | } 47 | 48 | /// 49 | /// Constructs a HMACSHA512Cng object using the given key, which will calculate the HMAC using the 50 | /// given algorithm provider and key. 51 | /// 52 | /// key to use when calculating the HMAC 53 | /// algorithm provider to calculate the HMAC in 54 | /// 55 | /// if or are null 56 | /// 57 | public HMACSHA512Cng(byte[] key, CngProvider algorithmProvider) 58 | { 59 | if (key == null) 60 | throw new ArgumentNullException("key"); 61 | if (algorithmProvider == null) 62 | throw new ArgumentNullException("algorithmProvider"); 63 | 64 | m_hmac = new BCryptHMAC(CngAlgorithm.Sha512, algorithmProvider, "SHA512", BlockSize, key); 65 | HashName = m_hmac.HashName; 66 | } 67 | 68 | protected override void Dispose(bool disposing) 69 | { 70 | try 71 | { 72 | if (disposing) 73 | { 74 | if (m_hmac != null) 75 | { 76 | (m_hmac as IDisposable).Dispose(); 77 | } 78 | } 79 | } 80 | finally 81 | { 82 | base.Dispose(disposing); 83 | } 84 | } 85 | 86 | // 87 | // Forwarded APIs 88 | // 89 | 90 | public override bool CanReuseTransform 91 | { 92 | get { return m_hmac.CanReuseTransform; } 93 | } 94 | 95 | public override bool CanTransformMultipleBlocks 96 | { 97 | get { return m_hmac.CanTransformMultipleBlocks; } 98 | } 99 | 100 | public override byte[] Hash 101 | { 102 | get { return m_hmac.Hash; } 103 | } 104 | 105 | public override int HashSize 106 | { 107 | get { return m_hmac.HashSize; } 108 | } 109 | 110 | public override int InputBlockSize 111 | { 112 | get { return m_hmac.InputBlockSize; } 113 | } 114 | 115 | public override byte[] Key 116 | { 117 | get { return m_hmac.Key; } 118 | set { m_hmac.Key = value; } 119 | } 120 | 121 | public override int OutputBlockSize 122 | { 123 | get { return m_hmac.OutputBlockSize; } 124 | } 125 | 126 | public CngProvider Provider 127 | { 128 | get { return m_hmac.Provider; } 129 | } 130 | 131 | protected override void HashCore(byte[] rgb, int ib, int cb) 132 | { 133 | m_hmac.HashCoreImpl(rgb, ib, cb); 134 | } 135 | 136 | protected override byte[] HashFinal() 137 | { 138 | return m_hmac.HashFinalImpl(); 139 | } 140 | 141 | public override void Initialize() 142 | { 143 | m_hmac.Initialize(); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/IAuthenticatedCryptoTransform.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Security.Cryptography; 5 | 6 | namespace LibUA.Security.Cryptography 7 | { 8 | /// 9 | /// Interface for crypto transforms that support generating an authentication tag. 10 | /// 11 | public interface IAuthenticatedCryptoTransform : ICryptoTransform2 12 | { 13 | /// 14 | /// Get the authentication tag produced by the transform. This is only valid in the encryption 15 | /// case and only after the final block has been transformed. 16 | /// 17 | /// 18 | /// If the crypto transform is a decryptor, or if the final block has not yet been transformed. 19 | /// 20 | byte[] GetTag(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/ICngAlgorithm.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Security.Cryptography; 5 | 6 | namespace LibUA.Security.Cryptography 7 | { 8 | /// 9 | /// Interface for algorithms implemented over the CNG layer of Windows to provide CNG implementation 10 | /// details through. 11 | /// 12 | public interface ICngAlgorithm 13 | { 14 | /// 15 | /// Gets the algorithm or key storage provider being used for the implementation of the CNG 16 | /// algorithm. 17 | /// 18 | CngProvider Provider { get; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/ICngAsymmetricAlgorithm.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Security; 5 | using System.Security.Cryptography; 6 | using System.Security.Permissions; 7 | 8 | namespace LibUA.Security.Cryptography 9 | { 10 | /// 11 | /// Interface for asymmetric algorithms implemented over the CNG layer of Windows to provide CNG 12 | /// implementation details through. 13 | /// 14 | public interface ICngAsymmetricAlgorithm : ICngAlgorithm 15 | { 16 | /// 17 | /// Get the CNG key being used by the asymmetric algorithm. 18 | /// 19 | /// 20 | /// This method requires that the immediate caller have SecurityPermission/UnmanagedCode 21 | /// 22 | CngKey Key 23 | { 24 | [SecurityCritical] 25 | [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] 26 | get; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/ICngSymmetricAlgorithm.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Security.Cryptography; 5 | 6 | namespace LibUA.Security.Cryptography 7 | { 8 | /// 9 | /// Interface for symmetric algorithms implemented over the CNG layer of Windows to provide CNG 10 | /// implementation details through. 11 | /// 12 | public interface ICngSymmetricAlgorithm : ICngAlgorithm 13 | { 14 | /// 15 | /// Get or set the CNG chaining mode the algorithm is using. 16 | /// 17 | CngChainingMode CngMode { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/ICryptoTransform2.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Security.Cryptography; 5 | 6 | namespace LibUA.Security.Cryptography 7 | { 8 | /// 9 | /// Extended crypto transform interface which provides extra information about the capabilities of a 10 | /// specific transform. 11 | /// 12 | public interface ICryptoTransform2 : ICryptoTransform 13 | { 14 | /// 15 | /// 16 | /// Can the transform be used in a chained mode - where it is invoked multiple times before 17 | /// the final ciphertext and tag are retrieved. (For example, can it transform each block in 18 | /// the input in seperate calls, or must they all come in through a single call.) 19 | /// 20 | /// 21 | /// This is different from CanTransformMultipleBlocks in that CanTransformMultipleBlocks 22 | /// indicates if a transform can handle multiple blocks of input in a single call, while 23 | /// CanChainBlocks indicates if a transform can chain multiple blocks of input across multiple 24 | /// calls to TransformBlock/TransformFinalBlock. 25 | /// 26 | /// 27 | bool CanChainBlocks { get; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/RNGCng.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Diagnostics; 5 | using System.Diagnostics.CodeAnalysis; 6 | using System.Security; 7 | using System.Security.Cryptography; 8 | 9 | namespace LibUA.Security.Cryptography 10 | { 11 | /// 12 | /// 13 | /// The RNGCng class provides a managed wrapper around the CNG random number generator. It 14 | /// provides the same interface as the other cryptographic random number generator implementation 15 | /// shipped with the .NET Framework, . 16 | /// 17 | /// 18 | /// RNGCng uses the BCrypt layer of CNG to do its work, and requires Windows Vista and the .NET 19 | /// Framework 3.5. 20 | /// 21 | /// 22 | public sealed class RNGCng : RandomNumberGenerator, ICngAlgorithm, IDisposable 23 | { 24 | private readonly SafeBCryptAlgorithmHandle m_algorithm; 25 | private readonly CngProvider m_implementation; 26 | 27 | private static readonly RNGCng s_rngCng = new RNGCng(); 28 | 29 | /// 30 | /// Creates a new instance of a random number generator object using the Microsoft Primitive 31 | /// Algorithm Provider. 32 | /// 33 | public RNGCng() : this(CngProvider2.MicrosoftPrimitiveAlgorithmProvider) 34 | { 35 | } 36 | 37 | /// 38 | /// Creates a new instance of a random number generator object using the specified 39 | /// algorithm provider. 40 | /// 41 | /// algorithm provider to use for random number generation 42 | /// if is null 43 | [SecurityCritical] 44 | [SecuritySafeCritical] 45 | public RNGCng(CngProvider algorithmProvider) 46 | { 47 | if (algorithmProvider == null) 48 | throw new ArgumentNullException("algorithmProvider"); 49 | 50 | m_algorithm = BCryptNative.OpenAlgorithm(BCryptNative.AlgorithmName.Rng, 51 | algorithmProvider.Provider); 52 | 53 | m_implementation = algorithmProvider; 54 | } 55 | 56 | public CngProvider Provider 57 | { 58 | get { return m_implementation; } 59 | } 60 | 61 | /// 62 | /// Static random number generator that can be shared within the AppDomain 63 | /// 64 | internal static RNGCng StaticRng 65 | { 66 | get { return s_rngCng; } 67 | } 68 | 69 | [SecurityCritical] 70 | [SecuritySafeCritical] 71 | public new void Dispose() 72 | { 73 | m_algorithm?.Dispose(); 74 | } 75 | 76 | /// 77 | /// Helper function to generate a random key value using the static RNG 78 | /// 79 | internal static byte[] GenerateKey(int size) 80 | { 81 | Debug.Assert(size > 0, "size > 0"); 82 | 83 | byte[] key = new byte[size]; 84 | StaticRng.GetBytes(key); 85 | return key; 86 | } 87 | 88 | /// 89 | /// 90 | /// GetBytes fills the input data array with randomly generated bytes. The input values of the 91 | /// array are ignored. 92 | /// 93 | /// 94 | /// This method is thread safe. 95 | /// 96 | /// 97 | /// array to fill with randomly generated bytes 98 | /// if is null 99 | [SecurityCritical] 100 | [SecuritySafeCritical] 101 | public override void GetBytes(byte[] data) 102 | { 103 | if (data == null) 104 | throw new ArgumentNullException("data"); 105 | 106 | BCryptNative.GenerateRandomBytes(m_algorithm, data); 107 | } 108 | 109 | /// 110 | /// GetNonZeroBytes is not implemented by the RNGCng class. 111 | /// 112 | /// GetNonZeroBytes is not implemented 113 | public override void GetNonZeroBytes(byte[] data) 114 | { 115 | throw new NotImplementedException(); 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/RSAPKCS1SHA256SignatureDescription.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Security.Cryptography; 6 | 7 | namespace LibUA.Security.Cryptography 8 | { 9 | /// 10 | /// 11 | /// The RSAPKCS1SHA256SignatureDescription class provides a signature description implementation 12 | /// for RSA-SHA256 signatures. It allows XML digital signatures to be produced using the 13 | /// http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 signature type. 14 | /// RSAPKCS1SHA256SignatureDescription provides the same interface as other signature description 15 | /// implementations shipped with the .NET Framework, such as 16 | /// . 17 | /// 18 | /// 19 | /// RSAPKCS1SHA256SignatureDescription is not generally intended for use on its own, instead it 20 | /// should be consumed by higher level cryptography services such as the XML digital signature 21 | /// stack. It can be registered in so that these services can create 22 | /// instances of this signature description and use RSA-SHA256 signatures. 23 | /// 24 | /// 25 | /// Registration in CryptoConfig requires editing the machine.config file found in the .NET 26 | /// Framework installation's configuration directory (such as 27 | /// %WINDIR%\Microsoft.NET\Framework\v2.0.50727\Config or 28 | /// %WINDIR%\Microsoft.NET\Framework64\v2.0.50727\Config) to include registration information on 29 | /// the type. For example: 30 | /// 31 | /// 32 | /// 34 | /// 35 | /// 36 | /// 37 | /// 38 | /// 39 | /// 40 | /// 41 | /// 42 | /// 43 | /// 44 | /// 45 | /// 46 | /// ]]> 47 | /// 48 | /// 49 | /// After adding this registration entry, the assembly which contains the 50 | /// RSAPKCS1SHA256SignatureDescription (in the example above Security.Cryptography.dll) needs to 51 | /// be added to the GAC. 52 | /// 53 | /// 54 | /// Note that on 64 bit machines, both the Framework and Framework64 machine.config files should 55 | /// be updated, and if the signature description assembly is built bit-specific it needs to be 56 | /// added to both the 32 and 64 bit GACs. 57 | /// 58 | /// 59 | /// RSA-SHA256 signatures are first available on the .NET Framework 3.5 SP 1 and as such the 60 | /// RSAPKCS1SHA256SignatureDescription requires .NET 3.5 SP 1 and Windows Server 2003 or greater 61 | /// to work properly. 62 | /// 63 | /// 64 | /// On Windows 2003, the default OID registrations are not setup for the SHA2 family of hash 65 | /// algorithms, and this can cause the .NET Framework v3.5 SP 1 to be unable to create RSA-SHA2 66 | /// signatures. To fix this problem, the 67 | /// method can be called to create the necessary OID registrations. 68 | /// 69 | /// 70 | public sealed class RSAPKCS1SHA256SignatureDescription : SignatureDescription 71 | { 72 | /// 73 | /// Construct an RSAPKCS1SHA256SignatureDescription object. The default settings for this object 74 | /// are: 75 | /// 76 | /// Digest algorithm - 77 | /// Key algorithm - 78 | /// Formatter algorithm - 79 | /// Deformatter algorithm - 80 | /// 81 | /// 82 | public RSAPKCS1SHA256SignatureDescription() 83 | { 84 | KeyAlgorithm = typeof(RSACryptoServiceProvider).FullName; 85 | DigestAlgorithm = typeof(SHA256Managed).FullName; // Note - SHA256CryptoServiceProvider is not registered with CryptoConfig 86 | FormatterAlgorithm = typeof(RSAPKCS1SignatureFormatter).FullName; 87 | DeformatterAlgorithm = typeof(RSAPKCS1SignatureDeformatter).FullName; 88 | } 89 | 90 | public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key) 91 | { 92 | if (key == null) 93 | throw new ArgumentNullException("key"); 94 | 95 | RSAPKCS1SignatureDeformatter deformatter = new RSAPKCS1SignatureDeformatter(key); 96 | deformatter.SetHashAlgorithm("SHA256"); 97 | return deformatter; 98 | } 99 | 100 | public override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key) 101 | { 102 | if (key == null) 103 | throw new ArgumentNullException("key"); 104 | 105 | RSAPKCS1SignatureFormatter formatter = new RSAPKCS1SignatureFormatter(key); 106 | formatter.SetHashAlgorithm("SHA256"); 107 | return formatter; 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/TripleDESCng.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Security.Cryptography; 6 | 7 | namespace LibUA.Security.Cryptography 8 | { 9 | /// 10 | /// 11 | /// The TripleDESCng class provides a wrapper for the CNG implementation of the 3DES algorithm. It 12 | /// provides the same interface as the 13 | /// implementation shipped with the .NET Framework. 14 | /// 15 | /// 16 | /// TripleDESCng uses the BCrypt layer of CNG to do its work, and requires Windows Vista and the 17 | /// .NET Framework 3.5. 18 | /// 19 | /// 20 | /// Since most of the TripleDESCng APIs are inherited from the base 21 | /// class, please see the MSDN documentation for TripleDES for a complete description. 22 | /// 23 | /// 24 | public sealed class TripleDESCng : TripleDES, ICngSymmetricAlgorithm 25 | { 26 | private readonly BCryptSymmetricAlgorithm m_symmetricAlgorithm; 27 | 28 | /// 29 | /// Constructs a TripleDESCng object. The default settings for this object are: 30 | /// 31 | /// Algorithm provider - Microsoft Primitive Algorithm Provider 32 | /// Block size - 64 bits 33 | /// Feedback size - 64 bits 34 | /// Key size - 192 bits 35 | /// Cipher mode - CipherMode.CBC 36 | /// Padding mode - PaddingMode.PKCS7 37 | /// 38 | /// 39 | public TripleDESCng() : this(CngProvider2.MicrosoftPrimitiveAlgorithmProvider) 40 | { 41 | } 42 | 43 | /// 44 | /// Constructs a TripleDESCng object which uses the specified algorithm provider. The default 45 | /// settings for this object are: 46 | /// 47 | /// Block size - 64 bits 48 | /// Feedback size - 64 bits 49 | /// Key size - 192 bits 50 | /// Cipher mode - CipherMode.CBC 51 | /// Padding mode - PaddingMode.PKCS7 52 | /// 53 | /// 54 | /// algorithm provider to use for 3DES computation 55 | /// if is null 56 | public TripleDESCng(CngProvider algorithmProvider) 57 | { 58 | if (algorithmProvider == null) 59 | throw new ArgumentNullException("algorithmProvider"); 60 | 61 | m_symmetricAlgorithm = new BCryptSymmetricAlgorithm(new CngAlgorithm(BCryptNative.AlgorithmName.TripleDes), 62 | algorithmProvider, 63 | LegalBlockSizesValue, 64 | LegalKeySizesValue) 65 | { 66 | // Propigate the default properties from the TripleDES class to the implementation algorithm. 67 | BlockSize = BlockSizeValue, 68 | KeySize = KeySizeValue, 69 | Mode = ModeValue, 70 | Padding = PaddingValue 71 | }; 72 | } 73 | 74 | protected override void Dispose(bool disposing) 75 | { 76 | try 77 | { 78 | if (disposing && m_symmetricAlgorithm != null) 79 | { 80 | (m_symmetricAlgorithm as IDisposable).Dispose(); 81 | } 82 | } 83 | finally 84 | { 85 | base.Dispose(disposing); 86 | } 87 | } 88 | 89 | // 90 | // Forwarded APIs 91 | // 92 | 93 | public override int BlockSize 94 | { 95 | get { return m_symmetricAlgorithm.BlockSize; } 96 | set { m_symmetricAlgorithm.BlockSize = value; } 97 | } 98 | 99 | public CngChainingMode CngMode 100 | { 101 | get { return m_symmetricAlgorithm.CngMode; } 102 | set { m_symmetricAlgorithm.CngMode = value; } 103 | } 104 | 105 | public override int FeedbackSize 106 | { 107 | get { return m_symmetricAlgorithm.FeedbackSize; } 108 | set { m_symmetricAlgorithm.FeedbackSize = value; } 109 | } 110 | 111 | public override byte[] IV 112 | { 113 | get { return m_symmetricAlgorithm.IV; } 114 | set { m_symmetricAlgorithm.IV = value; } 115 | } 116 | 117 | public override byte[] Key 118 | { 119 | get { return m_symmetricAlgorithm.Key; } 120 | set { m_symmetricAlgorithm.Key = value; } 121 | } 122 | 123 | public override int KeySize 124 | { 125 | get { return m_symmetricAlgorithm.KeySize; } 126 | set { m_symmetricAlgorithm.KeySize = value; } 127 | } 128 | 129 | public override KeySizes[] LegalBlockSizes 130 | { 131 | get { return m_symmetricAlgorithm.LegalBlockSizes; } 132 | } 133 | 134 | public override KeySizes[] LegalKeySizes 135 | { 136 | get { return m_symmetricAlgorithm.LegalBlockSizes; } 137 | } 138 | 139 | /// 140 | /// Gets or sets the cipher mode to use during encryption or decryption. Supported modes are: 141 | /// 142 | /// CipherMode.CBC 143 | /// CipherMode.ECB 144 | /// CipherMode.CFB 145 | /// 146 | /// 147 | public override CipherMode Mode 148 | { 149 | get { return m_symmetricAlgorithm.Mode; } 150 | set { m_symmetricAlgorithm.Mode = value; } 151 | } 152 | 153 | public override PaddingMode Padding 154 | { 155 | get { return m_symmetricAlgorithm.Padding; } 156 | set { m_symmetricAlgorithm.Padding = value; } 157 | } 158 | 159 | public CngProvider Provider 160 | { 161 | get { return m_symmetricAlgorithm.Provider; } 162 | } 163 | 164 | public override ICryptoTransform CreateDecryptor() 165 | { 166 | return m_symmetricAlgorithm.CreateDecryptor(); 167 | } 168 | 169 | public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV) 170 | { 171 | return m_symmetricAlgorithm.CreateDecryptor(rgbKey, rgbIV); 172 | } 173 | 174 | public override ICryptoTransform CreateEncryptor() 175 | { 176 | return m_symmetricAlgorithm.CreateEncryptor(); 177 | } 178 | 179 | public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV) 180 | { 181 | return m_symmetricAlgorithm.CreateEncryptor(rgbKey, rgbIV); 182 | } 183 | 184 | public override void GenerateIV() 185 | { 186 | m_symmetricAlgorithm.GenerateIV(); 187 | } 188 | 189 | public override void GenerateKey() 190 | { 191 | m_symmetricAlgorithm.GenerateKey(); 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/Win32Native.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Diagnostics; 5 | using System.Diagnostics.CodeAnalysis; 6 | using System.Runtime.CompilerServices; 7 | using System.Runtime.ConstrainedExecution; 8 | using System.Runtime.InteropServices; 9 | using System.Security; 10 | using Microsoft.Win32.SafeHandles; 11 | 12 | namespace LibUA.Security.Cryptography 13 | { 14 | /// 15 | /// Native interop layer for Win32 APIs 16 | /// 17 | internal static class Win32Native 18 | { 19 | // 20 | // Enumerations 21 | // 22 | 23 | [Flags] 24 | internal enum FormatMessageFlags 25 | { 26 | None = 0x00000000, 27 | AllocateBuffer = 0x00000100, // FORMAT_MESSAGE_ALLOCATE_BUFFER 28 | FromModule = 0x00000800, // FORMAT_MESSAGE_FROM_HMODULE 29 | FromSystem = 0x00001000, // FORMAT_MESSAGE_FROM_SYSTEM 30 | } 31 | 32 | // 33 | // Structures 34 | // 35 | 36 | [StructLayout(LayoutKind.Sequential)] 37 | internal struct SYSTEMTIME 38 | { 39 | internal ushort wYear; 40 | internal ushort wMonth; 41 | internal ushort wDayOfWeek; 42 | internal ushort wDay; 43 | internal ushort wHour; 44 | internal ushort wMinute; 45 | internal ushort wSecond; 46 | internal ushort wMilliseconds; 47 | 48 | internal SYSTEMTIME(DateTime time) 49 | { 50 | wYear = (ushort)time.Year; 51 | wMonth = (ushort)time.Month; 52 | wDayOfWeek = (ushort)time.DayOfWeek; 53 | wDay = (ushort)time.Day; 54 | wHour = (ushort)time.Hour; 55 | wMinute = (ushort)time.Minute; 56 | wSecond = (ushort)time.Second; 57 | wMilliseconds = (ushort)time.Millisecond; 58 | } 59 | } 60 | 61 | [SuppressUnmanagedCodeSecurity] 62 | private static class UnsafeNativeMethods 63 | { 64 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] 65 | internal static extern SafeLibraryHandle LoadLibrary(string lpFileName); 66 | 67 | [DllImport("kernel32.dll", SetLastError = true)] 68 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 69 | internal static extern IntPtr LocalFree(IntPtr hMem); 70 | 71 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 72 | internal static extern int FormatMessage(FormatMessageFlags dwFlags, 73 | SafeLibraryHandle lpSource, 74 | int dwMessageId, 75 | int dwLanguageId, 76 | [In, Out] ref IntPtr lpBuffer, 77 | int nSize, 78 | IntPtr pArguments); 79 | } 80 | 81 | // 82 | // Wrapper APIs 83 | // 84 | 85 | /// 86 | /// Lookup an error message in the message table of a specific library as well as the system 87 | /// message table. 88 | /// 89 | [SecurityCritical] 90 | [SecuritySafeCritical] 91 | internal static string FormatMessageFromLibrary(int message, string library) 92 | { 93 | Debug.Assert(!String.IsNullOrEmpty(library), "!String.IsNullOrEmpty(library)"); 94 | 95 | using (SafeLibraryHandle module = UnsafeNativeMethods.LoadLibrary(library)) 96 | { 97 | IntPtr messageBuffer = IntPtr.Zero; 98 | 99 | RuntimeHelpers.PrepareConstrainedRegions(); 100 | try 101 | { 102 | int result = UnsafeNativeMethods.FormatMessage(FormatMessageFlags.AllocateBuffer | FormatMessageFlags.FromModule | FormatMessageFlags.FromSystem, 103 | module, 104 | message, 105 | 0, 106 | ref messageBuffer, 107 | 0, 108 | IntPtr.Zero); 109 | if (result == 0) 110 | { 111 | Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 112 | } 113 | 114 | return Marshal.PtrToStringUni(messageBuffer); 115 | } 116 | finally 117 | { 118 | if (messageBuffer != IntPtr.Zero) 119 | { 120 | UnsafeNativeMethods.LocalFree(messageBuffer); 121 | } 122 | } 123 | } 124 | } 125 | 126 | /// 127 | /// Get an error message for an NTSTATUS error code 128 | /// 129 | internal static string GetNTStatusMessage(int ntstatus) 130 | { 131 | return FormatMessageFromLibrary(ntstatus, "ntdll.dll"); 132 | } 133 | } 134 | 135 | /// 136 | /// Safe handle base class for safe handles which are associated with an additional data buffer that 137 | /// must be kept alive for the same amount of time as the handle itself. 138 | /// 139 | /// This is required rather than having a seperate safe handle own the key data buffer blob so 140 | /// that we can ensure that the key handle is disposed of before the key data buffer is freed. 141 | /// 142 | internal abstract class SafeHandleWithBuffer : SafeHandleZeroOrMinusOneIsInvalid 143 | { 144 | private IntPtr m_dataBuffer; 145 | 146 | protected SafeHandleWithBuffer() : base(true) 147 | { 148 | return; 149 | } 150 | 151 | public override bool IsInvalid 152 | { 153 | get 154 | { 155 | return handle == IntPtr.Zero && // The handle is not valid 156 | m_dataBuffer == IntPtr.Zero; // And we don't own any native memory 157 | } 158 | } 159 | 160 | /// 161 | /// Buffer that holds onto the key data object. This data must be allocated with CoAllocTaskMem, 162 | /// or the ReleaseBuffer method must be overriden to match the deallocation function with the 163 | /// allocation function. Once the buffer is assigned into the DataBuffer property, the safe 164 | /// handle owns the buffer and users of this property should not attempt to free the memory. 165 | /// 166 | /// This property should be set only once, otherwise the first data buffer will leak. 167 | /// 168 | internal IntPtr DataBuffer 169 | { 170 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 171 | get { return m_dataBuffer; } 172 | 173 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 174 | set 175 | { 176 | Debug.Assert(m_dataBuffer == IntPtr.Zero, "SafeHandleWithBuffer already owns a data buffer - this will result in a native memory leak."); 177 | Debug.Assert(value != IntPtr.Zero, "value != IntPtr.Zero"); 178 | 179 | m_dataBuffer = value; 180 | } 181 | } 182 | 183 | /// 184 | /// Release the buffer associated with the handle 185 | /// 186 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 187 | protected virtual bool ReleaseBuffer() 188 | { 189 | Marshal.FreeCoTaskMem(m_dataBuffer); 190 | return true; 191 | } 192 | 193 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 194 | protected sealed override bool ReleaseHandle() 195 | { 196 | bool error = false; 197 | 198 | if (handle != IntPtr.Zero) 199 | { 200 | error = ReleaseNativeHandle(); 201 | } 202 | 203 | if (m_dataBuffer != IntPtr.Zero) 204 | { 205 | error &= ReleaseBuffer(); 206 | } 207 | 208 | return error; 209 | } 210 | 211 | /// 212 | /// Release just the native handle associated with the safe handle 213 | /// 214 | /// 215 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 216 | protected abstract bool ReleaseNativeHandle(); 217 | } 218 | 219 | /// 220 | /// SafeHandle for a native HMODULE 221 | /// 222 | internal sealed class SafeLibraryHandle : SafeHandleZeroOrMinusOneIsInvalid 223 | { 224 | private SafeLibraryHandle() : base(true) 225 | { 226 | } 227 | 228 | [DllImport("kernel32.dll")] 229 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 230 | [SuppressUnmanagedCodeSecurity] 231 | [return: MarshalAs(UnmanagedType.Bool)] 232 | private static extern bool FreeLibrary(IntPtr hModule); 233 | 234 | protected override bool ReleaseHandle() 235 | { 236 | return FreeLibrary(handle); 237 | } 238 | } 239 | 240 | /// 241 | /// SafeHandle for memory allocated with LocalAlloc 242 | /// 243 | internal sealed class SafeLocalAllocHandle : SafeHandleZeroOrMinusOneIsInvalid 244 | { 245 | private SafeLocalAllocHandle() : base(true) 246 | { 247 | } 248 | 249 | [DllImport("kernel32.dll")] 250 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 251 | [SuppressUnmanagedCodeSecurity] 252 | private static extern IntPtr LocalFree(IntPtr hMem); 253 | 254 | internal T Read(int offset) where T : struct 255 | { 256 | bool addedRef = false; 257 | RuntimeHelpers.PrepareConstrainedRegions(); 258 | try 259 | { 260 | DangerousAddRef(ref addedRef); 261 | 262 | unsafe 263 | { 264 | IntPtr pBase = new IntPtr((byte*)handle.ToPointer() + offset); 265 | return (T)Marshal.PtrToStructure(pBase, typeof(T)); 266 | } 267 | } 268 | finally 269 | { 270 | if (addedRef) 271 | { 272 | DangerousRelease(); 273 | } 274 | } 275 | 276 | } 277 | 278 | protected override bool ReleaseHandle() 279 | { 280 | return LocalFree(handle) == IntPtr.Zero; 281 | } 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/X509Certificates/SafeCertContextHandle.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Runtime.ConstrainedExecution; 6 | using System.Runtime.InteropServices; 7 | using System.Security; 8 | using System.Security.Permissions; 9 | using Microsoft.Win32.SafeHandles; 10 | 11 | namespace LibUA.Security.Cryptography.X509Certificates 12 | { 13 | /// 14 | /// 15 | /// SafeCertContextHandle provides a SafeHandle class for an X509Certificate's certificate context 16 | /// as stored in its 17 | /// property. This can be used instead of the raw IntPtr to avoid races with the garbage 18 | /// collector, ensuring that the X509Certificate object is not cleaned up from underneath you 19 | /// while you are still using the handle pointer. 20 | /// 21 | /// 22 | /// This safe handle type represents a native CERT_CONTEXT. 23 | /// (http://msdn.microsoft.com/en-us/library/aa377189.aspx) 24 | /// 25 | /// 26 | /// A SafeCertificateContextHandle for an X509Certificate can be obtained by calling the extension method. 28 | /// 29 | /// 30 | /// 31 | /// The immediate caller must have SecurityPermission/UnmanagedCode to use this type. 32 | /// 33 | [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] 34 | public sealed class SafeCertContextHandle : SafeHandleZeroOrMinusOneIsInvalid 35 | { 36 | private SafeCertContextHandle() : base(true) 37 | { 38 | } 39 | 40 | [DllImport("crypt32.dll")] 41 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 42 | [SuppressUnmanagedCodeSecurity] 43 | [return: MarshalAs(UnmanagedType.Bool)] 44 | private static extern bool CertFreeCertificateContext(IntPtr pCertContext); 45 | 46 | protected override bool ReleaseHandle() 47 | { 48 | return CertFreeCertificateContext(handle); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/X509Certificates/X509AlternateName.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Runtime.InteropServices; 6 | using System.Net; 7 | using System.Security; 8 | 9 | namespace LibUA.Security.Cryptography.X509Certificates 10 | { 11 | /// 12 | /// The X509Alternate name type represents alternate name information pulled from an X509 13 | /// certificate's subject or issuer alternate names extension. This type serves as the base for the 14 | /// more specific alternate name types which can contain more detailed data about the name. 15 | /// 16 | public class X509AlternateName 17 | { 18 | private readonly AlternateNameType m_type; 19 | 20 | /// 21 | /// Construct an empty X509AlternateName of the specified type 22 | /// 23 | public X509AlternateName(AlternateNameType type) 24 | { 25 | m_type = type; 26 | } 27 | 28 | /// 29 | /// Get the type of alternate name this object represents 30 | /// 31 | public AlternateNameType AlternateNameType 32 | { 33 | get { return m_type; } 34 | } 35 | 36 | /// 37 | /// Get the alternate name that this object represents. The type of object returned from this 38 | /// property depends upon how the specific alternate name type specifies its data. Strongly 39 | /// typed alternate name data can also be obtained from working with the subtypes directly. 40 | /// 41 | public virtual object AlternateName 42 | { 43 | get { return m_type; } 44 | } 45 | 46 | public override bool Equals(object obj) 47 | { 48 | X509AlternateName other = obj as X509AlternateName; 49 | if (other == null || other.GetType() != typeof(X509AlternateName)) 50 | { 51 | return false; 52 | } 53 | 54 | return AlternateNameType == other.AlternateNameType; 55 | } 56 | 57 | public override int GetHashCode() 58 | { 59 | return AlternateNameType.GetHashCode(); 60 | } 61 | 62 | public override string ToString() 63 | { 64 | return AlternateName.ToString(); 65 | } 66 | 67 | /// 68 | /// Create an X509Alternate name object from a native CERT_ALT_NAME_ENTRY structure 69 | /// 70 | [SecurityCritical] 71 | internal static X509AlternateName FromAltNameEntry(X509Native.CERT_ALT_NAME_ENTRY altNameEntry) 72 | { 73 | switch (altNameEntry.dwAltNameChoice) 74 | { 75 | case AlternateNameType.DirectoryName: 76 | return new X509AlternateNameBlob(altNameEntry.dwAltNameChoice, 77 | CapiNative.ReadBlob(altNameEntry.altName.DirectoryName)); 78 | 79 | case AlternateNameType.DnsName: 80 | return new X509AlternateNameString(altNameEntry.dwAltNameChoice, 81 | Marshal.PtrToStringUni(altNameEntry.altName.pwszDNSName)); 82 | 83 | case AlternateNameType.EdiPartyName: 84 | return new X509AlternateNameString(altNameEntry.dwAltNameChoice, 85 | Marshal.PtrToStringUni(altNameEntry.altName.pEdiPartyName)); 86 | 87 | case AlternateNameType.IPAddress: 88 | IPAddress ipAddress = new IPAddress(CapiNative.ReadBlob(altNameEntry.altName.IPAddress)); 89 | return new X509AlternateNameIPAddress(altNameEntry.dwAltNameChoice, 90 | ipAddress); 91 | 92 | case AlternateNameType.OtherName: 93 | X509Native.CERT_OTHER_NAME otherName = 94 | (X509Native.CERT_OTHER_NAME)Marshal.PtrToStructure(altNameEntry.altName.pOtherName, typeof(X509Native.CERT_OTHER_NAME)); 95 | 96 | Oid2 otherNameOid = Oid2.FindByValue(otherName.pszObjId); 97 | return new X509AlternateNameOther(CapiNative.ReadBlob(otherName.Value), otherNameOid); 98 | 99 | case AlternateNameType.RegisteredId: 100 | return new X509AlternateNameString(altNameEntry.dwAltNameChoice, 101 | Marshal.PtrToStringAnsi(altNameEntry.altName.pszRegisteredID)); 102 | 103 | case AlternateNameType.Rfc822Name: 104 | return new X509AlternateNameString(altNameEntry.dwAltNameChoice, 105 | Marshal.PtrToStringUni(altNameEntry.altName.pwszRfc822Name)); 106 | 107 | case AlternateNameType.Url: 108 | return new X509AlternateNameString(altNameEntry.dwAltNameChoice, 109 | Marshal.PtrToStringUni(altNameEntry.altName.pwszURL)); 110 | 111 | case AlternateNameType.X400Address: 112 | return new X509AlternateNameBlob(altNameEntry.dwAltNameChoice, 113 | CapiNative.ReadBlob(altNameEntry.altName.x400Address)); 114 | 115 | default: 116 | return new X509AlternateName(altNameEntry.dwAltNameChoice); 117 | } 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/X509Certificates/X509AlternateNameBlob.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Net; 5 | 6 | namespace LibUA.Security.Cryptography.X509Certificates 7 | { 8 | /// 9 | /// X509 alternate name implementation for alternate names stored as blobs. For instance, 10 | /// and 11 | /// use alternate names stored as blobs. 12 | /// 13 | public class X509AlternateNameBlob : X509AlternateName 14 | { 15 | private readonly byte[] m_blob; 16 | 17 | /// 18 | /// Create an alternate name for the given blob 19 | /// 20 | /// if is null 21 | public X509AlternateNameBlob(AlternateNameType type, byte[] blob) 22 | : base(type) 23 | { 24 | if (blob == null) 25 | throw new ArgumentNullException("blob"); 26 | 27 | m_blob = new byte[blob.Length]; 28 | Array.Copy(blob, m_blob, m_blob.Length); 29 | } 30 | 31 | public override object AlternateName 32 | { 33 | get { return GetBlob(); } 34 | } 35 | 36 | public override bool Equals(object obj) 37 | { 38 | X509AlternateNameBlob other = obj as X509AlternateNameBlob; 39 | if (other == null) 40 | { 41 | return false; 42 | } 43 | 44 | if (other.AlternateNameType != AlternateNameType) 45 | { 46 | return false; 47 | } 48 | 49 | if (other.m_blob.Length != m_blob.Length) 50 | { 51 | return false; 52 | } 53 | 54 | for (int i = 0; i < m_blob.Length; ++i) 55 | { 56 | if (other.m_blob[i] != m_blob[i]) 57 | { 58 | return false; 59 | } 60 | } 61 | 62 | return true; 63 | } 64 | 65 | /// 66 | /// Get the name blob 67 | /// 68 | public byte[] GetBlob() 69 | { 70 | byte[] blob = new byte[m_blob.Length]; 71 | Array.Copy(m_blob, blob, blob.Length); 72 | return blob; 73 | } 74 | 75 | public override int GetHashCode() 76 | { 77 | int hashCode = AlternateNameType.GetHashCode(); 78 | 79 | if (m_blob.Length > 4) 80 | { 81 | for (int i = 0; i < m_blob.Length; i += 4) 82 | { 83 | hashCode ^= BitConverter.ToInt32(m_blob, i); 84 | } 85 | } 86 | 87 | if (m_blob.Length > 0 && m_blob.Length % 4 != 0) 88 | { 89 | int remainder = 0; 90 | for (int i = 0; i < m_blob.Length % 4; ++i) 91 | { 92 | remainder |= (m_blob[m_blob.Length - i - 1]) << (8 * i); 93 | } 94 | 95 | hashCode ^= remainder; 96 | } 97 | 98 | return hashCode; 99 | } 100 | 101 | public override string ToString() 102 | { 103 | return AlternateNameType.ToString(); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/X509Certificates/X509AlternateNameIPAddress.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Net; 5 | 6 | namespace LibUA.Security.Cryptography.X509Certificates 7 | { 8 | /// 9 | /// X509 alternate name implementation for alternate names stored as IP addresses. The 10 | /// alternate name type is stored as an IP address. 11 | /// 12 | public sealed class X509AlternateNameIPAddress : X509AlternateName 13 | { 14 | private readonly IPAddress m_address; 15 | 16 | /// 17 | /// Create an alternate name for the given IP address 18 | /// 19 | /// if is null 20 | public X509AlternateNameIPAddress(AlternateNameType type, IPAddress address) : base(type) 21 | { 22 | if (address == null) 23 | throw new ArgumentNullException("address"); 24 | 25 | m_address = address; 26 | } 27 | 28 | /// 29 | /// IP address held in the name 30 | /// 31 | public IPAddress Address 32 | { 33 | get { return m_address; } 34 | } 35 | 36 | public override object AlternateName 37 | { 38 | get { return Address; } 39 | } 40 | 41 | public override bool Equals(object obj) 42 | { 43 | X509AlternateNameIPAddress other = obj as X509AlternateNameIPAddress; 44 | if (other == null) 45 | { 46 | return false; 47 | } 48 | 49 | return other.AlternateNameType == AlternateNameType && 50 | other.Address.Equals(Address); 51 | } 52 | 53 | public override int GetHashCode() 54 | { 55 | return AlternateNameType.GetHashCode() ^ Address.GetHashCode(); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/X509Certificates/X509AlternateNameOther.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Net; 5 | 6 | namespace LibUA.Security.Cryptography.X509Certificates 7 | { 8 | /// 9 | /// X509 alternate name implementation for other forms of alternate names. This type always uses 10 | /// the alternate name type, and should have its type 11 | /// determined via the value in its property. 12 | /// 13 | public sealed class X509AlternateNameOther : X509AlternateNameBlob 14 | { 15 | private readonly Oid2 m_oid; 16 | 17 | /// 18 | /// Create an alternate name for the given blob 19 | /// 20 | /// raw alternate name blob 21 | /// OID describing the type of alternate name 22 | /// 23 | /// if or are null 24 | /// 25 | public X509AlternateNameOther(byte[] blob, Oid2 oid) 26 | : base(AlternateNameType.OtherName, blob) 27 | { 28 | if (oid == null) 29 | throw new ArgumentNullException("oid"); 30 | 31 | m_oid = oid; 32 | } 33 | 34 | /// 35 | /// Get the OID representing the type of this alternate name 36 | /// 37 | public Oid2 Oid 38 | { 39 | get { return m_oid; } 40 | } 41 | 42 | public override bool Equals(object obj) 43 | { 44 | X509AlternateNameOther other = obj as X509AlternateNameOther; 45 | if (other == null) 46 | { 47 | return false; 48 | } 49 | 50 | return base.Equals(other) && 51 | String.Equals(other.Oid.Value, Oid.Value, StringComparison.Ordinal); 52 | } 53 | 54 | public override int GetHashCode() 55 | { 56 | return base.GetHashCode() ^ Oid.Value.GetHashCode(); 57 | } 58 | 59 | public override string ToString() 60 | { 61 | return Oid.Value; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/X509Certificates/X509AlternateNameString.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | 5 | namespace LibUA.Security.Cryptography.X509Certificates 6 | { 7 | /// 8 | /// X509 alternate name implementation for alternate names stored as strings. THe 9 | /// , , 10 | /// , , 11 | /// and alternate name types store their names as strings. 12 | /// 13 | public sealed class X509AlternateNameString : X509AlternateName 14 | { 15 | private readonly string m_name; 16 | 17 | /// 18 | /// Create an alternate name for the given string 19 | /// 20 | /// if is null 21 | public X509AlternateNameString(AlternateNameType type, string name) : base(type) 22 | { 23 | if (name == null) 24 | throw new ArgumentNullException("name"); 25 | 26 | m_name = name; 27 | } 28 | 29 | public override object AlternateName 30 | { 31 | get { return Name; } 32 | } 33 | 34 | /// 35 | /// Alternate name 36 | /// 37 | public string Name 38 | { 39 | get { return m_name; } 40 | } 41 | 42 | public override bool Equals(object obj) 43 | { 44 | X509AlternateNameString other = obj as X509AlternateNameString; 45 | if (other == null) 46 | { 47 | return false; 48 | } 49 | 50 | return other.AlternateNameType == AlternateNameType && 51 | String.Equals(other.Name, Name, StringComparison.Ordinal); 52 | } 53 | 54 | public override int GetHashCode() 55 | { 56 | return AlternateNameType.GetHashCode() ^ AlternateName.GetHashCode(); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/X509Certificates/X509Certificate2ExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Security; 6 | using System.Security.Permissions; 7 | using System.Security.Cryptography; 8 | using System.Security.Cryptography.X509Certificates; 9 | using LibUA.Security.Cryptography.X509Certificates; 10 | using Microsoft.Win32.SafeHandles; 11 | 12 | namespace LibUA.Security.Cryptography.X509Certificates 13 | { 14 | /// 15 | /// The X509Certificate2ExtensionMethods type provides several extension methods for the 16 | /// class. This type is in the Security.Cryptography.X509Certificates 17 | /// namespace (not the System.Security.Cryptography.X509Certificates namespace), so in order to use 18 | /// these extension methods, you will need to make sure you include this namespace as well as a 19 | /// reference to Security.Cryptography.dll. 20 | /// 21 | public static class X509Certificate2ExtensionMethods 22 | { 23 | /// 24 | /// 25 | /// The GetCngPrivateKey method will return a representing the private 26 | /// key of an X.509 certificate which has its private key stored with NCrypt rather than with 27 | /// CAPI. If the key is not stored with NCrypt or if there is no private key available, 28 | /// GetCngPrivateKey returns null. 29 | /// 30 | /// 31 | /// The HasCngKey method can be used to test if the certificate does have its private key 32 | /// stored with NCrypt. 33 | /// 34 | /// 35 | /// The X509Certificate that is used to get the key must be kept alive for the lifetime of the 36 | /// CngKey that is returned - otherwise the handle may be cleaned up when the certificate is 37 | /// finalized. 38 | /// 39 | /// 40 | /// The caller of this method must have SecurityPermission/UnmanagedCode. 41 | [SecurityCritical] 42 | [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] 43 | public static CngKey GetCngPrivateKey(this X509Certificate2 certificate) 44 | { 45 | if (!certificate.HasPrivateKey || !certificate.HasCngKey()) 46 | { 47 | return null; 48 | } 49 | 50 | using (SafeCertContextHandle certContext = certificate.GetCertificateContext()) 51 | using (SafeNCryptKeyHandle privateKeyHandle = X509Native.AcquireCngPrivateKey(certContext)) 52 | { 53 | // We need to assert for full trust when opening the CNG key because 54 | // CngKey.Open(SafeNCryptKeyHandle) does a full demand for full trust, and we want to allow 55 | // access to a certificate's private key by anyone who has access to the certificate itself. 56 | new PermissionSet(PermissionState.Unrestricted).Assert(); 57 | return CngKey.Open(privateKeyHandle, CngKeyHandleOpenOptions.None); 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/X509Certificates/X509CertificateCreationParameters.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Security; 6 | using System.Security.Cryptography; 7 | using System.Security.Cryptography.X509Certificates; 8 | using System.Security.Permissions; 9 | 10 | namespace LibUA.Security.Cryptography.X509Certificates 11 | { 12 | /// 13 | /// The X509CertificateCreationParameters class allows customization of the properties of an X509 14 | /// certificate that is being created. For instance, these parameters can be used with the 15 | /// 16 | /// API. 17 | /// 18 | public sealed class X509CertificateCreationParameters 19 | { 20 | private X500DistinguishedName m_subjectName; 21 | private X509CertificateCreationOptions m_certificateCreationOptions = X509CertificateCreationOptions.None; 22 | private X509CertificateSignatureAlgorithm m_signatureAlgorithm = X509CertificateSignatureAlgorithm.RsaSha1; 23 | private DateTime m_endTime = DateTime.UtcNow.AddYears(1); 24 | private DateTime m_startTime = DateTime.UtcNow; 25 | private readonly X509ExtensionCollection m_extensions = new X509ExtensionCollection(); 26 | private bool m_takeOwnershipOfKey = true; 27 | 28 | /// 29 | /// Creates a new X509CertificateCreationParameters object which can be used to create a new X509 30 | /// certificate issued to the specified subject. 31 | /// 32 | /// The name of the subject the new certificate will be issued to 33 | /// if is null 34 | public X509CertificateCreationParameters(X500DistinguishedName subjectName) 35 | { 36 | if (subjectName == null) 37 | throw new ArgumentNullException("subjectName"); 38 | 39 | m_subjectName = new X500DistinguishedName(subjectName); 40 | } 41 | 42 | /// 43 | /// Gets or sets the flags used to create the X509 certificate. The default value is 44 | /// X509CertificateCreationOptions.DoNotLinkKeyInformation. 45 | /// 46 | public X509CertificateCreationOptions CertificateCreationOptions 47 | { 48 | get { return m_certificateCreationOptions; } 49 | set { m_certificateCreationOptions = value; } 50 | } 51 | 52 | /// 53 | /// Gets or sets the expiration date of the newly created certificate. If not set, this property 54 | /// defaults to one year after the X509CertificateCreationParameters object is constructed. 55 | /// 56 | public DateTime EndTime 57 | { 58 | get { return m_endTime; } 59 | set { m_endTime = value; } 60 | } 61 | 62 | /// 63 | /// The Extensions property holds a collection of the X509Extensions that will be applied to the 64 | /// newly created certificate. 65 | /// 66 | /// 67 | /// This property requires SecurityPermission/UnmanagedCode to access 68 | /// 69 | public X509ExtensionCollection Extensions 70 | { 71 | [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)] 72 | [SecurityCritical] 73 | [SecuritySafeCritical] 74 | get 75 | { 76 | return ExtensionsNoDemand; 77 | } 78 | } 79 | 80 | internal X509ExtensionCollection ExtensionsNoDemand 81 | { 82 | [SecurityCritical] 83 | get 84 | { 85 | return m_extensions; 86 | } 87 | } 88 | 89 | /// 90 | /// Gets or sets the algorithm which will be used to sign the newly created certificate. If this 91 | /// property is not set, the default value is X509CertificateSignatureAlgorithm.RsaSha1. 92 | /// 93 | /// 94 | /// if the value specified is not a member of the 95 | /// enumeration. 96 | /// 97 | public X509CertificateSignatureAlgorithm SignatureAlgorithm 98 | { 99 | get { return m_signatureAlgorithm; } 100 | 101 | set 102 | { 103 | if (value < X509CertificateSignatureAlgorithm.RsaSha1 || 104 | value > X509CertificateSignatureAlgorithm.ECDsaSha512) 105 | { 106 | throw new ArgumentOutOfRangeException("value"); 107 | } 108 | 109 | m_signatureAlgorithm = value; 110 | } 111 | } 112 | 113 | /// 114 | /// Gets or sets a value indicating which object owns the lifetime of the incoming key 115 | /// once the certificate is created. If set to true, then the certificate owns the lifetime 116 | /// of the key and the key object may be destroyed. If set to false, the key object continues 117 | /// to own the key lifetime and must therefore outlive the certificate. 118 | /// 119 | public bool TakeOwnershipOfKey 120 | { 121 | get { return m_takeOwnershipOfKey; } 122 | set { m_takeOwnershipOfKey = value; } 123 | } 124 | 125 | /// 126 | /// Gets or sets the name of the subject that the newly created certificate will be issued to. 127 | /// 128 | /// if SubjectName is set to a null value 129 | public X500DistinguishedName SubjectName 130 | { 131 | get { return new X500DistinguishedName(m_subjectName); } 132 | set 133 | { 134 | if (value == null) 135 | throw new ArgumentNullException("value"); 136 | 137 | m_subjectName = new X500DistinguishedName(value); 138 | } 139 | } 140 | 141 | /// 142 | /// Gets or sets the time that the newly created certificate will become valid. If not set, this 143 | /// property defaults to the time that the X509CertificateCreationParameters object is created. 144 | /// 145 | public DateTime StartTime 146 | { 147 | get { return m_startTime; } 148 | set { m_startTime = value; } 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/X509Certificates/X509CertificateExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics.CodeAnalysis; 6 | using System.Runtime.InteropServices; 7 | using System.Security; 8 | using System.Security.Cryptography.X509Certificates; 9 | using System.Security.Permissions; 10 | using LibUA.Security.Cryptography.X509Certificates; 11 | 12 | namespace LibUA.Security.Cryptography.X509Certificates 13 | { 14 | /// 15 | /// The X509CertificateExtensionMethods type provides extension methods for the 16 | /// class. X509CertificateExtensionMethods is in the 17 | /// Security.Cryptography.X509Certificates namespace (not the 18 | /// System.Security.Cryptography.X509Certificates namespace), so in order to use these extension 19 | /// methods, you will need to make sure you include this namespace as well as a reference to 20 | /// Security.Cryptography.dll. 21 | /// 22 | public static class X509CertificateExtensionMethods 23 | { 24 | /// 25 | /// Get all the alternate names encoded under a specific extension OID. The and extension 27 | /// methods provide direct access to the subject and issuer names, which can be friendlier to 28 | /// use than this method. 29 | /// 30 | /// X509 certificate to get the alternate names of 31 | /// OID representing the alternate names to retrieve 32 | /// if is null 33 | /// 34 | /// The immediate caller must be fully trusted to use this method. 35 | /// 36 | [SecurityCritical] 37 | [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)] 38 | public static IList GetAlternateNames(this X509Certificate certificate, 39 | Oid2 alternateNameExtensionOid) 40 | { 41 | if (alternateNameExtensionOid == null) 42 | throw new ArgumentNullException("alternateNameExtensionOid"); 43 | 44 | List alternateNames = new List(); 45 | 46 | using (SafeCertContextHandle certContext = certificate.GetCertificateContext()) 47 | { 48 | // Make sure we have the extension requested 49 | if (X509Native.HasExtension(certContext, alternateNameExtensionOid.Value)) 50 | { 51 | // If so, get it from the certificate, and decode it into a buffer 52 | X509Native.CERT_EXTENSION alternateNameExtension = 53 | X509Native.FindExtension(certContext, alternateNameExtensionOid.Value); 54 | 55 | using (SafeLocalAllocHandle decodedBuffer = X509Native.DecodeExtension(alternateNameExtension)) 56 | { 57 | // This buffer contains CERT_ALT_NAME_INFO which points us at the alternate names we 58 | // were looking for 59 | X509Native.CERT_ALT_NAME_INFO altNameInfo = decodedBuffer.Read(0); 60 | for (int i = 0; i < altNameInfo.cAltEntry; ++i) 61 | { 62 | unsafe 63 | { 64 | X509Native.CERT_ALT_NAME_ENTRY* pAltNameEntry = (X509Native.CERT_ALT_NAME_ENTRY*)altNameInfo.rgAltEntry; 65 | alternateNames.Add(X509AlternateName.FromAltNameEntry(pAltNameEntry[i])); 66 | } 67 | } 68 | } 69 | } 70 | 71 | } 72 | 73 | return alternateNames; 74 | } 75 | 76 | /// 77 | /// Get a for the X509 certificate. The caller of this 78 | /// method owns the returned safe handle, and should dispose of it when they no longer need it. 79 | /// This handle can be used independently of the lifetime of the original X509 certificate. 80 | /// 81 | /// 82 | /// The immediate caller must have SecurityPermission/UnmanagedCode to use this method 83 | /// 84 | [SecurityCritical] 85 | [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] 86 | public static SafeCertContextHandle GetCertificateContext(this X509Certificate certificate) 87 | { 88 | SafeCertContextHandle certContext = X509Native.DuplicateCertContext(certificate.Handle); 89 | 90 | // Make sure to keep the X509Certificate object alive until after its certificate context is 91 | // duplicated, otherwise it could end up being closed out from underneath us before we get a 92 | // chance to duplicate the handle. 93 | GC.KeepAlive(certificate); 94 | 95 | return certContext; 96 | } 97 | 98 | /// 99 | /// Get all of the alternate names a certificate has for its issuer 100 | /// 101 | [SecurityCritical] 102 | [SecuritySafeCritical] 103 | public static IEnumerable GetIssuerAlternateNames(this X509Certificate certificate) 104 | { 105 | List alternateNames = new List(); 106 | 107 | Oid2 extensionOid = Oid2.FindByValue(CapiNative.WellKnownOids.IssuerAlternateName, 108 | OidGroup.ExtensionOrAttribute); 109 | alternateNames.AddRange(certificate.GetAlternateNames(extensionOid)); 110 | 111 | Oid2 extensionOid2 = Oid2.FindByValue(CapiNative.WellKnownOids.IssuerAlternateName2, 112 | OidGroup.ExtensionOrAttribute); 113 | alternateNames.AddRange(certificate.GetAlternateNames(extensionOid2)); 114 | 115 | return alternateNames; 116 | } 117 | 118 | /// 119 | /// Get all of the alternate names a certificate has for its subject 120 | /// 121 | [SecurityCritical] 122 | [SecuritySafeCritical] 123 | public static IEnumerable GetSubjectAlternateNames(this X509Certificate certificate) 124 | { 125 | List alternateNames = new List(); 126 | 127 | Oid2 extensionOid = Oid2.FindByValue(CapiNative.WellKnownOids.SubjectAlternateName, 128 | OidGroup.ExtensionOrAttribute); 129 | alternateNames.AddRange(certificate.GetAlternateNames(extensionOid)); 130 | 131 | Oid2 extensionOid2 = Oid2.FindByValue(CapiNative.WellKnownOids.SubjectAlternateName2, 132 | OidGroup.ExtensionOrAttribute); 133 | alternateNames.AddRange(certificate.GetAlternateNames(extensionOid2)); 134 | 135 | return alternateNames; 136 | } 137 | 138 | /// 139 | /// The HasCngKey method returns true if the X509Certificate is referencing a key stored with with 140 | /// NCrypt in CNG. It will return true if the certificate's key is a reference to a key stored in 141 | /// CNG, and false otherwise. For instance, if the key is stored with CAPI or if the key is not 142 | /// linked by the certificate and is contained directly in it, this method will return false. 143 | /// 144 | [SecurityCritical] 145 | [SecuritySafeCritical] 146 | public static bool HasCngKey(this X509Certificate certificate) 147 | { 148 | using (SafeCertContextHandle certContext = certificate.GetCertificateContext()) 149 | { 150 | if (X509Native.HasCertificateProperty(certContext, 151 | X509Native.CertificateProperty.KeyProviderInfo)) 152 | { 153 | X509Native.CRYPT_KEY_PROV_INFO keyProvInfo = 154 | X509Native.GetCertificateProperty(certContext, X509Native.CertificateProperty.KeyProviderInfo); 155 | 156 | return keyProvInfo.dwProvType == 0; 157 | } 158 | else 159 | { 160 | return false; 161 | } 162 | } 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/Xml/EncryptedXmlExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Diagnostics.CodeAnalysis; 5 | using LibUA.Security.Cryptography.Xml; 6 | using System.Xml; 7 | using System.Security.Cryptography.Xml; 8 | 9 | namespace LibUA.Security.Cryptography.Xml 10 | { 11 | /// 12 | /// The EncryptedXmlExtension methods type provides several extension methods for the 13 | /// class. This type is in the Security.Cryptography.Xml namespace (not 14 | /// the System.Security.Cryptography.Xml namespace), so in order to use these extension methods, you 15 | /// will need to make sure you include this namespace as well as a reference to 16 | /// Security.Cryptography.dll. 17 | /// 18 | public static class EncryptedXmlExtensionMethods 19 | { 20 | /// 21 | /// Replace the XML element with the decrypted data. This method works very much like the 22 | /// standard API, with one exception. If inputElement is 23 | /// the root element of an XML document, ReplaceData2 will ensure that any other top-level XML 24 | /// items (such as the XML declaration) will not be overwritten, whereas ReplaceData always 25 | /// overwrites the entire XML document with the decrypted data. 26 | /// 27 | public static void ReplaceData2(this EncryptedXml encryptedXml, 28 | XmlElement inputElement, 29 | byte[] decryptedData) 30 | { 31 | if (inputElement == null) 32 | throw new ArgumentNullException("inputElement"); 33 | if (decryptedData == null) 34 | throw new ArgumentNullException("decryptedData"); 35 | 36 | XmlNode parent = inputElement.ParentNode; 37 | if (parent.NodeType == XmlNodeType.Document) 38 | { 39 | // We're replacing the root element, so we need to 40 | // 1. Import the decrypted data into an XmlNode 41 | // 2. Get that node into the target document 42 | // 3. Replace the root element with the decrypted node 43 | 44 | XmlDocument importDocument = new XmlDocument(); 45 | importDocument.LoadXml(encryptedXml.Encoding.GetString(decryptedData)); 46 | 47 | XmlNode importedNode = inputElement.OwnerDocument.ImportNode(importDocument.DocumentElement, true); 48 | 49 | parent.RemoveChild(inputElement); 50 | parent.AppendChild(importedNode); 51 | } 52 | else 53 | { 54 | // We're not replacing the root, so the built-in ReplaceData API will work for this input 55 | // node. 56 | encryptedXml.ReplaceData(inputElement, decryptedData); 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/Xml/TransformFactory.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics.CodeAnalysis; 6 | using LibUA.Security.Cryptography.Xml; 7 | using System.Xml; 8 | using System.Security.Cryptography.Xml; 9 | 10 | namespace LibUA.Security.Cryptography.Xml 11 | { 12 | /// 13 | /// The TransformFactory class provides helper methods for programmatically creating transforms for 14 | /// use with the class. Since many of the transforms do not have constructors 15 | /// or other method that allow them to be created easily in code when creating an XML signature, they 16 | /// generally have to be constructed via XML. TransformFactory provides APIs that allow you to create 17 | /// these transforms without having to directly create the XML for the transform by hand. 18 | /// 19 | public static class TransformFactory 20 | { 21 | /// 22 | /// Creates an XPath transform for the given XPath query. The transform created from this method 23 | /// does not bring any XML namespaces into scope, so the XPath query must not rely on any XML 24 | /// namespaces from the XML being signed. 25 | /// 26 | /// XPath query to embed into the transform 27 | /// if is null 28 | public static XmlDsigXPathTransform CreateXPathTransform(string xpath) 29 | { 30 | return CreateXPathTransform(xpath, null); 31 | } 32 | 33 | /// 34 | /// 35 | /// Creates an XPath transform for the given XPath query. If 36 | /// is provided, it should contain mappings of XML namespace prefixes to namespace URIs. Each 37 | /// key in the dictionary will be interpreted as a prefix corresponding to the value's URI. 38 | /// 39 | /// 40 | /// The XPath query can rely upon the namespaces brought into scope by the 41 | /// dictionary, but not any other namespaces in the XML being 42 | /// signed. 43 | /// 44 | /// 45 | /// XPath query to embed into the transform 46 | /// optional XML namespace mappings to bring into scope for the query 47 | /// if is null 48 | public static XmlDsigXPathTransform CreateXPathTransform(string xpath, IDictionary namespaces) 49 | { 50 | if (xpath == null) 51 | throw new ArgumentNullException("xpath"); 52 | 53 | // XmlDsigXPath transform only sets its XPath query when it loads itself from XML. In order to 54 | // setup the transform, we'll build up XML representing the transform, and then load that XML 55 | // into the transform. 56 | XmlDocument doc = new XmlDocument(); 57 | XmlElement xpathElement = doc.CreateElement("XPath"); 58 | 59 | // The XPath query is the text value of the XPath node of the transform. 60 | xpathElement.InnerText = xpath; 61 | 62 | // Add the namespaces that should be in scope for the XPath expression. 63 | if (namespaces != null) 64 | { 65 | foreach (string namespaceAlais in namespaces.Keys) 66 | { 67 | // Namespaces in scope for the XPath query must be declared on the XPath element. For 68 | // each namespace mapping, generate a namespace declaration attribute to apply to the 69 | // XPath element. 70 | XmlAttribute namespaceDeclaration = doc.CreateAttribute("xmlns", 71 | namespaceAlais, 72 | "http://www.w3.org/2000/xmlns/"); 73 | namespaceDeclaration.Value = namespaces[namespaceAlais]; 74 | xpathElement.Attributes.Append(namespaceDeclaration); 75 | } 76 | } 77 | 78 | // Build a transform from the XML representation 79 | XmlDsigXPathTransform xpathTransform = new XmlDsigXPathTransform(); 80 | xpathTransform.LoadInnerXml(xpathElement.SelectNodes(".")); 81 | 82 | return xpathTransform; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /NET/LibUA/Security.Cryptography/Xml/XmlDsigNodeList.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | using System.Xml; 7 | 8 | namespace LibUA.Security.Cryptography.Xml 9 | { 10 | /// 11 | /// Basic implementation of an XmlNodeList 12 | /// 13 | internal sealed class XmlDSigNodeList : XmlNodeList 14 | { 15 | private readonly List m_list = new List(); 16 | 17 | public override int Count 18 | { 19 | get { return m_list.Count; } 20 | } 21 | 22 | public void Add(XmlNode node) 23 | { 24 | m_list.Add(node); 25 | } 26 | 27 | public override IEnumerator GetEnumerator() 28 | { 29 | return m_list.GetEnumerator(); 30 | } 31 | 32 | public override XmlNode Item(int index) 33 | { 34 | return m_list[index]; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /NET/LibUA/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LibUA 2 | Open-source OPC UA client and server library for .NET Framework and .NET Core based on IEC 62541. Available a library, a demo client and a demo server. Tested and commercially used in industrial applications with commercial vendors' UA servers and clients. 3 | 4 | Available as a nuget package for .NET Core (1.0.33): 5 | https://www.nuget.org/packages/nauful-LibUA-core 6 | 7 | ### Features 8 | - Fully supported OPC UA core client and OPC UA server specification. 9 | - OPC UA binary protocol with chunking. 10 | - Security profiles None, Basic128Rsa15, Basic256, Basic256Sha256, Aes128Sha256RsaOaep (.NET Standard only) and Aes256Sha256RsaPss (.NET Standard only). 11 | - Optimized memory buffers for encoding/decoding large and complex structures to/from raw bytes. 12 | - Support for all message types, node types, and default address space from the UA specification. 13 | - Support for signing and encrypted security profiles. 14 | - Anonymous, user/pass and certificate-based authentication. 15 | - Sessions, subscriptions (data change notifications and custom notifications), custom events and alarming. 16 | - Extendable server address space with hooks for client requests for access control, read handlers, write handlers, etc. 17 | - Support for reads, writes, updates, historical data and aggregation. 18 | - Server instances have low overhead: tested with hundreds of clients performing simultaneous historical reads, data change notification subscriptions and real-time writes. 19 | 20 | ### License 21 | Standard Apache License 2.0. 22 | - Permissions: Free for commercial use, modification, distribution, patent use and private use. 23 | - Conditions: Credit must be given to this github repository/owner, license and copyright notice, state changes. 24 | - Limitations: No trademark use, no liability, no warranty. 25 | 26 | ### Errata 27 | The demo client and server applications can create self-signed certificates with sufficient fields for most usage. Remember to move these to the trusted directory on a server when connecting to a server for the first time. 28 | --------------------------------------------------------------------------------