├── .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 |
--------------------------------------------------------------------------------