swarmauri_crypto_paramiko 0.3.0.dev4__tar.gz → 0.3.0.dev32__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.
- {swarmauri_crypto_paramiko-0.3.0.dev4 → swarmauri_crypto_paramiko-0.3.0.dev32}/PKG-INFO +73 -9
- {swarmauri_crypto_paramiko-0.3.0.dev4 → swarmauri_crypto_paramiko-0.3.0.dev32}/README.md +64 -4
- {swarmauri_crypto_paramiko-0.3.0.dev4 → swarmauri_crypto_paramiko-0.3.0.dev32}/pyproject.toml +13 -2
- {swarmauri_crypto_paramiko-0.3.0.dev4 → swarmauri_crypto_paramiko-0.3.0.dev32}/swarmauri_crypto_paramiko/ParamikoCrypto.py +159 -22
- {swarmauri_crypto_paramiko-0.3.0.dev4 → swarmauri_crypto_paramiko-0.3.0.dev32}/LICENSE +0 -0
- {swarmauri_crypto_paramiko-0.3.0.dev4 → swarmauri_crypto_paramiko-0.3.0.dev32}/swarmauri_crypto_paramiko/__init__.py +0 -0
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: swarmauri_crypto_paramiko
|
|
3
|
-
Version: 0.3.0.
|
|
3
|
+
Version: 0.3.0.dev32
|
|
4
4
|
Summary: Paramiko-backed RSA + AES-GCM crypto provider for Swarmauri
|
|
5
|
-
License: Apache-2.0
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: swarmauri,sdk,standards,crypto,paramiko,cryptography
|
|
8
|
+
Author: Jacob Stewart
|
|
9
|
+
Author-email: jacob@swarmauri.com
|
|
8
10
|
Requires-Python: >=3.10,<3.13
|
|
9
11
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
12
|
Classifier: Natural Language :: English
|
|
@@ -15,13 +17,16 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
15
17
|
Classifier: Development Status :: 3 - Alpha
|
|
16
18
|
Classifier: Topic :: Security :: Cryptography
|
|
17
19
|
Classifier: Intended Audience :: Developers
|
|
20
|
+
Classifier: Programming Language :: Python
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
23
|
Requires-Dist: cryptography (>=41)
|
|
19
24
|
Requires-Dist: paramiko (>=3.4)
|
|
20
25
|
Requires-Dist: swarmauri_base
|
|
21
26
|
Requires-Dist: swarmauri_core
|
|
22
27
|
Description-Content-Type: text/markdown
|
|
23
28
|
|
|
24
|
-

|
|
25
30
|
|
|
26
31
|
<p align="center">
|
|
27
32
|
<a href="https://pypi.org/project/swarmauri_crypto_paramiko/">
|
|
@@ -40,16 +45,39 @@ Description-Content-Type: text/markdown
|
|
|
40
45
|
|
|
41
46
|
## Swarmauri Crypto Paramiko
|
|
42
47
|
|
|
43
|
-
Paramiko-backed crypto provider implementing the `ICrypto` contract via
|
|
48
|
+
Paramiko-backed crypto provider implementing the `ICrypto` contract via
|
|
49
|
+
`CryptoBase`. Built on top of [`paramiko`](https://www.paramiko.org/) and
|
|
50
|
+
[`cryptography`](https://cryptography.io/), it exposes an asynchronous API for
|
|
51
|
+
several cryptographic primitives using OpenSSH-formatted public keys and
|
|
52
|
+
PEM-encoded private keys supplied through `KeyRef` objects.
|
|
44
53
|
|
|
45
|
-
|
|
46
|
-
|
|
54
|
+
### Features
|
|
55
|
+
|
|
56
|
+
- AES-256-GCM symmetric encrypt/decrypt (16/24/32 byte keys)
|
|
57
|
+
- RSA-OAEP(SHA-256) wrap/unwrap for OpenSSH RSA key pairs
|
|
58
|
+
- AES-256-GCM key wrap/unwrap when the KEK is symmetric
|
|
59
|
+
- RSA-OAEP(SHA-256) sealing for small payloads
|
|
47
60
|
- Multi-recipient hybrid envelopes using OpenSSH public keys
|
|
48
61
|
|
|
62
|
+
Keys are represented by `KeyRef` objects. Public keys should be provided in
|
|
63
|
+
OpenSSH format via `KeyRef.public`, while private keys are supplied as
|
|
64
|
+
PEM-encoded bytes in `KeyRef.material`. RSA sealing is limited to inputs no
|
|
65
|
+
larger than the modulus-dependent RSA-OAEP bound (`modulus_bytes - 2 * hash_len
|
|
66
|
+
- 2`). For larger payloads use the hybrid envelope mode instead.
|
|
67
|
+
|
|
49
68
|
## Installation
|
|
50
69
|
|
|
70
|
+
Choose the tool that matches your workflow:
|
|
71
|
+
|
|
51
72
|
```bash
|
|
73
|
+
# pip
|
|
52
74
|
pip install swarmauri_crypto_paramiko
|
|
75
|
+
|
|
76
|
+
# Poetry
|
|
77
|
+
poetry add swarmauri_crypto_paramiko
|
|
78
|
+
|
|
79
|
+
# uv
|
|
80
|
+
uv add swarmauri_crypto_paramiko
|
|
53
81
|
```
|
|
54
82
|
|
|
55
83
|
## Usage
|
|
@@ -106,13 +134,49 @@ wrapped = await crypto.wrap(recipient)
|
|
|
106
134
|
unwrapped = await crypto.unwrap(recipient, wrapped)
|
|
107
135
|
```
|
|
108
136
|
|
|
137
|
+
To wrap with a symmetric key-encryption key instead, provide the AES key bytes
|
|
138
|
+
in `KeyRef.material` and set `wrap_alg="AES-256-GCM"`:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
sym_kek = KeyRef(
|
|
142
|
+
kid="kek1",
|
|
143
|
+
version=1,
|
|
144
|
+
type=KeyType.SYMMETRIC,
|
|
145
|
+
uses=(KeyUse.WRAP, KeyUse.UNWRAP),
|
|
146
|
+
export_policy=ExportPolicy.SECRET_WHEN_ALLOWED,
|
|
147
|
+
material=b"\x01" * 32,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
wrapped = await crypto.wrap(sym_kek, wrap_alg="AES-256-GCM")
|
|
151
|
+
plaintext_key = await crypto.unwrap(sym_kek, wrapped)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### RSA Sealing for Small Payloads
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
# Using the `recipient` defined above
|
|
158
|
+
sealed = await crypto.seal(recipient, b"tiny secret")
|
|
159
|
+
plaintext = await crypto.unseal(recipient, sealed)
|
|
160
|
+
```
|
|
161
|
+
|
|
109
162
|
### Hybrid Envelope for Multiple Recipients
|
|
110
163
|
|
|
111
164
|
```python
|
|
112
165
|
env = await crypto.encrypt_for_many([recipient], b"secret")
|
|
113
166
|
```
|
|
114
167
|
|
|
168
|
+
Calling `encrypt_for_many` without overrides produces an AES-256-GCM ciphertext
|
|
169
|
+
shared by every recipient, while `env.recipients` holds RSA-OAEP-wrapped
|
|
170
|
+
session keys. Use `enc_alg="RSA-OAEP-SHA256-SEAL"` to emit individual RSA-OAEP
|
|
171
|
+
sealed payloads instead of a shared ciphertext when the plaintext fits within
|
|
172
|
+
the sealing size limit.
|
|
173
|
+
|
|
115
174
|
## Entry point
|
|
116
175
|
|
|
117
176
|
The provider is registered under the `swarmauri.cryptos` entry-point as `ParamikoCrypto`.
|
|
118
177
|
|
|
178
|
+
## Want to help?
|
|
179
|
+
|
|
180
|
+
If you want to contribute to swarmauri-sdk, read up on our
|
|
181
|
+
[guidelines for contributing](https://github.com/swarmauri/swarmauri-sdk/blob/master/CONTRIBUTING.md)
|
|
182
|
+
that will help you get started.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-

|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
4
|
<a href="https://pypi.org/project/swarmauri_crypto_paramiko/">
|
|
@@ -17,16 +17,39 @@
|
|
|
17
17
|
|
|
18
18
|
## Swarmauri Crypto Paramiko
|
|
19
19
|
|
|
20
|
-
Paramiko-backed crypto provider implementing the `ICrypto` contract via
|
|
20
|
+
Paramiko-backed crypto provider implementing the `ICrypto` contract via
|
|
21
|
+
`CryptoBase`. Built on top of [`paramiko`](https://www.paramiko.org/) and
|
|
22
|
+
[`cryptography`](https://cryptography.io/), it exposes an asynchronous API for
|
|
23
|
+
several cryptographic primitives using OpenSSH-formatted public keys and
|
|
24
|
+
PEM-encoded private keys supplied through `KeyRef` objects.
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
### Features
|
|
27
|
+
|
|
28
|
+
- AES-256-GCM symmetric encrypt/decrypt (16/24/32 byte keys)
|
|
29
|
+
- RSA-OAEP(SHA-256) wrap/unwrap for OpenSSH RSA key pairs
|
|
30
|
+
- AES-256-GCM key wrap/unwrap when the KEK is symmetric
|
|
31
|
+
- RSA-OAEP(SHA-256) sealing for small payloads
|
|
24
32
|
- Multi-recipient hybrid envelopes using OpenSSH public keys
|
|
25
33
|
|
|
34
|
+
Keys are represented by `KeyRef` objects. Public keys should be provided in
|
|
35
|
+
OpenSSH format via `KeyRef.public`, while private keys are supplied as
|
|
36
|
+
PEM-encoded bytes in `KeyRef.material`. RSA sealing is limited to inputs no
|
|
37
|
+
larger than the modulus-dependent RSA-OAEP bound (`modulus_bytes - 2 * hash_len
|
|
38
|
+
- 2`). For larger payloads use the hybrid envelope mode instead.
|
|
39
|
+
|
|
26
40
|
## Installation
|
|
27
41
|
|
|
42
|
+
Choose the tool that matches your workflow:
|
|
43
|
+
|
|
28
44
|
```bash
|
|
45
|
+
# pip
|
|
29
46
|
pip install swarmauri_crypto_paramiko
|
|
47
|
+
|
|
48
|
+
# Poetry
|
|
49
|
+
poetry add swarmauri_crypto_paramiko
|
|
50
|
+
|
|
51
|
+
# uv
|
|
52
|
+
uv add swarmauri_crypto_paramiko
|
|
30
53
|
```
|
|
31
54
|
|
|
32
55
|
## Usage
|
|
@@ -83,12 +106,49 @@ wrapped = await crypto.wrap(recipient)
|
|
|
83
106
|
unwrapped = await crypto.unwrap(recipient, wrapped)
|
|
84
107
|
```
|
|
85
108
|
|
|
109
|
+
To wrap with a symmetric key-encryption key instead, provide the AES key bytes
|
|
110
|
+
in `KeyRef.material` and set `wrap_alg="AES-256-GCM"`:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
sym_kek = KeyRef(
|
|
114
|
+
kid="kek1",
|
|
115
|
+
version=1,
|
|
116
|
+
type=KeyType.SYMMETRIC,
|
|
117
|
+
uses=(KeyUse.WRAP, KeyUse.UNWRAP),
|
|
118
|
+
export_policy=ExportPolicy.SECRET_WHEN_ALLOWED,
|
|
119
|
+
material=b"\x01" * 32,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
wrapped = await crypto.wrap(sym_kek, wrap_alg="AES-256-GCM")
|
|
123
|
+
plaintext_key = await crypto.unwrap(sym_kek, wrapped)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### RSA Sealing for Small Payloads
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
# Using the `recipient` defined above
|
|
130
|
+
sealed = await crypto.seal(recipient, b"tiny secret")
|
|
131
|
+
plaintext = await crypto.unseal(recipient, sealed)
|
|
132
|
+
```
|
|
133
|
+
|
|
86
134
|
### Hybrid Envelope for Multiple Recipients
|
|
87
135
|
|
|
88
136
|
```python
|
|
89
137
|
env = await crypto.encrypt_for_many([recipient], b"secret")
|
|
90
138
|
```
|
|
91
139
|
|
|
140
|
+
Calling `encrypt_for_many` without overrides produces an AES-256-GCM ciphertext
|
|
141
|
+
shared by every recipient, while `env.recipients` holds RSA-OAEP-wrapped
|
|
142
|
+
session keys. Use `enc_alg="RSA-OAEP-SHA256-SEAL"` to emit individual RSA-OAEP
|
|
143
|
+
sealed payloads instead of a shared ciphertext when the plaintext fits within
|
|
144
|
+
the sealing size limit.
|
|
145
|
+
|
|
92
146
|
## Entry point
|
|
93
147
|
|
|
94
148
|
The provider is registered under the `swarmauri.cryptos` entry-point as `ParamikoCrypto`.
|
|
149
|
+
|
|
150
|
+
## Want to help?
|
|
151
|
+
|
|
152
|
+
If you want to contribute to swarmauri-sdk, read up on our
|
|
153
|
+
[guidelines for contributing](https://github.com/swarmauri/swarmauri-sdk/blob/master/CONTRIBUTING.md)
|
|
154
|
+
that will help you get started.
|
{swarmauri_crypto_paramiko-0.3.0.dev4 → swarmauri_crypto_paramiko-0.3.0.dev32}/pyproject.toml
RENAMED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "swarmauri_crypto_paramiko"
|
|
3
|
-
version = "0.3.0.
|
|
3
|
+
version = "0.3.0.dev32"
|
|
4
4
|
description = "Paramiko-backed RSA + AES-GCM crypto provider for Swarmauri"
|
|
5
5
|
license = "Apache-2.0"
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
requires-python = ">=3.10,<3.13"
|
|
8
|
-
authors = [{ name = "
|
|
8
|
+
authors = [{ name = "Jacob Stewart", email = "jacob@swarmauri.com" }]
|
|
9
9
|
classifiers = [
|
|
10
10
|
"License :: OSI Approved :: Apache Software License",
|
|
11
11
|
"Natural Language :: English",
|
|
@@ -16,6 +16,9 @@ classifiers = [
|
|
|
16
16
|
"Development Status :: 3 - Alpha",
|
|
17
17
|
"Topic :: Security :: Cryptography",
|
|
18
18
|
"Intended Audience :: Developers",
|
|
19
|
+
"Programming Language :: Python",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
19
22
|
]
|
|
20
23
|
dependencies = [
|
|
21
24
|
"swarmauri_core",
|
|
@@ -23,6 +26,14 @@ dependencies = [
|
|
|
23
26
|
"cryptography>=41",
|
|
24
27
|
"paramiko>=3.4",
|
|
25
28
|
]
|
|
29
|
+
keywords = [
|
|
30
|
+
'swarmauri',
|
|
31
|
+
'sdk',
|
|
32
|
+
'standards',
|
|
33
|
+
'crypto',
|
|
34
|
+
'paramiko',
|
|
35
|
+
'cryptography',
|
|
36
|
+
]
|
|
26
37
|
|
|
27
38
|
[tool.uv.sources]
|
|
28
39
|
swarmauri_core = { workspace = true }
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
"""Paramiko-backed crypto provider with sealing support.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
For larger payloads, use AES-GCM + RSA-OAEP key-wrap (encrypt_for_many with enc_alg="AES-256-GCM").
|
|
3
|
+
This module implements the ``ICrypto`` contract using AES-256-GCM for
|
|
4
|
+
symmetric encryption and RSA-OAEP (SHA-256) for key wrapping and direct
|
|
5
|
+
sealing of small payloads.
|
|
6
|
+
|
|
7
|
+
Notes:
|
|
8
|
+
- RSA public keys must be supplied in OpenSSH format via ``KeyRef.public``.
|
|
9
|
+
- For unwrap and unseal operations, ``KeyRef.material`` must contain a
|
|
10
|
+
PEM-encoded RSA private key.
|
|
11
|
+
- Sealing is limited to inputs no larger than ``modulus_bytes -
|
|
12
|
+
2*hash_len - 2``. For larger payloads use
|
|
13
|
+
``encrypt_for_many(enc_alg="AES-256-GCM")``.
|
|
15
14
|
"""
|
|
16
15
|
|
|
17
16
|
from __future__ import annotations
|
|
@@ -46,17 +45,27 @@ _AEAD_DEFAULT = "AES-256-GCM"
|
|
|
46
45
|
|
|
47
46
|
@ComponentBase.register_type(CryptoBase, "ParamikoCrypto")
|
|
48
47
|
class ParamikoCrypto(CryptoBase):
|
|
49
|
-
"""
|
|
48
|
+
"""Crypto provider backed by Paramiko and cryptography.
|
|
49
|
+
|
|
50
|
+
Implements AES-256-GCM for symmetric operations and RSA-OAEP for key
|
|
51
|
+
wrapping and sealing.
|
|
52
|
+
"""
|
|
50
53
|
|
|
51
54
|
type: Literal["ParamikoCrypto"] = "ParamikoCrypto"
|
|
52
55
|
|
|
53
56
|
def supports(self) -> Dict[str, Iterable[Alg]]:
|
|
57
|
+
"""Return the algorithms supported by this provider.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Dict[str, Iterable[Alg]]: Mapping of operation names to the
|
|
61
|
+
algorithms the provider can execute.
|
|
62
|
+
"""
|
|
63
|
+
|
|
54
64
|
return {
|
|
55
65
|
"encrypt": (_AEAD_DEFAULT,),
|
|
56
66
|
"decrypt": (_AEAD_DEFAULT,),
|
|
57
67
|
"wrap": (_WRAP_ALG,),
|
|
58
68
|
"unwrap": (_WRAP_ALG,),
|
|
59
|
-
# NEW:
|
|
60
69
|
"seal": (_SEAL_ALG,),
|
|
61
70
|
"unseal": (_SEAL_ALG,),
|
|
62
71
|
}
|
|
@@ -104,6 +113,24 @@ class ParamikoCrypto(CryptoBase):
|
|
|
104
113
|
aad: Optional[bytes] = None,
|
|
105
114
|
nonce: Optional[bytes] = None,
|
|
106
115
|
) -> AEADCiphertext:
|
|
116
|
+
"""Encrypt plaintext with AES-GCM.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
key (KeyRef): Symmetric key reference containing the key bytes.
|
|
120
|
+
pt (bytes): Plaintext to encrypt.
|
|
121
|
+
alg (Optional[Alg]): AEAD algorithm to use. Defaults to
|
|
122
|
+
``AES-256-GCM`` when not provided.
|
|
123
|
+
aad (Optional[bytes]): Additional authenticated data.
|
|
124
|
+
nonce (Optional[bytes]): Nonce for AES-GCM. Random when omitted.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
AEADCiphertext: Ciphertext container with nonce and tag.
|
|
128
|
+
|
|
129
|
+
Raises:
|
|
130
|
+
UnsupportedAlgorithm: If an unsupported algorithm is requested.
|
|
131
|
+
ValueError: If the key material is missing or invalid.
|
|
132
|
+
"""
|
|
133
|
+
|
|
107
134
|
alg = self._normalize_aead_alg(alg)
|
|
108
135
|
if alg != _AEAD_DEFAULT:
|
|
109
136
|
raise UnsupportedAlgorithm(f"Unsupported AEAD algorithm: {alg}")
|
|
@@ -136,6 +163,22 @@ class ParamikoCrypto(CryptoBase):
|
|
|
136
163
|
*,
|
|
137
164
|
aad: Optional[bytes] = None,
|
|
138
165
|
) -> bytes:
|
|
166
|
+
"""Decrypt ciphertext produced by :meth:`encrypt`.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
key (KeyRef): Symmetric key reference containing the key bytes.
|
|
170
|
+
ct (AEADCiphertext): Ciphertext container to decrypt.
|
|
171
|
+
aad (Optional[bytes]): Additional authenticated data. Defaults to
|
|
172
|
+
the value stored in ``ct`` when omitted.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
bytes: Decrypted plaintext.
|
|
176
|
+
|
|
177
|
+
Raises:
|
|
178
|
+
UnsupportedAlgorithm: If an unsupported algorithm is requested.
|
|
179
|
+
ValueError: If the key material is missing.
|
|
180
|
+
"""
|
|
181
|
+
|
|
139
182
|
if self._normalize_aead_alg(ct.alg) != _AEAD_DEFAULT:
|
|
140
183
|
raise UnsupportedAlgorithm(f"Unsupported AEAD algorithm: {ct.alg}")
|
|
141
184
|
if key.material is None:
|
|
@@ -157,6 +200,24 @@ class ParamikoCrypto(CryptoBase):
|
|
|
157
200
|
*,
|
|
158
201
|
alg: Optional[Alg] = _SEAL_ALG,
|
|
159
202
|
) -> bytes:
|
|
203
|
+
"""Seal a small plaintext to a recipient's RSA public key.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
recipient (KeyRef): Recipient key reference with OpenSSH RSA
|
|
207
|
+
public key bytes in ``KeyRef.public``.
|
|
208
|
+
pt (bytes): Plaintext to encrypt.
|
|
209
|
+
alg (Optional[Alg]): Sealing algorithm identifier. Defaults to
|
|
210
|
+
``RSA-OAEP-SHA256-SEAL``.
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
bytes: Sealed ciphertext produced by RSA-OAEP.
|
|
214
|
+
|
|
215
|
+
Raises:
|
|
216
|
+
UnsupportedAlgorithm: If an unsupported algorithm is requested.
|
|
217
|
+
ValueError: If the recipient public key is missing.
|
|
218
|
+
IntegrityError: If the plaintext exceeds the RSA-OAEP size limit.
|
|
219
|
+
"""
|
|
220
|
+
|
|
160
221
|
if alg != _SEAL_ALG:
|
|
161
222
|
raise UnsupportedAlgorithm(f"Unsupported seal alg: {alg}")
|
|
162
223
|
if recipient.public is None:
|
|
@@ -182,6 +243,23 @@ class ParamikoCrypto(CryptoBase):
|
|
|
182
243
|
*,
|
|
183
244
|
alg: Optional[Alg] = _SEAL_ALG,
|
|
184
245
|
) -> bytes:
|
|
246
|
+
"""Unseal ciphertext using the recipient's RSA private key.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
recipient_priv (KeyRef): Recipient key reference containing a
|
|
250
|
+
PEM-encoded RSA private key in ``KeyRef.material``.
|
|
251
|
+
sealed (bytes): Ciphertext produced by :meth:`seal`.
|
|
252
|
+
alg (Optional[Alg]): Sealing algorithm identifier. Defaults to
|
|
253
|
+
``RSA-OAEP-SHA256-SEAL``.
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
bytes: Decrypted plaintext.
|
|
257
|
+
|
|
258
|
+
Raises:
|
|
259
|
+
UnsupportedAlgorithm: If an unsupported algorithm is requested.
|
|
260
|
+
ValueError: If the private key material is missing.
|
|
261
|
+
"""
|
|
262
|
+
|
|
185
263
|
if alg != _SEAL_ALG:
|
|
186
264
|
raise UnsupportedAlgorithm(f"Unsupported seal alg: {alg}")
|
|
187
265
|
if recipient_priv.material is None:
|
|
@@ -211,6 +289,33 @@ class ParamikoCrypto(CryptoBase):
|
|
|
211
289
|
aad: Optional[bytes] = None,
|
|
212
290
|
nonce: Optional[bytes] = None,
|
|
213
291
|
) -> MultiRecipientEnvelope:
|
|
292
|
+
"""Encrypt plaintext for multiple recipients.
|
|
293
|
+
|
|
294
|
+
Operates in two modes:
|
|
295
|
+
1. **Sealed**: Each recipient receives an individual RSA-OAEP sealed
|
|
296
|
+
ciphertext when ``enc_alg`` is ``_SEAL_ALG``.
|
|
297
|
+
2. **KEM+AEAD**: Generates a shared AES-GCM ciphertext and wraps the
|
|
298
|
+
session key for each recipient using RSA-OAEP.
|
|
299
|
+
|
|
300
|
+
Args:
|
|
301
|
+
recipients (Iterable[KeyRef]): Sequence of recipients.
|
|
302
|
+
pt (bytes): Plaintext to encrypt.
|
|
303
|
+
enc_alg (Optional[Alg]): Encryption algorithm for the shared
|
|
304
|
+
ciphertext. Defaults to ``AES-256-GCM``.
|
|
305
|
+
recipient_wrap_alg (Optional[Alg]): Wrapping algorithm for the
|
|
306
|
+
session key. Defaults to ``RSA-OAEP-SHA256``.
|
|
307
|
+
aad (Optional[bytes]): Additional authenticated data for AES-GCM.
|
|
308
|
+
nonce (Optional[bytes]): Nonce for AES-GCM. Random when omitted.
|
|
309
|
+
|
|
310
|
+
Returns:
|
|
311
|
+
MultiRecipientEnvelope: Envelope containing ciphertext and per-
|
|
312
|
+
recipient wrapped keys.
|
|
313
|
+
|
|
314
|
+
Raises:
|
|
315
|
+
UnsupportedAlgorithm: If an unsupported algorithm is requested.
|
|
316
|
+
ValueError: If required key material is missing.
|
|
317
|
+
"""
|
|
318
|
+
|
|
214
319
|
# 1) Sealed-style variant (per-recipient ciphertext; no shared ct)
|
|
215
320
|
if enc_alg == _SEAL_ALG:
|
|
216
321
|
recip_infos: list[RecipientInfo] = []
|
|
@@ -307,13 +412,28 @@ class ParamikoCrypto(CryptoBase):
|
|
|
307
412
|
nonce: Optional[bytes] = None,
|
|
308
413
|
aad: Optional[bytes] = None,
|
|
309
414
|
) -> WrappedKey:
|
|
310
|
-
"""Wrap a
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
415
|
+
"""Wrap a data-encryption key with the given key-encryption key.
|
|
416
|
+
|
|
417
|
+
Args:
|
|
418
|
+
kek (KeyRef): Key-encryption key reference. Provide an OpenSSH
|
|
419
|
+
RSA public key in ``KeyRef.public`` for RSA-OAEP wrapping or
|
|
420
|
+
symmetric key bytes in ``KeyRef.material`` for AES-GCM.
|
|
421
|
+
dek (Optional[bytes]): Data-encryption key to wrap. A random key
|
|
422
|
+
is generated when omitted.
|
|
423
|
+
wrap_alg (Optional[Alg]): Wrapping algorithm to use. Defaults to
|
|
424
|
+
``RSA-OAEP-SHA256``.
|
|
425
|
+
nonce (Optional[bytes]): Nonce for AES-GCM wrapping. Random when
|
|
426
|
+
omitted.
|
|
427
|
+
aad (Optional[bytes]): Additional authenticated data for AES-GCM
|
|
428
|
+
wrapping.
|
|
429
|
+
|
|
430
|
+
Returns:
|
|
431
|
+
WrappedKey: Container with the wrapped key material.
|
|
432
|
+
|
|
433
|
+
Raises:
|
|
434
|
+
UnsupportedAlgorithm: If an unsupported wrapping algorithm is
|
|
435
|
+
requested.
|
|
436
|
+
ValueError: If required key material is missing or invalid.
|
|
317
437
|
"""
|
|
318
438
|
|
|
319
439
|
wrap_alg = wrap_alg or _WRAP_ALG
|
|
@@ -372,7 +492,24 @@ class ParamikoCrypto(CryptoBase):
|
|
|
372
492
|
*,
|
|
373
493
|
aad: Optional[bytes] = None,
|
|
374
494
|
) -> bytes:
|
|
375
|
-
"""Unwrap a previously wrapped key.
|
|
495
|
+
"""Unwrap a previously wrapped key.
|
|
496
|
+
|
|
497
|
+
Args:
|
|
498
|
+
kek (KeyRef): Key-encryption key reference. Must contain the RSA
|
|
499
|
+
private key or symmetric key bytes corresponding to the
|
|
500
|
+
wrapping algorithm used.
|
|
501
|
+
wrapped (WrappedKey): Wrapped key to unwrap.
|
|
502
|
+
aad (Optional[bytes]): Additional authenticated data for AES-GCM
|
|
503
|
+
unwrapping.
|
|
504
|
+
|
|
505
|
+
Returns:
|
|
506
|
+
bytes: The unwrapped data-encryption key.
|
|
507
|
+
|
|
508
|
+
Raises:
|
|
509
|
+
UnsupportedAlgorithm: If an unsupported wrapping algorithm is
|
|
510
|
+
requested.
|
|
511
|
+
ValueError: If key material or required fields are missing.
|
|
512
|
+
"""
|
|
376
513
|
|
|
377
514
|
if wrapped.wrap_alg == _WRAP_ALG:
|
|
378
515
|
if kek.material is None:
|
|
File without changes
|
|
File without changes
|