Skip to content

Commit 1e3bdaa

Browse files
authored
feat: Readonly span support (#252)
# Changes ## Spans buffers and spans Adds new methods that allow passing in a buffer ``` CreatePasswordHash(ReadOnlySpan<char> inputKey, ReadOnlySpan<char> salt, Span<char> outputBuffer, out int outputBufferWritten, HashType hashType = HashType.None, EnhancedHashDelegate enhancedHashKeyGen = null) ``` Adds in buffer zeroing when no longer needed to reduce time in memory. Changed targeting and csproj defined constants to ensure net8 still gains the available support for span that came with the memory package and netstandard support. This could potentially start at 4.7.2 but the netstandard integration was iffy. ## Validate input length (Breaking) If the usage doesn't make use of the enhanced hash generation to retain entropy (aka the standard use) the library will throw when the input to hash length is greater than 72 bytes. This isn't standard behaviour in most bcrypt libraries where truncating silently is the default. But I believe this is necessary, should always have been in place, and will force developers to decide deliberately to truncate input at 72 if they wish to retain existing behaviour. ## Enhanced Hashing V3 * Split 'enhanced' versions into separate classes * Swap func for delegate * Add span based calls Along with switching the func to a bog standard delegate, splitting the enhanced versions into separate classes simplified maintaining the previous versions and adding in the new version. The v3 enhanced hash adds in keyed HMAC which apart from protecting against theorical risks of shucking adds a further uniqueness to the produced key material. ## Experimental SafeString support Hate SafeString, it's filled with lies and was really only a useful feature in Windows. In an API it should never be touched but there are some cases in Windows apps where people still require it to tick a box so I've added a sort of basic implementation This code requires unsafe enabled so will probably be disabled initially. ## SecureEquals check This basically needed to be made for the span handling but also allowed a few minor optimizations which mimic the code in the .net codebase. ## Net 10 We basically try to tag against the lts releases; the code may be updated to target sts between releases to assertain if there is any performance improvement worth having but otherwise its lts. ## Examples The api uses the identity extension to enable bcrypt passwords; chucked in a maui to test performance on android as we've been asked before by people doing the hashing at the device level ## Release Benchmarks Separate project that tests previous nuget package versions; its mostly as a simple way to test for regressions in performance while the other benchmark project is for testing components in a more targeted way. Resolves #211
2 parents 406d644 + d2661f8 commit 1e3bdaa

170 files changed

Lines changed: 7193 additions & 33074 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.codacy.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
exclude_paths:
2+
- ".github/**"
3+
- ".config/**"
4+
- "coverage/**"
5+
- "vendor/**"
6+
- "docs/**"
7+
- "examples/**"
8+
- "assets/**"
9+
- "tests/**"
10+
- "benchmarks/**"

.config/dotnet-tools.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"version": 1,
3+
"isRoot": true,
4+
"tools": {
5+
"dotnet-coverage": {
6+
"version": "18.1.0",
7+
"commands": [
8+
"dotnet-coverage"
9+
],
10+
"rollForward": false
11+
},
12+
"dotnet-stryker": {
13+
"version": "4.12.0",
14+
"commands": [
15+
"dotnet-stryker"
16+
],
17+
"rollForward": false
18+
},
19+
"docfx": {
20+
"version": "2.78.4",
21+
"commands": [
22+
"docfx"
23+
],
24+
"rollForward": false
25+
}
26+
}
27+
}

.editorconfig

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,5 +79,4 @@ csharp_new_line_before_finally = true
7979
csharp_new_line_before_members_in_object_initializers = true
8080
csharp_new_line_before_members_in_anonymous_types = true
8181

82-
83-
file_header_template = /*\nThe MIT License (MIT)\nCopyright (c) 2006 Damien Miller djm@mindrot.org (jBCrypt)\nCopyright (c) 2013 Ryan D. Emerle (.Net port)\nCopyright (c) 2016/2025 Chris McKee (.Net-core port / patches / new features)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files\n(the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,\nmerge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n*/
82+
file_header_template = /*\nThe MIT License (MIT)\nCopyright (c) 2006 Damien Miller djm@mindrot.org (jBCrypt)\nCopyright (c) 2013 Ryan D. Emerle (.Net port)\nCopyright (c) 2016 Chris McKee (.Net-core port / patches / new features)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files\n(the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,\nmerge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n*/

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* @chrismckee

.github/codeql/codeql-config.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
paths:
2+
- 'src'
3+
paths-ignore:
4+
- '**/examples/**'
5+
- '**/benchmarks/**'

.github/dependabot.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,8 @@ updates:
99
update-types: ["version-update:semver-major"]
1010
- dependency-name: "System.Runtime.Caching"
1111
update-types: ["version-update:semver-major"]
12-
reviewers:
13-
- "chrismckee"
1412

1513
- package-ecosystem: "github-actions"
1614
directory: "/"
1715
schedule:
1816
interval: "daily"
19-
reviewers:
20-
- "chrismckee"

.github/workflows/ci-build-pr.yml

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
name: CI PR Build
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches:
7+
- 'main'
8+
paths-ignore:
9+
- 'docs/**'
10+
- '.github/**'
11+
pull_request:
12+
branches:
13+
- 'main'
14+
paths-ignore:
15+
- 'docs/**'
16+
- '.github/**'
17+
18+
19+
permissions:
20+
contents: read
21+
issues: read
22+
pull-requests: write
23+
checks: write
24+
25+
env:
26+
DOTNET_NOLOGO: true
27+
DOTNET_GENERATE_ASPNET_CERTIFICATE: false
28+
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
29+
30+
jobs:
31+
build:
32+
name: Build and Test
33+
runs-on: ubuntu-24.04
34+
steps:
35+
- name: 'Harden Runner'
36+
uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
37+
with:
38+
egress-policy: audit
39+
40+
- name: 'Checkout'
41+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
42+
with:
43+
fetch-depth: 0 # avoid shallow clone so nbgv can do its work.
44+
45+
- name: 'Setup .NET SDK'
46+
uses: actions/setup-dotnet@baa11fbfe1d6520db94683bd5c7a3818018e4309 # v5.1.0
47+
with:
48+
dotnet-version: 10.x
49+
50+
- name: 'Restore external dependencies'
51+
run: dotnet restore
52+
53+
- name: 'Build'
54+
id: build
55+
run: dotnet build --configuration Debug --no-restore
56+
57+
- name: 'Test'
58+
id: test
59+
run: dotnet run --configuration Release --coverage --coverage-output-format cobertura --report-github --project tests/UnitTests/BCrypt.Net.UnitTests.csproj
60+
61+
- name: 'Generate Coverage Reports'
62+
uses: danielpalme/ReportGenerator-GitHub-Action@c4c5175a441c6603ec614f5084386dabe0e2295b # v5.4.12
63+
with:
64+
reports: "tests/**/*.cobertura.xml"
65+
targetdir: "${{ github.workspace }}"
66+
reporttypes: "Cobertura"
67+
verbosity: "Info"
68+
title: "Code Coverage"
69+
tag: "${{ github.run_number }}_${{ github.run_id }}"
70+
toolpath: "reportgeneratortool"
71+
license: ${{ secrets.REPORT_GENERATOR_LICENSE }}
72+
73+
- name: Publish Code Coverage Report
74+
uses: irongut/CodeCoverageSummary@51cc3a756ddcd398d447c044c02cb6aa83fdae95 # v1.3.0
75+
with:
76+
filename: "Cobertura.xml"
77+
badge: true
78+
fail_below_min: false # just informative for now
79+
format: markdown
80+
hide_branch_rate: false
81+
hide_complexity: false
82+
indicators: true
83+
output: both
84+
thresholds: "10 30"
85+
86+
- name: Upload Code Coverage Results
87+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
88+
with:
89+
name: coverage-results
90+
path: |
91+
${{ github.workspace }}/Cobertura.xml
92+
${{ github.workspace }}/code-coverage-results.md
93+
retention-days: 5
94+
95+
- name: Publish Test Results
96+
uses: EnricoMi/publish-unit-test-result-action@afb2984f4d89672b2f9d9c13ae23d53779671984 # v2.19.0
97+
if: always()
98+
with:
99+
files: "tests/**/TestResults.xml"
100+
101+
- name: Upload Test Artifacts
102+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
103+
with:
104+
name: test-results
105+
path: "tests/**/TestResults.xml"
106+
retention-days: 5

.github/workflows/ci-build.yml

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ on:
88
paths-ignore:
99
- 'docs/**'
1010
- '.github/**'
11-
pull_request:
12-
branches:
13-
- 'main'
11+
1412

1513
permissions:
1614
contents: read
@@ -29,19 +27,19 @@ jobs:
2927
runs-on: ubuntu-24.04
3028
steps:
3129
- name: 'Harden Runner'
32-
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
30+
uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
3331
with:
3432
egress-policy: audit
3533

3634
- name: 'Checkout'
37-
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
35+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
3836
with:
3937
fetch-depth: 0 # avoid shallow clone so nbgv can do its work.
4038

4139
- name: 'Setup .NET SDK'
42-
uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
40+
uses: actions/setup-dotnet@baa11fbfe1d6520db94683bd5c7a3818018e4309 # v5.1.0
4341
with:
44-
dotnet-version: 9.0.x
42+
dotnet-version: 10.0.x
4543

4644
- name: 'Restore external dependencies'
4745
run: dotnet restore
@@ -56,14 +54,11 @@ jobs:
5654
name: build-artifacts
5755
path: |
5856
src/**/BCrypt.*.nupkg
59-
src/**/BCrypt.*.dll
60-
src/**/BCrypt.*.deps.json
61-
src/**/BCrypt.*.xml
6257
retention-days: 5
6358

6459
- name: 'Test'
6560
id: test
66-
run: dotnet test --restore --collect:"XPlat Code Coverage" --logger junit --configuration Debug
61+
run: dotnet run --configuration Release --coverage --coverage-output-format cobertura --report-github --project tests/UnitTests/BCrypt.Net.UnitTests.csproj
6762

6863
- name: 'Create test summary'
6964
uses: test-summary/action@31493c76ec9e7aa675f1585d3ed6f1da69269a86 # v2.4
@@ -73,9 +68,9 @@ jobs:
7368
if: always()
7469

7570
- name: 'Generate Coverage Reports'
76-
uses: danielpalme/ReportGenerator-GitHub-Action@cc137d2b561c02b63ae869ffbe8f68af9d904bf4 # 5.4.6
71+
uses: danielpalme/ReportGenerator-GitHub-Action@c4c5175a441c6603ec614f5084386dabe0e2295b # v5.4.12
7772
with:
78-
reports: "tests/**/coverage.cobertura.xml"
73+
reports: "tests/**/*.cobertura.xml"
7974
targetdir: "${{ github.workspace }}"
8075
reporttypes: "Cobertura"
8176
verbosity: "Info"

.github/workflows/ci-manual-build-test-sign.yml

Lines changed: 0 additions & 121 deletions
This file was deleted.

0 commit comments

Comments
 (0)