├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── pull_request_template.md
└── workflows
│ ├── broken-links.yml
│ ├── sonar.yml
│ └── test.yml
├── .gitignore
├── .lycheeignore
├── Identity.snk
├── LICENSE
├── Mastercard.Developer.ClientEncryption.Core
├── Encryption
│ ├── AES
│ │ ├── AesCbc.cs
│ │ ├── AesEncryption.cs
│ │ └── AesGcm.cs
│ ├── EncryptionConfig.cs
│ ├── EncryptionConfigBuilder.cs
│ ├── EncryptionException.cs
│ ├── FieldLevelEncryption.cs
│ ├── FieldLevelEncryptionConfig.cs
│ ├── FieldLevelEncryptionConfigBuilder.cs
│ ├── FieldLevelEncryptionParams.cs
│ ├── JWE
│ │ ├── JweEncryption.cs
│ │ ├── JweHeader.cs
│ │ └── JweObject.cs
│ ├── JweConfig.cs
│ ├── JweConfigBuilder.cs
│ └── RSA
│ │ └── RsaEncryption.cs
├── Mastercard.Developer.ClientEncryption.Core.csproj
└── Utils
│ ├── Base64Utils.cs
│ ├── ByteUtils.cs
│ ├── EncodingUtils.cs
│ ├── EncryptionUtils.cs
│ ├── JsonUtils.cs
│ └── RsaKeyUtils.cs
├── Mastercard.Developer.ClientEncryption.RestSharp
├── Interceptors
│ └── RestSharpFieldLevelEncryptionInterceptor.cs
└── Mastercard.Developer.ClientEncryption.RestSharp.csproj
├── Mastercard.Developer.ClientEncryption.RestSharpV2
├── Interceptors
│ ├── RestSharpEncryptionInterceptor.cs
│ ├── RestSharpFieldLevelEncryptionInterceptor.cs
│ └── RestSharpJweEncryptionInterceptor.cs
└── Mastercard.Developer.ClientEncryption.RestSharpV2.csproj
├── Mastercard.Developer.ClientEncryption.Tests
├── Mastercard.Developer.ClientEncryption.Tests.csproj
├── Net4x
│ └── Mastercard.Developer.ClientEncryption.Tests.Net4x.csproj
└── Tests
│ ├── Encryption
│ ├── AES
│ │ └── AesEncryptionTest.cs
│ ├── EncryptionExceptionTest.cs
│ ├── FieldLevelEncryptionConfigBuilderTest.cs
│ ├── FieldLevelEncryptionParamsTest.cs
│ ├── FieldLevelEncryptionTest.cs
│ ├── JWE
│ │ ├── CbcJweObjectTest.cs
│ │ ├── GcmJweObjectTest.cs
│ │ ├── JweEncryptionTest.cs
│ │ └── JweHeaderTest.cs
│ ├── JweConfigBuilderTest.cs
│ └── RSA
│ │ └── RsaEncryptionTest.cs
│ ├── Interceptors
│ ├── RestResponseDouble.cs
│ ├── RestSharpFieldLevelEncryptionInterceptorTest.cs
│ ├── RestSharpV2CbcJweEncryptionInterceptorTest.cs
│ ├── RestSharpV2FieldLevelEncryptionInterceptorTest.cs
│ └── RestSharpV2GcmJweEncryptionInterceptorTest.cs
│ ├── Test
│ └── TestUtils.cs
│ ├── Utils
│ ├── Base64UtilsTest.cs
│ ├── ByteUtilsTest.cs
│ ├── EncodingUtilsTest.cs
│ ├── EncryptionUtilsTest.cs
│ ├── JsonUtilsTest.cs
│ └── RsaKeyUtilsTest.cs
│ └── _Resources
│ ├── Certificates
│ ├── test_certificate-1024.pem
│ ├── test_certificate-2048.der
│ ├── test_certificate-2048.pem
│ ├── test_certificate-4096.pem
│ └── test_certificate-512.pem
│ └── Keys
│ ├── Pkcs1
│ ├── test_key_pkcs1-1024.pem
│ ├── test_key_pkcs1-2048.pem
│ ├── test_key_pkcs1-2048_uneven_length.pem
│ ├── test_key_pkcs1-4096.pem
│ └── test_key_pkcs1-512.pem
│ ├── Pkcs12
│ └── test_key.p12
│ └── Pkcs8
│ ├── test_invalid_key.der
│ ├── test_key_pkcs8-1024.der
│ ├── test_key_pkcs8-1024.pem
│ ├── test_key_pkcs8-2048.der
│ ├── test_key_pkcs8-2048.pem
│ ├── test_key_pkcs8-4096.der
│ ├── test_key_pkcs8-4096.pem
│ ├── test_key_pkcs8-512.der
│ └── test_key_pkcs8-512.pem
├── Mastercard.Developer.ClientEncryption.sln
├── Mastercard.Developer.ClientEncryption.sln.DotSettings
├── README.md
└── icon.png
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a bug report to help us improve
4 | title: "[BUG] Description"
5 | labels: 'Issue: Bug'
6 | assignees: ''
7 |
8 | ---
9 |
10 | #### Bug Report Checklist
11 |
12 | - [ ] Have you provided a code sample to reproduce the issue?
13 | - [ ] Have you tested with the latest release to confirm the issue still exists?
14 | - [ ] Have you searched for related issues/PRs?
15 | - [ ] What's the actual output vs expected output?
16 |
17 |
20 |
21 | **Description**
22 | A clear and concise description of what is the question, suggestion, or issue and why this is a problem for you.
23 |
24 | **To Reproduce**
25 | Steps to reproduce the behavior.
26 |
27 | **Expected behavior**
28 | A clear and concise description of what you expected to happen.
29 |
30 | **Screenshots**
31 | If applicable, add screenshots to help explain your problem.
32 |
33 | **Additional context**
34 | Add any other context about the problem here (OS, language version, etc..).
35 |
36 |
37 | **Related issues/PRs**
38 | Has a similar issue/PR been reported/opened before?
39 |
40 | **Suggest a fix/enhancement**
41 | If you can't fix the bug yourself, perhaps you can point to what might be causing the problem (line of code or commit), or simply make a suggestion.
42 |
43 | *If this is a Feature request, please check out [this](feature_request.md).*
44 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: "[REQ] Feature Request Description"
5 | labels: 'Enhancement: Feature'
6 | assignees: ''
7 |
8 | ---
9 |
10 | ### Is your feature request related to a problem? Please describe.
11 |
12 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
13 |
14 | ### Describe the solution you'd like
15 |
16 | A clear and concise description of what you want to happen.
17 |
18 | ### Describe alternatives you've considered
19 |
20 | A clear and concise description of any alternative solutions or features you've considered.
21 |
22 | ### Additional context
23 |
24 | Add any other context or screenshots about the feature request here.
25 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 |
2 | ### PR checklist
3 |
4 | - [ ] An issue/feature request has been created for this PR
5 | - [ ] Pull Request title clearly describes the work in the pull request and the Pull Request description provides details about how to validate the work. Missing information here may result in a delayed response.
6 | - [ ] File the PR against the `master` branch
7 | - [ ] The code in this PR is covered by unit tests
8 |
9 | #### Link to issue/feature request: *add the link here*
10 |
11 | #### Description
12 | A clear and concise description of what is this PR for and any additional info might be useful for reviewing it.
13 |
--------------------------------------------------------------------------------
/.github/workflows/broken-links.yml:
--------------------------------------------------------------------------------
1 | 'on':
2 | push:
3 | branches:
4 | - "**"
5 | schedule:
6 | - cron: 0 16 * * *
7 | workflow_dispatch:
8 | name: broken links?
9 | jobs:
10 | linkChecker:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v3
14 |
15 | - name: Link Checker
16 | uses: lycheeverse/lychee-action@v1.8.0
17 | with:
18 | fail: true
19 |
--------------------------------------------------------------------------------
/.github/workflows/sonar.yml:
--------------------------------------------------------------------------------
1 | name: Sonar
2 | 'on':
3 | push:
4 | branches:
5 | - "**"
6 | pull_request_target:
7 | branches:
8 | - "**"
9 | types: [opened, synchronize, reopened, labeled]
10 | schedule:
11 | - cron: 0 16 * * *
12 | workflow_dispatch:
13 | jobs:
14 | build:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: actions/checkout@v2
18 | with:
19 | fetch-depth: 0
20 | - name: Check for external PR
21 | if: ${{ !(contains(github.event.pull_request.labels.*.name, 'safe') ||
22 | github.event.pull_request.head.repo.full_name == github.repository ||
23 | github.event_name != 'pull_request_target') }}
24 | run: echo "Unsecure PR, must be labelled with the 'safe' label, then run the workflow again" && exit 1
25 | - name: Setup .NET 8
26 | uses: actions/setup-dotnet@v4.3.1
27 | with:
28 | dotnet-version: 8.0.x
29 | - name: Setup java
30 | uses: actions/setup-java@v1
31 | with:
32 | java-version: '11'
33 | - name: Test
34 | env:
35 | NETCORE_TEST_PROJECT: >-
36 | Mastercard.Developer.ClientEncryption.Tests/Mastercard.Developer.ClientEncryption.Tests.csproj
37 | GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
38 | SONAR_TOKEN: '${{ secrets.SONAR_TOKEN }}'
39 | run: >
40 | export PATH="$PATH:$HOME/.dotnet/tools"
41 |
42 | dotnet tool install --global dotnet-sonarscanner
43 |
44 | dotnet sonarscanner begin \
45 | /k:"Mastercard_client-encryption-csharp" \
46 | /n:"client-encryption-csharp" \
47 | /o:"mastercard" \
48 | /d:sonar.host.url="https://sonarcloud.io" \
49 | /d:sonar.login="$SONAR_TOKEN" \
50 | /d:sonar.cs.vstest.reportsPaths="./Mastercard.Developer.ClientEncryption.Tests/bin/tests.trx" \
51 | /d:sonar.cs.opencover.reportsPaths="./Mastercard.Developer.ClientEncryption.Tests/bin/coverage.xml"
52 |
53 | dotnet test $NETCORE5_TEST_PROJECT -c Release
54 | -l:"trx;LogFileName=tests.trx" -r:"./Mastercard.Developer.ClientEncryption.Tests/bin/" /p:CollectCoverage=true
55 | /p:CoverletOutputFormat="opencover"
56 | /p:CoverletOutput="bin/coverage.xml"
57 |
58 | dotnet publish $NETCORE5_TEST_PROJECT -c Release
59 |
60 | dotnet sonarscanner end /d:sonar.login="$SONAR_TOKEN"
61 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Build & Test
2 | 'on':
3 | push:
4 | branches:
5 | - "**"
6 | pull_request:
7 | branches:
8 | - "**"
9 | schedule:
10 | - cron: 0 16 * * *
11 | workflow_dispatch:
12 | jobs:
13 | build:
14 | env:
15 | NET_TEST_PROJECT: >-
16 | Mastercard.Developer.ClientEncryption.Tests/Mastercard.Developer.ClientEncryption.Tests.csproj
17 | runs-on: ubuntu-latest
18 | strategy:
19 | matrix:
20 | dotnet:
21 | - 8.0.x
22 | include:
23 | - dotnet: 8.0.x
24 | TEST_PROJECT: $NETCORE_TEST_PROJECT
25 | steps:
26 | - name: Checkout code
27 | uses: actions/checkout@v2
28 | - name: Setup .NET 4
29 | uses: actions/setup-dotnet@v4.3.1
30 | with:
31 | dotnet-version: 8.0.x
32 |
33 | - name: Build using .NET 8
34 | run: >
35 | export PATH="$PATH:$HOME/.dotnet/tools"
36 |
37 | dotnet build ${{ env.NETCORE_TEST_PROJECT }} -c Release
38 | - name: Setup .NET [Core] ${{ matrix.dotnet }}
39 | uses: actions/setup-dotnet@v4.3.1
40 | with:
41 | dotnet-version: '${{ matrix.dotnet }}'
42 | - name: List .NET SDKs
43 | run: >
44 | dotnet --list-sdks
45 | - name: Run tests using .NET [Core] ${{ matrix.dotnet }}
46 | run: >
47 | export PATH="$PATH:$HOME/.dotnet/tools"
48 |
49 | dotnet test ${{ matrix.TEST_PROJECT }} -c Debug
50 | -l:"trx;LogFileName=tests.trx" -r:"bin/" /p:CollectCoverage=true
51 | /p:CoverletOutputFormat="opencover"
52 | /p:CoverletOutput="bin/coverage.xml"
53 | - name: Local publish
54 | run: >
55 | dotnet publish ${{ matrix.TEST_PROJECT }} -c Debug
56 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | .vscode/
30 | # Uncomment if you have tasks that create the project's static files in wwwroot
31 | #wwwroot/
32 |
33 | # Visual Studio 2017 auto generated files
34 | Generated\ Files/
35 |
36 | # MSTest test Results
37 | [Tt]est[Rr]esult*/
38 | [Bb]uild[Ll]og.*
39 |
40 | # SonarLint
41 | .sonarlint
42 | *.ruleset
43 |
44 | # NUNIT
45 | *.VisualState.xml
46 | TestResult.xml
47 |
48 | # Build Results of an ATL Project
49 | [Dd]ebugPS/
50 | [Rr]eleasePS/
51 | dlldata.c
52 |
53 | # Benchmark Results
54 | BenchmarkDotNet.Artifacts/
55 |
56 | # .NET Core
57 | project.lock.json
58 | project.fragment.lock.json
59 | artifacts/
60 | **/Properties/launchSettings.json
61 |
62 | # StyleCop
63 | StyleCopReport.xml
64 |
65 | # Files built by Visual Studio
66 | *_i.c
67 | *_p.c
68 | *_i.h
69 | *.ilk
70 | *.meta
71 | *.obj
72 | *.iobj
73 | *.pch
74 | *.pdb
75 | *.ipdb
76 | *.pgc
77 | *.pgd
78 | *.rsp
79 | *.sbr
80 | *.tlb
81 | *.tli
82 | *.tlh
83 | *.tmp
84 | *.tmp_proj
85 | *.log
86 | *.vspscc
87 | *.vssscc
88 | .builds
89 | *.pidb
90 | *.svclog
91 | *.scc
92 |
93 | # Chutzpah Test files
94 | _Chutzpah*
95 |
96 | # Visual C++ cache files
97 | ipch/
98 | *.aps
99 | *.ncb
100 | *.opendb
101 | *.opensdf
102 | *.sdf
103 | *.cachefile
104 | *.VC.db
105 | *.VC.VC.opendb
106 |
107 | # Visual Studio profiler
108 | *.psess
109 | *.vsp
110 | *.vspx
111 | *.sap
112 |
113 | # Visual Studio Trace Files
114 | *.e2e
115 |
116 | # TFS 2012 Local Workspace
117 | $tf/
118 |
119 | # Guidance Automation Toolkit
120 | *.gpState
121 |
122 | # ReSharper is a .NET coding add-in
123 | _ReSharper*/
124 | *.[Rr]e[Ss]harper
125 | *.DotSettings.user
126 |
127 | # JustCode is a .NET coding add-in
128 | .JustCode
129 |
130 | # TeamCity is a build add-in
131 | _TeamCity*
132 |
133 | # DotCover is a Code Coverage Tool
134 | *.dotCover
135 |
136 | # AxoCover is a Code Coverage Tool
137 | .axoCover/*
138 | !.axoCover/settings.json
139 |
140 | # Visual Studio code coverage results
141 | *.coverage
142 | *.coveragexml
143 |
144 | # NCrunch
145 | _NCrunch_*
146 | .*crunch*.local.xml
147 | nCrunchTemp_*
148 |
149 | # MightyMoose
150 | *.mm.*
151 | AutoTest.Net/
152 |
153 | # Web workbench (sass)
154 | .sass-cache/
155 |
156 | # Installshield output folder
157 | [Ee]xpress/
158 |
159 | # DocProject is a documentation generator add-in
160 | DocProject/buildhelp/
161 | DocProject/Help/*.HxT
162 | DocProject/Help/*.HxC
163 | DocProject/Help/*.hhc
164 | DocProject/Help/*.hhk
165 | DocProject/Help/*.hhp
166 | DocProject/Help/Html2
167 | DocProject/Help/html
168 |
169 | # Click-Once directory
170 | publish/
171 |
172 | # Publish Web Output
173 | *.[Pp]ublish.xml
174 | *.azurePubxml
175 | # Note: Comment the next line if you want to checkin your web deploy settings,
176 | # but database connection strings (with potential passwords) will be unencrypted
177 | *.pubxml
178 | *.publishproj
179 |
180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
181 | # checkin your Azure Web App publish settings, but sensitive information contained
182 | # in these scripts will be unencrypted
183 | PublishScripts/
184 |
185 | # NuGet Packages
186 | *.nupkg
187 | # The packages folder can be ignored because of Package Restore
188 | **/[Pp]ackages/*
189 | # except build/, which is used as an MSBuild target.
190 | !**/[Pp]ackages/build/
191 | # Uncomment if necessary however generally it will be regenerated when needed
192 | #!**/[Pp]ackages/repositories.config
193 | # NuGet v3's project.json files produces more ignorable files
194 | *.nuget.props
195 | *.nuget.targets
196 |
197 | # Microsoft Azure Build Output
198 | csx/
199 | *.build.csdef
200 |
201 | # Microsoft Azure Emulator
202 | ecf/
203 | rcf/
204 |
205 | # Windows Store app package directories and files
206 | AppPackages/
207 | BundleArtifacts/
208 | Package.StoreAssociation.xml
209 | _pkginfo.txt
210 | *.appx
211 |
212 | # Visual Studio cache files
213 | # files ending in .cache can be ignored
214 | *.[Cc]ache
215 | # but keep track of directories ending in .cache
216 | !*.[Cc]ache/
217 |
218 | # Others
219 | ClientBin/
220 | ~$*
221 | *~
222 | *.dbmdl
223 | *.dbproj.schemaview
224 | *.jfm
225 | *.pfx
226 | *.publishsettings
227 | orleans.codegen.cs
228 |
229 | # Including strong name files can present a security risk
230 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
231 | #*.snk
232 |
233 | # Since there are multiple workflows, uncomment next line to ignore bower_components
234 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
235 | #bower_components/
236 |
237 | # RIA/Silverlight projects
238 | Generated_Code/
239 |
240 | # Backup & report files from converting an old project file
241 | # to a newer Visual Studio version. Backup files are not needed,
242 | # because we have git ;-)
243 | _UpgradeReport_Files/
244 | Backup*/
245 | UpgradeLog*.XML
246 | UpgradeLog*.htm
247 | ServiceFabricBackup/
248 | *.rptproj.bak
249 |
250 | # SQL Server files
251 | *.mdf
252 | *.ldf
253 | *.ndf
254 |
255 | # Business Intelligence projects
256 | *.rdl.data
257 | *.bim.layout
258 | *.bim_*.settings
259 | *.rptproj.rsuser
260 |
261 | # Microsoft Fakes
262 | FakesAssemblies/
263 |
264 | # GhostDoc plugin setting file
265 | *.GhostDoc.xml
266 |
267 | # Node.js Tools for Visual Studio
268 | .ntvs_analysis.dat
269 | node_modules/
270 |
271 | # Visual Studio 6 build log
272 | *.plg
273 |
274 | # Visual Studio 6 workspace options file
275 | *.opt
276 |
277 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
278 | *.vbw
279 |
280 | # Visual Studio LightSwitch build output
281 | **/*.HTMLClient/GeneratedArtifacts
282 | **/*.DesktopClient/GeneratedArtifacts
283 | **/*.DesktopClient/ModelManifest.xml
284 | **/*.Server/GeneratedArtifacts
285 | **/*.Server/ModelManifest.xml
286 | _Pvt_Extensions
287 |
288 | # Paket dependency manager
289 | .paket/paket.exe
290 | paket-files/
291 |
292 | # FAKE - F# Make
293 | .fake/
294 |
295 | # JetBrains Rider
296 | .idea/
297 | *.sln.iml
298 |
299 | # CodeRush
300 | .cr/
301 |
302 | # Python Tools for Visual Studio (PTVS)
303 | __pycache__/
304 | *.pyc
305 |
306 | # Cake - Uncomment if you are using it
307 | # tools/**
308 | # !tools/packages.config
309 |
310 | # Tabs Studio
311 | *.tss
312 |
313 | # Telerik's JustMock configuration file
314 | *.jmconfig
315 |
316 | # BizTalk build output
317 | *.btp.cs
318 | *.btm.cs
319 | *.odx.cs
320 | *.xsd.cs
321 |
322 | # OpenCover UI analysis results
323 | OpenCover/
324 |
325 | # Azure Stream Analytics local run output
326 | ASALocalRun/
327 |
328 | # MSBuild Binary and Structured Log
329 | *.binlog
330 |
331 | # NVidia Nsight GPU debugger configuration file
332 | *.nvuser
333 |
334 | # MFractors (Xamarin productivity tool) working folder
335 | .mfractor/
336 |
337 | # Sonar
338 | .sonarqube
339 |
340 | # Generated documentation
341 | **/*.xml
342 |
--------------------------------------------------------------------------------
/.lycheeignore:
--------------------------------------------------------------------------------
1 | https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/csharp.md
2 | https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/csharp-netcore.md
3 |
--------------------------------------------------------------------------------
/Identity.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mastercard/client-encryption-csharp/7c9250c5a0c5f0d0d8520eb2c69e29ae09787a32/Identity.snk
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 - 2021 Mastercard
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Encryption/AES/AesCbc.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Security.Cryptography;
4 | using Mastercard.Developer.ClientEncryption.Core.Utils;
5 | using Mastercard.Developer.ClientEncryption.Core.Encryption.JWE;
6 |
7 | namespace Mastercard.Developer.ClientEncryption.Core.Encryption.AES
8 | {
9 | internal static class AesCbc
10 | {
11 | public static byte[] Decrypt(byte[] secretKeyBytes, JweObject jweObject)
12 | {
13 | // Extract the encryption key
14 | byte[] aesKey = new byte[16];
15 | Array.Copy(secretKeyBytes, 16, aesKey, 0, aesKey.Length);
16 |
17 | byte[] plaintext;
18 | using (var aes = Aes.Create())
19 | {
20 | aes.Key = aesKey;
21 | aes.Mode = CipherMode.CBC;
22 | aes.Padding = PaddingMode.PKCS7;
23 | aes.IV = Base64Utils.URLDecode(jweObject.Iv);
24 |
25 | byte[] ciphertext = Base64Utils.URLDecode(jweObject.CipherText);
26 | using (var decryptor = aes.CreateDecryptor())
27 | {
28 | using (var memoryStream = new MemoryStream(ciphertext))
29 | {
30 | using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
31 | {
32 | var output = new MemoryStream();
33 | var decrypted = new byte[Math.Min(1024, ciphertext.Length)];
34 | int byteCount;
35 | while ((byteCount = cryptoStream.Read(decrypted, 0, decrypted.Length)) > 0)
36 | {
37 | output.Write(decrypted, 0, byteCount);
38 | }
39 | plaintext = output.ToArray();
40 | }
41 | }
42 | }
43 | }
44 | return plaintext;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Encryption/AES/AesEncryption.cs:
--------------------------------------------------------------------------------
1 | using System.Security.Cryptography;
2 | using Mastercard.Developer.ClientEncryption.Core.Utils;
3 |
4 | namespace Mastercard.Developer.ClientEncryption.Core.Encryption.AES
5 | {
6 | static internal class AesEncryption
7 | {
8 | static internal byte[] GenerateIV()
9 | {
10 | byte[] iv = new byte[12]; // 96 bytes as per NIST recommendation..
11 | using (var rng = RandomNumberGenerator.Create())
12 | {
13 | rng.GetBytes(iv);
14 | }
15 | return iv;
16 | }
17 |
18 | static internal byte[] GenerateCek(int bitLength)
19 | {
20 | byte[] cekMaterial = new byte[ByteUtils.ByteCount(bitLength)];
21 | using (var rng = RandomNumberGenerator.Create())
22 | {
23 | rng.GetBytes(cekMaterial);
24 | }
25 | return cekMaterial;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Encryption/AES/AesGcm.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Mastercard.Developer.ClientEncryption.Core.Utils;
3 | using Mastercard.Developer.ClientEncryption.Core.Encryption.JWE;
4 |
5 | namespace Mastercard.Developer.ClientEncryption.Core.Encryption.AES
6 | {
7 | internal class AesGcmAuthenticated
8 | {
9 | public byte[] Ciphertext { get; private set; }
10 | public byte[] AuthTag { get; private set; }
11 |
12 | internal AesGcmAuthenticated(byte[] ciphertext, byte[] authTag)
13 | {
14 | Ciphertext = ciphertext;
15 | AuthTag = authTag;
16 | }
17 | }
18 |
19 | internal static class AesGcm
20 | {
21 | internal static byte[] Decrypt(byte[] secretKeyBytes, JweObject jweObject)
22 | {
23 | #if NETSTANDARD2_1
24 | byte[] plaintext;
25 | using (var aes = new System.Security.Cryptography.AesGcm(secretKeyBytes))
26 | {
27 | byte[] nonce = Base64Utils.URLDecode(jweObject.Iv);
28 | byte[] aad = Encoding.ASCII.GetBytes(jweObject.RawHeader);
29 | byte[] authTag = Base64Utils.URLDecode(jweObject.AuthTag);
30 | byte[] ciphertext = Base64Utils.URLDecode(jweObject.CipherText);
31 | plaintext = new byte[ciphertext.Length];
32 |
33 | aes.Decrypt(nonce, ciphertext, authTag, plaintext, aad);
34 | }
35 | return plaintext;
36 | #else
37 | throw new EncryptionException("AES/GCM/NoPadding is unsupported on .NET Standard < 2.1");
38 | #endif
39 | }
40 |
41 | internal static AesGcmAuthenticated Encrypt(byte[] secretKeyBytes, byte[] nonce, byte[] plaintext, byte[] aad)
42 | {
43 | #if NETSTANDARD2_1
44 | byte[] ciphertext = new byte[plaintext.Length];
45 | byte[] authTag = new byte[System.Security.Cryptography.AesGcm.TagByteSizes.MaxSize];
46 | using (var aes = new System.Security.Cryptography.AesGcm(secretKeyBytes))
47 | {
48 | aes.Encrypt(nonce, plaintext, ciphertext, authTag, aad);
49 | }
50 | return new AesGcmAuthenticated(ciphertext, authTag);
51 | #else
52 | throw new EncryptionException("AES/GCM/NoPadding is unsupported on .NET Standard < 2.1");
53 | #endif
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Encryption/EncryptionConfig.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Security.Cryptography;
3 | using System.Security.Cryptography.X509Certificates;
4 | #pragma warning disable 1591 // "Missing XML comment for publicly visible type or member."
5 |
6 | namespace Mastercard.Developer.ClientEncryption.Core.Encryption
7 | {
8 | ///
9 | /// A POCO for storing the encryption/decryption configuration.
10 | ///
11 | public abstract class EncryptionConfig
12 | {
13 | ///
14 | /// The different methods of encryption
15 | ///
16 | public enum EncryptionScheme
17 | {
18 | Legacy,
19 | Jwe
20 | }
21 |
22 | ///
23 | /// The encryption scheme to be used
24 | ///
25 | public EncryptionScheme Scheme { get; internal set; }
26 |
27 | ///
28 | /// The digest algorithm to be used for the RSA OAEP padding. Example: "SHA-512".
29 | ///
30 | public string OaepPaddingDigestAlgorithm { get; internal set; }
31 |
32 | ///
33 | /// The SHA-256 hex-encoded digest of the key used for encryption (optional, the digest will be
34 | /// automatically computed if this field is null or empty).
35 | /// Example: "c3f8ef7053c4fb306f7476e7d1956f0aa992ff9dfdd5244b912a1d377ff3a84f"
36 | ///
37 | public string EncryptionKeyFingerprint { get; internal set; }
38 |
39 | ///
40 | /// A certificate object whose public key will be used for encryption.
41 | ///
42 | public X509Certificate2 EncryptionCertificate { get; internal set; }
43 |
44 | ///
45 | /// A private key object to be used for decryption.
46 | ///
47 | public RSA DecryptionKey { get; internal set; }
48 |
49 | ///
50 | /// A list of JSON paths to encrypt in request payloads.
51 | ///
52 | ///
53 | /// new Dictionary<string, string>
54 | /// {
55 | /// { "$.path.to.element.to.be.encrypted", "$.path.to.object.where.to.store.encryption.fields" }
56 | /// };
57 | ///
58 | public Dictionary EncryptionPaths { get; internal set; } = new Dictionary();
59 |
60 | ///
61 | /// A list of JSON paths to decrypt in response payloads.
62 | ///
63 | ///
64 | /// new Dictionary<string, string>
65 | /// {
66 | /// { "$.path.to.object.with.encryption.fields", "$.path.where.to.write.decrypted.element" }
67 | /// };
68 | ///
69 | public Dictionary DecryptionPaths { get; internal set; } = new Dictionary();
70 |
71 | ///
72 | /// The name of the payload field where to write/read the encrypted data value.
73 | ///
74 | public string EncryptedValueFieldName { get; internal set; }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Encryption/EncryptionConfigBuilder.cs:
--------------------------------------------------------------------------------
1 | #pragma warning disable 1591 // "Missing XML comment for publicly visible type or member."
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Security.Cryptography;
6 | using System.Security.Cryptography.X509Certificates;
7 | using Mastercard.Developer.ClientEncryption.Core.Utils;
8 |
9 | using static Mastercard.Developer.ClientEncryption.Core.Utils.JsonUtils;
10 |
11 | namespace Mastercard.Developer.ClientEncryption.Core.Encryption
12 | {
13 | ///
14 | /// A base class for configuration builders.
15 | ///
16 | public abstract class EncryptionConfigBuilder
17 | {
18 | protected internal X509Certificate2 _encryptionCertificate;
19 | protected internal string _encryptionKeyFingerprint;
20 | protected internal RSA _decryptionKey;
21 | protected internal readonly Dictionary _encryptionPaths = new Dictionary();
22 | protected internal readonly Dictionary _decryptionPaths = new Dictionary();
23 | protected internal string _encryptedValueFieldName;
24 | protected internal string _oaepPaddingDigestAlgorithm;
25 |
26 | protected internal void CheckJsonPathParameterValues()
27 | {
28 | foreach (var key in _decryptionPaths.Keys)
29 | {
30 | if (!IsPathDefinite(key) || !IsPathDefinite(_decryptionPaths[key]))
31 | {
32 | throw new ArgumentException("JSON paths for decryption must point to a single item!");
33 | }
34 | }
35 |
36 | foreach (var key in _encryptionPaths.Keys)
37 | {
38 | if (!IsPathDefinite(key) || !IsPathDefinite(_encryptionPaths[key]))
39 | {
40 | throw new ArgumentException("JSON paths for encryption must point to a single item!");
41 | }
42 | }
43 | }
44 |
45 | protected internal void ComputeEncryptionKeyFingerprintWhenNeeded()
46 | {
47 | try
48 | {
49 | if (_encryptionCertificate == null || !string.IsNullOrEmpty(_encryptionKeyFingerprint))
50 | {
51 | // No encryption certificate set or certificate fingerprint already provided
52 | return;
53 | }
54 | var encodedKey = RsaKeyUtils.GetEncoded(_encryptionCertificate.PublicKey);
55 | var keyFingerprintBytes = Sha256Digest(encodedKey);
56 | _encryptionKeyFingerprint = EncodingUtils.HexEncode(keyFingerprintBytes);
57 | }
58 | catch (Exception e)
59 | {
60 | throw new EncryptionException("Failed to compute encryption key fingerprint!", e);
61 | }
62 | }
63 |
64 | protected internal static byte[] Sha256Digest(byte[] inputBytes)
65 | {
66 | var sha256 = SHA256.Create();
67 | return sha256.ComputeHash(inputBytes);
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Encryption/EncryptionException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | #pragma warning disable 1591 // "Missing XML comment for publicly visible type or member."
3 |
4 | namespace Mastercard.Developer.ClientEncryption.Core.Encryption
5 | {
6 | public class EncryptionException : Exception
7 | {
8 | public EncryptionException(string message, Exception innerException) : base(message, innerException) {}
9 | public EncryptionException(string message) : base(message) {}
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Encryption/FieldLevelEncryptionConfig.cs:
--------------------------------------------------------------------------------
1 | #pragma warning disable 1591 // "Missing XML comment for publicly visible type or member."
2 |
3 | namespace Mastercard.Developer.ClientEncryption.Core.Encryption
4 | {
5 | ///
6 | /// A POCO for storing the encryption/decryption configuration.
7 | ///
8 | public class FieldLevelEncryptionConfig : EncryptionConfig
9 | {
10 | ///
11 | /// The different ways of encoding the field and header values.
12 | ///
13 | public enum FieldValueEncoding
14 | {
15 | Base64,
16 | Hex
17 | }
18 |
19 | internal FieldLevelEncryptionConfig() {}
20 |
21 | ///
22 | /// The SHA-256 hex-encoded digest of the certificate used for encryption (optional, the digest will be
23 | /// automatically computed if this field is null or empty).
24 | /// Example: "4d9d7540be320429ffc8e6506f054525816e2d0e95a85247d5b58be713f28be0"
25 | ///
26 | public string EncryptionCertificateFingerprint { get; internal set; }
27 |
28 | ///
29 | /// The name of the payload field where to write/read the digest algorithm used for
30 | /// the RSA OAEP padding (optional, the field won't be set if the name is null or empty).
31 | ///
32 | public string OaepPaddingDigestAlgorithmFieldName { get; internal set; }
33 |
34 | ///
35 | /// The name of the HTTP header where to write/read the digest algorithm used for
36 | /// the RSA OAEP padding (optional, the header won't be set if the name is null or empty).
37 | ///
38 | public string OaepPaddingDigestAlgorithmHeaderName { get; internal set; }
39 |
40 | ///
41 | /// The name of the payload field where to write/read the initialization vector value.
42 | ///
43 | public string IvFieldName { get; internal set; }
44 |
45 | ///
46 | /// The name of the header where to write/read the initialization vector value.
47 | ///
48 | public string IvHeaderName { get; internal set; }
49 |
50 | ///
51 | /// The name of the payload field where to write/read the one-time usage encrypted symmetric key.
52 | ///
53 | public string EncryptedKeyFieldName { get; internal set; }
54 |
55 | ///
56 | /// The name of the header where to write/read the one-time usage encrypted symmetric key.
57 | ///
58 | public string EncryptedKeyHeaderName { get; internal set; }
59 |
60 | ///
61 | /// The name of the payload field where to write/read the digest of the encryption
62 | /// certificate (optional, the field won't be set if the name is null or empty).
63 | ///
64 | public string EncryptionCertificateFingerprintFieldName { get; internal set; }
65 |
66 | ///
67 | /// The name of the header where to write/read the digest of the encryption
68 | /// certificate (optional, the header won't be set if the name is null or empty).
69 | ///
70 | public string EncryptionCertificateFingerprintHeaderName { get; internal set; }
71 |
72 | ///
73 | /// The name of the payload field where to write/read the digest of the encryption
74 | /// key (optional, the field won't be set if the name is null or empty).
75 | ///
76 | public string EncryptionKeyFingerprintFieldName { get; internal set; }
77 |
78 | ///
79 | /// The name of the header where to write/read the digest of the encryption
80 | /// key (optional, the header won't be set if the name is null or empty).
81 | ///
82 | public string EncryptionKeyFingerprintHeaderName { get; internal set; }
83 |
84 | ///
85 | /// How the field/header values have to be encoded.
86 | ///
87 | public FieldValueEncoding ValueEncoding { get; internal set; }
88 |
89 | ///
90 | /// If the encryption parameters must be written to/read from HTTP payloads.
91 | ///
92 | public bool UseHttpPayloads() => !string.IsNullOrEmpty(EncryptedKeyFieldName) && !string.IsNullOrEmpty(IvFieldName);
93 |
94 | ///
95 | /// If the encryption parameters must be written to/read from HTTP headers.
96 | ///
97 | public bool UseHttpHeaders() => !string.IsNullOrEmpty(EncryptedKeyHeaderName) && !string.IsNullOrEmpty(IvHeaderName);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Encryption/FieldLevelEncryptionParams.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Security.Cryptography;
3 | using System.Security.Cryptography.X509Certificates;
4 | using Mastercard.Developer.ClientEncryption.Core.Utils;
5 | #pragma warning disable 1591 // "Missing XML comment for publicly visible type or member."
6 |
7 | namespace Mastercard.Developer.ClientEncryption.Core.Encryption
8 | {
9 | ///
10 | /// Encryption parameters for computing field level encryption/decryption.
11 | ///
12 | public class FieldLevelEncryptionParams
13 | {
14 | private const int SymmetricKeySize = 128;
15 |
16 | ///
17 | /// Initialization vector value.
18 | ///
19 | public string IvValue { get; private set; }
20 |
21 | ///
22 | /// Encrypted key value.
23 | ///
24 | public string EncryptedKeyValue { get; private set; }
25 |
26 | ///
27 | /// Digest algorithm to be used for the RSA OAEP padding. Example: "SHA-512".
28 | ///
29 | public string OaepPaddingDigestAlgorithmValue { get; private set; }
30 |
31 | private FieldLevelEncryptionConfig Config { get; set; }
32 | private byte[] SecretKeyBytes { get; set; }
33 | private byte[] IvBytes { get; set; }
34 |
35 | private FieldLevelEncryptionParams() {}
36 |
37 | public FieldLevelEncryptionParams(FieldLevelEncryptionConfig config, string ivValue, string encryptedKeyValue, string oaepPaddingDigestAlgorithmValue = null)
38 | {
39 | IvValue = ivValue;
40 | EncryptedKeyValue = encryptedKeyValue;
41 | OaepPaddingDigestAlgorithmValue = oaepPaddingDigestAlgorithmValue;
42 | Config = config;
43 | }
44 |
45 | ///
46 | /// Generate encryption parameters.
47 | ///
48 | ///
49 | public static FieldLevelEncryptionParams Generate(FieldLevelEncryptionConfig config)
50 | {
51 | // Generate a random IV
52 | var ivBytes = GenerateIv();
53 | var ivValue = EncodingUtils.EncodeBytes(ivBytes, config.ValueEncoding);
54 |
55 | // Generate an AES secret key
56 | var secretKeyBytes = GenerateSecretKey();
57 |
58 | // Encrypt the secret key
59 | var encryptedSecretKeyBytes = RsaEncryption.WrapSecretKey(config.EncryptionCertificate.GetRSAPublicKey(), secretKeyBytes, config.OaepPaddingDigestAlgorithm);
60 | var encryptedKeyValue = EncodingUtils.EncodeBytes(encryptedSecretKeyBytes, config.ValueEncoding);
61 |
62 | // Compute the OAEP padding digest algorithm
63 | var oaepPaddingDigestAlgorithmValue = config.OaepPaddingDigestAlgorithm.Replace("-", string.Empty);
64 |
65 | return new FieldLevelEncryptionParams
66 | {
67 | IvValue = ivValue,
68 | EncryptedKeyValue = encryptedKeyValue,
69 | OaepPaddingDigestAlgorithmValue = oaepPaddingDigestAlgorithmValue,
70 | Config = config,
71 | SecretKeyBytes = secretKeyBytes,
72 | IvBytes = ivBytes
73 | };
74 | }
75 |
76 | private static byte[] GenerateIv()
77 | {
78 | using (var aes = Aes.Create())
79 | {
80 | if (aes == null)
81 | {
82 | throw new EncryptionException("Failed to generate IV, AES instance is null!");
83 | }
84 |
85 | aes.GenerateIV();
86 | return aes.IV;
87 | }
88 | }
89 |
90 | private static byte[] GenerateSecretKey()
91 | {
92 | using (var aes = Aes.Create())
93 | {
94 | if (aes == null)
95 | {
96 | throw new EncryptionException("Failed to generate secret key, AES instance is null!");
97 | }
98 |
99 | aes.KeySize = SymmetricKeySize;
100 | aes.GenerateKey();
101 | return aes.Key;
102 | }
103 | }
104 |
105 | internal byte[] GetSecretKeyBytes()
106 | {
107 | try
108 | {
109 | if (SecretKeyBytes != null)
110 | {
111 | return SecretKeyBytes;
112 | }
113 | // Decrypt the AES secret key
114 | var encryptedSecretKeyBytes = EncodingUtils.DecodeValue(EncryptedKeyValue, Config.ValueEncoding);
115 | SecretKeyBytes = RsaEncryption.UnwrapSecretKey(Config, encryptedSecretKeyBytes, OaepPaddingDigestAlgorithmValue);
116 | return SecretKeyBytes;
117 | }
118 | catch (Exception e)
119 | {
120 | throw new EncryptionException("Failed to decode and unwrap the provided secret key value!", e);
121 | }
122 | }
123 |
124 | internal byte[] GetIvBytes()
125 | {
126 | try
127 | {
128 | if (IvBytes != null)
129 | {
130 | return IvBytes;
131 | }
132 | // Decode the IV
133 | IvBytes = EncodingUtils.DecodeValue(IvValue, Config.ValueEncoding);
134 | return IvBytes;
135 | }
136 | catch (Exception e)
137 | {
138 | throw new EncryptionException("Failed to decode the provided IV value!", e);
139 | }
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Encryption/JWE/JweEncryption.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Newtonsoft.Json;
3 | using Newtonsoft.Json.Linq;
4 | using Mastercard.Developer.ClientEncryption.Core.Utils;
5 | #pragma warning disable 1591 // "Missing XML comment for publicly visible type or member."
6 |
7 | namespace Mastercard.Developer.ClientEncryption.Core.Encryption.JWE
8 | {
9 | public static class JweEncryption
10 | {
11 | private const string Algorithm = "RSA-OAEP-256";
12 | private const string Encryption = "A256GCM";
13 | private const string ContentType = "application/json";
14 |
15 | public static string EncryptPayload(string payload, JweConfig config)
16 | {
17 | try
18 | {
19 | // Parse the given payload
20 | var payloadToken = JsonUtils.ParsePayload(payload);
21 |
22 | // Encrypt
23 | foreach (var entry in config.EncryptionPaths)
24 | {
25 | var jsonPathIn = entry.Key;
26 | var jsonPathOut = entry.Value;
27 | payloadToken = EncryptPayloadPath(payloadToken, jsonPathIn, jsonPathOut, config);
28 | }
29 |
30 | return payloadToken.ToString();
31 | }
32 | catch (Exception ex)
33 | {
34 | throw new EncryptionException("Payload encryption failed!", ex);
35 | }
36 | }
37 |
38 | public static string DecryptPayload(string payload, JweConfig config)
39 | {
40 | try
41 | {
42 | // Parse the given payload
43 | var payloadToken = JsonUtils.ParsePayload(payload);
44 |
45 | // Perform decryption
46 | foreach (var entry in config.DecryptionPaths)
47 | {
48 | var jsonPathIn = entry.Key;
49 | var jsonPathOut = entry.Value;
50 | payloadToken = DecryptPayloadPath(payloadToken, jsonPathIn, jsonPathOut, config);
51 | }
52 | return payloadToken.ToString();
53 | }
54 | catch (Exception ex)
55 | {
56 | throw new EncryptionException("Payload decryption failed!", ex);
57 | }
58 | }
59 |
60 | private static JToken DecryptPayloadPath(JToken payload, string jsonPathIn, string jsonPathOut, JweConfig config)
61 | {
62 | var token = payload.SelectToken(jsonPathIn);
63 | if (JsonUtils.IsNullOrEmptyJson(token))
64 | {
65 | // Nothing to decrypt
66 | return payload;
67 | }
68 |
69 | // Read and remove encrypted data and encryption fields at the given JSON path
70 | var encryptedValue = ReadAndDeleteJsonKey(payload, token, config.EncryptedValueFieldName);
71 | if (string.IsNullOrEmpty(encryptedValue))
72 | {
73 | // Nothing to decrypt
74 | return payload;
75 | }
76 | var jweObject = JweObject.Parse(encryptedValue);
77 | var decryptedValue = jweObject.Decrypt(config);
78 |
79 | if ("$".Equals(jsonPathOut))
80 | {
81 | return JsonUtils.ParsePayload(decryptedValue);
82 | }
83 |
84 | JsonUtils.CheckOrCreateOutObject(payload, jsonPathOut);
85 | JsonUtils.AddDecryptedDataToPayload(payload, decryptedValue, jsonPathOut);
86 |
87 | // Remove the input
88 | token = payload.SelectToken(jsonPathIn);
89 | if (null != token && token.Parent != null)
90 | {
91 | token.Parent.Remove();
92 | }
93 | return payload;
94 | }
95 |
96 | private static string ReadAndDeleteJsonKey(JToken context, JToken token, string key)
97 | {
98 | if (string.IsNullOrEmpty(key)) return token.ToString();
99 | var value = context.SelectToken(key);
100 | if (null != value && null != value.Parent)
101 | {
102 | value.Parent.Remove();
103 | }
104 | return token.ToString();
105 | }
106 |
107 | private static JToken EncryptPayloadPath(JToken json, string jsonPathIn, string jsonPathOut, JweConfig config)
108 | {
109 | var token = json.SelectToken(jsonPathIn);
110 | if (JsonUtils.IsNullOrEmptyJson(token))
111 | {
112 | // Nothing to encrypt
113 | return json;
114 | }
115 |
116 | // Encode and encrypt
117 | var inJsonString = JsonUtils.SanitizeJson(token.ToString(Formatting.None));
118 | var header = new JweHeader(Algorithm, Encryption, config.EncryptionKeyFingerprint, ContentType);
119 | var encrypted = JweObject.Encrypt(config, inJsonString, header);
120 |
121 | // Delete data in the clear
122 | if ("$".Equals(jsonPathIn))
123 | {
124 | // Create a new object
125 | json = JObject.Parse("{}");
126 | }
127 | else
128 | {
129 | token.Parent.Remove();
130 | }
131 |
132 | JsonUtils.CheckOrCreateOutObject(json, jsonPathOut);
133 | var outJsonToken = json.SelectToken(jsonPathOut) as JObject;
134 | JsonUtils.AddOrReplaceJsonKey(outJsonToken, config.EncryptedValueFieldName, encrypted);
135 | return json;
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Encryption/JWE/JweHeader.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Newtonsoft.Json.Linq;
3 | using Mastercard.Developer.ClientEncryption.Core.Utils;
4 | #pragma warning disable 1591 // "Missing XML comment for publicly visible type or member."
5 |
6 | namespace Mastercard.Developer.ClientEncryption.Core.Encryption.JWE
7 | {
8 | internal sealed class JweHeader
9 | {
10 | private const string Algorithm = "alg";
11 | private const string KeyId = "kid";
12 | private const string EncryptionAlgorithm = "enc";
13 | private const string ContentType = "cty";
14 |
15 | public string Enc { get; }
16 | public string Kid { get; }
17 | public string Alg { get; }
18 | public string Cty { get; }
19 |
20 | public JweHeader(string alg, string enc, string kid, string cty)
21 | {
22 | Alg = alg;
23 | Enc = enc;
24 | Kid = kid;
25 | Cty = cty;
26 | }
27 |
28 | public JObject Json =>
29 | new JObject(
30 | new JProperty(KeyId, Kid),
31 | new JProperty(ContentType, Cty),
32 | new JProperty(EncryptionAlgorithm, Enc),
33 | new JProperty(Algorithm, Alg)
34 | );
35 |
36 | public static JweHeader Parse(string encoded)
37 | {
38 | // Decode and parse the string
39 | var decoded = Base64Utils.URLDecode(encoded);
40 | var json = Encoding.UTF8.GetString(decoded);
41 | var jobject = JObject.Parse(json);
42 |
43 | // Wrap it up
44 | return new JweHeader(
45 | ((string)jobject[Algorithm]),
46 | ((string)jobject[EncryptionAlgorithm]),
47 | ((string)jobject[KeyId]),
48 | ((string)jobject[ContentType])
49 | );
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Encryption/JWE/JweObject.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using Mastercard.Developer.ClientEncryption.Core.Utils;
4 | using Mastercard.Developer.ClientEncryption.Core.Encryption.AES;
5 | using System.Security.Cryptography.X509Certificates;
6 | #pragma warning disable 1591 // "Missing XML comment for publicly visible type or member."
7 |
8 | namespace Mastercard.Developer.ClientEncryption.Core.Encryption.JWE
9 | {
10 | internal class JweObject
11 | {
12 | private const string A128CBC_HS256 = "A128CBC-HS256";
13 | private const string A256GCM = "A256GCM";
14 | private const string A128GCM = "A128GCM";
15 | private const string A192GCM = "A192GCM";
16 |
17 | public JweHeader Header { get; private set; }
18 | public string RawHeader { get; private set; }
19 | public string EncryptedKey { get; private set; }
20 | public string Iv { get; private set; }
21 | public string CipherText { get; private set; }
22 | public string AuthTag { get; private set; }
23 |
24 | public string Decrypt(JweConfig config)
25 | {
26 | var unwrappedKey = RsaEncryption.UnwrapSecretKey(config, Base64Utils.URLDecode(EncryptedKey), "SHA-256");
27 | if (unwrappedKey == null)
28 | {
29 | throw new EncryptionException($"Failed to unwrap key {EncryptedKey}");
30 | }
31 |
32 | var encryptionMethod = Header.Enc;
33 |
34 | byte[] plaintext;
35 | switch (encryptionMethod)
36 | {
37 | case A256GCM:
38 | plaintext = AesGcm.Decrypt(unwrappedKey, this);
39 | break;
40 | case A128GCM:
41 | plaintext = AesGcm.Decrypt(unwrappedKey, this);
42 | break;
43 | case A192GCM:
44 | plaintext = AesGcm.Decrypt(unwrappedKey, this);
45 | break;
46 | case A128CBC_HS256:
47 | plaintext = AesCbc.Decrypt(unwrappedKey, this);
48 | break;
49 | default:
50 | throw new EncryptionException($"Encryption method {encryptionMethod} is not supported");
51 | }
52 | return Encoding.UTF8.GetString(plaintext);
53 | }
54 |
55 | public static string Encrypt(JweConfig config, string payload, JweHeader header)
56 | {
57 | var cek = AesEncryption.GenerateCek(256);
58 | var encryptedSecretKeyBytes = RsaEncryption.WrapSecretKey(config.EncryptionCertificate.GetRSAPublicKey(), cek, "SHA-256");
59 | var encryptedKey = Base64Utils.URLEncode(encryptedSecretKeyBytes);
60 |
61 | var iv = AesEncryption.GenerateIV();
62 | var payloadBytes = Encoding.UTF8.GetBytes(payload);
63 |
64 | var headerString = header.Json.ToString();
65 | var encodedHeader = Base64Utils.URLEncode(Encoding.UTF8.GetBytes(headerString));
66 | var aad = Encoding.ASCII.GetBytes(encodedHeader);
67 |
68 | var encrypted = AesGcm.Encrypt(cek, iv, payloadBytes, aad);
69 | return Serialize(encodedHeader, encryptedKey, Base64Utils.URLEncode(iv), Base64Utils.URLEncode(encrypted.Ciphertext), Base64Utils.URLEncode(encrypted.AuthTag));
70 | }
71 |
72 | public static JweObject Parse(string encryptedPayload)
73 | {
74 | var fields = encryptedPayload.Trim().Split('.');
75 |
76 | var jweObject = new JweObject();
77 | jweObject.RawHeader = fields[0];
78 | jweObject.Header = JweHeader.Parse(jweObject.RawHeader);
79 | jweObject.EncryptedKey = fields[1];
80 | jweObject.Iv = fields[2];
81 | jweObject.CipherText = fields[3];
82 | jweObject.AuthTag = fields[4];
83 | return jweObject;
84 | }
85 |
86 | internal static string Serialize(string header, string encryptedKey, string iv, string cipherText, string authTag)
87 | {
88 | return header + "." +
89 | encryptedKey +
90 | '.' +
91 | iv +
92 | '.' +
93 | cipherText +
94 | '.' +
95 | authTag;
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Encryption/JweConfig.cs:
--------------------------------------------------------------------------------
1 | #pragma warning disable 1591 // "Missing XML comment for publicly visible type or member."
2 |
3 | namespace Mastercard.Developer.ClientEncryption.Core.Encryption
4 | {
5 | public class JweConfig : EncryptionConfig
6 | {
7 | internal JweConfig() { }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Encryption/JweConfigBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Security.Cryptography;
4 | using System.Security.Cryptography.X509Certificates;
5 |
6 | namespace Mastercard.Developer.ClientEncryption.Core.Encryption
7 | {
8 | ///
9 | /// A builder class for .
10 | ///
11 | public class JweConfigBuilder : EncryptionConfigBuilder
12 | {
13 | private JweConfigBuilder() { }
14 |
15 | ///
16 | /// Get an instance of the builder.
17 | ///
18 | public static JweConfigBuilder AJweEncryptionConfig() => new JweConfigBuilder();
19 |
20 | ///
21 | /// See:
22 | ///
23 | public JweConfigBuilder WithEncryptionCertificate(X509Certificate2 encryptionCertificate)
24 | {
25 | _encryptionCertificate = encryptionCertificate;
26 | return this;
27 | }
28 |
29 | ///
30 | /// See:
31 | ///
32 | public JweConfigBuilder WithEncryptionKeyFingerprint(string encryptionKeyFingerprint)
33 | {
34 | _encryptionKeyFingerprint = encryptionKeyFingerprint;
35 | return this;
36 | }
37 |
38 | ///
39 | /// See:
40 | ///
41 | public JweConfigBuilder WithDecryptionKey(RSA decryptionKey)
42 | {
43 | _decryptionKey = decryptionKey;
44 | return this;
45 | }
46 |
47 | ///
48 | /// See:
49 | ///
50 | public JweConfigBuilder WithEncryptionPath(string jsonPathIn, string jsonPathOut)
51 | {
52 | _encryptionPaths.Add(jsonPathIn, jsonPathOut);
53 | return this;
54 | }
55 |
56 | ///
57 | /// See:
58 | ///
59 | public JweConfigBuilder WithDecryptionPath(string jsonPathIn, string jsonPathOut)
60 | {
61 | _decryptionPaths.Add(jsonPathIn, jsonPathOut);
62 | return this;
63 | }
64 |
65 | ///
66 | /// See:
67 | ///
68 | public JweConfigBuilder WithEncryptedValueFieldName(string encryptedValueFieldName)
69 | {
70 | _encryptedValueFieldName = encryptedValueFieldName;
71 | return this;
72 | }
73 |
74 | ///
75 | /// Build a
76 | ///
77 | public JweConfig Build()
78 | {
79 | CheckParameterValues();
80 | ComputeEncryptionKeyFingerprintWhenNeeded();
81 | CheckJsonPathParameterValues();
82 |
83 | return new JweConfig
84 | {
85 | EncryptionCertificate = _encryptionCertificate,
86 | EncryptionKeyFingerprint = _encryptionKeyFingerprint,
87 | DecryptionKey = _decryptionKey,
88 | EncryptionPaths = _encryptionPaths.Count == 0 ? new Dictionary { { "$", "$" } } : _encryptionPaths,
89 | DecryptionPaths = _decryptionPaths.Count == 0 ? new Dictionary { { "$.encryptedData", "$" } } : _decryptionPaths,
90 | EncryptedValueFieldName = _encryptedValueFieldName ?? "encryptedData",
91 | Scheme = EncryptionConfig.EncryptionScheme.Jwe
92 | };
93 | }
94 |
95 | private void CheckParameterValues()
96 | {
97 | if (_decryptionKey == null && _encryptionCertificate == null)
98 | {
99 | throw new ArgumentException("You must include at least an encryption certificate or a decryption key");
100 | }
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Encryption/RSA/RsaEncryption.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Security.Cryptography;
3 |
4 | namespace Mastercard.Developer.ClientEncryption.Core.Encryption
5 | {
6 | static internal class RsaEncryption
7 | {
8 | internal static byte[] WrapSecretKey(System.Security.Cryptography.RSA publicKey, byte[] keyBytes, String oaepDigestAlgorithm)
9 | {
10 | try
11 | {
12 | return publicKey.Encrypt(keyBytes,
13 | "SHA-256".Equals(oaepDigestAlgorithm)
14 | ? RSAEncryptionPadding.OaepSHA256
15 | : RSAEncryptionPadding.OaepSHA512);
16 | }
17 | catch (Exception e)
18 | {
19 | throw new EncryptionException("Failed to wrap secret key!", e);
20 | }
21 | }
22 |
23 | internal static byte[] UnwrapSecretKey(EncryptionConfig config, byte[] keyBytes, string oaepDigestAlgorithm)
24 | {
25 | try
26 | {
27 | if (!oaepDigestAlgorithm.Contains("-"))
28 | {
29 | oaepDigestAlgorithm = oaepDigestAlgorithm.Replace("SHA", "SHA-");
30 | }
31 |
32 | var decryptionKey = config.DecryptionKey;
33 | return decryptionKey.Decrypt(keyBytes,
34 | "SHA-256".Equals(oaepDigestAlgorithm)
35 | ? RSAEncryptionPadding.OaepSHA256
36 | : RSAEncryptionPadding.OaepSHA512);
37 | }
38 | catch (Exception e)
39 | {
40 | throw new EncryptionException("Failed to unwrap secret key!", e);
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Mastercard.Developer.ClientEncryption.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | true
6 | 1.9.3
7 | Mastercard.Developer.ClientEncryption.Core
8 | Mastercard
9 | Mastercard
10 | LICENSE
11 | https://github.com/Mastercard/client-encryption-csharp
12 | See: https://github.com/Mastercard/client-encryption-csharp/releases
13 | https://github.com/Mastercard/client-encryption-csharp
14 | Library for Mastercard API compliant payload encryption/decryption
15 |
16 | true
17 | ../Identity.snk
18 | 1.0.0.0
19 | 1.9.3
20 | Mastercard.Developer.ClientEncryption.Core.xml
21 | true
22 | snupkg
23 | icon.png
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | True
32 |
33 |
34 |
35 |
36 |
37 |
38 | <_Parameter1>Mastercard.Developer.ClientEncryption.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b50e085c4583209974a6a902505c534b21b205b9e627c583beea690b541d67fdfe8dc53e50c6a0653f0e3e7828d75432a50df4c4b5348ca4e662e42af603cc97636fb2393ef995babf19bc51644c30296a3edf0afd0182cfc21d0c836da5af922e3631a52a2dc5ed2edc8c568f41ff3d41c82fbe27e6bf4fe4df3e50568b65c8
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Utils/Base64Utils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Mastercard.Developer.ClientEncryption.Core.Utils
4 | {
5 | internal static class Base64Utils
6 | {
7 | // c.f. https://datatracker.ietf.org/doc/html/rfc7515#appendix-C
8 | internal static string URLEncode(byte[] bytes)
9 | {
10 | string s = Convert.ToBase64String(bytes);
11 | s = s.Split('=')[0];
12 | s = s.Replace('+', '-');
13 | s = s.Replace('/', '_');
14 | return s;
15 | }
16 |
17 | internal static byte[] URLDecode(string encoded)
18 | {
19 | string s = encoded.Replace('_', '/').Replace('-', '+');
20 | switch (s.Length % 4)
21 | {
22 | case 2:
23 | s += "==";
24 | break;
25 |
26 | case 3:
27 | s += "=";
28 | break;
29 | }
30 | return Convert.FromBase64String(s);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Utils/ByteUtils.cs:
--------------------------------------------------------------------------------
1 | namespace Mastercard.Developer.ClientEncryption.Core.Utils
2 | {
3 | internal static class ByteUtils
4 | {
5 | static internal int ByteCount(int bitCount)
6 | {
7 | int byteCount = (bitCount / 8);
8 | return ((bitCount % 8) == 0)
9 | ? byteCount
10 | : (byteCount + 1);
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Utils/EncodingUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using static Mastercard.Developer.ClientEncryption.Core.Encryption.FieldLevelEncryptionConfig;
4 |
5 | namespace Mastercard.Developer.ClientEncryption.Core.Utils
6 | {
7 | internal static class EncodingUtils
8 | {
9 | internal static string EncodeBytes(byte[] bytes, FieldValueEncoding encoding)
10 | {
11 | return encoding == FieldValueEncoding.Hex ? HexEncode(bytes) : Convert.ToBase64String(bytes);
12 | }
13 |
14 | internal static byte[] DecodeValue(string value, FieldValueEncoding encoding)
15 | {
16 | return encoding == FieldValueEncoding.Hex ? HexDecode(value) : Convert.FromBase64String(value);
17 | }
18 |
19 | internal static byte[] HexDecode(string value)
20 | {
21 | if (value == null) throw new ArgumentNullException(nameof(value));
22 | return Enumerable.Range(0, value.Length)
23 | .Where(x => x % 2 == 0)
24 | .Select(x => Convert.ToByte(value.Substring(x, 2), 16))
25 | .ToArray();
26 | }
27 |
28 | internal static string HexEncode(byte[] bytes)
29 | {
30 | if (bytes == null) throw new ArgumentNullException(nameof(bytes));
31 | var hexString = BitConverter.ToString(bytes);
32 | return hexString.Replace("-", string.Empty).ToLower();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Utils/EncryptionUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Security.Cryptography;
3 | using System.Security.Cryptography.X509Certificates;
4 |
5 | namespace Mastercard.Developer.ClientEncryption.Core.Utils
6 | {
7 | ///
8 | /// Utility class for loading certificates and keys.
9 | ///
10 | public static class EncryptionUtils
11 | {
12 | ///
13 | /// Populate a X509 encryption certificate object with the certificate data at the given file path.
14 | ///
15 | public static X509Certificate2 LoadEncryptionCertificate(string certificatePath)
16 | {
17 | if (certificatePath == null) throw new ArgumentNullException(nameof(certificatePath));
18 | return new X509Certificate2(certificatePath);
19 | }
20 |
21 | ///
22 | /// Load a RSA decryption key from a file (PEM or DER).
23 | ///
24 | public static RSA LoadDecryptionKey(string keyFilePath) => RsaKeyUtils.ReadPrivateKeyFile(keyFilePath);
25 |
26 | ///
27 | /// Load a RSA decryption key out of a PKCS#12 container.
28 | ///
29 | public static RSA LoadDecryptionKey(string pkcs12KeyFilePath, string decryptionKeyAlias, string decryptionKeyPassword,
30 | X509KeyStorageFlags keyStorageFlags = X509KeyStorageFlags.DefaultKeySet)
31 | {
32 | if (pkcs12KeyFilePath == null) throw new ArgumentNullException(nameof(pkcs12KeyFilePath));
33 | var certificate = new X509Certificate2(pkcs12KeyFilePath, decryptionKeyPassword, keyStorageFlags);
34 | return certificate.GetRSAPrivateKey();
35 | }
36 |
37 | ///
38 | /// Load a RSA decryption key from a byte array.
39 | ///
40 | public static RSA LoadDecryptionKey(byte[] key) => RsaKeyUtils.ReadPrivateKey(key);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Utils/JsonUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Newtonsoft.Json.Linq;
3 | using System.Text.RegularExpressions;
4 | using Newtonsoft.Json;
5 |
6 | namespace Mastercard.Developer.ClientEncryption.Core.Utils
7 | {
8 | internal static class JsonUtils
9 | {
10 | private static readonly Regex LastElementInPathRegExp = new Regex(".*(\\['.*'\\])"); // Returns "['obj2']" for "$['obj1']['obj2']"
11 |
12 | ///
13 | /// Get JSON path to the parent of the object at the given JSON path.
14 | ///
15 | internal static string GetParentJsonPath(string jsonPath)
16 | {
17 | if (string.IsNullOrEmpty(jsonPath)) throw new ArgumentException(nameof(jsonPath));
18 |
19 | if ("$".Equals(jsonPath))
20 | {
21 | throw new InvalidOperationException($"Unable to find parent for '{jsonPath}'");
22 | }
23 |
24 | // "$.['path'].['to'].['object']"?
25 | var match = LastElementInPathRegExp.Match(jsonPath);
26 | if (match.Success)
27 | {
28 | return jsonPath.Replace(match.Groups[match.Groups.Count - 1].Value, string.Empty);
29 | }
30 |
31 | // "$.path.to.object"?
32 | var lastIndexOfDot = jsonPath.LastIndexOf(".", StringComparison.Ordinal);
33 | if (lastIndexOfDot != -1)
34 | {
35 | return jsonPath.Substring(0, lastIndexOfDot);
36 | }
37 |
38 | // "object"
39 | return "$";
40 | }
41 |
42 | ///
43 | /// Get object key at the given JSON path.
44 | ///
45 | internal static string GetJsonElementKey(string jsonPath)
46 | {
47 | if (string.IsNullOrEmpty(jsonPath)) throw new ArgumentException(nameof(jsonPath));
48 |
49 | if ("$".Equals(jsonPath))
50 | {
51 | throw new InvalidOperationException($"Unable to find object key for '{jsonPath}'");
52 | }
53 |
54 | // "$.['path'].['to'].['object']"?
55 | var match = LastElementInPathRegExp.Match(jsonPath);
56 | if (match.Success)
57 | {
58 | return match.Groups[match.Groups.Count - 1].Value.Replace("['", "").Replace("']", "");
59 | }
60 |
61 | // "$.path.to.object"?
62 | var lastIndexOfDot = jsonPath.LastIndexOf(".", StringComparison.Ordinal);
63 | if (lastIndexOfDot != -1)
64 | {
65 | return jsonPath.Substring(lastIndexOfDot + 1, jsonPath.Length - lastIndexOfDot - 1);
66 | }
67 |
68 | // "object"
69 | return jsonPath;
70 | }
71 |
72 | ///
73 | /// Checks if a JSON path points to a single item or if it potentially returns multiple items.
74 | /// See: https://github.com/json-path/JsonPath
75 | ///
76 | internal static bool IsPathDefinite(string path)
77 | {
78 | return !path.Contains("*") && !path.Contains("..") && !path.Contains("@") && !path.Contains(",");
79 | }
80 | ///
81 | /// Parses the Json payload with specified parameters
82 | ///
83 | /// payloadToken
84 | internal static JToken ParsePayload(string payload)
85 | {
86 | var jsonReader = new JsonTextReader(new System.IO.StringReader(payload)) {
87 | DateParseHandling = DateParseHandling.None
88 | };
89 |
90 | return JToken.ReadFrom(jsonReader);
91 | }
92 |
93 | internal static void CheckOrCreateOutObject(JToken payloadObject, string jsonPathOut)
94 | {
95 | var outJsonToken = payloadObject.SelectToken(jsonPathOut);
96 | if (null != outJsonToken)
97 | {
98 | // Object already exists
99 | AssertIsObject(outJsonToken, jsonPathOut);
100 | return;
101 | }
102 |
103 | // Path does not exist: if parent exists then we create a new object under the parent
104 | var parentJsonPath = GetParentJsonPath(jsonPathOut);
105 | var parentJsonObject = payloadObject.SelectToken(parentJsonPath);
106 | if (parentJsonObject == null)
107 | {
108 | throw new InvalidOperationException($"Parent path not found in payload: '{parentJsonPath}'!");
109 | }
110 | var elementKey = JsonUtils.GetJsonElementKey(jsonPathOut);
111 | (parentJsonObject as JObject)?.Add(elementKey, new JObject());
112 | }
113 |
114 | internal static void AssertIsObject(JToken jToken, string jsonPath)
115 | {
116 | if (!(jToken is JObject))
117 | {
118 | throw new InvalidOperationException($"JSON object expected at path: '{jsonPath}'!");
119 | }
120 | }
121 |
122 | internal static string SanitizeJson(string json)
123 | {
124 | return json.Replace("\n", string.Empty)
125 | .Replace("\r", string.Empty)
126 | .Replace("\t", string.Empty)
127 | .Replace(Environment.NewLine, string.Empty);
128 | }
129 |
130 | internal static void AddOrReplaceJsonKey(JObject jsonObject, string key, JToken value)
131 | {
132 | jsonObject.Remove(key);
133 | jsonObject.Add(key, value);
134 | }
135 |
136 | internal static bool IsNullOrEmptyJson(JToken token)
137 | {
138 | if (token == null)
139 | {
140 | return true;
141 | }
142 | switch (token.Type)
143 | {
144 | case JTokenType.Array:
145 | case JTokenType.Object:
146 | return !token.HasValues;
147 |
148 | case JTokenType.String:
149 | return token.ToString() == String.Empty;
150 |
151 | case JTokenType.Null:
152 | return true;
153 | }
154 | return false;
155 | }
156 |
157 | internal static void AddDecryptedDataToPayload(JToken payloadObject, string decryptedValue, string jsonPathOut)
158 | {
159 | try
160 | {
161 | // Object?
162 | var decryptedValueObject = JObject.Parse(decryptedValue);
163 | var outJsonObject = payloadObject.SelectToken(jsonPathOut) as JObject;
164 | outJsonObject?.Merge(decryptedValueObject); // Merge the two objects
165 | }
166 | catch
167 | {
168 | try
169 | {
170 | // Array?
171 | var decryptedValueObject = JArray.Parse(decryptedValue);
172 | payloadObject.SelectToken(jsonPathOut).Replace(decryptedValueObject);
173 | }
174 | catch
175 | {
176 | // Primitive type
177 | payloadObject.SelectToken(jsonPathOut).Replace(AsPrimitiveValue(decryptedValue));
178 | }
179 | }
180 | }
181 |
182 | private static JToken AsPrimitiveValue(string value)
183 | {
184 | // Boolean?
185 | if ("true".Equals(value.ToLower()) || "false".Equals(value.ToLower()))
186 | {
187 | return bool.Parse(value);
188 | }
189 |
190 | // Numeric?
191 | try
192 | {
193 | return long.Parse(value);
194 | }
195 | catch
196 | {
197 | // Not a number, do nothing
198 | }
199 |
200 | // String
201 | return value;
202 | }
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Core/Utils/RsaKeyUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Linq;
4 | using System.Security.Cryptography;
5 | using System.Security.Cryptography.X509Certificates;
6 | using System.Text;
7 |
8 | namespace Mastercard.Developer.ClientEncryption.Core.Utils
9 | {
10 | internal static class RsaKeyUtils
11 | {
12 | private const string Pkcs1PemHeader = "-----BEGIN RSA PRIVATE KEY-----";
13 | private const string Pkcs1PemFooter = "-----END RSA PRIVATE KEY-----";
14 | private const string Pkcs8PemHeader = "-----BEGIN PRIVATE KEY-----";
15 | private const string Pkcs8PemFooter = "-----END PRIVATE KEY-----";
16 |
17 | internal static RSA ReadPrivateKeyFile(string keyFilePath)
18 | {
19 | if (keyFilePath == null) throw new ArgumentNullException(nameof(keyFilePath));
20 | var key = File.ReadAllBytes(keyFilePath);
21 | return ReadPrivateKey(key);
22 | }
23 |
24 | internal static RSA ReadPrivateKey(byte[] key)
25 | {
26 | var keyString = Encoding.UTF8.GetString(key);
27 | if (keyString.Contains(Pkcs1PemHeader))
28 | {
29 | // OpenSSL / PKCS#1 Base64 PEM encoded file
30 | keyString = keyString.Replace(Pkcs1PemHeader, string.Empty);
31 | keyString = keyString.Replace(Pkcs1PemFooter, string.Empty);
32 | keyString = keyString.Replace(Environment.NewLine, string.Empty);
33 | return ReadPkcs1Key(Convert.FromBase64String(keyString));
34 | }
35 |
36 | if (keyString.Contains(Pkcs8PemHeader))
37 | {
38 | // PKCS#8 Base64 PEM encoded file
39 | keyString = keyString.Replace(Pkcs8PemHeader, string.Empty);
40 | keyString = keyString.Replace(Pkcs8PemFooter, string.Empty);
41 | keyString = keyString.Replace(Environment.NewLine, string.Empty);
42 | return ReadPkcs8Key(Convert.FromBase64String(keyString));
43 | }
44 | return ReadPkcs8Key(key);
45 | }
46 |
47 | private static RSA ReadPkcs8Key(byte[] pkcs8Bytes)
48 | {
49 | try
50 | {
51 | var memoryStream = new MemoryStream(pkcs8Bytes);
52 | var keyLength = (int) memoryStream.Length;
53 | var reader = new BinaryReader(memoryStream);
54 |
55 | var bytes = reader.ReadUInt16();
56 | if (bytes == 0x8130)
57 | {
58 | reader.ReadByte();
59 | }
60 | else if (bytes == 0x8230)
61 | {
62 | reader.ReadByte();
63 | reader.ReadByte();
64 | }
65 | else
66 | {
67 | throw new ArgumentException("Failed to parse PKCS#8 key, 0x8130 or 0x8230 was expected!");
68 | }
69 |
70 | bytes = reader.ReadByte();
71 | if (bytes != 0x02)
72 | {
73 | throw new ArgumentException("Failed to parse PKCS#8 key, 0x02 was expected!");
74 | }
75 |
76 | bytes = reader.ReadUInt16();
77 | if (bytes != 0x0001)
78 | {
79 | throw new ArgumentException("Failed to parse PKCS#8 key, 0x0001 was expected!");
80 | }
81 |
82 | if (!reader.ReadBytes(15).SequenceEqual(new byte[] { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 }))
83 | {
84 | throw new ArgumentException("Failed to parse PKCS#8 key, RSA OID was expected!");
85 | }
86 |
87 | bytes = reader.ReadByte();
88 | if (bytes != 0x04)
89 | {
90 | throw new ArgumentException("Failed to parse PKCS#8 key, 0x04 was expected!");
91 | }
92 |
93 | bytes = reader.ReadByte();
94 | if (bytes == 0x81)
95 | {
96 | reader.ReadByte();
97 | }
98 | else if (bytes == 0x82)
99 | {
100 | reader.ReadByte();
101 | reader.ReadByte();
102 | }
103 |
104 | var pkcs1Bytes = reader.ReadBytes((int) (keyLength - memoryStream.Position));
105 | return ReadPkcs1Key(pkcs1Bytes);
106 | }
107 | catch (ArgumentException)
108 | {
109 | throw;
110 | }
111 | catch (Exception e)
112 | {
113 | throw new ArgumentException("Failed to parse PKCS#8 key!", e);
114 | }
115 | }
116 |
117 | private static RSA ReadPkcs1Key(byte[] pkcs1Bytes)
118 | {
119 | try
120 | {
121 | var memoryStream = new MemoryStream(pkcs1Bytes);
122 | var reader = new BinaryReader(memoryStream);
123 |
124 | var bytes = reader.ReadUInt16();
125 | if (bytes == 0x8130)
126 | {
127 | reader.ReadByte();
128 | }
129 | else if (bytes == 0x8230)
130 | {
131 | reader.ReadByte();
132 | reader.ReadByte();
133 | }
134 | else
135 | {
136 | throw new ArgumentException("Failed to parse PKCS#1 key, 0x8130 or 0x8230 was expected!");
137 | }
138 |
139 | var versionBytes = reader.ReadUInt16();
140 | if (versionBytes != 0x0102)
141 | {
142 | throw new ArgumentException("Failed to parse PKCS#1 key, 0x0102 was expected!");
143 | }
144 |
145 | bytes = reader.ReadByte();
146 | if (bytes != 0x00)
147 | {
148 | throw new ArgumentException("Failed to parse PKCS#1 key, 0x00 was expected!");
149 | }
150 |
151 | byte[] padded(byte[] array, int totalLength)
152 | {
153 | var currentLength = array.Length;
154 | if(currentLength >= totalLength) {
155 | return array;
156 | }
157 |
158 | var paddedArray = new byte[totalLength];
159 | Array.Copy(array, 0, paddedArray, totalLength - currentLength, currentLength);
160 |
161 | return paddedArray;
162 | }
163 |
164 | var modulus = reader.ReadBytes(GetIntegerSize(reader));
165 |
166 | var modulusLength = modulus.Length;
167 | var modulusHalfLength = (modulus.Length + 1) / 2; // half length rounded up
168 |
169 | var publicExponent = reader.ReadBytes(GetIntegerSize(reader));
170 | var privateExponent = padded(reader.ReadBytes(GetIntegerSize(reader)), modulusLength);
171 | var prime1 = padded(reader.ReadBytes(GetIntegerSize(reader)), modulusHalfLength);
172 | var prime2 = padded(reader.ReadBytes(GetIntegerSize(reader)), modulusHalfLength);
173 | var exponent1 = padded(reader.ReadBytes(GetIntegerSize(reader)), modulusHalfLength);
174 | var exponent2 = padded(reader.ReadBytes(GetIntegerSize(reader)), modulusHalfLength);
175 | var coefficient = padded(reader.ReadBytes(GetIntegerSize(reader)), modulusHalfLength);
176 |
177 | var rsa = CreateRsa();
178 | rsa.ImportParameters(new RSAParameters
179 | {
180 | Modulus = modulus,
181 | Exponent = publicExponent,
182 | D = privateExponent ,
183 | P = prime1,
184 | Q = prime2,
185 | DP = exponent1,
186 | DQ = exponent2,
187 | InverseQ = coefficient
188 | });
189 | return rsa;
190 | }
191 | catch (ArgumentException)
192 | {
193 | throw;
194 | }
195 | catch (Exception e)
196 | {
197 | throw new ArgumentException("Failed to parse PKCS#1 key!", e);
198 | }
199 | }
200 |
201 | private static RSA CreateRsa()
202 | {
203 | var rsa = RSA.Create();
204 | switch (rsa.GetType().Name)
205 | {
206 | case "RSACryptoServiceProvider":
207 | {
208 | // .NET Framework 4.6+: we need a RSACng key for OaepSHA256 and OaepSHA512
209 | var rsaCngType = Type.GetType("System.Security.Cryptography.RSACng, System.Security.Cryptography.Cng");
210 | if (null == rsaCngType)
211 | {
212 | throw new NotSupportedException("Failed to create a RSACng key! Consider adding System.Security.Cryptography.Cng to your project.");
213 | }
214 | return Activator.CreateInstance(rsaCngType) as RSA;
215 | }
216 | default:
217 | return rsa;
218 | }
219 | }
220 |
221 | ///
222 | /// Returns the DER-encoded form of a key (exact same binary as https://docs.oracle.com/javase/7/docs/api/java/security/Key.html#getEncoded())
223 | ///
224 | internal static byte[] GetEncoded(PublicKey publicRsaKey)
225 | {
226 | var rawKeyBytes = publicRsaKey.EncodedKeyValue.RawData;
227 | var rawKeyLength = rawKeyBytes.Length + 1;
228 | byte[] sequenceBytes;
229 | byte[] bitStringBytes;
230 | byte[] oidBytes = { 0x30, 0xD, 0x6, 0x9, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0xD, 0x1, 0x1, 0x1, 0x5, 0x0 }; // 1.2.840.113549.1.1.1, NULL
231 |
232 | if (rawKeyLength > 270)
233 | {
234 | // 2048, 4096 bits
235 | var totalLength = rawKeyLength + 19;
236 | sequenceBytes = new byte[] { 0x30, 0x82, (byte) ((totalLength >> 8) & 0xff), (byte) (totalLength & 0xff) };
237 | bitStringBytes = new byte[] { 0x3, 0x82, (byte) ((rawKeyLength >> 8) & 0xff), (byte) (rawKeyLength & 0xff) };
238 | }
239 | else if (rawKeyLength > 140)
240 | {
241 | // 1024 bits
242 | var totalLength = rawKeyLength + 18;
243 | sequenceBytes = new byte[] { 0x30, 0x81, (byte) (totalLength & 0xff) };
244 | bitStringBytes = new byte[] { 0x3, 0x81, (byte) (rawKeyLength & 0xff) };
245 | }
246 | else
247 | {
248 | // 512 bits
249 | var totalLength = rawKeyLength + 17;
250 | sequenceBytes = new byte[] { 0x30, (byte) (totalLength & 0xff) };
251 | bitStringBytes = new byte[] { 0x3, (byte) (rawKeyLength & 0xff) };
252 | }
253 |
254 | return sequenceBytes.Concat(oidBytes)
255 | .Concat(bitStringBytes)
256 | .Concat(new byte[] { 0x0 })
257 | .Concat(rawKeyBytes)
258 | .ToArray();
259 | }
260 |
261 | private static int GetIntegerSize(BinaryReader reader)
262 | {
263 | int size;
264 | var bytes = reader.ReadByte();
265 | if (bytes != 0x02)
266 | {
267 | return 0;
268 | }
269 |
270 | bytes = reader.ReadByte();
271 | if (bytes == 0x81)
272 | {
273 | size = reader.ReadByte();
274 | }
275 | else if (bytes == 0x82)
276 | {
277 | var high = reader.ReadByte();
278 | var low = reader.ReadByte();
279 | size = BitConverter.ToInt32(new byte[] { low, high, 0x00, 0x00 }, 0);
280 | }
281 | else
282 | {
283 | size = bytes;
284 | }
285 |
286 | while (reader.ReadByte() == 0x00)
287 | {
288 | size -= 1;
289 | }
290 |
291 | reader.BaseStream.Seek(-1, SeekOrigin.Current);
292 | return size;
293 | }
294 | }
295 | }
296 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.RestSharp/Interceptors/RestSharpFieldLevelEncryptionInterceptor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Reflection;
4 | using Mastercard.Developer.ClientEncryption.Core.Encryption;
5 | using RestSharp.Portable;
6 |
7 | namespace Mastercard.Developer.ClientEncryption.RestSharp.Interceptors
8 | {
9 | ///
10 | /// A class for encrypting RestSharp requests and decrypting RestSharp responses.
11 | ///
12 | public class RestSharpFieldLevelEncryptionInterceptor
13 | {
14 | private readonly FieldLevelEncryptionConfig _config;
15 |
16 | ///
17 | /// Constructor.
18 | ///
19 | public RestSharpFieldLevelEncryptionInterceptor(FieldLevelEncryptionConfig config)
20 | {
21 | _config = config;
22 | }
23 |
24 | ///
25 | /// Encrypt RestSharp request payloads.
26 | ///
27 | /// A RestSharp request object
28 | public void InterceptRequest(IRestRequest request)
29 | {
30 | if (request == null) throw new ArgumentNullException(nameof(request));
31 |
32 | try
33 | {
34 | // Check request actually has a payload
35 | var bodyParam = request.Parameters.FirstOrDefault(param => param.Type == ParameterType.RequestBody);
36 | if (bodyParam == null)
37 | {
38 | // Nothing to encrypt
39 | return;
40 | }
41 | var payload = bodyParam.Value.ToString();
42 | if (string.IsNullOrEmpty(payload))
43 | {
44 | // Nothing to encrypt
45 | return;
46 | }
47 |
48 | // Encrypt fields & update headers
49 | string encryptedPayload;
50 | if (_config.UseHttpHeaders())
51 | {
52 | // Generate encryption params and add them as HTTP headers
53 | var parameters = FieldLevelEncryptionParams.Generate(_config);
54 | UpdateRequestHeader(request, _config.IvHeaderName, parameters.IvValue);
55 | UpdateRequestHeader(request, _config.EncryptedKeyHeaderName, parameters.EncryptedKeyValue);
56 | UpdateRequestHeader(request, _config.EncryptionCertificateFingerprintHeaderName, _config.EncryptionCertificateFingerprint);
57 | UpdateRequestHeader(request, _config.EncryptionKeyFingerprintHeaderName, _config.EncryptionKeyFingerprint);
58 | UpdateRequestHeader(request, _config.OaepPaddingDigestAlgorithmHeaderName, parameters.OaepPaddingDigestAlgorithmValue);
59 | encryptedPayload = FieldLevelEncryption.EncryptPayload(payload, _config, parameters);
60 | }
61 | else
62 | {
63 | // Encryption params will be stored in the payload
64 | encryptedPayload = FieldLevelEncryption.EncryptPayload(payload, _config);
65 | }
66 |
67 | // Update body and content length
68 | bodyParam.Value = encryptedPayload;
69 | UpdateRequestHeader(request, "Content-Length", encryptedPayload.Length);
70 | }
71 | catch (EncryptionException)
72 | {
73 | throw;
74 | }
75 | catch (Exception e)
76 | {
77 | throw new EncryptionException("Failed to intercept and encrypt request!", e);
78 | }
79 | }
80 |
81 | ///
82 | /// Decrypt RestSharp response payloads.
83 | ///
84 | /// A RestSharp response object
85 | public void InterceptResponse(IRestResponse response)
86 | {
87 | if (response == null) throw new ArgumentNullException(nameof(response));
88 |
89 | try
90 | {
91 | // Read response payload
92 | var encryptedPayload = response.Content;
93 | if (string.IsNullOrEmpty(encryptedPayload))
94 | {
95 | // Nothing to decrypt
96 | return;
97 | }
98 |
99 | // Decrypt fields & update headers
100 | string decryptedPayload;
101 | if (_config.UseHttpHeaders())
102 | {
103 | // Read encryption params from HTTP headers and delete headers
104 | var ivValue = ReadAndRemoveHeader(response, _config.IvHeaderName);
105 | var encryptedKeyValue = ReadAndRemoveHeader(response, _config.EncryptedKeyHeaderName);
106 | var oaepPaddingDigestAlgorithmValue = ReadAndRemoveHeader(response, _config.OaepPaddingDigestAlgorithmHeaderName);
107 | ReadAndRemoveHeader(response, _config.EncryptionCertificateFingerprintHeaderName);
108 | ReadAndRemoveHeader(response, _config.EncryptionKeyFingerprintHeaderName);
109 | var parameters = new FieldLevelEncryptionParams(_config, ivValue, encryptedKeyValue, oaepPaddingDigestAlgorithmValue);
110 | decryptedPayload = FieldLevelEncryption.DecryptPayload(encryptedPayload, _config, parameters);
111 | }
112 | else
113 | {
114 | // Encryption params are stored in the payload
115 | decryptedPayload = FieldLevelEncryption.DecryptPayload(encryptedPayload, _config);
116 | }
117 |
118 | // Update body and content length
119 | var contentTypeInfo = response.GetType().GetTypeInfo().GetDeclaredField("_content");
120 | contentTypeInfo.SetValue(response, new Lazy(() => decryptedPayload));
121 | }
122 | catch (EncryptionException)
123 | {
124 | throw;
125 | }
126 | catch (Exception e)
127 | {
128 | throw new EncryptionException("Failed to intercept and decrypt response!", e);
129 | }
130 | }
131 |
132 | private static void UpdateRequestHeader(IRestRequest request, string name, object value)
133 | {
134 | if (string.IsNullOrEmpty(name))
135 | {
136 | // Do nothing
137 | return;
138 | }
139 |
140 | request.AddOrUpdateHeader(name, value);
141 | }
142 |
143 | private static string ReadAndRemoveHeader(IRestResponse response, string name)
144 | {
145 | if (string.IsNullOrEmpty(name) || !response.Headers.Contains(name))
146 | {
147 | // Do nothing
148 | return null;
149 | }
150 |
151 | var value = response.Headers.GetValue(name);
152 | response.Headers.Remove(name);
153 | return value;
154 | }
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.RestSharp/Mastercard.Developer.ClientEncryption.RestSharp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | true
6 | 1.9.3
7 | Mastercard.Developer.ClientEncryption.RestSharp
8 | Mastercard
9 | Mastercard
10 | LICENSE
11 | https://github.com/Mastercard/client-encryption-csharp
12 | See: https://github.com/Mastercard/client-encryption-csharp/releases
13 | https://github.com/Mastercard/client-encryption-csharp
14 | RestSharp Portable extension for Mastercard API compliant payload encryption/decryption
15 |
16 | true
17 | ../Identity.snk
18 | 1.0.0.0
19 | 1.9.3
20 | Mastercard.Developer.ClientEncryption.RestSharp.xml
21 | true
22 | snupkg
23 | icon.png
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | True
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.RestSharpV2/Interceptors/RestSharpEncryptionInterceptor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text.Json;
4 | using Mastercard.Developer.ClientEncryption.Core.Encryption;
5 | using Header = RestSharp.HeaderParameter;
6 | using RestSharp;
7 | using System.Collections.Generic;
8 |
9 |
10 | namespace Mastercard.Developer.ClientEncryption.RestSharpV2.Interceptors
11 | {
12 | ///
13 | /// A base class for encrypting RestSharp requests and decrypting RestSharp responses.
14 | ///
15 | public abstract class RestSharpEncryptionInterceptor
16 | {
17 | ///
18 | ///
19 | ///
20 | ///
21 | ///
22 | public static RestSharpEncryptionInterceptor From(EncryptionConfig config)
23 | {
24 | if (config.Scheme.Equals(EncryptionConfig.EncryptionScheme.Jwe))
25 | {
26 | return new RestSharpJweEncryptionInterceptor((JweConfig) config);
27 | }
28 | return new RestSharpFieldLevelEncryptionInterceptor((FieldLevelEncryptionConfig)config);
29 | }
30 |
31 | ///
32 | /// Encrypt RestSharp request payloads.
33 | ///
34 | /// A RestSharp request object
35 | public void InterceptRequest(RestRequest request)
36 | {
37 | if (request == null) throw new ArgumentNullException(nameof(request));
38 |
39 | try
40 | {
41 | // We will have to intercept the response later
42 | request.OnBeforeDeserialization = InterceptResponse;
43 |
44 | // Check request actually has a payload
45 | var bodyParam = request.Parameters.FirstOrDefault(param => param.Type == ParameterType.RequestBody);
46 | if (bodyParam?.Value == null)
47 | {
48 | // Nothing to encrypt
49 | return;
50 | }
51 |
52 | var payload = bodyParam.Value;
53 | if (!(payload is string))
54 | {
55 | payload = JsonSerializer.Serialize(payload);
56 | }
57 |
58 | // Encrypt fields & update headers
59 | string encryptedPayload = EncryptPayload(request, payload.ToString());
60 |
61 | // Update body and content length
62 | request.RemoveParameter(bodyParam);
63 | request.AddBody(encryptedPayload);
64 | UpdateRequestHeader(request, "Content-Length", encryptedPayload.Length);
65 | }
66 | catch (EncryptionException)
67 | {
68 | throw;
69 | }
70 | catch (Exception e)
71 | {
72 | throw new EncryptionException("Failed to intercept and encrypt request!", e);
73 | }
74 | }
75 |
76 | ///
77 | /// Decrypt RestSharp response payloads.
78 | ///
79 | /// A RestSharp response object
80 | public void InterceptResponse(RestResponse response)
81 | {
82 | if (response == null) throw new ArgumentNullException(nameof(response));
83 |
84 | try
85 | {
86 | // Read response payload
87 | var encryptedPayload = response.Content;
88 | if (string.IsNullOrEmpty(encryptedPayload))
89 | {
90 | // Nothing to decrypt
91 | return;
92 | }
93 |
94 | // Decrypt fields & return
95 | string decryptedPayload = DecryptPayload(response, encryptedPayload);
96 | response.Content = decryptedPayload;
97 | UpdateResponseHeader(response, "Content-Length", decryptedPayload.Length);
98 | }
99 | catch (EncryptionException)
100 | {
101 | throw;
102 | }
103 | catch (Exception e)
104 | {
105 | throw new EncryptionException("Failed to intercept and decrypt response!", e);
106 | }
107 | }
108 |
109 | ///
110 | /// Encrypt a RestSharp request payload.
111 | ///
112 | /// A RestSharp request object
113 | /// The payload to be encrypted
114 | /// The encrypted payload
115 | internal abstract string EncryptPayload(RestRequest request, string payload);
116 |
117 | ///
118 | /// Decrypt a RestSharp response payload
119 | ///
120 | /// A RestSharp response object
121 | /// The encrypted payload to be decrypted
122 | /// The decrypted payload
123 | internal abstract string DecryptPayload(RestResponse response, string encryptedPayload);
124 |
125 | internal static void UpdateResponseHeader(RestResponse response, string name, object value)
126 | {
127 | if (string.IsNullOrEmpty(name))
128 | {
129 | // Do nothing
130 | return;
131 | }
132 |
133 | // Scan
134 | List updatedHeaders = response.Headers.ToList();
135 | foreach (Header p in response.Headers)
136 | {
137 | if (p.Name.Equals(name))
138 | {
139 | updatedHeaders.Remove(p);
140 | updatedHeaders.Add(new Header(name, value.ToString()));
141 | response.Headers = updatedHeaders;
142 | return;
143 | }
144 | }
145 |
146 | // If we get here, there is no such header, so add one
147 | updatedHeaders.Add(new Header(name, value.ToString()));
148 | response.Headers = updatedHeaders;
149 | }
150 |
151 | internal static void UpdateRequestHeader(RestRequest request, string name, object value)
152 | {
153 | if (string.IsNullOrEmpty(name))
154 | {
155 | // Do nothing
156 | return;
157 | }
158 |
159 | request.AddHeader(name, value.ToString());
160 | }
161 |
162 | internal static string ReadAndRemoveHeader(RestResponse response, string name)
163 | {
164 | var header = response.Headers.ToList().Find(h => h.Name == name);
165 | if (string.IsNullOrEmpty(name) || header == null)
166 | {
167 | // Do nothing
168 | return null;
169 | }
170 |
171 | var updatedHeaders = response.Headers.ToList().FindAll(h => h.Name != name);
172 | response.Headers = updatedHeaders;
173 | return header.Value?.ToString() ?? string.Empty;
174 | }
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.RestSharpV2/Interceptors/RestSharpFieldLevelEncryptionInterceptor.cs:
--------------------------------------------------------------------------------
1 | using RestSharp;
2 | using Mastercard.Developer.ClientEncryption.Core.Encryption;
3 |
4 | namespace Mastercard.Developer.ClientEncryption.RestSharpV2.Interceptors
5 | {
6 | ///
7 | /// A class for encrypting RestSharp requests and decrypting RestSharp responses,
8 | /// using Field Level Encryption
9 | ///
10 | public class RestSharpFieldLevelEncryptionInterceptor : RestSharpEncryptionInterceptor
11 | {
12 | private readonly FieldLevelEncryptionConfig _config;
13 |
14 | ///
15 | /// Constructor.
16 | ///
17 | public RestSharpFieldLevelEncryptionInterceptor(FieldLevelEncryptionConfig config)
18 | {
19 | _config = config;
20 | }
21 |
22 | ///
23 | /// Encrypt a RestSharp request payload.
24 | ///
25 | /// A RestSharp request object
26 | /// The payload to be encrypted
27 | /// The encrypted payload
28 | internal override string EncryptPayload(RestRequest request, string payload)
29 | {
30 | // Encrypt fields & update headers
31 | string encryptedPayload;
32 | if (_config.UseHttpHeaders())
33 | {
34 | // Generate encryption params and add them as HTTP headers
35 | var parameters = FieldLevelEncryptionParams.Generate(_config);
36 | UpdateRequestHeader(request, _config.IvHeaderName, parameters.IvValue);
37 | UpdateRequestHeader(request, _config.EncryptedKeyHeaderName, parameters.EncryptedKeyValue);
38 | UpdateRequestHeader(request, _config.EncryptionCertificateFingerprintHeaderName, _config.EncryptionCertificateFingerprint);
39 | UpdateRequestHeader(request, _config.EncryptionKeyFingerprintHeaderName, _config.EncryptionKeyFingerprint);
40 | UpdateRequestHeader(request, _config.OaepPaddingDigestAlgorithmHeaderName, parameters.OaepPaddingDigestAlgorithmValue);
41 | encryptedPayload = FieldLevelEncryption.EncryptPayload(payload.ToString(), _config, parameters);
42 | }
43 | else
44 | {
45 | // Encryption params will be stored in the payload
46 | encryptedPayload = FieldLevelEncryption.EncryptPayload(payload.ToString(), _config);
47 | }
48 | return encryptedPayload;
49 | }
50 |
51 | ///
52 | /// Decrypt a RestSharp response payload
53 | ///
54 | /// A RestSharp response object
55 | /// The encrypted payload to be decrypted
56 | /// The decrypted payload
57 | internal override string DecryptPayload(RestResponse response, string encryptedPayload)
58 | {
59 | // Decrypt fields & update headers
60 | string decryptedPayload;
61 | if (_config.UseHttpHeaders())
62 | {
63 | // Read encryption params from HTTP headers and delete headers
64 | var ivValue = ReadAndRemoveHeader(response, _config.IvHeaderName);
65 | var encryptedKeyValue = ReadAndRemoveHeader(response, _config.EncryptedKeyHeaderName);
66 | var oaepPaddingDigestAlgorithmValue = ReadAndRemoveHeader(response, _config.OaepPaddingDigestAlgorithmHeaderName);
67 | ReadAndRemoveHeader(response, _config.EncryptionCertificateFingerprintHeaderName);
68 | ReadAndRemoveHeader(response, _config.EncryptionKeyFingerprintHeaderName);
69 | var parameters = new FieldLevelEncryptionParams(_config, ivValue, encryptedKeyValue, oaepPaddingDigestAlgorithmValue);
70 | decryptedPayload = FieldLevelEncryption.DecryptPayload(encryptedPayload, _config, parameters);
71 | }
72 | else
73 | {
74 | // Encryption params are stored in the payload
75 | decryptedPayload = FieldLevelEncryption.DecryptPayload(encryptedPayload, _config);
76 | }
77 | return decryptedPayload;
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.RestSharpV2/Interceptors/RestSharpJweEncryptionInterceptor.cs:
--------------------------------------------------------------------------------
1 | using RestSharp;
2 | using Mastercard.Developer.ClientEncryption.Core.Encryption;
3 | using Mastercard.Developer.ClientEncryption.Core.Encryption.JWE;
4 |
5 | namespace Mastercard.Developer.ClientEncryption.RestSharpV2.Interceptors
6 | {
7 | ///
8 | /// A class for encrypting RestSharp requests and decrypting RestSharp responses,
9 | /// using JSON Web Encryption.
10 | ///
11 | internal class RestSharpJweEncryptionInterceptor : RestSharpEncryptionInterceptor
12 | {
13 | private readonly JweConfig _config;
14 |
15 | ///
16 | /// Constructor.
17 | ///
18 | public RestSharpJweEncryptionInterceptor(JweConfig config)
19 | {
20 | _config = config;
21 | }
22 |
23 | ///
24 | /// Encrypt a RestSharp request payload.
25 | ///
26 | /// A RestSharp request object
27 | /// The payload to be encrypted
28 | /// The encrypted payload
29 | internal override string EncryptPayload(RestRequest request, string payload)
30 | {
31 | return JweEncryption.EncryptPayload(payload, _config);
32 | }
33 |
34 | ///
35 | /// Decrypt a RestSharp response payload
36 | ///
37 | /// A RestSharp response object
38 | /// The encrypted payload to be decrypted
39 | /// The decrypted payload
40 | internal override string DecryptPayload(RestResponse response, string encryptedPayload)
41 | {
42 | return JweEncryption.DecryptPayload(encryptedPayload, _config);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.RestSharpV2/Mastercard.Developer.ClientEncryption.RestSharpV2.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard2.1
4 | true
5 | 1.9.3
6 | Mastercard.Developer.ClientEncryption.RestSharpV2
7 | Mastercard
8 | Mastercard
9 | LICENSE
10 | https://github.com/Mastercard/client-encryption-csharp
11 | See: https://github.com/Mastercard/client-encryption-csharp/releases
12 | https://github.com/Mastercard/client-encryption-csharp
13 | RestSharp extension for Mastercard API compliant payload encryption/decryption
14 |
15 | true
16 | ../Identity.snk
17 | 1.0.0.0
18 | 1.9.3
19 | Mastercard.Developer.ClientEncryption.RestSharpV2.xml
20 | true
21 | snupkg
22 | icon.png
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | True
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | <_Parameter1>Mastercard.Developer.ClientEncryption.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b50e085c4583209974a6a902505c534b21b205b9e627c583beea690b541d67fdfe8dc53e50c6a0653f0e3e7828d75432a50df4c4b5348ca4e662e42af603cc97636fb2393ef995babf19bc51644c30296a3edf0afd0182cfc21d0c836da5af922e3631a52a2dc5ed2edc8c568f41ff3d41c82fbe27e6bf4fe4df3e50568b65c8
46 |
47 |
48 |
49 |
50 |
51 | <_Parameter1>Mastercard.Developer.ClientEncryption.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b50e085c4583209974a6a902505c534b21b205b9e627c583beea690b541d67fdfe8dc53e50c6a0653f0e3e7828d75432a50df4c4b5348ca4e662e42af603cc97636fb2393ef995babf19bc51644c30296a3edf0afd0182cfc21d0c836da5af922e3631a52a2dc5ed2edc8c568f41ff3d41c82fbe27e6bf4fe4df3e50568b65c8
52 |
53 |
54 |
55 |
56 |
57 |
58 | <_Parameter1>Mastercard.Developer.ClientEncryption.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b50e085c4583209974a6a902505c534b21b205b9e627c583beea690b541d67fdfe8dc53e50c6a0653f0e3e7828d75432a50df4c4b5348ca4e662e42af603cc97636fb2393ef995babf19bc51644c30296a3edf0afd0182cfc21d0c836da5af922e3631a52a2dc5ed2edc8c568f41ff3d41c82fbe27e6bf4fe4df3e50568b65c8
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Mastercard.Developer.ClientEncryption.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8
4 | Debug
5 | AnyCPU
6 | {DE07F478-E087-4FAA-80E2-220671C70418}
7 | Tests
8 | Properties
9 | Mastercard.Developer.ClientEncryption.Tests
10 | Mastercard.Developer.ClientEncryption.Tests
11 | 512
12 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
13 | False
14 | UnitTest
15 |
16 |
17 |
18 |
19 |
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 |
28 |
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 | true
38 |
39 |
40 | ../Identity.snk
41 |
42 |
43 |
44 | _Resources\Certificates\test_certificate-1024.pem
45 | Always
46 |
47 |
48 | _Resources\Certificates\test_certificate-2048.der
49 | Always
50 |
51 |
52 | _Resources\Certificates\test_certificate-2048.pem
53 | Always
54 |
55 |
56 | _Resources\Certificates\test_certificate-4096.pem
57 | Always
58 |
59 |
60 | _Resources\Certificates\test_certificate-512.pem
61 | Always
62 |
63 |
64 | _Resources\Keys\Pkcs1\test_key_pkcs1-1024.pem
65 | Always
66 |
67 |
68 | _Resources\Keys\Pkcs1\test_key_pkcs1-2048.pem
69 | Always
70 |
71 |
72 | _Resources\Keys\Pkcs1\test_key_pkcs1-2048_uneven_length.pem
73 | Always
74 |
75 |
76 | _Resources\Keys\Pkcs1\test_key_pkcs1-4096.pem
77 | Always
78 |
79 |
80 | _Resources\Keys\Pkcs1\test_key_pkcs1-512.pem
81 | Always
82 |
83 |
84 | _Resources\Keys\Pkcs12\test_key.p12
85 | Always
86 |
87 |
88 | _Resources\Keys\Pkcs8\test_invalid_key.der
89 | Always
90 |
91 |
92 | _Resources\Keys\Pkcs8\test_key_pkcs8-1024.der
93 | Always
94 |
95 |
96 | _Resources\Keys\Pkcs8\test_key_pkcs8-1024.pem
97 | Always
98 |
99 |
100 | _Resources\Keys\Pkcs8\test_key_pkcs8-2048.der
101 | Always
102 |
103 |
104 | _Resources\Keys\Pkcs8\test_key_pkcs8-2048.pem
105 | Always
106 |
107 |
108 | _Resources\Keys\Pkcs8\test_key_pkcs8-4096.der
109 | Always
110 |
111 |
112 | _Resources\Keys\Pkcs8\test_key_pkcs8-4096.pem
113 | Always
114 |
115 |
116 | _Resources\Keys\Pkcs8\test_key_pkcs8-512.der
117 | Always
118 |
119 |
120 | _Resources\Keys\Pkcs8\test_key_pkcs8-512.pem
121 | Always
122 |
123 |
124 |
125 |
126 | {8ffa4f79-9d2c-4807-bad7-8e2f0a15e099}
127 | Mastercard.Developer.ClientEncryption.Core
128 |
129 |
130 | {bc6f2c72-16a3-44cb-ad68-3acd8a465640}
131 | Mastercard.Developer.ClientEncryption.RestSharpV2
132 |
133 |
134 | {4abdad88-8dc4-4463-91ec-74a711d6acfb}
135 | Mastercard.Developer.ClientEncryption.RestSharp
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Encryption/AES/AesEncryptionTest.cs:
--------------------------------------------------------------------------------
1 | using Mastercard.Developer.ClientEncryption.Core.Encryption.AES;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 |
4 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.AES
5 | {
6 | [TestClass]
7 | public class AesEncryptionTest
8 | {
9 | [TestMethod]
10 | public void TestGenerateIV()
11 | {
12 | // WHEN
13 | byte[] iv = AesEncryption.GenerateIV();
14 |
15 | // THEN
16 | Assert.AreEqual(12, iv.Length);
17 | }
18 |
19 | [TestMethod]
20 | public void TestGenerateCek()
21 | {
22 | // WHEN
23 | byte[] cek = AesEncryption.GenerateCek(256);
24 |
25 | // THEN
26 | Assert.AreEqual(32, cek.Length);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Encryption/EncryptionExceptionTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using Mastercard.Developer.ClientEncryption.Core.Encryption;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 |
6 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Encryption
7 | {
8 | [TestClass]
9 | public class EncryptionExceptionTest
10 | {
11 | [TestMethod]
12 | public void TestConstructor1()
13 | {
14 | try
15 | {
16 | throw new EncryptionException("Something happened!", new IOException());
17 | }
18 | catch (Exception e)
19 | {
20 | Assert.AreEqual("Something happened!", e.Message);
21 | Assert.IsTrue(e.InnerException is IOException);
22 | }
23 | }
24 |
25 | [TestMethod]
26 | public void TestConstructor2()
27 | {
28 | try
29 | {
30 | throw new EncryptionException("Something happened!");
31 | }
32 | catch (Exception e)
33 | {
34 | Assert.AreEqual("Something happened!", e.Message);
35 | Assert.IsNull(e.InnerException);
36 | }
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Encryption/FieldLevelEncryptionParamsTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Mastercard.Developer.ClientEncryption.Core.Encryption;
3 | using Mastercard.Developer.ClientEncryption.Tests.NetCore.Test;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 |
6 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Encryption
7 | {
8 | [TestClass]
9 | public class FieldLevelEncryptionParamsTest
10 | {
11 | [TestMethod]
12 | public void TestGenerate_Nominal()
13 | {
14 | // GIVEN
15 | var config = TestUtils.GetTestFieldLevelEncryptionConfigBuilder().Build();
16 |
17 | // WHEN
18 | var parameters = FieldLevelEncryptionParams.Generate(config);
19 |
20 | // THEN
21 | Assert.IsNotNull(parameters.IvValue);
22 | Assert.IsNotNull(parameters.GetIvBytes());
23 | Assert.IsNotNull(parameters.EncryptedKeyValue);
24 | Assert.IsNotNull(parameters.GetSecretKeyBytes());
25 | Assert.AreEqual("SHA256", parameters.OaepPaddingDigestAlgorithmValue);
26 | }
27 |
28 | [TestMethod]
29 | [ExpectedException(typeof(EncryptionException))]
30 | public void TestGetIvBytes_ShouldThrowEncryptionException_WhenFailsToDecodeIV()
31 | {
32 | try
33 | {
34 | // GIVEN
35 | var config = TestUtils.GetTestFieldLevelEncryptionConfigBuilder().Build();
36 | var parameters = new FieldLevelEncryptionParams(config, "INVALID VALUE", null);
37 |
38 | // WHEN
39 | var ivBytes = parameters.GetIvBytes();
40 | Assert.Fail($"Unexpected {ivBytes}");
41 | }
42 | catch (Exception e)
43 | {
44 | // THEN
45 | Assert.AreEqual("Failed to decode the provided IV value!", e.Message);
46 | throw;
47 | }
48 | }
49 |
50 | [TestMethod]
51 | [ExpectedException(typeof(EncryptionException))]
52 | public void TestGetSecretKeyBytes_ShouldThrowEncryptionException_WhenFailsToReadEncryptedKey()
53 | {
54 | try
55 | {
56 | // GIVEN
57 | var config = TestUtils.GetTestFieldLevelEncryptionConfigBuilder().Build();
58 | var parameters = new FieldLevelEncryptionParams(config, null, "INVALID VALUE");
59 |
60 | // WHEN
61 | var secretKeyBytes = parameters.GetSecretKeyBytes();
62 | Assert.Fail($"Unexpected {secretKeyBytes}");
63 | }
64 | catch (Exception e)
65 | {
66 | // THEN
67 | Assert.AreEqual("Failed to decode and unwrap the provided secret key value!", e.Message);
68 | throw;
69 | }
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Encryption/JWE/CbcJweObjectTest.cs:
--------------------------------------------------------------------------------
1 | using Mastercard.Developer.ClientEncryption.Core.Encryption.JWE;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using Mastercard.Developer.ClientEncryption.Tests.NetCore.Test;
4 |
5 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Encryption.JWE
6 | {
7 | [TestClass]
8 | public class CbcJweObjectTest
9 | {
10 | [TestMethod]
11 | public void TestDecrypt_ShouldReturnDecryptedPayload_WhenPayloadIsCbcEncrypted()
12 | {
13 | // GIVEN
14 | JweObject jweObject = TestUtils.GetTestCbcJweObject();
15 |
16 | // WHEN
17 | string decryptedPayload = jweObject.Decrypt(TestUtils.GetTestJweConfigBuilder().Build());
18 |
19 | // THEN
20 | Assert.AreEqual("bar", decryptedPayload);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Encryption/JWE/GcmJweObjectTest.cs:
--------------------------------------------------------------------------------
1 | using Mastercard.Developer.ClientEncryption.Core.Encryption;
2 | using Mastercard.Developer.ClientEncryption.Core.Encryption.JWE;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 | using Mastercard.Developer.ClientEncryption.Tests.NetCore.Test;
5 |
6 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Encryption.JWE
7 | {
8 | [TestClass]
9 | public class GcmJweObjectTest
10 | {
11 | [TestMethod]
12 | #if !NETCOREAPP3_1 && !NET5_0_OR_GREATER
13 | [ExpectedException(typeof(EncryptionException), "AES/GCM/NoPadding is unsupported on .NET Standard < 2.1")]
14 | #endif
15 | public void TestDecrypt_ShouldReturnDecryptedPayload_WhenPayloadIs256GcmEncrypted()
16 | {
17 | // GIVEN
18 | JweObject jweObject = TestUtils.GetTest256GcmJweObject();
19 |
20 | // WHEN
21 | string decryptedPayload = jweObject.Decrypt(TestUtils.GetTestJweConfigBuilder().Build());
22 |
23 | // THEN
24 | Assert.AreEqual("{\"foo\":\"bar\"}", decryptedPayload);
25 | }
26 |
27 | public void TestDecrypt_ShouldReturnDecryptedPayload_WhenPayloadIs192GcmEncrypted()
28 | {
29 | // GIVEN
30 | JweObject jweObject = TestUtils.GetTest192GcmJweObject();
31 |
32 | // WHEN
33 | string decryptedPayload = jweObject.Decrypt(TestUtils.GetTestJweConfigBuilder().Build());
34 |
35 | // THEN
36 | Assert.AreEqual("{\"foo\":\"bar\"}", decryptedPayload);
37 | }
38 |
39 | public void TestDecrypt_ShouldReturnDecryptedPayload_WhenPayloadIs128GcmEncrypted()
40 | {
41 | // GIVEN
42 | JweObject jweObject = TestUtils.GetTest128GcmJweObject();
43 |
44 | // WHEN
45 | string decryptedPayload = jweObject.Decrypt(TestUtils.GetTestJweConfigBuilder().Build());
46 |
47 | // THEN
48 | Assert.AreEqual("{\"foo\":\"bar\"}", decryptedPayload);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Encryption/JWE/JweEncryptionTest.cs:
--------------------------------------------------------------------------------
1 | using Mastercard.Developer.ClientEncryption.Core.Encryption;
2 | using Mastercard.Developer.ClientEncryption.Core.Encryption.JWE;
3 | using Mastercard.Developer.ClientEncryption.Tests.NetCore.Test;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 | using Newtonsoft.Json.Linq;
6 |
7 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Encryption.JWE
8 | {
9 | [TestClass]
10 | public class JweEncryptionTest
11 | {
12 | [TestMethod]
13 | #if !NETCOREAPP3_1 && !NET5_0_OR_GREATER
14 | [ExpectedException(typeof(EncryptionException), "AES/GCM/NoPadding is unsupported on .NET Standard < 2.1")]
15 | #endif
16 | public void TestEncryptPayload_ShouldEncryptRootArrays()
17 | {
18 | // GIVEN
19 | const string payload = @"[
20 | {},
21 | {}
22 | ]";
23 | var config = TestUtils.GetTestJweConfigBuilder()
24 | .WithEncryptionPath("$", "$")
25 | .WithDecryptionPath("$.encryptedData", "$")
26 | .Build();
27 |
28 | // WHEN
29 | var encryptedPayload = JweEncryption.EncryptPayload(payload, config);
30 |
31 | // THEN
32 | var encryptedPayloadObject = JObject.Parse(encryptedPayload);
33 | Assert.IsNotNull(encryptedPayloadObject);
34 | TestUtils.AssertDecryptedJweEquals("[{},{}]", encryptedPayload, config);
35 | }
36 |
37 | [TestMethod]
38 | #if !NETCOREAPP3_1 && !NET5_0_OR_GREATER
39 | [ExpectedException(typeof(EncryptionException), "AES/GCM/NoPadding is unsupported on .NET Standard < 2.1")]
40 | #endif
41 | public void TestEncryptPayload_ShouldCreateEncryptedValue_WhenOutPathParentDoesNotExistInPayload()
42 | {
43 | // GIVEN
44 | const string payload = @"{""data"": {}}";
45 | var config = TestUtils.GetTestJweConfigBuilder()
46 | .WithEncryptionPath("$", "$.encryptedDataParent")
47 | .Build();
48 |
49 | // WHEN
50 | var encryptedPayload = JweEncryption.EncryptPayload(payload, config);
51 |
52 | // THEN
53 | var encryptedPayloadObject = JObject.Parse(encryptedPayload);
54 | Assert.IsNull(encryptedPayloadObject["data"]);
55 | Assert.IsNotNull(encryptedPayloadObject["encryptedDataParent"]);
56 | Assert.IsNotNull(encryptedPayloadObject["encryptedDataParent"]["encryptedData"]);
57 | }
58 |
59 | [TestMethod]
60 | #if !NETCOREAPP3_1 && !NET5_0_OR_GREATER
61 | [ExpectedException(typeof(EncryptionException), "AES/GCM/NoPadding is unsupported on .NET Standard < 2.1")]
62 | #endif
63 | public void TestDecryptPayload_ShouldDecryptRootArrays()
64 | {
65 | // GIVEN
66 | const string encryptedPayload = @"{
67 | ""encryptedData"": ""ew0KICAia2lkIjogIjc2MWIwMDNjMWVhZGUzYTU0OTBlNTAwMGQzNzg4N2JhYTVlNmVjMGUyMjZjMDc3MDZlNTk5NDUxZmMwMzJhNzkiLA0KICAiY3R5IjogImFwcGxpY2F0aW9uL2pzb24iLA0KICAiZW5jIjogIkEyNTZHQ00iLA0KICAiYWxnIjogIlJTQS1PQUVQLTI1NiINCn0.ycN7kc7qfknufAz96VcgA6L-oTeY38S9oD6iFNTyw72sA4r82dyJeHL14z_Zd7V2NoOh1XEro6zPaG78jdRpq62F0Ajyqbupem2a-E5LtKRXXH3CucVlVtMoLfbt2Ao8u_oFLwytMjV_lVO7YH5UsOXjfzL2Bw7KNRdz4wQEQ2yXQpf8ajLPp98RBSLMxStv7vhIDuZxVpCRBx_KqKuB8Y0kF_CxRUQZVlgumCv97rGG_nsW01XfnfekMuAJntnG9Bi9NmrX8bwkLV3YZf7iO_kzR_D-kuyFtaXqUvXBLpUkchESgLX8IXYMLXxevk04VNl2WiPH5gs_VVzSCfXbHw.8l1G7U85BKOQh5Tu.Omcqk8Sung.TNzFb9bt57TioF-zpEOZBA""
68 | }";
69 | var config = TestUtils.GetTestJweConfigBuilder()
70 | .WithDecryptionPath("$.encryptedData", "$")
71 | .Build();
72 |
73 | // WHEN
74 | var payload = JweEncryption.DecryptPayload(encryptedPayload, config);
75 |
76 | // THEN
77 | TestUtils.AssertPayloadEquals("[{},{}]", payload);
78 | }
79 |
80 | [TestMethod]
81 | #if !NETCOREAPP3_1 && !NET5_0_OR_GREATER
82 | [ExpectedException(typeof(EncryptionException), "AES/GCM/NoPadding is unsupported on .NET Standard < 2.1")]
83 | #endif
84 | public void TestDecryptPayload_ShouldSupportPayloadWithEncryptedValueParent()
85 | {
86 | // GIVEN
87 | const string encryptedPayload = @"{
88 | ""encryptedDataParent"": {
89 | ""encryptedData"": ""ew0KICAia2lkIjogIjc2MWIwMDNjMWVhZGUzYTU0OTBlNTAwMGQzNzg4N2JhYTVlNmVjMGUyMjZjMDc3MDZlNTk5NDUxZmMwMzJhNzkiLA0KICAiY3R5IjogImFwcGxpY2F0aW9uL2pzb24iLA0KICAiZW5jIjogIkEyNTZHQ00iLA0KICAiYWxnIjogIlJTQS1PQUVQLTI1NiINCn0.QHdpgZKcR7e4TNddxHQOTk6R8IYhB4wfnHwUu5d3UhCcr6x6u8KWgPLrn2M95WV1xkjF7jnbOVYO-xE0e5Kx5laIVQNvjYpPxxYqzOQ-F16NwkkGgiZ8UnVi8qYYR1RO2fuqt6xP0_9VNnWpO541_kEMcCrk-6HFRjPU_4AF-wKAUdxInXOrUCOWi7-2uocraAYyLuh1PR0W002p9nVoOY7KXbA-Pf3gmEO9TgCDBFxmtn2dKwYxRPI6tkBYCB2n6h1rIIjQNI4kb-ErV8_vdppIPlB0-o0ONVlHWfnDbgZ3b8SIBEnZNn01MAPbC8visu41ODoNwhuKirD_MzvhTQ.GFYD8LCwXkc2eHPC.T1v8SZikvVAd76g.NbdYvwvKsUVbbSUqaX3Afw""
90 | }
91 | }";
92 | var config = TestUtils.GetTestJweConfigBuilder()
93 | .WithDecryptionPath("$.encryptedDataParent.encryptedData", "$")
94 | .Build();
95 |
96 | // WHEN
97 | var payload = JweEncryption.DecryptPayload(encryptedPayload, config);
98 |
99 | // THEN
100 | TestUtils.AssertPayloadEquals("{\"data\": {}}", payload);
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Encryption/JWE/JweHeaderTest.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Mastercard.Developer.ClientEncryption.Core.Encryption.JWE;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 |
5 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Encryption.JWE
6 | {
7 | [TestClass]
8 | public class JweHeaderTest
9 | {
10 | [TestMethod]
11 | public void TestToJson_ShouldReturnJsonJweHeader()
12 | {
13 | JweHeader header = new JweHeader("RSA-OAEP-256", "A256GCM", "123", "application/json");
14 |
15 | Assert.AreEqual(
16 | "{\"kid\":\"123\",\"cty\":\"application/json\",\"enc\":\"A256GCM\",\"alg\":\"RSA-OAEP-256\"}",
17 | header.Json.ToString(Formatting.None)
18 | );
19 | }
20 |
21 | [TestMethod]
22 | public void TestParseJweHeader_ShouldCorrectlyParseJweHeader()
23 | {
24 | JweHeader header = JweHeader.Parse("eyJraWQiOiI3NjFiMDAzYzFlYWRlM2E1NDkwZTUwMDBkMzc4ODdiYWE1ZTZlYzBlMjI2YzA3NzA2ZTU5OTQ1MWZjMDMyYTc5IiwiY3R5IjoiYXBwbGljYXRpb25cL2pzb24iLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0");
25 |
26 | Assert.AreEqual("A256GCM", header.Enc);
27 | Assert.AreEqual("RSA-OAEP-256", header.Alg);
28 | Assert.AreEqual("application/json", header.Cty);
29 | Assert.AreEqual("761b003c1eade3a5490e5000d37887baa5e6ec0e226c07706e599451fc032a79", header.Kid);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Encryption/JweConfigBuilderTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Mastercard.Developer.ClientEncryption.Core.Encryption;
5 | using Mastercard.Developer.ClientEncryption.Tests.NetCore.Test;
6 | using Microsoft.VisualStudio.TestTools.UnitTesting;
7 |
8 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Encryption
9 | {
10 | [TestClass]
11 | public class JweConfigBuilderTest
12 | {
13 | [TestMethod]
14 | public void TestBuild_Nominal()
15 | {
16 | var config = JweConfigBuilder.AJweEncryptionConfig()
17 | .WithEncryptionPath("$.payload", "$.encryptedPayload")
18 | .WithEncryptionCertificate(TestUtils.GetTestEncryptionCertificate())
19 | .WithDecryptionPath("$.encryptedPayload", "$.payload")
20 | .WithDecryptionKey(TestUtils.GetTestDecryptionKey())
21 | .WithEncryptedValueFieldName("encryptedValue")
22 | .Build();
23 |
24 | Assert.IsNotNull(config);
25 | Assert.AreEqual(1, config.EncryptionPaths.Count);
26 | Assert.IsNotNull(config.EncryptionCertificate);
27 | Assert.AreEqual(1, config.DecryptionPaths.Count);
28 | Assert.IsNotNull(config.DecryptionKey);
29 | Assert.AreEqual("encryptedValue", config.EncryptedValueFieldName);
30 | Assert.AreEqual(EncryptionConfig.EncryptionScheme.Jwe, config.Scheme);
31 | }
32 |
33 | [TestMethod]
34 | public void TestBuild_ResultShouldBeAssignableToGenericEncryptionConfig()
35 | {
36 | EncryptionConfig config = TestUtils.GetTestJweConfigBuilder().Build();
37 | Assert.IsNotNull(config);
38 | }
39 |
40 | [TestMethod]
41 | public void TestBuild_ShouldComputeCertificateKeyFingerprint_WhenFingerprintNotSet()
42 | {
43 | EncryptionConfig config = TestUtils.GetTestJweConfigBuilder().Build();
44 | Assert.AreEqual("761b003c1eade3a5490e5000d37887baa5e6ec0e226c07706e599451fc032a79", config.EncryptionKeyFingerprint);
45 | }
46 |
47 | [TestMethod]
48 | public void TestBuild_ShouldUseEncryptionKeyFingerprint_WhenFingerprintIsSet()
49 | {
50 | EncryptionConfig config = TestUtils.GetTestJweConfigBuilder().WithEncryptionKeyFingerprint("this-is-a-test-fingerprint").Build();
51 | Assert.AreEqual("this-is-a-test-fingerprint", config.EncryptionKeyFingerprint);
52 | }
53 |
54 | [TestMethod]
55 | [ExpectedException(typeof(EncryptionException))]
56 | public void TestBuild_ShouldThrowEncryptionException_WhenInvalidEncryptionCertificate()
57 | {
58 | TestUtils.GetTestJweConfigBuilder()
59 | .WithEncryptionCertificate(TestUtils.GetTestInvalidEncryptionCertificate() )
60 | .Build();
61 | }
62 |
63 | [TestMethod]
64 | public void TestBuild_ShouldFallbackToDefaults()
65 | {
66 | // WHEN
67 | var config = JweConfigBuilder.AJweEncryptionConfig()
68 | .WithEncryptionCertificate(TestUtils.GetTestEncryptionCertificate())
69 | .Build();
70 |
71 | // THEN
72 | var expectedDecryptionPaths = new Dictionary {{"$.encryptedData", "$"}};
73 | var expectedEncryptionPaths = new Dictionary {{ "$", "$" }};
74 | Assert.AreEqual(expectedDecryptionPaths.Count, config.DecryptionPaths.Count);
75 | Assert.AreEqual(expectedEncryptionPaths.Count, config.EncryptionPaths.Count);
76 | Assert.AreEqual(0, expectedDecryptionPaths.Except(config.DecryptionPaths).Count());
77 | Assert.AreEqual(0, expectedDecryptionPaths.Except(config.DecryptionPaths).Count());
78 | Assert.AreEqual("encryptedData", config.EncryptedValueFieldName);
79 | }
80 |
81 | [TestMethod]
82 | [ExpectedException(typeof(ArgumentException))]
83 | public void TestBuild_ShouldThrowArgumentException_WhenMissingDecryptionKey()
84 | {
85 | try
86 | {
87 | JweConfigBuilder.AJweEncryptionConfig().Build();
88 | }
89 | catch (Exception e)
90 | {
91 | Assert.AreEqual("You must include at least an encryption certificate or a decryption key", e.Message);
92 | throw;
93 | }
94 | }
95 |
96 | [TestMethod]
97 | [ExpectedException(typeof(ArgumentException))]
98 | public void TestBuild_ShouldThrowArgumentException_WhenNotDefiniteDecryptionPath()
99 | {
100 | try
101 | {
102 | JweConfigBuilder.AJweEncryptionConfig()
103 | .WithDecryptionPath("$.encryptedPayloads[*]", "$.payload")
104 | .WithDecryptionKey(TestUtils.GetTestDecryptionKey())
105 | .Build();
106 | }
107 | catch (Exception e)
108 | {
109 | Assert.AreEqual("JSON paths for decryption must point to a single item!", e.Message);
110 | throw;
111 | }
112 | }
113 |
114 | [TestMethod]
115 | [ExpectedException(typeof(ArgumentException))]
116 | public void TestBuild_ShouldThrowArgumentException_WhenNotDefiniteEncryptionPath()
117 | {
118 | try
119 | {
120 | JweConfigBuilder.AJweEncryptionConfig()
121 | .WithEncryptionPath("$.payloads[*]", "$.encryptedPayload")
122 | .WithEncryptionCertificate(TestUtils.GetTestEncryptionCertificate())
123 | .Build();
124 | }
125 | catch (Exception e)
126 | {
127 | Assert.AreEqual("JSON paths for encryption must point to a single item!", e.Message);
128 | throw;
129 | }
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Encryption/RSA/RsaEncryptionTest.cs:
--------------------------------------------------------------------------------
1 | using Mastercard.Developer.ClientEncryption.Core.Encryption;
2 | using Mastercard.Developer.ClientEncryption.Tests.NetCore.Test;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 | using System;
5 | using System.Linq;
6 | using System.Security.Cryptography.X509Certificates;
7 |
8 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Encryption
9 | {
10 | [TestClass]
11 | public class RsaEncryptionTest
12 | {
13 | [TestMethod]
14 | public void TestWrapUnwrapSecretKey_ShouldReturnTheOriginalKey()
15 | {
16 | // GIVEN
17 | var config = TestUtils.GetTestFieldLevelEncryptionConfigBuilder().Build();
18 | var originalKeyBytes = Convert.FromBase64String("mZzmzoURXI3Vk0vdsPkcFw==");
19 |
20 | // WHEN
21 | var wrappedKeyBytes = RsaEncryption.WrapSecretKey(config.EncryptionCertificate.GetRSAPublicKey(), originalKeyBytes, config.OaepPaddingDigestAlgorithm);
22 | var unwrappedKeyBytes = RsaEncryption.UnwrapSecretKey(config, wrappedKeyBytes, config.OaepPaddingDigestAlgorithm);
23 |
24 | // THEN
25 | Assert.IsTrue(originalKeyBytes.SequenceEqual(unwrappedKeyBytes));
26 | }
27 |
28 | [TestMethod]
29 | public void TestUnwrapSecretKey_InteroperabilityTest_OaepSha256()
30 | {
31 | // GIVEN
32 | var config = TestUtils.GetTestFieldLevelEncryptionConfigBuilder()
33 | .WithOaepPaddingDigestAlgorithm("SHA-256")
34 | .Build();
35 | const string wrappedKey = "ZLB838BRWW2/BtdFFAWBRYShw/gBxXSwItpxEZ9zaSVEDHo7n+SyVYU7mayd+9vHkR8OdpqwpXM68t0VOrWI8LD8A2pRaYx8ICyhVFya4OeiWlde05Rhsk+TNwwREPbiw1RgjT8aedRJJYbAZdLb9XEI415Kb/UliHyvsdHMb6vKyYIjUHB/pSGAAmgds56IhIJGfvnBLPZfSHmGgiBT8WXLRuuf1v48aIadH9S0FfoyVGTaLYr+2eznSTAFC0ZBnzebM3mQI5NGQNviTnEJ0y+uZaLE/mthiKgkv1ZybyDPx2xJK2n05sNzfIWKmnI/SOb65RZLlo1Q+N868l2m9g==";
36 | var wrappedKeyBytes = Convert.FromBase64String(wrappedKey);
37 |
38 | // WHEN
39 | var unwrappedKeyBytes = RsaEncryption.UnwrapSecretKey(config, wrappedKeyBytes, config.OaepPaddingDigestAlgorithm);
40 |
41 | // THEN
42 | var expectedKeyBytes = Convert.FromBase64String("mZzmzoURXI3Vk0vdsPkcFw==");
43 | Assert.IsTrue(expectedKeyBytes.SequenceEqual(unwrappedKeyBytes));
44 | }
45 |
46 | [TestMethod]
47 | public void TestUnwrapSecretKey_InteroperabilityTest_OaepSha512()
48 | {
49 | // GIVEN
50 | var config = TestUtils.GetTestFieldLevelEncryptionConfigBuilder()
51 | .WithOaepPaddingDigestAlgorithm("SHA-512")
52 | .Build();
53 | const string wrappedKey = "RuruMYP5rG6VP5vS4kVznIrSOjUzXyOhtD7bYlVqwniWTvxxZC73UDluwDhpLwX5QJCsCe8TcwGiQRX1u+yWpBveHDRmDa03hrc3JRJALEKPyN5tnt5w7aI4dLRnLuNoXbYoTSc4V47Z3gaaK6q2rEjydx2sQ/SyVmeUJN7NgxkhtHTyVWTymEM1ythL+AaaQ5AaXedhpWKhG06XYZIX4KV7T9cHEn+See6RVGGB2RUPHBJjrxJo5JoVSfnWN0gkTMyuwbmVaTWfsowbvh8GFibFT7h3uXyI3b79NiauyB7scXp9WidGues3MrTx4dKZrSbs3uHxzPKmCDZimuKfwg==";
54 | var wrappedKeyBytes = Convert.FromBase64String(wrappedKey);
55 |
56 | // WHEN
57 | var unwrappedKeyBytes = RsaEncryption.UnwrapSecretKey(config, wrappedKeyBytes, config.OaepPaddingDigestAlgorithm);
58 |
59 | // THEN
60 | var expectedKeyBytes = Convert.FromBase64String("mZzmzoURXI3Vk0vdsPkcFw==");
61 | Assert.IsTrue(expectedKeyBytes.SequenceEqual(unwrappedKeyBytes));
62 | }
63 |
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Interceptors/RestResponseDouble.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Net;
4 | using RestSharp;
5 | using RestRequest = RestSharp.RestRequest;
6 | using RestResponse = RestSharp.RestResponse;
7 |
8 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Interceptors
9 | {
10 | internal class RestResponseDouble : RestResponse
11 | {
12 | public new RestRequest Request { get; set; } = null;
13 | public new Uri ResponseUri { get; set; } = null;
14 | public new string Server { get; set; }
15 | public new byte[] RawBytes { get; set; } = null;
16 | public new string ContentType { get; set; } = null;
17 | public new long ContentLength { get; set; }
18 | public new string ContentEncoding { get; set; }
19 | public new IList Headers { get; }
20 | public new ResponseStatus ResponseStatus { get; set; }
21 | public new string ErrorMessage { get; set; }
22 | public new Exception ErrorException { get; set; }
23 | public Version ProtocolVersion { get; set; }
24 | public new HttpStatusCode StatusCode { get; set; } = HttpStatusCode.OK;
25 | public new bool IsSuccessful => true;
26 |
27 | public new string StatusDescription { get; set; } = null;
28 |
29 | private Lazy _content;
30 |
31 | public RestResponseDouble(IList headers, string content)
32 | {
33 | Headers = headers;
34 | Content = content;
35 | base.Headers = (IReadOnlyCollection)headers;
36 | base.Content = content;
37 | }
38 |
39 | public new string Content
40 | {
41 | get => _content.Value;
42 | set => _content = new Lazy(() => value);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Interceptors/RestSharpV2CbcJweEncryptionInterceptorTest.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using Mastercard.Developer.ClientEncryption.Core.Encryption;
3 | using Mastercard.Developer.ClientEncryption.RestSharpV2.Interceptors;
4 | using Mastercard.Developer.ClientEncryption.Tests.NetCore.Test;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 | using Method = RestSharp.Method;
7 | using Header = RestSharp.HeaderParameter;
8 | using ParameterType = RestSharp.ParameterType;
9 | using RestRequest = RestSharp.RestRequest;
10 | using RestSharp;
11 |
12 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Interceptors
13 | {
14 | [TestClass]
15 | public class RestSharpV2CbcJweEncryptionInterceptorTest
16 | {
17 | [TestMethod]
18 | public void TestFrom_ShouldReturnTheCorrectInterceptor()
19 | {
20 | // GIVEN
21 | EncryptionConfig config = TestUtils.GetTestJweConfigBuilder().Build();
22 |
23 | // WHEN
24 | RestSharpEncryptionInterceptor interceptor = RestSharpEncryptionInterceptor.From(config);
25 |
26 | // THEN
27 | Assert.IsTrue(interceptor is RestSharpJweEncryptionInterceptor);
28 | }
29 |
30 | [TestMethod]
31 | public void TestIntercept_ShouldDoNothing_WhenNoPayload()
32 | {
33 | // GIVEN
34 | var config = TestUtils.GetTestJweConfigBuilder().Build();
35 |
36 | // WHEN
37 | var request = new RestRequest
38 | {
39 | Method = Method.Get,
40 | Resource = "/service"
41 | };
42 |
43 | // THEN
44 | var fixture = RestSharpEncryptionInterceptor.From(config);
45 | fixture.InterceptRequest(request);
46 | }
47 |
48 | [TestMethod]
49 | public void TestInterceptResponse_ShouldDecryptWithA128CBC_HS256Encryption()
50 | {
51 | // GIVEN
52 | string encryptedPayload = "{" +
53 | "\"encryptedPayload\":\"eyJraWQiOiI3NjFiMDAzYzFlYWRlM2E1NDkwZTUwMDBkMzc4ODdiYWE1ZTZlYzBlMjI2YzA3NzA2ZTU5OTQ1MWZjMDMyYTc5IiwiY3R5IjoiYXBwbGljYXRpb25cL2pzb24iLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.5bsamlChk0HR3Nqg2UPJ2Fw4Y0MvC2pwWzNv84jYGkOXyqp1iwQSgETGaplIa7JyLg1ZWOqwNHEx3N7gsN4nzwAnVgz0eta6SsoQUE9YQ-5jek0COslUkoqIQjlQYJnYur7pqttDibj87fcw13G2agle5fL99j1QgFPjNPYqH88DMv481XGFa8O3VfJhW93m73KD2gvE5GasOPOkFK9wjKXc9lMGSgSArp3Awbc_oS2Cho_SbsvuEQwkhnQc2JKT3IaSWu8yK7edNGwD6OZJLhMJzWJlY30dUt2Eqe1r6kMT0IDRl7jHJnVIr2Qpe56CyeZ9V0aC5RH1mI5dYk4kHg.yI0CS3NdBrz9CCW2jwBSDw.6zr2pOSmAGdlJG0gbH53Eg.UFgf3-P9UjgMocEu7QA_vQ\"}";
54 | var config = TestUtils.GetTestJweConfigBuilder()
55 | .WithDecryptionPath("$.encryptedPayload", "$.foo")
56 | .Build();
57 |
58 | // WHEN
59 | var response = RestResponseWithContentLength(encryptedPayload);
60 | var fixture = RestSharpEncryptionInterceptor.From(config);
61 | fixture.InterceptResponse(response);
62 |
63 | // THEN
64 | var payload = response.Content;
65 | TestUtils.AssertPayloadEquals("{\"foo\":\"bar\"}", payload);
66 | var contentLengthHeaderParam = response.Headers.FirstOrDefault(param => param.Type == ParameterType.HttpHeader);
67 | Assert.IsNotNull(contentLengthHeaderParam);
68 | Assert.AreEqual(payload.Length.ToString(), contentLengthHeaderParam.Value);
69 | }
70 |
71 | [TestMethod]
72 | public void TestInterceptResponse_ShouldDoNothing_WhenNoPayload()
73 | {
74 | // GIVEN
75 | var config = TestUtils.GetTestJweConfigBuilder().Build();
76 | var response = new RestResponseDouble(null, null);
77 |
78 | // WHEN
79 | var fixture = RestSharpEncryptionInterceptor.From(config);
80 | fixture.InterceptResponse(response);
81 | }
82 |
83 | [TestMethod]
84 | [ExpectedException(typeof(EncryptionException))] // <-- THEN
85 | public void TestInterceptResponse_ShouldThrowException_WhenDecryptionFails()
86 | {
87 | // GIVEN
88 | string encryptedPayload = "{\"encryptedPayload\":\"NOT-VALID\"}";
89 | var config = TestUtils.GetTestJweConfigBuilder()
90 | .WithDecryptionPath("$", "$")
91 | .WithEncryptedValueFieldName("encryptedPayload")
92 | .Build();
93 | var response = RestResponseWithContentLength(encryptedPayload);
94 |
95 | // WHEN
96 | var fixture = RestSharpEncryptionInterceptor.From(config);
97 | fixture.InterceptResponse(response);
98 | }
99 |
100 | internal static RestResponse RestResponseWithContentLength(string content)
101 | {
102 | Header[] headers = { new Header("Content-Length", content.Length.ToString()) };
103 | return new RestResponseDouble(headers, content);
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Interceptors/RestSharpV2GcmJweEncryptionInterceptorTest.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using Mastercard.Developer.ClientEncryption.Core.Encryption;
3 | using Mastercard.Developer.ClientEncryption.RestSharpV2.Interceptors;
4 | using Mastercard.Developer.ClientEncryption.Tests.NetCore.Test;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 | using RestSharp;
7 | using Method = RestSharp.Method;
8 | using ParameterType = RestSharp.ParameterType;
9 | using RestRequest = RestSharp.RestRequest;
10 |
11 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Interceptors
12 | {
13 | [TestClass]
14 | public class RestSharpV2GcmJweEncryptionInterceptorTest
15 | {
16 | [TestMethod]
17 | #if !NETCOREAPP3_1 && !NET5_0_OR_GREATER
18 | [ExpectedException(typeof(EncryptionException), "AES/GCM/NoPadding is unsupported on .NET Standard < 2.1")]
19 | # endif
20 | public void TestIntercept_ShouldEncryptRequestPayloadAndUpdateContentLengthHeader()
21 | {
22 | // GIVEN
23 | var config = TestUtils.GetTestJweConfigBuilder()
24 | .WithEncryptionPath("$","$")
25 | .WithEncryptedValueFieldName("encryptedFoo")
26 | .Build();
27 | var request = new RestRequest
28 | {
29 | Method = Method.Post,
30 | Resource = "/service"
31 | };
32 | request.AddBody("{\"foo\":\"bar\"}");
33 |
34 | // WHEN
35 | var fixture = RestSharpEncryptionInterceptor.From(config);
36 | fixture.InterceptRequest(request);
37 |
38 | // THEN
39 | var encryptedPayloadParam = request.Parameters.FirstOrDefault(param => param.Type == ParameterType.RequestBody);
40 | Assert.IsNotNull(encryptedPayloadParam);
41 | var encryptedPayload = encryptedPayloadParam.Value?.ToString();
42 | Assert.IsNotNull(encryptedPayload);
43 | Assert.IsFalse(encryptedPayload.Contains("foo"));
44 | Assert.IsTrue(encryptedPayload.Contains("encryptedFoo"));
45 | var contentLengthHeaderParam = request.Parameters.FirstOrDefault(param => param.Type == ParameterType.HttpHeader);
46 | Assert.IsNotNull(contentLengthHeaderParam);
47 | Assert.AreEqual(encryptedPayload.Length.ToString(), contentLengthHeaderParam.Value);
48 | }
49 |
50 | [TestMethod]
51 | #if !NETCOREAPP3_1 && !NET5_0_OR_GREATER
52 | [ExpectedException(typeof(EncryptionException), "AES/GCM/NoPadding is unsupported on .NET Standard < 2.1")]
53 | # endif
54 | public void TestInterceptResponse_ShouldDecryptResponsePayloadAndUpdateContentLengthHeader()
55 | {
56 | // GIVEN
57 | const string encryptedPayload = "{" +
58 | "\"encryptedPayload\":\"eyJraWQiOiI3NjFiMDAzYzFlYWRlM2E1NDkwZTUwMDBkMzc4ODdiYWE1ZTZlYzBlMjI2YzA3NzA2ZTU5OTQ1MWZjMDMyYTc5IiwiY3R5IjoiYXBwbGljYXRpb25cL2pzb24iLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.8c6vxeZOUBS8A9SXYUSrRnfl1ht9xxciB7TAEv84etZhQQ2civQKso-htpa2DWFBSUm-UYlxb6XtXNXZxuWu-A0WXjwi1K5ZAACc8KUoYnqPldEtC9Q2bhbQgc_qZF_GxeKrOZfuXc9oi45xfVysF_db4RZ6VkLvY2YpPeDGEMX_nLEjzqKaDz_2m0Ae_nknr0p_Nu0m5UJgMzZGR4Sk1DJWa9x-WJLEyo4w_nRDThOjHJshOHaOU6qR5rdEAZr_dwqnTHrjX9Qm9N9gflPGMaJNVa4mvpsjz6LJzjaW3nJ2yCoirbaeJyCrful6cCiwMWMaDMuiBDPKa2ovVTy0Sw.w0Nkjxl0T9HHNu4R.suRZaYu6Ui05Z3-vsw.akknMr3Dl4L0VVTGPUszcA\"}";
59 | var config = TestUtils.GetTestJweConfigBuilder()
60 | .WithDecryptionPath("$.encryptedPayload", "$")
61 | .Build();
62 |
63 | // WHEN
64 | var response = RestSharpV2CbcJweEncryptionInterceptorTest.RestResponseWithContentLength(encryptedPayload);
65 | var fixture = RestSharpEncryptionInterceptor.From(config);
66 | fixture.InterceptResponse(response);
67 |
68 | // THEN
69 | var payload = response.Content;
70 | TestUtils.AssertPayloadEquals("{\"foo\":\"bar\"}", payload);
71 | var contentLengthHeaderParam = response.Headers.FirstOrDefault(param => param.Type == ParameterType.HttpHeader);
72 | Assert.IsNotNull(contentLengthHeaderParam);
73 | Assert.AreEqual(payload.Length.ToString(), contentLengthHeaderParam.Value);
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Test/TestUtils.cs:
--------------------------------------------------------------------------------
1 | using System.Security.Cryptography;
2 | using System.Security.Cryptography.X509Certificates;
3 | using Mastercard.Developer.ClientEncryption.Core.Encryption;
4 | using Mastercard.Developer.ClientEncryption.Core.Encryption.JWE;
5 | using Mastercard.Developer.ClientEncryption.Core.Utils;
6 | using Microsoft.VisualStudio.TestTools.UnitTesting;
7 | using Newtonsoft.Json.Linq;
8 | // ReSharper disable once InconsistentNaming
9 |
10 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Test
11 | {
12 | internal static class TestUtils
13 | {
14 | internal static X509Certificate2 GetTestEncryptionCertificate()
15 | {
16 | return EncryptionUtils.LoadEncryptionCertificate("./_Resources/Certificates/test_certificate-2048.pem");
17 | }
18 |
19 | internal static X509Certificate2 GetTestInvalidEncryptionCertificate() => new X509Certificate2(); // No key
20 |
21 | internal static RSA GetTestDecryptionKey()
22 | {
23 | return EncryptionUtils.LoadDecryptionKey("./_Resources/Keys/Pkcs8/test_key_pkcs8-2048.der");
24 | }
25 |
26 | internal static FieldLevelEncryptionConfigBuilder GetTestFieldLevelEncryptionConfigBuilder()
27 | {
28 | return FieldLevelEncryptionConfigBuilder.AFieldLevelEncryptionConfig()
29 | .WithEncryptionCertificate(GetTestEncryptionCertificate())
30 | .WithDecryptionKey(GetTestDecryptionKey())
31 | .WithOaepPaddingDigestAlgorithm("SHA-256")
32 | .WithEncryptedValueFieldName("encryptedValue")
33 | .WithEncryptedKeyFieldName("encryptedKey")
34 | .WithIvFieldName("iv")
35 | .WithOaepPaddingDigestAlgorithmFieldName("oaepHashingAlgorithm")
36 | .WithEncryptionCertificateFingerprintFieldName("encryptionCertificateFingerprint")
37 | .WithEncryptionCertificateFingerprint("80810fc13a8319fcf0e2ec322c82a4c304b782cc3ce671176343cfe8160c2279")
38 | .WithEncryptionKeyFingerprintFieldName("encryptionKeyFingerprint")
39 | .WithEncryptionKeyFingerprint("761b003c1eade3a5490e5000d37887baa5e6ec0e226c07706e599451fc032a79")
40 | .WithValueEncoding(FieldLevelEncryptionConfig.FieldValueEncoding.Hex);
41 | }
42 |
43 | internal static void AssertDecryptedPayloadEquals(string expectedPayload, string encryptedPayload, FieldLevelEncryptionConfig config)
44 | {
45 | var payloadString = FieldLevelEncryption.DecryptPayload(encryptedPayload, config);
46 | AssertPayloadEquals(expectedPayload, payloadString);
47 | }
48 |
49 | internal static void AssertDecryptedJweEquals(string expectedPayload, string encryptedPayload, JweConfig config)
50 | {
51 | var payloadString = JweEncryption.DecryptPayload(encryptedPayload, config);
52 | AssertPayloadEquals(expectedPayload, payloadString);
53 | }
54 |
55 | internal static void AssertPayloadEquals(string expectedPayload, string payload)
56 | {
57 | var expectedPayloadToken = JsonUtils.ParsePayload(expectedPayload);
58 | var payloadToken = JsonUtils.ParsePayload(payload);
59 | Assert.AreEqual(expectedPayloadToken.ToString(), payloadToken.ToString());
60 | }
61 |
62 | internal static JweConfigBuilder GetTestJweConfigBuilder()
63 | {
64 | return JweConfigBuilder.AJweEncryptionConfig()
65 | .WithEncryptionCertificate(GetTestEncryptionCertificate())
66 | .WithDecryptionKey(GetTestDecryptionKey());
67 | }
68 |
69 | internal static JweObject GetTestCbcJweObject()
70 | {
71 | return JweObject.Parse("eyJraWQiOiI3NjFiMDAzYzFlYWRlM2E1NDkwZTUwMDBkMzc4ODdiYWE1ZTZlYzBlMjI2YzA3NzA2ZTU5OTQ1MWZjMDMyYTc5IiwiY3R5IjoiYXBwbGljYXRpb25cL2pzb24iLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.5bsamlChk0HR3Nqg2UPJ2Fw4Y0MvC2pwWzNv84jYGkOXyqp1iwQSgETGaplIa7JyLg1ZWOqwNHEx3N7gsN4nzwAnVgz0eta6SsoQUE9YQ-5jek0COslUkoqIQjlQYJnYur7pqttDibj87fcw13G2agle5fL99j1QgFPjNPYqH88DMv481XGFa8O3VfJhW93m73KD2gvE5GasOPOkFK9wjKXc9lMGSgSArp3Awbc_oS2Cho_SbsvuEQwkhnQc2JKT3IaSWu8yK7edNGwD6OZJLhMJzWJlY30dUt2Eqe1r6kMT0IDRl7jHJnVIr2Qpe56CyeZ9V0aC5RH1mI5dYk4kHg.yI0CS3NdBrz9CCW2jwBSDw.6zr2pOSmAGdlJG0gbH53Eg.UFgf3-P9UjgMocEu7QA_vQ");
72 | }
73 |
74 | internal static JweObject GetTest256GcmJweObject()
75 | {
76 | return JweObject.Parse("eyJraWQiOiI3NjFiMDAzYzFlYWRlM2E1NDkwZTUwMDBkMzc4ODdiYWE1ZTZlYzBlMjI2YzA3NzA2ZTU5OTQ1MWZjMDMyYTc5IiwiY3R5IjoiYXBwbGljYXRpb25cL2pzb24iLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.8c6vxeZOUBS8A9SXYUSrRnfl1ht9xxciB7TAEv84etZhQQ2civQKso-htpa2DWFBSUm-UYlxb6XtXNXZxuWu-A0WXjwi1K5ZAACc8KUoYnqPldEtC9Q2bhbQgc_qZF_GxeKrOZfuXc9oi45xfVysF_db4RZ6VkLvY2YpPeDGEMX_nLEjzqKaDz_2m0Ae_nknr0p_Nu0m5UJgMzZGR4Sk1DJWa9x-WJLEyo4w_nRDThOjHJshOHaOU6qR5rdEAZr_dwqnTHrjX9Qm9N9gflPGMaJNVa4mvpsjz6LJzjaW3nJ2yCoirbaeJyCrful6cCiwMWMaDMuiBDPKa2ovVTy0Sw.w0Nkjxl0T9HHNu4R.suRZaYu6Ui05Z3-vsw.akknMr3Dl4L0VVTGPUszcA");
77 | }
78 |
79 | internal static JweObject GetTest128GcmJweObject()
80 | {
81 | return JweObject.Parse("eyJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.WtvYljbsjdEv-Ttxx1p6PgyIrOsLpj1FMF9NQNhJUAHlKchAo5QImgEgIdgJE7HC2KfpNcHiQVqKKZq_y201FVzpicDkNzlPJr5kIH4Lq-oC5iP0agWeou9yK5vIxFRP__F_B8HSuojBJ3gDYT_KdYffUIHkm_UysNj4PW2RIRlafJ6RKYanVzk74EoKZRG7MIr3pTU6LIkeQUW41qYG8hz6DbGBOh79Nkmq7Oceg0ZwCn1_MruerP-b15SGFkuvOshStT5JJp7OOq82gNAOkMl4fylEj2-vADjP7VSK8GlqrA7u9Tn-a4Q28oy0GOKr1Z-HJgn_CElknwkUTYsWbg.PKl6_kvZ4_4MjmjW.AH6pGFkn7J49hBQcwg.zdyD73TcuveImOy4CRnVpw");
82 | }
83 |
84 | internal static JweObject GetTest192GcmJweObject()
85 | {
86 | return JweObject.Parse("eyJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.FWC8PVaZoR2TRKwKO4syhSJReezVIvtkxU_yKh4qODNvlVr8t8ttvySJ-AjM8xdI6vNyIg9jBMWASG4cE49jT9FYuQ72fP4R-Td4vX8wpB8GonQj40yLqZyfRLDrMgPR20RcQDW2ThzLXsgI55B5l5fpwQ9Nhmx8irGifrFWOcJ_k1dUSBdlsHsYxkjRKMENu5x4H6h12gGZ21aZSPtwAj9msMYnKLdiUbdGmGG_P8a6gPzc9ih20McxZk8fHzXKujjukr_1p5OO4o1N4d3qa-YI8Sns2fPtf7xPHnwi1wipmCC6ThFLU80r3173RXcpyZkF8Y3UacOS9y1f8eUfVQ.JRE7kZLN4Im1Rtdb.eW_lJ-U330n0QHqZnQ._r5xYVvMCrvICwLz4chjdw");
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Utils/Base64UtilsTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Mastercard.Developer.ClientEncryption.Core.Utils;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 |
5 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Utils
6 | {
7 | [TestClass]
8 | public class Base64UtilsTest
9 | {
10 | private static readonly Tuple TestVector1 = Tuple.Create("Ct6FrAEg4OVsWaeI+2wNIG0RSCFEW/PLWzueZqUbwDw=", "Ct6FrAEg4OVsWaeI-2wNIG0RSCFEW_PLWzueZqUbwDw");
11 | private static readonly Tuple TestVector2 = Tuple.Create("zRbseYGWpTaOpr4o+aBDjwQ9Pn/yHTxm5uPt0JKIH5nRdg==", "zRbseYGWpTaOpr4o-aBDjwQ9Pn_yHTxm5uPt0JKIH5nRdg");
12 |
13 | [TestMethod]
14 | public void TestBase64URLEncode()
15 | {
16 | var vectors = new Tuple[]{ TestVector1, TestVector2 };
17 | foreach (var vector in vectors)
18 | {
19 | Assert.AreEqual(
20 | vector.Item2,
21 | Base64Utils.URLEncode(
22 | Convert.FromBase64String(vector.Item1)
23 | )
24 | );
25 | }
26 | }
27 |
28 | [TestMethod]
29 | public void TestBase64URLDecode()
30 | {
31 | var vectors = new Tuple[] { TestVector1, TestVector2 };
32 | foreach (var vector in vectors)
33 | {
34 | CollectionAssert.AreEqual(
35 | Convert.FromBase64String(vector.Item1),
36 | Base64Utils.URLDecode(vector.Item2)
37 | );
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Utils/ByteUtilsTest.cs:
--------------------------------------------------------------------------------
1 | using Mastercard.Developer.ClientEncryption.Core.Utils;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 |
4 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Utils
5 | {
6 | [TestClass]
7 | public class ByteUtilsTest
8 | {
9 | [TestMethod]
10 | public void TestByteCountWithRemainder()
11 | {
12 | // GIVEN
13 | const int bitLength = 33;
14 |
15 | // WHEN
16 | int byteCount = ByteUtils.ByteCount(bitLength);
17 |
18 | // THEN
19 | Assert.AreEqual(5, byteCount);
20 | }
21 |
22 | [TestMethod]
23 | public void TestByteCountWithoutRemainder()
24 | {
25 | // GIVEN
26 | const int bitLength = 64;
27 |
28 | // WHEN
29 | int byteCount = ByteUtils.ByteCount(bitLength);
30 |
31 | // THEN
32 | Assert.AreEqual(8, byteCount);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Utils/EncodingUtilsTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Security.Cryptography;
4 | using System.Text;
5 | using Mastercard.Developer.ClientEncryption.Core.Utils;
6 | using Microsoft.VisualStudio.TestTools.UnitTesting;
7 |
8 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Utils
9 | {
10 | [TestClass]
11 | public class EncodingUtilsTest
12 | {
13 | [TestMethod]
14 | public void TestHexEncode()
15 | {
16 | Assert.AreEqual("00", EncodingUtils.HexEncode(new byte[1]));
17 | Assert.AreEqual("736f6d652064617461", EncodingUtils.HexEncode(Encoding.ASCII.GetBytes("some data")));
18 | Assert.AreEqual("", EncodingUtils.HexEncode(Encoding.ASCII.GetBytes("")));
19 | }
20 |
21 | [TestMethod]
22 | [ExpectedException(typeof(ArgumentNullException))]
23 | public void TestHexEncode_ShouldThrowArgumentNullException_WhenNullValue()
24 | {
25 | EncodingUtils.HexEncode(null);
26 | }
27 |
28 | [TestMethod]
29 | public void TestHexEncode_ShouldKeepLeadingZeros()
30 | {
31 | var hex = EncodingUtils.HexEncode(SHA256.Create().ComputeHash(Encoding.ASCII.GetBytes("WIDDIES")));
32 | Assert.AreEqual("000000c71f1bda5b63f5165243e10394bc9ebf62e394ef7c6e049c920ea1b181", hex);
33 | }
34 |
35 | [TestMethod]
36 | public void TestHexDecode()
37 | {
38 | Assert.IsTrue(new byte[1].SequenceEqual(EncodingUtils.HexDecode("00")));
39 | Assert.IsTrue(Encoding.ASCII.GetBytes("some data").SequenceEqual(EncodingUtils.HexDecode("736f6d652064617461")));
40 | Assert.IsTrue(Encoding.ASCII.GetBytes("some data").SequenceEqual(EncodingUtils.HexDecode("736F6D652064617461")));
41 | Assert.IsTrue(Encoding.ASCII.GetBytes("").SequenceEqual(EncodingUtils.HexDecode("")));
42 | }
43 |
44 | [TestMethod]
45 | [ExpectedException(typeof(FormatException))]
46 | public void TestHexDecode_ShouldThrowFormatException_WhenNotAnHexValue()
47 | {
48 | EncodingUtils.HexDecode("not an hex string!");
49 | }
50 |
51 | [TestMethod]
52 | [ExpectedException(typeof(ArgumentNullException))]
53 | public void TestHexDecode_ShouldThrowArgumentNullException_WhenNullValue()
54 | {
55 | EncodingUtils.HexDecode(null);
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Utils/EncryptionUtilsTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Security.Cryptography.X509Certificates;
4 | using Mastercard.Developer.ClientEncryption.Core.Utils;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 |
7 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Utils
8 | {
9 | [TestClass]
10 | public class EncryptionUtilsTest
11 | {
12 | [TestMethod]
13 | public void TestLoadEncryptionCertificate_ShouldSupportDer()
14 | {
15 | // GIVEN
16 | const string certificatePath = "./_Resources/Certificates/test_certificate-2048.der";
17 |
18 | // WHEN
19 | var certificate = EncryptionUtils.LoadEncryptionCertificate(certificatePath);
20 |
21 | // THEN
22 | Assert.IsNotNull(certificate);
23 | Assert.AreEqual("X509", certificate.GetFormat());
24 | Assert.IsNotNull(certificate.GetRSAPublicKey());
25 | Assert.AreNotEqual("RSACryptoServiceProvider", certificate.GetRSAPublicKey().GetType().Name); // We expect a RSACng (Windows) or a RSAOpenSsl (Linux, macOS)
26 | }
27 |
28 | [TestMethod]
29 | public void TestLoadEncryptionCertificate_ShouldSupportPem()
30 | {
31 | // GIVEN
32 | const string certificatePath = "./_Resources/Certificates/test_certificate-2048.pem";
33 |
34 | // WHEN
35 | var certificate = EncryptionUtils.LoadEncryptionCertificate(certificatePath);
36 |
37 | // THEN
38 | Assert.IsNotNull(certificate);
39 | Assert.AreEqual("X509", certificate.GetFormat());
40 | Assert.IsNotNull(certificate.GetRSAPublicKey());
41 | Assert.AreNotEqual("RSACryptoServiceProvider", certificate.GetRSAPublicKey().GetType().Name);
42 | }
43 |
44 | [TestMethod]
45 | public void TestLoadDecryptionKey_ShouldSupportUnencryptedKeyFile()
46 | {
47 | // GIVEN
48 | const string keyPath = "./_Resources/Keys/Pkcs8/test_key_pkcs8-2048.der";
49 |
50 | // WHEN
51 | var privateKey = EncryptionUtils.LoadDecryptionKey(keyPath);
52 |
53 | // THEN
54 | Assert.IsNotNull(privateKey);
55 | Assert.AreNotEqual("RSACryptoServiceProvider", privateKey.GetType().Name);
56 | Assert.AreEqual(2048, privateKey.KeySize);
57 | }
58 |
59 | [TestMethod]
60 | public void TestLoadDecryptionKey_ShouldSupportPkcs12()
61 | {
62 | // GIVEN
63 | const string keyContainerPath = "./_Resources/Keys/Pkcs12/test_key.p12";
64 | const string keyAlias = "mykeyalias";
65 | const string keyPassword = "Password1";
66 |
67 | // WHEN
68 | const X509KeyStorageFlags flags = X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable; // https://github.com/dotnet/corefx/issues/14745
69 | var privateKey = EncryptionUtils.LoadDecryptionKey(keyContainerPath, keyAlias, keyPassword, flags);
70 |
71 | // THEN
72 | Assert.AreNotEqual("RSACryptoServiceProvider", privateKey.GetType().Name);
73 | Assert.AreEqual(2048, privateKey.KeySize);
74 | }
75 |
76 | [TestMethod]
77 | public void TestLoadDecryptionKey_ShouldSupportByteArray()
78 | {
79 | // GIVEN
80 | const string keyPath = "./_Resources/Keys/Pkcs8/test_key_pkcs8-2048.der";
81 | var keyBytes = File.ReadAllBytes(keyPath);
82 |
83 | // WHEN
84 | var privateKey = EncryptionUtils.LoadDecryptionKey(keyBytes);
85 |
86 | // THEN
87 | Assert.AreNotEqual("RSACryptoServiceProvider", privateKey.GetType().Name);
88 | Assert.AreEqual(2048, privateKey.KeySize);
89 | }
90 |
91 | [TestMethod]
92 | [ExpectedException(typeof(ArgumentException))] // THEN
93 | public void TestLoadDecryptionKey_ShouldThrowArgumentException_WhenInvalidKey()
94 | {
95 | // GIVEN
96 | const string keyPath = "./_Resources/Keys/Pkcs8/test_invalid_key.der";
97 |
98 | // WHEN
99 | EncryptionUtils.LoadDecryptionKey(keyPath);
100 | }
101 |
102 | [TestMethod]
103 | [ExpectedException(typeof(FileNotFoundException))] // THEN
104 | public void TestLoadDecryptionKey_ShouldThrowFileNotFoundException_WhenKeyFileDoesNotExist()
105 | {
106 | // GIVEN
107 | const string keyPath = "./_Resources/Keys/some_file";
108 |
109 | // WHEN
110 | EncryptionUtils.LoadDecryptionKey(keyPath);
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Utils/JsonUtilsTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Mastercard.Developer.ClientEncryption.Core.Utils;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 | using Newtonsoft.Json.Linq;
5 |
6 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Utils
7 | {
8 | [TestClass]
9 | public class JsonUtilsTest
10 | {
11 | [TestMethod]
12 | public void TestGetParentJsonPath_Nominal()
13 | {
14 | // GIVEN
15 | const string jsonPath1 = "$['obj1']['obj2']['obj3']";
16 | const string jsonPath2 = "obj1.obj2";
17 | const string jsonPath3 = "$.obj1.obj2";
18 | const string jsonPath4 = "obj1";
19 |
20 | // WHEN
21 | var parentJsonPath1 = JsonUtils.GetParentJsonPath(jsonPath1);
22 | var parentJsonPath2 = JsonUtils.GetParentJsonPath(jsonPath2);
23 | var parentJsonPath3 = JsonUtils.GetParentJsonPath(jsonPath3);
24 | var parentJsonPath4 = JsonUtils.GetParentJsonPath(jsonPath4);
25 |
26 | // THEN
27 | Assert.AreEqual("$['obj1']['obj2']", parentJsonPath1);
28 | Assert.AreEqual("obj1", parentJsonPath2);
29 | Assert.AreEqual("$.obj1", parentJsonPath3);
30 | Assert.AreEqual("$", parentJsonPath4);
31 | }
32 |
33 | [TestMethod]
34 | public void TestGetJsonElementKey_Nominal()
35 | {
36 | // GIVEN
37 | const string jsonPath1 = "$['obj0']['obj1']['obj2']";
38 | const string jsonPath2 = "obj1.obj2";
39 | const string jsonPath3 = "$.obj1.obj2";
40 | const string jsonPath4 = "obj2";
41 |
42 | // WHEN
43 | var jsonElementKey1 = JsonUtils.GetJsonElementKey(jsonPath1);
44 | var jsonElementKey2 = JsonUtils.GetJsonElementKey(jsonPath2);
45 | var jsonElementKey3 = JsonUtils.GetJsonElementKey(jsonPath3);
46 | var jsonElementKey4 = JsonUtils.GetJsonElementKey(jsonPath4);
47 |
48 | // THEN
49 | Assert.AreEqual("obj2", jsonElementKey1);
50 | Assert.AreEqual("obj2", jsonElementKey2);
51 | Assert.AreEqual("obj2", jsonElementKey3);
52 | Assert.AreEqual("obj2", jsonElementKey4);
53 | }
54 |
55 | [TestMethod]
56 | [ExpectedException(typeof(ArgumentException))] // THEN
57 | public void TestGetParentJsonPath_ShouldThrowArgumentException_WhenJsonPathNullOrEmpty()
58 | {
59 | try
60 | {
61 | // GIVEN
62 | const string jsonPath = "";
63 |
64 | // WHEN
65 | JsonUtils.GetParentJsonPath(jsonPath);
66 | }
67 | catch (Exception e)
68 | {
69 | // THEN
70 | Assert.AreEqual("jsonPath", e.Message);
71 | throw;
72 | }
73 |
74 | }
75 |
76 | [TestMethod]
77 | [ExpectedException(typeof(ArgumentException))] // THEN
78 | public void TestGetJsonElementKey_ShouldThrowArgumentException_WhenJsonPathNullOrEmpty()
79 | {
80 | try
81 | {
82 | // GIVEN
83 | const string jsonPath = "";
84 |
85 | // WHEN
86 | JsonUtils.GetJsonElementKey(jsonPath);
87 | }
88 | catch (Exception e)
89 | {
90 | // THEN
91 | Assert.AreEqual("jsonPath", e.Message);
92 | throw;
93 | }
94 | }
95 |
96 | [TestMethod]
97 | [ExpectedException(typeof(InvalidOperationException))] // THEN
98 | public void TestGetParentJsonPath_ShouldThrowInvalidOperationException_WhenNoParent()
99 | {
100 | try
101 | {
102 | // GIVEN
103 | const string jsonPath = "$";
104 |
105 | // WHEN
106 | JsonUtils.GetParentJsonPath(jsonPath);
107 | }
108 | catch (Exception e)
109 | {
110 | // THEN
111 | Assert.AreEqual("Unable to find parent for '$'", e.Message);
112 | throw;
113 | }
114 | }
115 |
116 | [TestMethod]
117 | [ExpectedException(typeof(InvalidOperationException))] // THEN
118 | public void TestGetJsonElementKey_ShouldThrowInvalidOperationException_WhenNoKey()
119 | {
120 | try
121 | {
122 | // GIVEN
123 | const string jsonPath = "$";
124 |
125 | // WHEN
126 | JsonUtils.GetJsonElementKey(jsonPath);
127 | }
128 | catch (Exception e)
129 | {
130 | // THEN
131 | Assert.AreEqual("Unable to find object key for '$'", e.Message);
132 | throw;
133 | }
134 | }
135 |
136 | [TestMethod]
137 | public void TestParsePayload()
138 | {
139 | // GIVEN
140 | const string payload = "{\"num\":123, timestamp:\"2024-02-12T00:00:00-05:00\"}";
141 | JToken token = JsonUtils.ParsePayload(payload);
142 |
143 | // WHEN
144 | string num = token.SelectToken("num").ToString();
145 | string timestamp = token.SelectToken("timestamp").ToString();
146 | // THEN
147 | Assert.AreEqual(num, "123");
148 | Assert.AreEqual(timestamp, "2024-02-12T00:00:00-05:00");
149 |
150 | // WHEN
151 | var defaultToken = JToken.Parse(payload);
152 | num = defaultToken.SelectToken("num").ToString();
153 | timestamp = defaultToken.SelectToken("timestamp").ToString();
154 |
155 | // THEN
156 | Assert.AreEqual(num, "123");
157 | Assert.AreNotEqual(timestamp, "2024-02-12T00:00:00-05:00");
158 |
159 |
160 | }
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/Utils/RsaKeyUtilsTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using Mastercard.Developer.ClientEncryption.Core.Utils;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 |
6 | namespace Mastercard.Developer.ClientEncryption.Tests.NetCore.Utils
7 | {
8 | [TestClass]
9 | public class RsaKeyUtilsTest
10 | {
11 |
12 | [TestMethod]
13 | [DataRow("./_Resources/Keys/Pkcs8/test_key_pkcs8-512.pem", 512)]
14 | [DataRow("./_Resources/Keys/Pkcs8/test_key_pkcs8-1024.pem", 1024)]
15 | [DataRow("./_Resources/Keys/Pkcs8/test_key_pkcs8-2048.pem", 2048)]
16 | [DataRow("./_Resources/Keys/Pkcs8/test_key_pkcs8-4096.pem", 4096)]
17 | [DataRow("./_Resources/Keys/Pkcs8/test_key_pkcs8-512.der", 512)]
18 | [DataRow("./_Resources/Keys/Pkcs8/test_key_pkcs8-1024.der", 1024)]
19 | [DataRow("./_Resources/Keys/Pkcs8/test_key_pkcs8-2048.der", 2048)]
20 | [DataRow("./_Resources/Keys/Pkcs8/test_key_pkcs8-4096.der", 4096)]
21 | [DataRow("./_Resources/Keys/Pkcs1/test_key_pkcs1-512.pem", 512)]
22 | [DataRow("./_Resources/Keys/Pkcs1/test_key_pkcs1-1024.pem", 1024)]
23 | [DataRow("./_Resources/Keys/Pkcs1/test_key_pkcs1-2048.pem", 2048)]
24 | [DataRow("./_Resources/Keys/Pkcs1/test_key_pkcs1-4096.pem", 4096)]
25 | public void TestReadPrivateKeyFile(string keyPath, int expectedKeySize)
26 | {
27 | // WHEN
28 | var rsa = RsaKeyUtils.ReadPrivateKeyFile(keyPath);
29 |
30 | // THEN
31 | Assert.AreNotEqual("RSACryptoServiceProvider", rsa.GetType().Name); // We expect a RSACng (Windows) or a RSAOpenSsl (Linux, macOS)
32 | Assert.AreEqual(expectedKeySize, rsa.KeySize);
33 | }
34 |
35 | [TestMethod]
36 | [DataRow("./_Resources/Keys/Pkcs8/test_key_pkcs8-512.pem", 512)]
37 | [DataRow("./_Resources/Keys/Pkcs8/test_key_pkcs8-1024.pem", 1024)]
38 | [DataRow("./_Resources/Keys/Pkcs8/test_key_pkcs8-2048.pem", 2048)]
39 | [DataRow("./_Resources/Keys/Pkcs8/test_key_pkcs8-4096.pem", 4096)]
40 | [DataRow("./_Resources/Keys/Pkcs8/test_key_pkcs8-512.der", 512)]
41 | [DataRow("./_Resources/Keys/Pkcs8/test_key_pkcs8-1024.der", 1024)]
42 | [DataRow("./_Resources/Keys/Pkcs8/test_key_pkcs8-2048.der", 2048)]
43 | [DataRow("./_Resources/Keys/Pkcs8/test_key_pkcs8-4096.der", 4096)]
44 | [DataRow("./_Resources/Keys/Pkcs1/test_key_pkcs1-512.pem", 512)]
45 | [DataRow("./_Resources/Keys/Pkcs1/test_key_pkcs1-1024.pem", 1024)]
46 | [DataRow("./_Resources/Keys/Pkcs1/test_key_pkcs1-2048.pem", 2048)]
47 | //[DataRow("./_Resources/Keys/Pkcs1/test_key_pkcs1-2048_uneven_length.pem", 2048)] -- uncomment for local testing.
48 | [DataRow("./_Resources/Keys/Pkcs1/test_key_pkcs1-4096.pem", 4096)]
49 | public void TestReadPrivateKey(string keyPath, int expectedKeySize)
50 | {
51 | // GIVEN
52 | var bytes = File.ReadAllBytes(keyPath);
53 | // WHEN
54 | var rsa = RsaKeyUtils.ReadPrivateKey(bytes);
55 |
56 | // THEN
57 | Assert.AreNotEqual("RSACryptoServiceProvider", rsa.GetType().Name); // We expect a RSACng (Windows) or a RSAOpenSsl (Linux, macOS)
58 | Assert.AreEqual(expectedKeySize, rsa.KeySize);
59 | }
60 |
61 | [TestMethod]
62 | public void TestGetEncoded_ShouldSupportPublicKey512bits()
63 | {
64 | // GIVEN
65 | const string certificatePath = "./_Resources/Certificates/test_certificate-512.pem";
66 | var certificate = EncryptionUtils.LoadEncryptionCertificate(certificatePath);
67 |
68 | // WHEN
69 | var encodedBytes = RsaKeyUtils.GetEncoded(certificate.PublicKey);
70 |
71 | // THEN
72 | const string javaGetEncodedKeyValue = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANgkcDW0LBw2whiJld9zMq2fs56NdZcPxaM4kbN5NJKcWMv/120mOUrRlqsxdN0slsqvnyxG+D+weHdEQVFcUn8CAwEAAQ==";
73 | Assert.AreEqual(javaGetEncodedKeyValue, Convert.ToBase64String(encodedBytes));
74 | }
75 |
76 | [TestMethod]
77 | public void TestGetEncoded_ShouldSupportPublicKey1024bits()
78 | {
79 | // GIVEN
80 | const string certificatePath = "./_Resources/Certificates/test_certificate-1024.pem";
81 | var certificate = EncryptionUtils.LoadEncryptionCertificate(certificatePath);
82 |
83 | // WHEN
84 | var encodedBytes = RsaKeyUtils.GetEncoded(certificate.PublicKey);
85 |
86 | // THEN
87 | const string javaGetEncodedKeyValue = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDih8akxCCa30Pv5epkBWt4KzpGaXqeyB/ydbj3Hq7ylvHnJwrb9cJ4MbsKzox2JUbtYg/AVXCaQTDlsXfql6+O51ptKLWWilyzAZb5/okpOx2DlzHe4c/crrDfMnF0UA2sFbmzqSUVpNY7NjE7tquRhYueJTT2RpAGGANMReMhjwIDAQAB";
88 | Assert.AreEqual(javaGetEncodedKeyValue, Convert.ToBase64String(encodedBytes));
89 | }
90 |
91 | [TestMethod]
92 | public void TestGetEncoded_ShouldSupportPublicKey2048bits()
93 | {
94 | // GIVEN
95 | const string certificatePath = "./_Resources/Certificates/test_certificate-2048.pem";
96 | var certificate = EncryptionUtils.LoadEncryptionCertificate(certificatePath);
97 |
98 | // WHEN
99 | var encodedBytes = RsaKeyUtils.GetEncoded(certificate.PublicKey);
100 |
101 | // THEN
102 | const string javaGetEncodedKeyValue = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9Mp6gEFp9E+/1SS5XrUyYKMbE7eU0dyJCfmJPz8YOkOYV7ohqwXQvjlaP/YazZ6bbmYfa2WCraOpW0o2BYijHgQ7z2a2Az87rKdAtCpZSKFW82Ijnsw++lx7EABI3tFF282ZV7LT13n9m4th5Kldukk9euy+TuJqCvPu4xzE/NE+l4LFMr8rfD47EPQkrun5w/TXwkmJrdnG9ejl3BLQO06Ns6Bs516geiYZ7RYxtI8Xnu0ZC0fpqDqjCPZBTORkiFeLocEPRbTgo1H+0xQFNdsMH1/0F1BI+hvdxlbc3+kHZFZFoeBMkR3jC8jDXOXNCMNWb13Tin6HqPReO0KW8wIDAQAB";
103 | Assert.AreEqual(javaGetEncodedKeyValue, Convert.ToBase64String(encodedBytes));
104 | }
105 |
106 | [TestMethod]
107 | public void TestGetEncoded_ShouldSupportPublicKey4096bits()
108 | {
109 | // GIVEN
110 | const string certificatePath = "./_Resources/Certificates/test_certificate-4096.pem";
111 | var certificate = EncryptionUtils.LoadEncryptionCertificate(certificatePath);
112 |
113 | // WHEN
114 | var encodedBytes = RsaKeyUtils.GetEncoded(certificate.PublicKey);
115 |
116 | // THEN
117 | const string javaGetEncodedValue = "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAygN/8OUwDKbTIt5zguBP4sBF1GCWpKsV6Nt2llfMNqugd/9xM2BI4WyINNSzQDA69Qp+ce2mAkqxO72l7BhBdGitHDRrU4QAun/ls+ECrWZ5ug9iFZD2dsrLxj08gLRlybwFCUjuLLK5QUjB4HfbgAxkgYfVBgluIgA6G7Lcr9rQr57F53IZ5hM9ppcbNeb9HlW5wHV+tHW/1l9ZcOS5TJPP5ptV3aHneMpVKB8TJIMjSiWZt+6bs1VoCB2jaxaVNC2jkgzInezsqGur+G7Zq5oofcRDKyDt8imXf71i3BcM7d7fOur/r5gB0k6Kc+UGSzQK2oVP54T/0X52+2eKV8NqGF3Lpu5Poy5Nq0rID3L1Db81P7qUrrISuMkLP+uPPbFk4A6ZuczNAbxXARjSwOFhshUHEVKIW7FWeWWCCY5Ti21eWG9Recl5ahA7aHLogTFqyhAqV5h4l7D/icoxr2TAOkllFGLCRZ3ad43ET7gXPttiqu3SPstUFbuqDbmt3Yp4ZuoDA3+KEeSXYPaIn+J9Drm4B6gMTrTh/i0eRdKc9VFYmIgVJGRH4X6KCAO3erhzAUuFRKELJl1g6i0xZnPLICSktG+dBWkiFSqkLIsxPc9K4o9ZEOmhALih8gLEitXIcze7TT4ohhJsuA9T4GVMBRaQiAHo9fK2PF7h+WcCAwEAAQ==";
118 | Assert.AreEqual(javaGetEncodedValue, Convert.ToBase64String(encodedBytes));
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Certificates/test_certificate-1024.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIICZjCCAc+gAwIBAgIUBq7cHZY6mebdaqpq+GoZfipDAhYwDQYJKoZIhvcNAQEL
3 | BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
4 | GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xOTAzMjgxOTUzMDRaFw0yOTAz
5 | MjUxOTUzMDRaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
6 | HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwgZ8wDQYJKoZIhvcNAQEB
7 | BQADgY0AMIGJAoGBAOKHxqTEIJrfQ+/l6mQFa3grOkZpep7IH/J1uPcervKW8ecn
8 | Ctv1wngxuwrOjHYlRu1iD8BVcJpBMOWxd+qXr47nWm0otZaKXLMBlvn+iSk7HYOX
9 | Md7hz9yusN8ycXRQDawVubOpJRWk1js2MTu2q5GFi54lNPZGkAYYA0xF4yGPAgMB
10 | AAGjUzBRMB0GA1UdDgQWBBS164KE51INf9Utho+9oZokMMqdEDAfBgNVHSMEGDAW
11 | gBS164KE51INf9Utho+9oZokMMqdEDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
12 | DQEBCwUAA4GBANNwxvtZVZjRStZ3SsoeHxAUZyqL+ZAWzgWOXv2pwIeJUR/rKlKJ
13 | 71894OktqM8YH/eA3eSXPcs8tF5r8mUL+F0yF+ipmkb379oQnUO6dka1KL68+SZE
14 | 0p9NWB1A8fqbMdJC0s5Ba1g1k1WFoGX/jKULasrrgGWORnxYoykwF2hq
15 | -----END CERTIFICATE-----
16 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Certificates/test_certificate-2048.der:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mastercard/client-encryption-csharp/7c9250c5a0c5f0d0d8520eb2c69e29ae09787a32/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Certificates/test_certificate-2048.der
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Certificates/test_certificate-2048.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDITCCAgmgAwIBAgIJANLIazc8xI4iMA0GCSqGSIb3DQEBBQUAMCcxJTAjBgNV
3 | BAMMHHd3dy5qZWFuLWFsZXhpcy1hdWZhdXZyZS5jb20wHhcNMTkwMjIxMDg1MTM1
4 | WhcNMjkwMjE4MDg1MTM1WjAnMSUwIwYDVQQDDBx3d3cuamVhbi1hbGV4aXMtYXVm
5 | YXV2cmUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9Mp6gEFp
6 | 9E+/1SS5XrUyYKMbE7eU0dyJCfmJPz8YOkOYV7ohqwXQvjlaP/YazZ6bbmYfa2WC
7 | raOpW0o2BYijHgQ7z2a2Az87rKdAtCpZSKFW82Ijnsw++lx7EABI3tFF282ZV7LT
8 | 13n9m4th5Kldukk9euy+TuJqCvPu4xzE/NE+l4LFMr8rfD47EPQkrun5w/TXwkmJ
9 | rdnG9ejl3BLQO06Ns6Bs516geiYZ7RYxtI8Xnu0ZC0fpqDqjCPZBTORkiFeLocEP
10 | RbTgo1H+0xQFNdsMH1/0F1BI+hvdxlbc3+kHZFZFoeBMkR3jC8jDXOXNCMNWb13T
11 | in6HqPReO0KW8wIDAQABo1AwTjAdBgNVHQ4EFgQUDtqNZacrC6wR53kCpw/BfG2C
12 | t3AwHwYDVR0jBBgwFoAUDtqNZacrC6wR53kCpw/BfG2Ct3AwDAYDVR0TBAUwAwEB
13 | /zANBgkqhkiG9w0BAQUFAAOCAQEAJ09tz2BDzSgNOArYtF4lgRtjViKpV7gHVqtc
14 | 3xQT9ujbaxEgaZFPbf7/zYfWZfJggX9T54NTGqo5AXM0l/fz9AZ0bOm03rnF2I/F
15 | /ewhSlHYzvKiPM+YaswaRo1M1UPPgKpLlRDMO0u5LYiU5ICgCNm13TWgjBlzLpP6
16 | U4z2iBNq/RWBgYxypi/8NMYZ1RcCrAVSt3QnW6Gp+vW/HrE7KIlAp1gFdme3Xcx1
17 | vDRpA+MeeEyrnc4UNIqT/4bHGkKlIMKdcjZgrFfEJVFav3eJ4CZ7ZSV6Bx+9yRCL
18 | DPGlRJLISxgwsOTuUmLOxjotRxO8TdR5e1V+skEtfEctMuSVYA==
19 | -----END CERTIFICATE-----
20 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Certificates/test_certificate-4096.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | 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
31 | -----END CERTIFICATE-----
32 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Certificates/test_certificate-512.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIB4TCCAYugAwIBAgIUcINgyQ60WIgYlx6fqrRJlOplzb8wDQYJKoZIhvcNAQEL
3 | BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
4 | GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xOTAzMjgxOTUyMjRaFw0yOTAz
5 | MjUxOTUyMjRaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
6 | HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwXDANBgkqhkiG9w0BAQEF
7 | AANLADBIAkEA2CRwNbQsHDbCGImV33MyrZ+zno11lw/FoziRs3k0kpxYy//XbSY5
8 | StGWqzF03SyWyq+fLEb4P7B4d0RBUVxSfwIDAQABo1MwUTAdBgNVHQ4EFgQUuz7A
9 | dJlXdmbv8xITrsbtg/xU4UQwHwYDVR0jBBgwFoAUuz7AdJlXdmbv8xITrsbtg/xU
10 | 4UQwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAANBABvhfdhBC/8Suhhu
11 | 2kB4kj0FU/8J6oG0MDxT8mT/yFKw1TdQcFGRAwu+Rfc74GsSPQ3JdgjLh8FqSzud
12 | p8kMX50=
13 | -----END CERTIFICATE-----
14 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs1/test_key_pkcs1-1024.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIICXQIBAAKBgQDHul8A7MM3ynx1XRxmLCRZ1Lr66QppWP5ZaEotsQPpFtyq3w/x
3 | dLWZd5XXQcIb/wUQWcbxBWYJPMk/GVQ3pvkIKEqC+h08VdXtfbBlM+RE8OYaQW5O
4 | Fg7YjHgL/WvCka6VJ990RuX9Zdj9TUu8GyqERll/XUDACs85atbSW6PBQQIDAQAB
5 | AoGBAL9acs0LCZn5OLalB6FoJ0edhasA/MWjysRUI8WU898s1SwsXDUEkTxAk2HR
6 | kayK7woUSYL/nhu5jkIS/Vn4clvH7XRkch22cjAAs4oGZXUUlVrcXFDiR0o2OqAI
7 | Xh24ESM/tpDWmn/N30afn31TBAKxgY5Ej2SrmK5gjSeMGI9xAkEA+gPM/P+jLiwy
8 | wuiS4QRYxeDFtluaafl7UHR/I6vL9VaqOptwV1e/JlytKNMCwoMqadd739/BAX9d
9 | qNgpniHC9QJBAMyCZBAc8PIjfM1h4seEDeb2mxl1Y2DmcDUVWIt+E4Zs3m1I59we
10 | VgY/BwX4UIElhgsVjNo6qXYPbWiql4/tzZ0CQQCLJ6RnyO2NXIJgY8yku6Ohd6r0
11 | BeZbR8XwEPdW5l8eTb9v4WZU5vz4oCqtB02I8DKiOJK1F7g4WijKOo5neoklAkBt
12 | G9/w7M/sD9zk4qWQVrboE4faRFPZ/fe9in7sJT6biHf/DFePi6vPt06y87FXxcJH
13 | JZ85SvTgZQi1P9aO1ovNAkAVxgJq94CKCZjOiks5xTro6V0pYdsx0tuuIlx/vGVG
14 | H3bcmpSm/S54nSovzbEDN7gKr4CSSsAQqC6oPwJSQN6m
15 | -----END RSA PRIVATE KEY-----
16 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs1/test_key_pkcs1-2048.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEpQIBAAKCAQEAzCT8ABttdAfW851VVNMSkpgcWZ1yFTgxNu+coPpL8Ug1OZgR
3 | YOgg+fcj/A8MTYs/yXgIJhI1goXVF/9NZPfryrBPxeFIOJe+CGePGMgXv3F7o9uV
4 | 010zcyImgKntv3NrLCVw9trzIIaKNgvwgmPDhegHsWpVMr7Lk2DL5QmPE28J8ekJ
5 | nYfHJzGUSlJYJpCoCVtO7bPPDCcWgrlOzoagTujtpyBRWAPRJoA1J2b7uvzrqmuU
6 | Gf8Yqg8MIeN7Uuxs4jSk3rsDXMCE5cCVKa+bfoTV1XRQJ2PABdNuvwH/wqosRg3Y
7 | TgFdWM46AY4DgIzzqY/xSeLibd1Hzg2wHQTM6wIDAQABAoIBAQDLmjtnk/NXHRaK
8 | RCm9/wHwCRuFWV1VwoR7KQGLH/er/ntvJLZ4cyuogo92Lj/z+uS0eC2QYurRcc81
9 | LuCuygF2VuBJGEXig5z5Xue+LJpaysEojLHia3sL4kyKWHCRWHjUP8dpvLdtgiHI
10 | g6HtObjhDajWjpnIkbgSFiFlHmJ/WqA7IjEOehGiqTjrfyXpL8rbcGt+chJb2z0s
11 | RdlABjl1MT2s9cCHZLwz6x1eDQDDYyw2pRRmEddMZ5VWtAd37I8RWl2NHrMsggca
12 | JzIA5LnddsRqmMVw7+1qFIIK0ZHOTknvvgQ8+U7P+r8v7+3mufvX4JakPingj543
13 | slbOGapBAoGBAO1F4REeKfCpGMo7kWZsAASAkEb+5Fcu4jrEzZkf2jk5WC4zkWlm
14 | SAqay1WLIEGP25LCo0o8vTEfx0tONukJMmEJewVi551Nxz+clcrbiJRcX6P8RTCe
15 | cJtQjUOqwHDvKNNpcAE8zz0YOLotJxhCH5ST3aE07sc159K9EGMzedrhAoGBANxB
16 | vbghMxN7lTuSvxMOwNQOWgKfWzV+fTXLQ7SgFhICqEV67nYHm0r/j9lN2Vtxuh6L
17 | hqZ2r1khzEOhyHz7YBINAYUqjjoFAVUfsHZ7auM7sdQBZx1VwS2XRPglgpso9wEh
18 | TEz75C7LH4/2nu1BIVAduE2cc95wKPEUexps/E1LAoGBAIppxFSvCvpIOpzmyPg9
19 | snjt4rx3vw6Y3AI6glF8Qlo1eJpjHMWmlAoTqOA7K9LzL7zabFVHP3qjtifY9bFV
20 | 2xy+YhSPUNvz3nLeToerL26UwHoyFM667qe8AtxhhKec7Gz/ygX+ykoykg0RgAfn
21 | svKCm7yJ2208pgLKpf+orMIhAoGBALrpMxWRXuW2pzKR2oJSr8KEl0/Iab9gouLG
22 | pqMegvwvsxqbMseItvkTHMB8tupJ/Xa0UsTqzOznqI7wONIPBDztOpAGSAHmg3X4
23 | WWiCXXeODd9qfVXAkxmcWBP4yPfg8JPN7REbZU1sZFFoKQAPmDSDtAZwsUdfiO7k
24 | wX7wY783AoGAQ646bcqPKXmNCc2oo4O4VgcC2afzNuxoUfLgFehVREj/tbhtOpN4
25 | NwhAsQhNz4uh1UmlulKTTGZ67VWikAiQ8ip5HSBMRVT/A4ZCUh5ondU1yVxH6Q0+
26 | eyQ+FF+jTgnAdMp0smLw7yem6HcekksgdNwhDKifFTI13mKWUh8gBew=
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs1/test_key_pkcs1-2048_uneven_length.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEpAIBAAKCAQEAvyWF3MO6BkKPopRSKWHTTutHMd19BrTEhHoR1UDu6T5eJj7M
3 | +/iAFr7+Or7WxykNi7tqZ5HIcLYNbgvxhpaTNATg+gYA975LhixGafjFIR4Npxux
4 | ub4FRiHMQLB9I+xtjPkT5YCK4W0FGq6WAlQdqmbkGA+tPgkwEPTUUzYddsfXExIh
5 | FYAtOUHGnvbpcUUzsAo8VEd2n5b0+BPybC/2CZkNe6DEztVWQmw+/S/7mzE1XMEZ
6 | ECo9blPkuPeZseWtvZQiV1SqPLww0tPzJDT31rZKXcXfF84SMs5VMqBBMgxi3Lqs
7 | SXoGLjVZIq1sZzulw/MfzMf4CnkvptOuHpQUOQIDAQABAoIBAQCNUyno8tGsZS7u
8 | vakNraV1OSGXbcJN3gNaS4K54FuEGje0IUSfm7jgmHARcR4NfH3mbTgbwT6ojwHn
9 | hNTrhJLrqBvK3/uBMLJYTo31NhhSBw1jG2fJBASUONLylUrA78KDs3kRe3uzdk6K
10 | zrBZmM2iOpa0b4rQTiy6rLn7mAwq0Ad59gHMyY63m9wCgKrD12ZFP5x8K56RHxQr
11 | NlqzafqVvboNSQ9XSLat/GgT1aEGcFqXyd1R/3T+wScAX5QkUb4YI2Y5xVlbwxvb
12 | er4s0hMpUAhDte6oRK6AIwCmg+G9WBJEiwZ8u4/5o3QZiBxwgENCXyvEjzBYV1Vi
13 | q9vwcnqtAoGBAPXArBqnJUXtCP1fsEVNJbgCT4HiZxqeZVh345MJLTkm38eBqAKf
14 | 7Lr5RzTDnNlzY2qFqwinDYtD1kC8AcvLPt/MEzApPKC9/8oVi62v0sSdrglzICLg
15 | 7WREwQ9W4dffqiXF12Bev1RDDMAUTXiZnslQlInp4BPuJrpcUplMGjtXAoGBAMcd
16 | 8vpwbfUg3/4VQ+XTOZZKz8tF7KMcpqoWoHZpkv3kawIiVygILp162AKBPCMz/Nmg
17 | k5KNvfef9k3gcSu6D8EMLnec7EUa/FSoMDqjBzI3h+DIrNAVaA2siBVNc9I0KMT7
18 | YxJk5iFR9+oBl/BrLT+Xw3aS7Z0C17lwjuYrYALvAoGAAP5jc8QjQXIg7C1b4Bvc
19 | wC66NZM9yXzEeiQZ9nk+BpIiq4LZtBEDewoRAKSd2L8/sqmRtHpAcsS2K4jp1PIg
20 | cfU4SqSQCzJZe2603uHsH0Fn97/QbHOuYg5pHW/DgAT2giqXoVsguO2AerJaUdeF
21 | Ldk2kIwyjMIUxAIlj1sgbAcCgYBDEbB1cQdoqSEp2YncURC1sg9aHfyAyeNE5ug3
22 | 2onboWP1/RE0d8UT4HwAI/3Ysbs6pt7uX3YcgbIaOz6DhxGlafAA9EeVY2iZL2nH
23 | ZoCXBqNrMM0c7gj1iibwXf1kUZNl/nM5j+kAUjbaiJzgK4m7QOhi+Uy2NW3qlaJc
24 | n0Gg2wKBgQCqWjP97Dwv0nyr3vnM+49B7BL7PYldjIy2RCwHYCN/JwfaihLt+EZ1
25 | ZhCDk9S0aANGjKrZB8bUdGq9DY6cPO4QJjmtfVmdHWT8XIP5mrYbUob4fTvcP1UH
26 | nN/hiGpa1AvhNoU4MQ2OGiK87mBPtfD5nwQh6aNnvglmFUjpL6FaWA==
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs1/test_key_pkcs1-4096.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | 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
51 | -----END RSA PRIVATE KEY-----
52 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs1/test_key_pkcs1-512.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIBOQIBAAJBAOiY+DyTnjyIs41Z9SfqIEV+0BUuDqC4iceBIY98yTTGtlIkb27M
3 | DJjBAW2fhrxyG8Cb74SspmcD4u/mxrm6460CAwEAAQJAbbwViUa/paF8zFg/gAhG
4 | F2Nfuk5TWmIVpoj2k2J07q9W9JeY5sJfLvFwwsMc/vY6FPHGSO0P4sQ3MQHo1zyA
5 | RQIhAPir1/laHualWd5ssAJrvzoK7EtVSnjbuU1tVKBTLwnvAiEA73Paq1U0wO12
6 | DyfRcE+UQ1NwvROLVn0XQA/MAGMj+CMCIDjwMA2aQwUQy1kQjeSgAzMpGR3Os7Sk
7 | qvM9m2jyYwzlAiBrBFJUhI5BM1+yQk9+bHKM7HvUZSm/C8UaYnUAL07iFQIgCLIh
8 | fJ5xPiUD6tO1jn0Kauf1DOlwhDQC10zpOitM8xo=
9 | -----END RSA PRIVATE KEY-----
10 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs12/test_key.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mastercard/client-encryption-csharp/7c9250c5a0c5f0d0d8520eb2c69e29ae09787a32/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs12/test_key.p12
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs8/test_invalid_key.der:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mastercard/client-encryption-csharp/7c9250c5a0c5f0d0d8520eb2c69e29ae09787a32/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs8/test_invalid_key.der
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs8/test_key_pkcs8-1024.der:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mastercard/client-encryption-csharp/7c9250c5a0c5f0d0d8520eb2c69e29ae09787a32/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs8/test_key_pkcs8-1024.der
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs8/test_key_pkcs8-1024.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALCcqlioDdtVqSIW
3 | /Y0PUM0YX5Us76B6VSS5e9LwFeK9g/jsrfGs72WdRxEX1uHTzZXHGimMmmODqv4M
4 | bZ5Qbbs7dCZwSKlqNlSKLx40zwy4xZh1ie/UJ2CgUhu62wXDnUMg4HE0l9oY5g/P
5 | BXvSbuGM87gMnNOk0E+pfWHjQbvlAgMBAAECgYBggfuD3rFTvYdinXWH82qP6FWy
6 | yo9W/gIwwzqqlY8gC7dl+s9CVOGsgTkoWgKN/JNG2Tmuoqpq3rQ9hsUP0Ztj32ty
7 | VfEWqKipDtC0x2xi2D7I25gxVLu521tqLhoaWN1oWdPraflXEkEY9p8CD8tzxc6Q
8 | wi6ShZ8TSacuLvivgQJBAOd/X4iNmmPZ0AY+ZVri4Ic+YXOOapagkXuR2Y5pcRfw
9 | 3jueEwZMIo142L+dFZMDORsqPhFwwCzOcbn2NEID4ckCQQDDTh607HbkvXAwYHDZ
10 | 6gpczrhSAkpjQ0fffOFuF8sI5A64KjnTGte+fm8ic5Mess1oP6LdaS0HvJs4n+m7
11 | nPc9AkEApTwbOmKoQoEjpHFA8wBhducls8+BcQYnEWZnPOkyGf6JAVCxD5ukRgpt
12 | 20cKMSbpyeP67YPnB5RLRIrhfgU7UQJAX3d5NRD9UPR0uYD6yNpJNHJr0NKD0B+c
13 | K1dczjbdLTxlIYqqd1GAsgIViu6ZtIDMPTAWCUqXE1gTO8uXMfkZNQJASgdEiTiI
14 | EnZLto+1hRr/fYNzIJHDelJ2oGtzbRmUtXQ8d489obsZusK2kSPWgX1lzXjvrv07
15 | jznkRk0QtDG8Vw==
16 | -----END PRIVATE KEY-----
17 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs8/test_key_pkcs8-2048.der:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mastercard/client-encryption-csharp/7c9250c5a0c5f0d0d8520eb2c69e29ae09787a32/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs8/test_key_pkcs8-2048.der
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs8/test_key_pkcs8-2048.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD0ynqAQWn0T7/V
3 | JLletTJgoxsTt5TR3IkJ+Yk/Pxg6Q5hXuiGrBdC+OVo/9hrNnptuZh9rZYKto6lb
4 | SjYFiKMeBDvPZrYDPzusp0C0KllIoVbzYiOezD76XHsQAEje0UXbzZlXstPXef2b
5 | i2HkqV26ST167L5O4moK8+7jHMT80T6XgsUyvyt8PjsQ9CSu6fnD9NfCSYmt2cb1
6 | 6OXcEtA7To2zoGznXqB6JhntFjG0jxee7RkLR+moOqMI9kFM5GSIV4uhwQ9FtOCj
7 | Uf7TFAU12wwfX/QXUEj6G93GVtzf6QdkVkWh4EyRHeMLyMNc5c0Iw1ZvXdOKfoeo
8 | 9F47QpbzAgMBAAECggEAK3dMmzuCSdxjTsCPnc6E3H35z914Mm97ceb6RN26OpZI
9 | FcO6OLj2oOBkMxlLFxnDta2yhIpo0tZNuyUJRKBHfov35tLxHNB8kyK7rYIbincD
10 | joHtm0PfJuuG+odiaRY11lrCkLzzOr6xlo4AWu7r8qkQnqQtAqrXc4xu7artG4rf
11 | MIunGnjjWQGzovtey1JgZctO97MU4Wvw18vgYBI6JM4eHJkZxgEhVQblBTKZs4Of
12 | iWk6MRHchgvqnWugwl213FgCzwy9cnyxTP13i9QKaFzL29TYmmN6bRWBH95z41M8
13 | IAa0CGahrSJjudZCFwsFh413YWv/pdqdkKHg1sqseQKBgQD641RYQkMn4G9vOiwB
14 | /is5M0OAhhUdWH1QtB8vvhY5ISTjFMqgIIVQvGmqDDk8QqFMOfFFqLtnArGn8HrK
15 | mBXMpRigS4ae/QgHEz34/RFjNDQ9zxIf/yoCRH5PmnPPU6x8j3bj/vJMRQA6/yng
16 | oca+9qvi3R32AtC5DUELnwyzNwKBgQD5x1iEV+albyCNNyLoT/f6LSH1NVcO+0IO
17 | vIaAVMtfy+hEEXz7izv3/AgcogVZzRARSK0qsQ+4WQN6Q2WG5cQYSyB92PR+Vgwh
18 | nagVvA+QHNDL988xoMhB5r2D2IVSRuTB2EOg7LiWHUHIExaxVkbADODDj7YV2aQC
19 | JVv0gbDQJQKBgQCaABix5Fqci6NbPvXsczvM7K6uoZ8sWDjz5NyPzbqObs3ZpdWK
20 | 3Ot4V270tnQbjTq9M4PqIlyGKp0qXO7ClQAskdq/6hxEU0UuMp2DzLNzlYPLvON/
21 | SH1czvZJnqEfzli+TMHJyaCpOGGf1Si7fhIk/f0cUGYnsCq2rHAU1hhRmQKBgE/B
22 | JTRs1MqyJxSwLEc9cZLCYntnYrr342nNLK1BZgbalvlVFDFFjgpqwTRTT54S6jR6
23 | nkBpdPmKAqBBcOOX7ftL0b4dTkQguZLqQkdeWyHK8aiPIetYyVixkoXM1xUkadqz
24 | cTSrIW1dPiniXnaVc9XSxtnqw1tKuSGuSCRUXN65AoGBAN/AmT1S4PAQpSWufC8N
25 | UJey8S0bURUNNjd52MQ7pWzGq2QC00+dBLkTPj3KOGYpXw9ScZPbxOthBFzHOxER
26 | Wo16AFw3OeRtn4VB1QJ9XvoA/oz4lEhJKbwUfuFGGvSpYvg3vZcOHF2zlvcUu7C0
27 | ub/WhOjV9jZvU5B2Ev8x1neb
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs8/test_key_pkcs8-4096.der:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mastercard/client-encryption-csharp/7c9250c5a0c5f0d0d8520eb2c69e29ae09787a32/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs8/test_key_pkcs8-4096.der
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs8/test_key_pkcs8-4096.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCydHTLH/qEJ2gr
3 | 4EgO/3jE43lJlTbNag1CKSCOVXjh4V0keItReYgk+B7/IOn/UOTj75MRVsXpxyXi
4 | UJW+kwaIX26TLuW3fZVc466ipH1ftrMG0bbB686Tk+TmzAycBQGMLCx7sCzemO+t
5 | VFI+BKgjfOj/bl91HRTEX0ESC6BRUK13gfyQJelOu1OZkV5efHMi4AmDW8jUwOKH
6 | KZ3ZlScm9D0Ghe6CT8i/MY4CgYRvgnEqQUUmd/QnpJJkR7e5m0uWlCDGIf3ZLjbI
7 | gZsVInrSeQ8I/gloZYbZuUhQUdObR56DghuTKr5VWc+huqtVcwcBfEfCP7FIFK9R
8 | 7mqkQmGrW4pbTsBigs9vAzlDmjWQFhXJ0zV2hlABVixqwvOxMEt19gJADfYmFsgv
9 | OWytmjmZCuQgbmjOCdGSqp9UeWGl+U4jbRJTuRsOb5CS1XtUx9drsZJ+YLvFSsvB
10 | 1wXYm7Pt9Rx2v6UfJtLVMtW8q286BPeQ2FFmiPewgPnk1RyeQb1Luw1NuRdvBLHq
11 | 81Ll5HNf6Fd6/ZC9kgwEhcE9LVjTX8HXQmSc8XIjV9uI/wjPyyb5t0hGlrqkXya9
12 | /U86q9v6PXFJ47K0ZW1/+FSzbKCFDNiJI1RWKn9M9CSRPEOKZdNH/lQjSKzCbN9Q
13 | Db8i2T8MLA+6lnt4fwax6KsPMPl4gwIDAQABAoICAA2S8CNXPl35BWJ4/+IsKoqH
14 | Zv1i3TVIwNNsf250L+q2krgodyhuXx24xdrQLRxfkdmIqp4iBJHgtQ/+4zUIx/Ft
15 | mOKXKaAIbGkRZII4ktTJ99on74fWoPL2x+2KTdc8Rj7cSVHrN66C4ZBEnrDa99Mj
16 | ODHdumMVIDRDrpZpzfsBcQBrIcPxLkrv0s8WkKANRVC8y9xzCdatCU4Qq1IWl1DO
17 | OSoa2+aLnRB1+4BTS7iTqnn1VwYzD55IVV5NWjtDBb/hapDHmyB+9GnR+fLkmYUS
18 | 8kLT1/FZ76T2A/sgDkF8dCE6r1BFaw7g8vsxUMECK+FAC9FJuPlroV5RDUmLRxR6
19 | Lgo/glwt3BQi5LvYMA87CEn+hRG1Rh0SgsN2d2EFebPGZF5LJQfgpN/BHB41Sgrs
20 | FCyPoVRR11q72JBVOCUrhS8inuHmR1XFzmhkfj55Yl+RdBSIVYfNQ3JD1p4nRO5E
21 | Rl4POp4jgoYOhPRFr8oZmwnUP8cZNOxNE8ll1yqVXoIM30iscSmCJUI8cngJ1dJ3
22 | ouVVgytcaYETHm7dwAQbgxfb4grxv/S8nloC9rbDPoCujJOeXQHICQwJcTmR/73+
23 | pLzTxMAVV6gJA4stGvCwE2IeTtJsoU3fV5HEhXAuQhIks4B8/SGTBZBoLhShTUqS
24 | Yb0fSHOTubjAirPV8krBAoIBAQDbbwk+zDtIUwqBqT4pVstb/h4+rYQDQL0cNgUq
25 | bioyrr87QtRbtt8XLjCC//+B21OghcYCRMwLulZ706znCfTOmcMPZVuJsbWTk/mC
26 | qt5hM/sFD6z5IMHOdIj7x7Rlhx3akA0HBFy+GZtNmBoQyo6j9h550SdKDIZTfeAY
27 | J7cKcz41uEfNpZgeQgdu9jL+wbh3IaZ9S2IDGQO6pNjfIDiLvqrUTLWrHAcM9s4a
28 | ozFCSBVlIAWXjExhJ3N3/zIA4Mvk2qyU4j6J/g4QvHsAor8sz6vdnWMsMXq0n6aG
29 | 9ntgp94HNbosU3Ko3BHsEJopzcxXn+okM5sWDoMMVgfzDrZhAoIBAQDQMUcyyrn8
30 | sZh6VA2cN8uAPbjkBhzPYYSXpAa7p+jT4CD55+dhwjqjiVX2xxklwj8k4a8dhfFL
31 | MKA10NUH+FviiLEawqpgImysu1FUhxRIS8f8E5X3fxHtQWu70fBZjb3p71rmjhlY
32 | Tr12XeVvJKecG2jal7KwxPuMVLVQAXaRqu+3SE+GLtMv1X+zKSpvEr/CsMXyZ7hT
33 | SGFBdLi447lOLGRN82ZItCqKGxTmT6depN2XRDu13d1OHk4kSpb1YI3lajhsKL7g
34 | vPhd1VJszpbVgN5rADGfQvWzWe2HLKtorkt5Au0rDkEfNdsVLX2tCGQNHZ8yXeco
35 | gTj2wZJGfJFjAoIBAQDKrrcFcDNZzIop1Z97I5ZW9FQPZMpJDuUeR69hz7vecJZm
36 | MIZh6HoLuThJ6BejZGjMHoQU2GL4ejcjzRMpnIKoylHnyKFSf/jNxaJz1Uvu0MqN
37 | lDsbKeyZu/5DQeUY2kLy/Jdr4dWgKZrPgyygUdiLDex8bHoz5Xm1aNEyvoxNdMED
38 | caGxC8GEQU0IaxQTR/AQ6d4UYSq43cQaA+Xlwqc4PPchfXFYCV1h1h3tcMsxA8/v
39 | RjKkFoz+OChpsCgJs5nhWzKJmqhVYXqwbsfWgHzA8Vk4LAXMbi9+4vA4PTccwjFM
40 | y42ZH8MKwas0NumOr26NiUIGCjy3lNPq8xQIp5BBAoIBAQCHdIhuc5gu4R3j+Wwh
41 | h+vPtFjng1KbW0d5oi7/SXAi6mCKOGhDIqwkWuajeUbTWl7bEDtvagZkdW7HlOgG
42 | F4ExEt6oGp/fjIZInFd+N6TqpOOpDtU0AmkXhMkjmqRWn/JAkosCFtJGsnRy3wS4
43 | G5Ex8GN4VdrdSEyiMTsGou0SObVd+p5DH5QoOzCq0M3bFsfNVFZ2MSWsihs9C0Rk
44 | h0W5pwhb71FNXGuRD625a3nqCjpigPKYkZG7kdwloKI3ZGruKP4s4RXQAyNVacYH
45 | JSLeJsqPs8CVbmuOFaSFnnqn0T8prM3ChbO5KsEwNjjeq+bs4akCjDYqFGmLosYZ
46 | NlMhAoIBADqds6s0/8elWPiLZAPrJKI383YzFroXGEXSNVOUQLDK0TNuW+RSQLus
47 | tA6YD7IdqIgYxHL1jk2kZDB1SlGi2+dtTvXrKXcvtbA6p7SprjrIqsGFpOAOBMjB
48 | rt1qcAkLV7QY4B0JnFDYN/MzhsXqrMksUERj0zitdrd8UQkM50BuMqsHOJa57o8o
49 | XJBWTGoeqblS6LvAKA6Hvf59B1iMWFDXZlhMnI0+jXYZcM9E9T6t9w5OrmN3b0kH
50 | zwJVWGAq9g13GpQjl/mLJHL2WG4/3dzVafyb2vy9pIMMp6dCRwLS9n3w5wzxqTrp
51 | FRc4BkVecBOq/WYXqKWZ/tFJ/Ib/uG0=
52 | -----END PRIVATE KEY-----
53 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs8/test_key_pkcs8-512.der:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mastercard/client-encryption-csharp/7c9250c5a0c5f0d0d8520eb2c69e29ae09787a32/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs8/test_key_pkcs8-512.der
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.Tests/Tests/_Resources/Keys/Pkcs8/test_key_pkcs8-512.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEArnaGWuy6JFTryzOL
3 | 5Sj6DxTV9dVwPcPWV3p9ihr33ZGcTR2juFzWGxTQFKMRJg63rr7+ISphxDAepFRf
4 | LDbOKwIDAQABAkADPrsjB9IyiM3V+sB4Y7m6/BU6vFyZGYJsICAjqHrByUKsSXfj
5 | YTf0O8gs/9BNmvx/pl91fWfQS/NqAj1XdVdJAiEA6GJHQUlSvwgGfQrf0rVLWWOA
6 | aBkR+GFwop19oD+6JTUCIQDAMV7aYV3QNOw3krCzHfWJ146TilQzRCLhDJTwjJRx
7 | 3wIgRY/1yINMc8bROmkg6xA+B/oTHBY1HOb+Mo92ZZvt+ukCIFoozu5zLqc1rHqF
8 | fg8Ixt7bGC9ufQFvvU0FsfkGebzRAiBhuLkH4fTAIyDjtTAm0DbJ+80eub5P/qm0
9 | fjESCk2mng==
10 | -----END PRIVATE KEY-----
11 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30406.217
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mastercard.Developer.ClientEncryption.Core", "Mastercard.Developer.ClientEncryption.Core\Mastercard.Developer.ClientEncryption.Core.csproj", "{8FFA4F79-9D2C-4807-BAD7-8E2F0A15E099}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mastercard.Developer.ClientEncryption.RestSharp", "Mastercard.Developer.ClientEncryption.RestSharp\Mastercard.Developer.ClientEncryption.RestSharp.csproj", "{4ABDAD88-8DC4-4463-91EC-74A711D6ACFB}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9FF81251-FD39-4A8E-9092-99D23D1EFFE3}"
11 | ProjectSection(SolutionItems) = preProject
12 | LICENSE = LICENSE
13 | README.md = README.md
14 | EndProjectSection
15 | EndProject
16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mastercard.Developer.ClientEncryption.RestSharpV2", "Mastercard.Developer.ClientEncryption.RestSharpV2\Mastercard.Developer.ClientEncryption.RestSharpV2.csproj", "{BC6F2C72-16A3-44CB-AD68-3ACD8A465640}"
17 | EndProject
18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mastercard.Developer.ClientEncryption.Tests", "Mastercard.Developer.ClientEncryption.Tests\Mastercard.Developer.ClientEncryption.Tests.csproj", "{5F44EDFF-8818-44F0-9A60-8FED8ABC36C0}"
19 | EndProject
20 | Global
21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
22 | Debug|Any CPU = Debug|Any CPU
23 | Release|Any CPU = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
26 | {8FFA4F79-9D2C-4807-BAD7-8E2F0A15E099}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {8FFA4F79-9D2C-4807-BAD7-8E2F0A15E099}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {8FFA4F79-9D2C-4807-BAD7-8E2F0A15E099}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {8FFA4F79-9D2C-4807-BAD7-8E2F0A15E099}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {4ABDAD88-8DC4-4463-91EC-74A711D6ACFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {4ABDAD88-8DC4-4463-91EC-74A711D6ACFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {4ABDAD88-8DC4-4463-91EC-74A711D6ACFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {4ABDAD88-8DC4-4463-91EC-74A711D6ACFB}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {DE07F478-E087-4FAA-80E2-220671C70418}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {DE07F478-E087-4FAA-80E2-220671C70418}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {DE07F478-E087-4FAA-80E2-220671C70418}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {DE07F478-E087-4FAA-80E2-220671C70418}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {BC6F2C72-16A3-44CB-AD68-3ACD8A465640}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {BC6F2C72-16A3-44CB-AD68-3ACD8A465640}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {BC6F2C72-16A3-44CB-AD68-3ACD8A465640}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {BC6F2C72-16A3-44CB-AD68-3ACD8A465640}.Release|Any CPU.Build.0 = Release|Any CPU
42 | {6BDFFEF6-994D-404E-AA54-9D2319CD6776}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43 | {6BDFFEF6-994D-404E-AA54-9D2319CD6776}.Debug|Any CPU.Build.0 = Debug|Any CPU
44 | {6BDFFEF6-994D-404E-AA54-9D2319CD6776}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 | {6BDFFEF6-994D-404E-AA54-9D2319CD6776}.Release|Any CPU.Build.0 = Release|Any CPU
46 | {5F44EDFF-8818-44F0-9A60-8FED8ABC36C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
47 | {5F44EDFF-8818-44F0-9A60-8FED8ABC36C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
48 | {5F44EDFF-8818-44F0-9A60-8FED8ABC36C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
49 | {5F44EDFF-8818-44F0-9A60-8FED8ABC36C0}.Release|Any CPU.Build.0 = Release|Any CPU
50 | EndGlobalSection
51 | GlobalSection(SolutionProperties) = preSolution
52 | HideSolutionNode = FALSE
53 | EndGlobalSection
54 | GlobalSection(ExtensibilityGlobals) = postSolution
55 | SolutionGuid = {0BA6CB82-AD23-4F2E-BEC3-CA02F18DFF99}
56 | EndGlobalSection
57 | EndGlobal
58 |
--------------------------------------------------------------------------------
/Mastercard.Developer.ClientEncryption.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
3 | True
4 | True
5 | True
6 | True
7 | True
8 | True
9 | True
10 | True
11 | True
12 | True
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mastercard/client-encryption-csharp/7c9250c5a0c5f0d0d8520eb2c69e29ae09787a32/icon.png
--------------------------------------------------------------------------------