purecrypt 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. purecrypt-0.1.1/.github/CODEOWNERS +3 -0
  2. purecrypt-0.1.1/.github/dependabot.yml +16 -0
  3. purecrypt-0.1.1/.github/workflows/ci.yml +59 -0
  4. purecrypt-0.1.1/.github/workflows/codeql.yml +35 -0
  5. purecrypt-0.1.1/.github/workflows/dependency-review.yml +22 -0
  6. purecrypt-0.1.1/.github/workflows/release.yml +63 -0
  7. purecrypt-0.1.1/.github/workflows/scorecard.yml +42 -0
  8. purecrypt-0.1.1/.github/workflows/zizmor.yml +28 -0
  9. purecrypt-0.1.1/.gitignore +11 -0
  10. purecrypt-0.1.1/CHANGELOG.md +34 -0
  11. purecrypt-0.1.1/CONTRIBUTING.md +19 -0
  12. purecrypt-0.1.1/LICENSE +12 -0
  13. purecrypt-0.1.1/Makefile +16 -0
  14. purecrypt-0.1.1/PKG-INFO +103 -0
  15. purecrypt-0.1.1/README.md +82 -0
  16. purecrypt-0.1.1/SECURITY.md +6 -0
  17. purecrypt-0.1.1/pyproject.toml +111 -0
  18. purecrypt-0.1.1/src/purecrypt/__init__.py +39 -0
  19. purecrypt-0.1.1/src/purecrypt/_pbes2.py +215 -0
  20. purecrypt-0.1.1/src/purecrypt/_utils.py +51 -0
  21. purecrypt-0.1.1/src/purecrypt/aes.py +449 -0
  22. purecrypt-0.1.1/src/purecrypt/asn1.py +404 -0
  23. purecrypt-0.1.1/src/purecrypt/chacha.py +216 -0
  24. purecrypt-0.1.1/src/purecrypt/ec.py +726 -0
  25. purecrypt-0.1.1/src/purecrypt/eddsa.py +267 -0
  26. purecrypt-0.1.1/src/purecrypt/exceptions.py +38 -0
  27. purecrypt-0.1.1/src/purecrypt/hashes.py +152 -0
  28. purecrypt-0.1.1/src/purecrypt/kdf.py +447 -0
  29. purecrypt-0.1.1/src/purecrypt/pem.py +107 -0
  30. purecrypt-0.1.1/src/purecrypt/py.typed +0 -0
  31. purecrypt-0.1.1/src/purecrypt/rsa.py +794 -0
  32. purecrypt-0.1.1/src/purecrypt/x25519.py +184 -0
  33. purecrypt-0.1.1/src/purecrypt/x509.py +1203 -0
  34. purecrypt-0.1.1/tests/__init__.py +1 -0
  35. purecrypt-0.1.1/tests/data/bundle.pem +66 -0
  36. purecrypt-0.1.1/tests/data/critext_leaf.pem +21 -0
  37. purecrypt-0.1.1/tests/data/critext_leaf_key.pem +28 -0
  38. purecrypt-0.1.1/tests/data/critsan_leaf.pem +22 -0
  39. purecrypt-0.1.1/tests/data/critsan_leaf_key.pem +28 -0
  40. purecrypt-0.1.1/tests/data/ec_leaf.pem +13 -0
  41. purecrypt-0.1.1/tests/data/ec_leaf_key.pem +5 -0
  42. purecrypt-0.1.1/tests/data/ec_root.pem +13 -0
  43. purecrypt-0.1.1/tests/data/ec_root_key.pem +5 -0
  44. purecrypt-0.1.1/tests/data/ed25519_leaf.pem +11 -0
  45. purecrypt-0.1.1/tests/data/ed25519_leaf_key.pem +3 -0
  46. purecrypt-0.1.1/tests/data/ed25519_root.pem +12 -0
  47. purecrypt-0.1.1/tests/data/ed25519_root_key.pem +3 -0
  48. purecrypt-0.1.1/tests/data/expired_leaf.pem +20 -0
  49. purecrypt-0.1.1/tests/data/expired_leaf_key.pem +28 -0
  50. purecrypt-0.1.1/tests/data/expired_root.pem +20 -0
  51. purecrypt-0.1.1/tests/data/expired_root_key.pem +28 -0
  52. purecrypt-0.1.1/tests/data/generate.sh +260 -0
  53. purecrypt-0.1.1/tests/data/ku_leaf.pem +20 -0
  54. purecrypt-0.1.1/tests/data/ku_leaf_key.pem +28 -0
  55. purecrypt-0.1.1/tests/data/ku_root.pem +21 -0
  56. purecrypt-0.1.1/tests/data/ku_root_key.pem +28 -0
  57. purecrypt-0.1.1/tests/data/plain_leaf.pem +20 -0
  58. purecrypt-0.1.1/tests/data/plain_leaf_key.pem +28 -0
  59. purecrypt-0.1.1/tests/data/plain_root.pem +20 -0
  60. purecrypt-0.1.1/tests/data/plain_root_key.pem +28 -0
  61. purecrypt-0.1.1/tests/data/pss_leaf.pem +22 -0
  62. purecrypt-0.1.1/tests/data/pss_leaf_key.pem +28 -0
  63. purecrypt-0.1.1/tests/data/rsa_inter.pem +21 -0
  64. purecrypt-0.1.1/tests/data/rsa_inter_key.pem +28 -0
  65. purecrypt-0.1.1/tests/data/rsa_inter_p0.pem +21 -0
  66. purecrypt-0.1.1/tests/data/rsa_inter_p0_key.pem +28 -0
  67. purecrypt-0.1.1/tests/data/rsa_leaf.der +0 -0
  68. purecrypt-0.1.1/tests/data/rsa_leaf.pem +24 -0
  69. purecrypt-0.1.1/tests/data/rsa_leaf_key.pem +28 -0
  70. purecrypt-0.1.1/tests/data/rsa_leaf_nods.pem +20 -0
  71. purecrypt-0.1.1/tests/data/rsa_leaf_nods_key.pem +28 -0
  72. purecrypt-0.1.1/tests/data/rsa_leaf_nosan.pem +21 -0
  73. purecrypt-0.1.1/tests/data/rsa_leaf_nosan_key.pem +28 -0
  74. purecrypt-0.1.1/tests/data/rsa_root.der +0 -0
  75. purecrypt-0.1.1/tests/data/rsa_root.pem +21 -0
  76. purecrypt-0.1.1/tests/data/rsa_root_key.pem +28 -0
  77. purecrypt-0.1.1/tests/data/rsa_subca.pem +20 -0
  78. purecrypt-0.1.1/tests/data/rsa_subca_key.pem +28 -0
  79. purecrypt-0.1.1/tests/data/rsa_subleaf.pem +20 -0
  80. purecrypt-0.1.1/tests/data/rsa_subleaf_key.pem +28 -0
  81. purecrypt-0.1.1/tests/data/sha1_leaf.pem +20 -0
  82. purecrypt-0.1.1/tests/data/sha1_leaf_key.pem +28 -0
  83. purecrypt-0.1.1/tests/data/untrusted_leaf.pem +20 -0
  84. purecrypt-0.1.1/tests/data/untrusted_leaf_key.pem +28 -0
  85. purecrypt-0.1.1/tests/data/untrusted_root.pem +21 -0
  86. purecrypt-0.1.1/tests/data/untrusted_root_key.pem +28 -0
  87. purecrypt-0.1.1/tests/data/v1_leaf.pem +22 -0
  88. purecrypt-0.1.1/tests/data/v1_leaf_key.pem +28 -0
  89. purecrypt-0.1.1/tests/data/v1_root.pem +18 -0
  90. purecrypt-0.1.1/tests/data/v1_root_key.pem +28 -0
  91. purecrypt-0.1.1/tests/data/zero_serial.pem +20 -0
  92. purecrypt-0.1.1/tests/data/zero_serial_key.pem +28 -0
  93. purecrypt-0.1.1/tests/fixtures/ec_enc.pem +8 -0
  94. purecrypt-0.1.1/tests/fixtures/ec_enc_aes192_sha224.pem +8 -0
  95. purecrypt-0.1.1/tests/fixtures/ec_enc_default_prf.pem +8 -0
  96. purecrypt-0.1.1/tests/fixtures/ec_pkcs8.pem +5 -0
  97. purecrypt-0.1.1/tests/fixtures/generate.sh +26 -0
  98. purecrypt-0.1.1/tests/fixtures/rsa_enc.pem +30 -0
  99. purecrypt-0.1.1/tests/fixtures/rsa_enc_aes128_sha512.pem +30 -0
  100. purecrypt-0.1.1/tests/fixtures/rsa_pkcs8.pem +28 -0
  101. purecrypt-0.1.1/tests/test_aes.py +469 -0
  102. purecrypt-0.1.1/tests/test_asn1.py +260 -0
  103. purecrypt-0.1.1/tests/test_chacha.py +217 -0
  104. purecrypt-0.1.1/tests/test_ec.py +478 -0
  105. purecrypt-0.1.1/tests/test_eddsa.py +154 -0
  106. purecrypt-0.1.1/tests/test_fuzz_asymmetric.py +180 -0
  107. purecrypt-0.1.1/tests/test_fuzz_symmetric.py +127 -0
  108. purecrypt-0.1.1/tests/test_hashes.py +122 -0
  109. purecrypt-0.1.1/tests/test_kdf.py +320 -0
  110. purecrypt-0.1.1/tests/test_pbes2.py +447 -0
  111. purecrypt-0.1.1/tests/test_pem.py +87 -0
  112. purecrypt-0.1.1/tests/test_rsa.py +502 -0
  113. purecrypt-0.1.1/tests/test_x25519.py +116 -0
  114. purecrypt-0.1.1/tests/test_x509.py +893 -0
  115. purecrypt-0.1.1/tests/vectors.py +236 -0
  116. purecrypt-0.1.1/uv.lock +890 -0
@@ -0,0 +1,3 @@
1
+ # SPDX-License-Identifier: 0BSD
2
+
3
+ * @Sudo-Ivan
@@ -0,0 +1,16 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: github-actions
4
+ directory: /
5
+ schedule:
6
+ interval: weekly
7
+ cooldown:
8
+ default-days: 7
9
+ open-pull-requests-limit: 5
10
+ - package-ecosystem: uv
11
+ directory: /
12
+ schedule:
13
+ interval: weekly
14
+ cooldown:
15
+ default-days: 7
16
+ open-pull-requests-limit: 5
@@ -0,0 +1,59 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ schedule:
8
+ - cron: "9 7 * * 1"
9
+
10
+ permissions: {}
11
+
12
+ jobs:
13
+ lint:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
17
+ with:
18
+ egress-policy: audit
19
+
20
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
21
+ with:
22
+ persist-credentials: false
23
+
24
+ - uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
25
+ with:
26
+ version: "0.11.32"
27
+ enable-cache: true
28
+
29
+ - run: uv sync --locked
30
+
31
+ - run: uv run ruff check .
32
+ - run: uv run ruff format --check .
33
+ - run: uv run bandit -r src/
34
+ - run: uv run mypy
35
+ - run: uvx ty check src tests
36
+
37
+ test:
38
+ runs-on: ubuntu-latest
39
+ strategy:
40
+ fail-fast: false
41
+ matrix:
42
+ python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
43
+ steps:
44
+ - uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
45
+ with:
46
+ egress-policy: audit
47
+
48
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
49
+ with:
50
+ persist-credentials: false
51
+
52
+ - uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
53
+ with:
54
+ version: "0.11.32"
55
+ enable-cache: true
56
+
57
+ - run: uv python install ${{ matrix.python }}
58
+ - run: uv sync --locked --python ${{ matrix.python }}
59
+ - run: uv run pytest --cov
@@ -0,0 +1,35 @@
1
+ name: CodeQL
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ schedule:
8
+ - cron: "17 3 * * 4"
9
+
10
+ permissions: {}
11
+
12
+ jobs:
13
+ analyze:
14
+ runs-on: ubuntu-latest
15
+ permissions:
16
+ actions: read
17
+ contents: read
18
+ security-events: write
19
+ steps:
20
+ - uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
21
+ with:
22
+ egress-policy: audit
23
+
24
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
25
+ with:
26
+ persist-credentials: false
27
+
28
+ - uses: github/codeql-action/init@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
29
+ with:
30
+ languages: python
31
+ queries: security-and-quality
32
+
33
+ - uses: github/codeql-action/analyze@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
34
+ with:
35
+ category: "/language:python"
@@ -0,0 +1,22 @@
1
+ name: Dependency Review
2
+
3
+ on:
4
+ pull_request:
5
+
6
+ permissions: {}
7
+
8
+ jobs:
9
+ dependency-review:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: read
13
+ steps:
14
+ - uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
15
+ with:
16
+ egress-policy: audit
17
+
18
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
19
+ with:
20
+ persist-credentials: false
21
+
22
+ - uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
@@ -0,0 +1,63 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ permissions: {}
8
+
9
+ jobs:
10
+ release:
11
+ runs-on: ubuntu-latest
12
+ environment:
13
+ name: pypi
14
+ url: https://pypi.org/p/purecrypt
15
+ permissions:
16
+ contents: write
17
+ id-token: write
18
+ attestations: write
19
+ steps:
20
+ - uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
21
+ with:
22
+ egress-policy: audit
23
+
24
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
25
+ with:
26
+ persist-credentials: false
27
+
28
+ - uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
29
+ with:
30
+ version: "0.11.32"
31
+
32
+ - run: uv sync --locked
33
+
34
+ - name: Verify tag matches package version
35
+ run: |
36
+ tag="${GITHUB_REF_NAME#v}"
37
+ version="$(uv run python -c 'import purecrypt; print(purecrypt.__version__)')"
38
+ if [ "$tag" != "$version" ]; then
39
+ echo "tag $tag does not match package version $version" >&2
40
+ exit 1
41
+ fi
42
+
43
+ - run: uv build
44
+
45
+ - name: Attest build provenance
46
+ uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
47
+ with:
48
+ subject-path: dist/*
49
+
50
+ - uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
51
+ with:
52
+ attestations: true
53
+
54
+ - name: Create GitHub release
55
+ env:
56
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
57
+ run: |
58
+ gh release create "${GITHUB_REF_NAME}" \
59
+ --repo "${GITHUB_REPOSITORY}" \
60
+ --verify-tag \
61
+ --title "${GITHUB_REF_NAME}" \
62
+ --generate-notes \
63
+ dist/*
@@ -0,0 +1,42 @@
1
+ name: OpenSSF Scorecard
2
+
3
+ on:
4
+ branch_protection_rule:
5
+ push:
6
+ branches: [master]
7
+ workflow_dispatch:
8
+ schedule:
9
+ - cron: "42 5 * * 6"
10
+
11
+ permissions: read-all
12
+
13
+ jobs:
14
+ analysis:
15
+ runs-on: ubuntu-latest
16
+ permissions:
17
+ security-events: write
18
+ id-token: write
19
+ steps:
20
+ - uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
21
+ with:
22
+ egress-policy: audit
23
+
24
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
25
+ with:
26
+ persist-credentials: false
27
+
28
+ - uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
29
+ with:
30
+ results_file: results.sarif
31
+ results_format: sarif
32
+ publish_results: true
33
+
34
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
35
+ with:
36
+ name: SARIF file
37
+ path: results.sarif
38
+ retention-days: 5
39
+
40
+ - uses: github/codeql-action/upload-sarif@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
41
+ with:
42
+ sarif_file: results.sarif
@@ -0,0 +1,28 @@
1
+ name: zizmor
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ paths: [.github/**]
7
+ pull_request:
8
+ paths: [.github/**]
9
+
10
+ permissions: {}
11
+
12
+ jobs:
13
+ zizmor:
14
+ runs-on: ubuntu-latest
15
+ permissions:
16
+ security-events: write
17
+ steps:
18
+ - uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
19
+ with:
20
+ egress-policy: audit
21
+
22
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23
+ with:
24
+ persist-credentials: false
25
+
26
+ - uses: zizmorcore/zizmor-action@cc914d7f3750a2d13d75c7f184a1060aa0e9d482 # v0.6.4
27
+ with:
28
+ advanced-security: false
@@ -0,0 +1,11 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ build/
5
+ dist/
6
+ .venv/
7
+ .mypy_cache/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ .coverage*
11
+ htmlcov/
@@ -0,0 +1,34 @@
1
+ # Changelog
2
+
3
+ ## [0.1.1] - Unreleased
4
+
5
+ Fix the release workflow's package-name placeholder. No library
6
+ changes.
7
+
8
+ ## [0.1.0] - Unreleased
9
+
10
+ Initial release. Pure-Python primitives with no dependencies and no
11
+ Rust. See the README security notice: pure Python cannot provide
12
+ constant-time execution, so secret-key operations must not run where a
13
+ co-located attacker can measure timing.
14
+
15
+ - AES-128/192/256 block cipher with ECB, CBC, CTR and GCM (AEAD)
16
+ - ChaCha20, Poly1305, ChaCha20-Poly1305 and XChaCha20-Poly1305
17
+ - Ed25519 signatures (RFC 8032) and X25519/X448 key exchange (RFC 7748)
18
+ - ECDSA and ECDH over P-256, P-384, P-521 and secp256k1 with RFC 6979
19
+ deterministic k
20
+ - RSA key generation, PSS and PKCS#1 v1.5 signatures, OAEP and
21
+ PKCS#1 v1.5 encryption, PKCS#1/PKCS#8/SPKI/SEC1 serialization
22
+ - Encrypted PKCS#8 (RFC 5958) via PBES2 with PBKDF2-HMAC and AES-CBC
23
+ - X.509 certificate parsing and validation (RFC 5280): chain building,
24
+ signature verification for RSA/ECDSA/Ed25519, critical-extension
25
+ policy, and RFC 6125 hostname matching
26
+ - HKDF, PBKDF2, scrypt and Argon2id
27
+ - Minimal strict DER and PEM codecs for keys and certificates
28
+ - Hash and HMAC facades over hashlib
29
+
30
+ Side-channel hardening: RSA private operations blinded with a random
31
+ factor and verified against the public exponent before release, fixed
32
+ iteration scalar multiplication with mask-selected adds on all curves,
33
+ mask-arithmetic Montgomery cswap, uniform full-buffer padding scans,
34
+ and constant-time-style comparisons on all secret-derived values.
@@ -0,0 +1,19 @@
1
+ # Contributing
2
+
3
+ Report bugs through GitHub issues. Security reports go to
4
+ security@quad4.io (see SECURITY.md).
5
+
6
+ ## Setup
7
+
8
+ uv sync
9
+ make check
10
+
11
+ `make check` runs the full local gate: ruff lint and format, bandit,
12
+ mypy strict, ty, and pytest with coverage.
13
+
14
+ ## Conventions
15
+
16
+ - No runtime dependencies unless the project genuinely needs one.
17
+ - Source files start with the SPDX license identifier.
18
+ - Public API changes need tests.
19
+ - Commit messages: short, imperative, formal.
@@ -0,0 +1,12 @@
1
+ Copyright (c) 2026 Quad4
2
+
3
+ Permission to use, copy, modify, and/or distribute this software for any purpose
4
+ with or without fee is hereby granted.
5
+
6
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
7
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
8
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
9
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
10
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
11
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
12
+ PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,16 @@
1
+ .PHONY: check lint test build
2
+
3
+ check: lint test
4
+
5
+ lint:
6
+ uv run ruff check .
7
+ uv run ruff format --check .
8
+ uv run bandit -r src/
9
+ uv run mypy
10
+ uvx ty check src tests
11
+
12
+ test:
13
+ uv run pytest --cov --cov-report=term-missing
14
+
15
+ build:
16
+ uv build
@@ -0,0 +1,103 @@
1
+ Metadata-Version: 2.5
2
+ Name: purecrypt
3
+ Version: 0.1.1
4
+ Summary: Pure-Python cryptographic primitives. No dependencies, no Rust. NOT READY FOR PRODUCTION.
5
+ Project-URL: Homepage, https://quad4.io
6
+ Project-URL: Repository, https://github.com/Quad4-Software/python-library-template
7
+ Project-URL: Issues, https://github.com/Quad4-Software/python-library-template/issues
8
+ Project-URL: Changelog, https://github.com/Quad4-Software/python-library-template/blob/master/CHANGELOG.md
9
+ Author: Quad4
10
+ License-Expression: 0BSD
11
+ License-File: LICENSE
12
+ Keywords: aes,chacha20,cryptography,ed25519,pure-python,rsa
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: BSD License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+
22
+ # purecrypt
23
+
24
+ [![CI](https://github.com/Quad4-Software/purecrypt/actions/workflows/ci.yml/badge.svg)](https://github.com/Quad4-Software/purecrypt/actions/workflows/ci.yml)
25
+ [![CodeQL](https://github.com/Quad4-Software/purecrypt/actions/workflows/codeql.yml/badge.svg)](https://github.com/Quad4-Software/purecrypt/actions/workflows/codeql.yml)
26
+ [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/Quad4-Software/purecrypt/badge)](https://securityscorecards.dev/viewer/?uri=github.com/Quad4-Software/purecrypt)
27
+ [![PyPI](https://img.shields.io/pypi/v/purecrypt.svg)](https://pypi.org/project/purecrypt/)
28
+ [![License: 0BSD](https://img.shields.io/badge/license-0BSD-blue)](LICENSE)
29
+
30
+ > **Security notice.** Pure Python cannot provide constant-time
31
+ > execution. Secret-key operations (signing, decryption, key exchange)
32
+ > are hardened against the obvious leaks: RSA blinding, fixed-iteration
33
+ > scalar multiplication with mask-selected adds, uniform error paths,
34
+ > and constant-time-style comparisons. Residual timing variance in the
35
+ > interpreter remains, so do not run secret-key operations where a
36
+ > co-located attacker can measure timing. Public-data operations such
37
+ > as certificate validation and signature verification are unaffected.
38
+ > For high-assurance deployments use audited native implementations
39
+ > such as `cryptography` (OpenSSL) or `PyNaCl` (libsodium).
40
+
41
+ Pure-Python cryptographic primitives for Python 3.10+. No
42
+ dependencies, no Rust, no C extensions: only `hashlib`, `hmac` and
43
+ `secrets` from the standard library.
44
+
45
+ ## Install
46
+
47
+ pip install purecrypt
48
+
49
+ ## Contents
50
+
51
+ - AES-128/192/256 with ECB, CBC, CTR and GCM (AEAD)
52
+ - ChaCha20, Poly1305, ChaCha20-Poly1305 and XChaCha20-Poly1305
53
+ - Ed25519 signatures and X25519 key exchange
54
+ - ECDSA and ECDH over P-256, P-384, P-521 and secp256k1 (RFC 6979
55
+ deterministic signatures)
56
+ - RSA: key generation, PSS and PKCS#1 v1.5 signatures, OAEP and
57
+ PKCS#1 v1.5 encryption, PKCS#1/PKCS#8/SPKI serialization, encrypted
58
+ PKCS#8 (PBES2/AES-CBC)
59
+ - X.509 certificate parsing, signature verification, RFC 5280 chain
60
+ validation and RFC 6125 hostname matching
61
+ - HKDF, PBKDF2, scrypt and Argon2id
62
+ - Minimal DER/PEM handling for key serialization
63
+ - SHA-2, SHA-3, SHAKE, BLAKE2 and HMAC facades over hashlib
64
+
65
+ ## Example
66
+
67
+ ```python
68
+ from purecrypt.aes import gcm_decrypt, gcm_encrypt
69
+ from purecrypt.eddsa import Ed25519PrivateKey
70
+ from purecrypt.x509 import Certificate, validate_chain, verify_hostname
71
+
72
+ key, nonce = b"k" * 32, b"n" * 12
73
+ ct, tag = gcm_encrypt(key, nonce, b"secret", aad=b"hdr")
74
+ assert gcm_decrypt(key, nonce, ct, tag, aad=b"hdr") == b"secret"
75
+
76
+ priv = Ed25519PrivateKey.generate()
77
+ sig = priv.sign(b"message")
78
+ priv.public_key().verify(sig, b"message")
79
+
80
+ leaf = Certificate.from_pem(pem_text)
81
+ validate_chain(leaf, intermediates, trust_roots)
82
+ verify_hostname(leaf, "example.com")
83
+ ```
84
+
85
+ ## Known limitations
86
+
87
+ - No constant-time guarantees. Python semantics preclude them.
88
+ - Secret zeroization is best-effort (mutable buffers are wiped where
89
+ practical, but interpreter copies are out of scope).
90
+ - RSA PKCS#1 v1.5 decryption is inherently Bleichenbacher-prone. Use
91
+ OAEP.
92
+ - X.509 validation covers RFC 5280 path rules and RFC 6125 hostnames,
93
+ but there is no revocation checking (no CRL or OCSP) and no name or
94
+ policy constraint enforcement. A critical extension whose semantics
95
+ are not enforced fails validation.
96
+ - No TLS. That is a different and much larger problem.
97
+
98
+ ## Development
99
+
100
+ uv sync --group dev
101
+ make check
102
+
103
+ License: 0BSD. Quad4 Software, https://quad4.io
@@ -0,0 +1,82 @@
1
+ # purecrypt
2
+
3
+ [![CI](https://github.com/Quad4-Software/purecrypt/actions/workflows/ci.yml/badge.svg)](https://github.com/Quad4-Software/purecrypt/actions/workflows/ci.yml)
4
+ [![CodeQL](https://github.com/Quad4-Software/purecrypt/actions/workflows/codeql.yml/badge.svg)](https://github.com/Quad4-Software/purecrypt/actions/workflows/codeql.yml)
5
+ [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/Quad4-Software/purecrypt/badge)](https://securityscorecards.dev/viewer/?uri=github.com/Quad4-Software/purecrypt)
6
+ [![PyPI](https://img.shields.io/pypi/v/purecrypt.svg)](https://pypi.org/project/purecrypt/)
7
+ [![License: 0BSD](https://img.shields.io/badge/license-0BSD-blue)](LICENSE)
8
+
9
+ > **Security notice.** Pure Python cannot provide constant-time
10
+ > execution. Secret-key operations (signing, decryption, key exchange)
11
+ > are hardened against the obvious leaks: RSA blinding, fixed-iteration
12
+ > scalar multiplication with mask-selected adds, uniform error paths,
13
+ > and constant-time-style comparisons. Residual timing variance in the
14
+ > interpreter remains, so do not run secret-key operations where a
15
+ > co-located attacker can measure timing. Public-data operations such
16
+ > as certificate validation and signature verification are unaffected.
17
+ > For high-assurance deployments use audited native implementations
18
+ > such as `cryptography` (OpenSSL) or `PyNaCl` (libsodium).
19
+
20
+ Pure-Python cryptographic primitives for Python 3.10+. No
21
+ dependencies, no Rust, no C extensions: only `hashlib`, `hmac` and
22
+ `secrets` from the standard library.
23
+
24
+ ## Install
25
+
26
+ pip install purecrypt
27
+
28
+ ## Contents
29
+
30
+ - AES-128/192/256 with ECB, CBC, CTR and GCM (AEAD)
31
+ - ChaCha20, Poly1305, ChaCha20-Poly1305 and XChaCha20-Poly1305
32
+ - Ed25519 signatures and X25519 key exchange
33
+ - ECDSA and ECDH over P-256, P-384, P-521 and secp256k1 (RFC 6979
34
+ deterministic signatures)
35
+ - RSA: key generation, PSS and PKCS#1 v1.5 signatures, OAEP and
36
+ PKCS#1 v1.5 encryption, PKCS#1/PKCS#8/SPKI serialization, encrypted
37
+ PKCS#8 (PBES2/AES-CBC)
38
+ - X.509 certificate parsing, signature verification, RFC 5280 chain
39
+ validation and RFC 6125 hostname matching
40
+ - HKDF, PBKDF2, scrypt and Argon2id
41
+ - Minimal DER/PEM handling for key serialization
42
+ - SHA-2, SHA-3, SHAKE, BLAKE2 and HMAC facades over hashlib
43
+
44
+ ## Example
45
+
46
+ ```python
47
+ from purecrypt.aes import gcm_decrypt, gcm_encrypt
48
+ from purecrypt.eddsa import Ed25519PrivateKey
49
+ from purecrypt.x509 import Certificate, validate_chain, verify_hostname
50
+
51
+ key, nonce = b"k" * 32, b"n" * 12
52
+ ct, tag = gcm_encrypt(key, nonce, b"secret", aad=b"hdr")
53
+ assert gcm_decrypt(key, nonce, ct, tag, aad=b"hdr") == b"secret"
54
+
55
+ priv = Ed25519PrivateKey.generate()
56
+ sig = priv.sign(b"message")
57
+ priv.public_key().verify(sig, b"message")
58
+
59
+ leaf = Certificate.from_pem(pem_text)
60
+ validate_chain(leaf, intermediates, trust_roots)
61
+ verify_hostname(leaf, "example.com")
62
+ ```
63
+
64
+ ## Known limitations
65
+
66
+ - No constant-time guarantees. Python semantics preclude them.
67
+ - Secret zeroization is best-effort (mutable buffers are wiped where
68
+ practical, but interpreter copies are out of scope).
69
+ - RSA PKCS#1 v1.5 decryption is inherently Bleichenbacher-prone. Use
70
+ OAEP.
71
+ - X.509 validation covers RFC 5280 path rules and RFC 6125 hostnames,
72
+ but there is no revocation checking (no CRL or OCSP) and no name or
73
+ policy constraint enforcement. A critical extension whose semantics
74
+ are not enforced fails validation.
75
+ - No TLS. That is a different and much larger problem.
76
+
77
+ ## Development
78
+
79
+ uv sync --group dev
80
+ make check
81
+
82
+ License: 0BSD. Quad4 Software, https://quad4.io
@@ -0,0 +1,6 @@
1
+ # Security policy
2
+
3
+ Only the latest release is supported.
4
+
5
+ Report vulnerabilities to security@quad4.io. Do not open public issues for
6
+ security reports.
@@ -0,0 +1,111 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "purecrypt"
7
+ dynamic = ["version"]
8
+ description = "Pure-Python cryptographic primitives. No dependencies, no Rust. NOT READY FOR PRODUCTION."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "0BSD"
12
+ authors = [{ name = "Quad4" }]
13
+ keywords = ["cryptography", "aes", "chacha20", "ed25519", "rsa", "pure-python"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: BSD License",
18
+ "Operating System :: OS Independent",
19
+ "Programming Language :: Python :: 3",
20
+ "Typing :: Typed",
21
+ ]
22
+ dependencies = []
23
+
24
+ [project.urls]
25
+ Homepage = "https://quad4.io"
26
+ Repository = "https://github.com/Quad4-Software/python-library-template"
27
+ Issues = "https://github.com/Quad4-Software/python-library-template/issues"
28
+ Changelog = "https://github.com/Quad4-Software/python-library-template/blob/master/CHANGELOG.md"
29
+
30
+ [tool.hatch.version]
31
+ path = "src/purecrypt/__init__.py"
32
+
33
+ [dependency-groups]
34
+ dev = [
35
+ "pytest>=9.1.1",
36
+ "pytest-cov>=7.1.0",
37
+ "ruff>=0.16.8",
38
+ "bandit>=1.9.4",
39
+ "mypy>=2.3.1",
40
+ "hypothesis>=6.168.0",
41
+ "ty>=0.0.83",
42
+ ]
43
+
44
+ [tool.ruff]
45
+ target-version = "py310"
46
+ src = ["src", "tests"]
47
+
48
+ [tool.ruff.lint]
49
+ select = [
50
+ "E", "W", # pycodestyle
51
+ "F", # pyflakes
52
+ "I", # isort
53
+ "N", # pep8-naming
54
+ "UP", # pyupgrade
55
+ "YTT", # sys.version misuse
56
+ "FA", # future annotations
57
+ "A", # builtins shadowing
58
+ "B", # flake8-bugbear
59
+ "BLE", # blind except
60
+ "C4", # comprehensions
61
+ "C90", # mccabe complexity
62
+ "DTZ", # timezone-aware datetimes
63
+ "ERA", # commented-out code
64
+ "FURB", # refurb
65
+ "G", # logging format
66
+ "ICN", # import conventions
67
+ "ISC", # implicit string concat
68
+ "LOG", # logging
69
+ "PERF", # perflint
70
+ "PGH", # pygrep hooks
71
+ "PIE", # misc lints
72
+ "PT", # pytest style
73
+ "PTH", # pathlib
74
+ "RET", # return
75
+ "RSE", # raise/return
76
+ "S", # bandit rules
77
+ "SIM", # simplify
78
+ "SLOT", # __slots__
79
+ "T20", # print
80
+ "TRY", # exception handling
81
+ "RUF", # ruff-specific
82
+ ]
83
+ ignore = [
84
+ "ISC001", # single-line implicit concat conflicts with the formatter
85
+ "TRY003", # long messages in raise calls are fine
86
+ ]
87
+
88
+ [tool.ruff.lint.per-file-ignores]
89
+ "tests/*" = ["S101", "S603"]
90
+ # Names intentionally mirror the cryptography package's exception API.
91
+ "src/purecrypt/exceptions.py" = ["N818"]
92
+
93
+ [tool.mypy]
94
+ strict = true
95
+ files = ["src", "tests"]
96
+
97
+ [tool.bandit]
98
+ exclude_dirs = ["tests"]
99
+
100
+ [tool.coverage.run]
101
+ branch = true
102
+ source = ["src/purecrypt"]
103
+
104
+ [tool.coverage.report]
105
+ show_missing = true
106
+ fail_under = 80
107
+
108
+ [tool.pytest.ini_options]
109
+ testpaths = ["tests"]
110
+ xfail_strict = true
111
+ filterwarnings = ["error"]