panda-crypto-py 0.1.0__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.
- panda_crypto_py-0.1.0/LICENSE +21 -0
- panda_crypto_py-0.1.0/PKG-INFO +283 -0
- panda_crypto_py-0.1.0/README.md +238 -0
- panda_crypto_py-0.1.0/pyproject.toml +109 -0
- panda_crypto_py-0.1.0/setup.cfg +4 -0
- panda_crypto_py-0.1.0/src/panda/__init__.py +62 -0
- panda_crypto_py-0.1.0/src/panda/audit/__init__.py +23 -0
- panda_crypto_py-0.1.0/src/panda/audit/logger.py +160 -0
- panda_crypto_py-0.1.0/src/panda/blind_index/__init__.py +11 -0
- panda_crypto_py-0.1.0/src/panda/blind_index/blind_index.py +145 -0
- panda_crypto_py-0.1.0/src/panda/cli/__init__.py +7 -0
- panda_crypto_py-0.1.0/src/panda/cli/commands.py +513 -0
- panda_crypto_py-0.1.0/src/panda/crypto/__init__.py +54 -0
- panda_crypto_py-0.1.0/src/panda/crypto/cipher.py +239 -0
- panda_crypto_py-0.1.0/src/panda/crypto/envelope.py +125 -0
- panda_crypto_py-0.1.0/src/panda/crypto/errors.py +50 -0
- panda_crypto_py-0.1.0/src/panda/crypto/keys.py +655 -0
- panda_crypto_py-0.1.0/src/panda/integrations/__init__.py +7 -0
- panda_crypto_py-0.1.0/src/panda/integrations/django.py +183 -0
- panda_crypto_py-0.1.0/src/panda/integrations/fastapi.py +205 -0
- panda_crypto_py-0.1.0/src/panda/integrations/flask.py +140 -0
- panda_crypto_py-0.1.0/src/panda/masking/__init__.py +12 -0
- panda_crypto_py-0.1.0/src/panda/masking/masker.py +73 -0
- panda_crypto_py-0.1.0/src/panda/storage/__init__.py +13 -0
- panda_crypto_py-0.1.0/src/panda/storage/storage.py +86 -0
- panda_crypto_py-0.1.0/src/panda/telemetry/__init__.py +11 -0
- panda_crypto_py-0.1.0/src/panda/telemetry/telemetry.py +144 -0
- panda_crypto_py-0.1.0/src/panda_crypto_py.egg-info/PKG-INFO +283 -0
- panda_crypto_py-0.1.0/src/panda_crypto_py.egg-info/SOURCES.txt +33 -0
- panda_crypto_py-0.1.0/src/panda_crypto_py.egg-info/dependency_links.txt +1 -0
- panda_crypto_py-0.1.0/src/panda_crypto_py.egg-info/entry_points.txt +2 -0
- panda_crypto_py-0.1.0/src/panda_crypto_py.egg-info/requires.txt +22 -0
- panda_crypto_py-0.1.0/src/panda_crypto_py.egg-info/top_level.txt +1 -0
- panda_crypto_py-0.1.0/tests/test_cipher.py +176 -0
- panda_crypto_py-0.1.0/tests/test_envelope.py +106 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Bidang Persandian dan Keamanan Informasi - Dinas Komunikasi dan Informatika Provinsi Jawa Timur
|
|
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.
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: panda-crypto-py
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Private And Secure Data Access - Field-level encryption SDK for Python
|
|
5
|
+
Author-email: Bidang Persandian dan Keamanan Informasi - Dinas Komunikasi dan Informatika Provinsi Jawa Timur <csirt@jatimprov.go.id>
|
|
6
|
+
Maintainer-email: Bidang Persandian dan Keamanan Informasi - Dinas Komunikasi dan Informatika Provinsi Jawa Timur <csirt@jatimprov.go.id>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/jatimprovcsirt/panda-py
|
|
9
|
+
Project-URL: Documentation, https://panda.jatimprovcsirt.go.id
|
|
10
|
+
Project-URL: Repository, https://github.com/jatimprovcsirt/panda-py
|
|
11
|
+
Project-URL: Issues, https://github.com/jatimprovcsirt/panda-py/issues
|
|
12
|
+
Keywords: encryption,security,gdpr,pdp,privacy,aes-256-gcm
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Security :: Cryptography
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: cryptography>=41.0.0
|
|
28
|
+
Requires-Dist: click>=8.0.0
|
|
29
|
+
Provides-Extra: django
|
|
30
|
+
Requires-Dist: django>=3.2; extra == "django"
|
|
31
|
+
Provides-Extra: flask
|
|
32
|
+
Requires-Dist: flask>=2.0; extra == "flask"
|
|
33
|
+
Provides-Extra: fastapi
|
|
34
|
+
Requires-Dist: fastapi>=0.68.0; extra == "fastapi"
|
|
35
|
+
Requires-Dist: pydantic>=2.0.0; extra == "fastapi"
|
|
36
|
+
Provides-Extra: dev
|
|
37
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
39
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
40
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
41
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
42
|
+
Provides-Extra: all
|
|
43
|
+
Requires-Dist: panda-py[dev,django,fastapi,flask]; extra == "all"
|
|
44
|
+
Dynamic: license-file
|
|
45
|
+
|
|
46
|
+
# PANDA Python SDK
|
|
47
|
+
|
|
48
|
+
Private And Secure Data Access — Field-level encryption SDK for Python applications.
|
|
49
|
+
|
|
50
|
+
## Overview
|
|
51
|
+
|
|
52
|
+
PANDA (Private And Secure Data Access) is a cross-language SDK for field-level encryption and masking of sensitive personal data. The Python implementation provides the same features as the PHP, Node.js, and Go versions:
|
|
53
|
+
|
|
54
|
+
- **AES-256-GCM encryption** with envelope wire format
|
|
55
|
+
- **Masking-by-default** decrypted values
|
|
56
|
+
- **Blind indexing** for searchable encrypted fields
|
|
57
|
+
- **Multiple key providers**: Local (.env), HashiCorp Vault, Infisical
|
|
58
|
+
- **CLI tool** for initialization and key management
|
|
59
|
+
- **Framework integrations**: Django, Flask, FastAPI
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install panda-crypto-py
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Quick Start
|
|
68
|
+
|
|
69
|
+
### 1. Initialize PANDA
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
panda init --token panda_demo_76d08573d453cdbdb4bf5704d13f8f54d57cd3c47c9b4be2
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The wizard will guide you through:
|
|
76
|
+
- Selecting a key provider (Local, Vault, or Infisical)
|
|
77
|
+
- Configuring your provider
|
|
78
|
+
- Generating your first encryption key
|
|
79
|
+
|
|
80
|
+
### 2. Use in Your Code
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from panda.crypto import FieldCipher, LocalKeyProvider
|
|
84
|
+
|
|
85
|
+
# Create cipher with local keys
|
|
86
|
+
key_provider = LocalKeyProvider()
|
|
87
|
+
cipher = FieldCipher(key_provider)
|
|
88
|
+
|
|
89
|
+
# Encrypt data
|
|
90
|
+
envelope = cipher.encrypt("3201012501990001", kid="nik-key")
|
|
91
|
+
|
|
92
|
+
# Decrypt (returns masked value by default)
|
|
93
|
+
masked = cipher.decrypt(envelope)
|
|
94
|
+
print(masked) # "32************01"
|
|
95
|
+
|
|
96
|
+
# Decrypt raw (audited operation)
|
|
97
|
+
raw = cipher.decrypt_raw(envelope)
|
|
98
|
+
print(raw) # "3201012501990001"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Key Providers
|
|
102
|
+
|
|
103
|
+
### Local (Environment Variables)
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from panda.crypto import LocalKeyProvider
|
|
107
|
+
|
|
108
|
+
# Keys are read from PANDA_KEY_<KID> environment variables
|
|
109
|
+
# PANDA_KEY_NIK_KEY=<base64-encoded-32-byte-key>
|
|
110
|
+
key_provider = LocalKeyProvider()
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### HashiCorp Vault
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from panda.crypto import VaultKeyProvider
|
|
117
|
+
|
|
118
|
+
key_provider = VaultKeyProvider(
|
|
119
|
+
vault_url="http://localhost:8200",
|
|
120
|
+
vault_token="your-token",
|
|
121
|
+
mount_path="secret"
|
|
122
|
+
)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Infisical
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from panda.crypto import InfisicalKeyProvider
|
|
129
|
+
|
|
130
|
+
key_provider = InfisicalKeyProvider(
|
|
131
|
+
site_url="https://app.infisical.com",
|
|
132
|
+
client_id="your-client-id",
|
|
133
|
+
client_secret="your-client-secret",
|
|
134
|
+
project_id="your-project-id",
|
|
135
|
+
environment="dev"
|
|
136
|
+
)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Masking
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from panda.masking import Masker
|
|
143
|
+
|
|
144
|
+
# Default: keep 2 leading, 2 trailing characters
|
|
145
|
+
masked = Masker.mask("3201012501990001")
|
|
146
|
+
# "32************01"
|
|
147
|
+
|
|
148
|
+
# Custom masking
|
|
149
|
+
masked = Masker.mask(
|
|
150
|
+
"3201012501990001",
|
|
151
|
+
keep_leading=3,
|
|
152
|
+
keep_trailing=1,
|
|
153
|
+
mask_char="*"
|
|
154
|
+
)
|
|
155
|
+
# "320*************1"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Blind Indexing
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
from panda.blind_index import BlindIndexer
|
|
162
|
+
|
|
163
|
+
# Generate blind index for searchable encryption
|
|
164
|
+
index = BlindIndexer.generate(
|
|
165
|
+
plaintext="3201012501990001",
|
|
166
|
+
key="blind-index-key",
|
|
167
|
+
normalization="digits" # or "lowercase", "trim", "raw"
|
|
168
|
+
)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Framework Integration
|
|
172
|
+
|
|
173
|
+
### Django
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
# settings.py
|
|
177
|
+
INSTALLED_APPS = [
|
|
178
|
+
...
|
|
179
|
+
'panda.integrations.django',
|
|
180
|
+
]
|
|
181
|
+
|
|
182
|
+
PANDA = {
|
|
183
|
+
'KEY_PROVIDER_DRIVER': 'local',
|
|
184
|
+
'DEFAULT_KID': 'default-key',
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
# models.py
|
|
188
|
+
from panda.integrations.django.fields import EncryptedField
|
|
189
|
+
from django.db import models
|
|
190
|
+
|
|
191
|
+
class Citizen(models.Model):
|
|
192
|
+
nik = EncryptedField(kid='nik-key')
|
|
193
|
+
name = models.CharField(max_length=200)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Flask
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
from flask import Flask
|
|
200
|
+
from panda.integrations.flask import PandaFlask
|
|
201
|
+
|
|
202
|
+
app = Flask(__name__)
|
|
203
|
+
panda = PandaFlask(app)
|
|
204
|
+
|
|
205
|
+
@app.route('/encrypt')
|
|
206
|
+
def encrypt():
|
|
207
|
+
envelope = panda.cipher.encrypt("sensitive data", kid="my-key")
|
|
208
|
+
return envelope.to_json()
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### FastAPI
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
from fastapi import FastAPI
|
|
215
|
+
from panda.integrations.fastapi import PandaFastAPI
|
|
216
|
+
|
|
217
|
+
app = FastAPI()
|
|
218
|
+
panda = PandaFastAPI(app)
|
|
219
|
+
|
|
220
|
+
@app.post("/encrypt")
|
|
221
|
+
def encrypt_endpoint(data: str):
|
|
222
|
+
envelope = panda.cipher.encrypt(data, kid="my-key")
|
|
223
|
+
return envelope.to_dict()
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## CLI Commands
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
# Initialize PANDA
|
|
230
|
+
panda init --token <your-token>
|
|
231
|
+
|
|
232
|
+
# Generate a new key
|
|
233
|
+
panda generate --kid my-key
|
|
234
|
+
|
|
235
|
+
# Check status
|
|
236
|
+
panda status
|
|
237
|
+
|
|
238
|
+
# View configuration
|
|
239
|
+
panda config
|
|
240
|
+
|
|
241
|
+
# Remove PANDA from project
|
|
242
|
+
panda deinit
|
|
243
|
+
|
|
244
|
+
# Migrate existing plaintext data
|
|
245
|
+
panda migrate table_name column_name
|
|
246
|
+
|
|
247
|
+
# Rotate encryption key
|
|
248
|
+
panda rotate-key --old-kid old-key --new-kid new-key
|
|
249
|
+
|
|
250
|
+
# Permanently shred a key
|
|
251
|
+
panda shred my-key
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Envelope Format
|
|
255
|
+
|
|
256
|
+
Encrypted fields use a standardized JSON envelope:
|
|
257
|
+
|
|
258
|
+
```json
|
|
259
|
+
{
|
|
260
|
+
"v": 1,
|
|
261
|
+
"alg": "aes-256-gcm",
|
|
262
|
+
"kid": "key-identifier",
|
|
263
|
+
"nonce": "<base64 12-byte IV>",
|
|
264
|
+
"ciphertext": "<base64 ciphertext + 16-byte auth tag>"
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Documentation
|
|
269
|
+
|
|
270
|
+
- [Full Documentation](docs/)
|
|
271
|
+
- [Envelope Format Spec](spec/envelope-format.md)
|
|
272
|
+
- [CLI Reference](docs/cli.md)
|
|
273
|
+
- [Framework Integrations](docs/integrations.md)
|
|
274
|
+
|
|
275
|
+
## License
|
|
276
|
+
|
|
277
|
+
MIT License - See LICENSE file for details.
|
|
278
|
+
|
|
279
|
+
## Support
|
|
280
|
+
|
|
281
|
+
For issues and questions:
|
|
282
|
+
- GitHub Issues: https://github.com/jatimprovcsirt/panda-py/issues
|
|
283
|
+
- Documentation: https://panda.jatimprovcsirt.go.id
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# PANDA Python SDK
|
|
2
|
+
|
|
3
|
+
Private And Secure Data Access — Field-level encryption SDK for Python applications.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
PANDA (Private And Secure Data Access) is a cross-language SDK for field-level encryption and masking of sensitive personal data. The Python implementation provides the same features as the PHP, Node.js, and Go versions:
|
|
8
|
+
|
|
9
|
+
- **AES-256-GCM encryption** with envelope wire format
|
|
10
|
+
- **Masking-by-default** decrypted values
|
|
11
|
+
- **Blind indexing** for searchable encrypted fields
|
|
12
|
+
- **Multiple key providers**: Local (.env), HashiCorp Vault, Infisical
|
|
13
|
+
- **CLI tool** for initialization and key management
|
|
14
|
+
- **Framework integrations**: Django, Flask, FastAPI
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install panda-crypto-py
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### 1. Initialize PANDA
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
panda init --token panda_demo_76d08573d453cdbdb4bf5704d13f8f54d57cd3c47c9b4be2
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The wizard will guide you through:
|
|
31
|
+
- Selecting a key provider (Local, Vault, or Infisical)
|
|
32
|
+
- Configuring your provider
|
|
33
|
+
- Generating your first encryption key
|
|
34
|
+
|
|
35
|
+
### 2. Use in Your Code
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from panda.crypto import FieldCipher, LocalKeyProvider
|
|
39
|
+
|
|
40
|
+
# Create cipher with local keys
|
|
41
|
+
key_provider = LocalKeyProvider()
|
|
42
|
+
cipher = FieldCipher(key_provider)
|
|
43
|
+
|
|
44
|
+
# Encrypt data
|
|
45
|
+
envelope = cipher.encrypt("3201012501990001", kid="nik-key")
|
|
46
|
+
|
|
47
|
+
# Decrypt (returns masked value by default)
|
|
48
|
+
masked = cipher.decrypt(envelope)
|
|
49
|
+
print(masked) # "32************01"
|
|
50
|
+
|
|
51
|
+
# Decrypt raw (audited operation)
|
|
52
|
+
raw = cipher.decrypt_raw(envelope)
|
|
53
|
+
print(raw) # "3201012501990001"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Key Providers
|
|
57
|
+
|
|
58
|
+
### Local (Environment Variables)
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from panda.crypto import LocalKeyProvider
|
|
62
|
+
|
|
63
|
+
# Keys are read from PANDA_KEY_<KID> environment variables
|
|
64
|
+
# PANDA_KEY_NIK_KEY=<base64-encoded-32-byte-key>
|
|
65
|
+
key_provider = LocalKeyProvider()
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### HashiCorp Vault
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from panda.crypto import VaultKeyProvider
|
|
72
|
+
|
|
73
|
+
key_provider = VaultKeyProvider(
|
|
74
|
+
vault_url="http://localhost:8200",
|
|
75
|
+
vault_token="your-token",
|
|
76
|
+
mount_path="secret"
|
|
77
|
+
)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Infisical
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from panda.crypto import InfisicalKeyProvider
|
|
84
|
+
|
|
85
|
+
key_provider = InfisicalKeyProvider(
|
|
86
|
+
site_url="https://app.infisical.com",
|
|
87
|
+
client_id="your-client-id",
|
|
88
|
+
client_secret="your-client-secret",
|
|
89
|
+
project_id="your-project-id",
|
|
90
|
+
environment="dev"
|
|
91
|
+
)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Masking
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from panda.masking import Masker
|
|
98
|
+
|
|
99
|
+
# Default: keep 2 leading, 2 trailing characters
|
|
100
|
+
masked = Masker.mask("3201012501990001")
|
|
101
|
+
# "32************01"
|
|
102
|
+
|
|
103
|
+
# Custom masking
|
|
104
|
+
masked = Masker.mask(
|
|
105
|
+
"3201012501990001",
|
|
106
|
+
keep_leading=3,
|
|
107
|
+
keep_trailing=1,
|
|
108
|
+
mask_char="*"
|
|
109
|
+
)
|
|
110
|
+
# "320*************1"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Blind Indexing
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from panda.blind_index import BlindIndexer
|
|
117
|
+
|
|
118
|
+
# Generate blind index for searchable encryption
|
|
119
|
+
index = BlindIndexer.generate(
|
|
120
|
+
plaintext="3201012501990001",
|
|
121
|
+
key="blind-index-key",
|
|
122
|
+
normalization="digits" # or "lowercase", "trim", "raw"
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Framework Integration
|
|
127
|
+
|
|
128
|
+
### Django
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
# settings.py
|
|
132
|
+
INSTALLED_APPS = [
|
|
133
|
+
...
|
|
134
|
+
'panda.integrations.django',
|
|
135
|
+
]
|
|
136
|
+
|
|
137
|
+
PANDA = {
|
|
138
|
+
'KEY_PROVIDER_DRIVER': 'local',
|
|
139
|
+
'DEFAULT_KID': 'default-key',
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
# models.py
|
|
143
|
+
from panda.integrations.django.fields import EncryptedField
|
|
144
|
+
from django.db import models
|
|
145
|
+
|
|
146
|
+
class Citizen(models.Model):
|
|
147
|
+
nik = EncryptedField(kid='nik-key')
|
|
148
|
+
name = models.CharField(max_length=200)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Flask
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from flask import Flask
|
|
155
|
+
from panda.integrations.flask import PandaFlask
|
|
156
|
+
|
|
157
|
+
app = Flask(__name__)
|
|
158
|
+
panda = PandaFlask(app)
|
|
159
|
+
|
|
160
|
+
@app.route('/encrypt')
|
|
161
|
+
def encrypt():
|
|
162
|
+
envelope = panda.cipher.encrypt("sensitive data", kid="my-key")
|
|
163
|
+
return envelope.to_json()
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### FastAPI
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
from fastapi import FastAPI
|
|
170
|
+
from panda.integrations.fastapi import PandaFastAPI
|
|
171
|
+
|
|
172
|
+
app = FastAPI()
|
|
173
|
+
panda = PandaFastAPI(app)
|
|
174
|
+
|
|
175
|
+
@app.post("/encrypt")
|
|
176
|
+
def encrypt_endpoint(data: str):
|
|
177
|
+
envelope = panda.cipher.encrypt(data, kid="my-key")
|
|
178
|
+
return envelope.to_dict()
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## CLI Commands
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Initialize PANDA
|
|
185
|
+
panda init --token <your-token>
|
|
186
|
+
|
|
187
|
+
# Generate a new key
|
|
188
|
+
panda generate --kid my-key
|
|
189
|
+
|
|
190
|
+
# Check status
|
|
191
|
+
panda status
|
|
192
|
+
|
|
193
|
+
# View configuration
|
|
194
|
+
panda config
|
|
195
|
+
|
|
196
|
+
# Remove PANDA from project
|
|
197
|
+
panda deinit
|
|
198
|
+
|
|
199
|
+
# Migrate existing plaintext data
|
|
200
|
+
panda migrate table_name column_name
|
|
201
|
+
|
|
202
|
+
# Rotate encryption key
|
|
203
|
+
panda rotate-key --old-kid old-key --new-kid new-key
|
|
204
|
+
|
|
205
|
+
# Permanently shred a key
|
|
206
|
+
panda shred my-key
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Envelope Format
|
|
210
|
+
|
|
211
|
+
Encrypted fields use a standardized JSON envelope:
|
|
212
|
+
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"v": 1,
|
|
216
|
+
"alg": "aes-256-gcm",
|
|
217
|
+
"kid": "key-identifier",
|
|
218
|
+
"nonce": "<base64 12-byte IV>",
|
|
219
|
+
"ciphertext": "<base64 ciphertext + 16-byte auth tag>"
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Documentation
|
|
224
|
+
|
|
225
|
+
- [Full Documentation](docs/)
|
|
226
|
+
- [Envelope Format Spec](spec/envelope-format.md)
|
|
227
|
+
- [CLI Reference](docs/cli.md)
|
|
228
|
+
- [Framework Integrations](docs/integrations.md)
|
|
229
|
+
|
|
230
|
+
## License
|
|
231
|
+
|
|
232
|
+
MIT License - See LICENSE file for details.
|
|
233
|
+
|
|
234
|
+
## Support
|
|
235
|
+
|
|
236
|
+
For issues and questions:
|
|
237
|
+
- GitHub Issues: https://github.com/jatimprovcsirt/panda-py/issues
|
|
238
|
+
- Documentation: https://panda.jatimprovcsirt.go.id
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "panda-crypto-py"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Private And Secure Data Access - Field-level encryption SDK for Python"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Bidang Persandian dan Keamanan Informasi - Dinas Komunikasi dan Informatika Provinsi Jawa Timur", email = "csirt@jatimprov.go.id"}
|
|
14
|
+
]
|
|
15
|
+
maintainers = [
|
|
16
|
+
{name = "Bidang Persandian dan Keamanan Informasi - Dinas Komunikasi dan Informatika Provinsi Jawa Timur", email = "csirt@jatimprov.go.id"}
|
|
17
|
+
]
|
|
18
|
+
keywords = ["encryption", "security", "gdpr", "pdp", "privacy", "aes-256-gcm"]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 3 - Alpha",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"License :: OSI Approved :: MIT License",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3.8",
|
|
25
|
+
"Programming Language :: Python :: 3.9",
|
|
26
|
+
"Programming Language :: Python :: 3.10",
|
|
27
|
+
"Programming Language :: Python :: 3.11",
|
|
28
|
+
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Topic :: Security :: Cryptography",
|
|
30
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
dependencies = [
|
|
34
|
+
"cryptography>=41.0.0",
|
|
35
|
+
"click>=8.0.0",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.optional-dependencies]
|
|
39
|
+
django = [
|
|
40
|
+
"django>=3.2",
|
|
41
|
+
]
|
|
42
|
+
flask = [
|
|
43
|
+
"flask>=2.0",
|
|
44
|
+
]
|
|
45
|
+
fastapi = [
|
|
46
|
+
"fastapi>=0.68.0",
|
|
47
|
+
"pydantic>=2.0.0",
|
|
48
|
+
]
|
|
49
|
+
dev = [
|
|
50
|
+
"pytest>=7.0.0",
|
|
51
|
+
"pytest-cov>=4.0.0",
|
|
52
|
+
"black>=23.0.0",
|
|
53
|
+
"ruff>=0.1.0",
|
|
54
|
+
"mypy>=1.0.0",
|
|
55
|
+
]
|
|
56
|
+
all = [
|
|
57
|
+
"panda-py[django,flask,fastapi,dev]",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
[project.urls]
|
|
61
|
+
Homepage = "https://github.com/jatimprovcsirt/panda-py"
|
|
62
|
+
Documentation = "https://panda.jatimprovcsirt.go.id"
|
|
63
|
+
Repository = "https://github.com/jatimprovcsirt/panda-py"
|
|
64
|
+
Issues = "https://github.com/jatimprovcsirt/panda-py/issues"
|
|
65
|
+
|
|
66
|
+
[project.scripts]
|
|
67
|
+
panda = "panda.cli.commands:main"
|
|
68
|
+
|
|
69
|
+
[tool.setuptools]
|
|
70
|
+
package-dir = {"" = "src"}
|
|
71
|
+
|
|
72
|
+
[tool.setuptools.packages.find]
|
|
73
|
+
where = ["src"]
|
|
74
|
+
|
|
75
|
+
[tool.black]
|
|
76
|
+
line-length = 100
|
|
77
|
+
target-version = ["py38", "py39", "py310", "py311"]
|
|
78
|
+
|
|
79
|
+
[tool.ruff]
|
|
80
|
+
line-length = 100
|
|
81
|
+
target-version = "py38"
|
|
82
|
+
select = ["E", "F", "I", "N", "W"]
|
|
83
|
+
ignore = ["E501"]
|
|
84
|
+
|
|
85
|
+
[tool.mypy]
|
|
86
|
+
python_version = "3.8"
|
|
87
|
+
warn_return_any = true
|
|
88
|
+
warn_unused_configs = true
|
|
89
|
+
disallow_untyped_defs = false
|
|
90
|
+
ignore_missing_imports = true
|
|
91
|
+
|
|
92
|
+
[tool.pytest.ini_options]
|
|
93
|
+
testpaths = ["tests"]
|
|
94
|
+
python_files = ["test_*.py"]
|
|
95
|
+
python_classes = ["Test*"]
|
|
96
|
+
python_functions = ["test_*"]
|
|
97
|
+
addopts = "-v --cov=panda --cov-report=term-missing"
|
|
98
|
+
|
|
99
|
+
[tool.coverage.run]
|
|
100
|
+
source = ["src"]
|
|
101
|
+
omit = ["*/tests/*"]
|
|
102
|
+
|
|
103
|
+
[tool.coverage.report]
|
|
104
|
+
exclude_lines = [
|
|
105
|
+
"pragma: no cover",
|
|
106
|
+
"def __repr__",
|
|
107
|
+
"raise NotImplementedError",
|
|
108
|
+
"if TYPE_CHECKING:",
|
|
109
|
+
]
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""
|
|
2
|
+
PANDA - Private And Secure Data Access SDK for Python
|
|
3
|
+
|
|
4
|
+
Field-level encryption and masking for sensitive personal data.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
__version__ = "0.1.0"
|
|
8
|
+
|
|
9
|
+
from .crypto import (
|
|
10
|
+
FieldCipher,
|
|
11
|
+
Envelope,
|
|
12
|
+
LocalKeyProvider,
|
|
13
|
+
VaultKeyProvider,
|
|
14
|
+
InfisicalKeyProvider,
|
|
15
|
+
create_key_provider,
|
|
16
|
+
KeyNotFoundError,
|
|
17
|
+
AuthenticationFailedError,
|
|
18
|
+
EncryptionError
|
|
19
|
+
)
|
|
20
|
+
from .masking import Masker, MaskingConfig
|
|
21
|
+
from .blind_index import BlindIndexer
|
|
22
|
+
from .audit import AuditLogger, ConsoleAuditLogger, NullAuditLogger
|
|
23
|
+
from .telemetry import TelemetryClient
|
|
24
|
+
from .storage import TLSVerifier, MySqlAdapter, PostgresAdapter
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
# Version
|
|
28
|
+
"__version__",
|
|
29
|
+
|
|
30
|
+
# Core crypto
|
|
31
|
+
"FieldCipher",
|
|
32
|
+
"Envelope",
|
|
33
|
+
"LocalKeyProvider",
|
|
34
|
+
"VaultKeyProvider",
|
|
35
|
+
"InfisicalKeyProvider",
|
|
36
|
+
"create_key_provider",
|
|
37
|
+
|
|
38
|
+
# Errors
|
|
39
|
+
"KeyNotFoundError",
|
|
40
|
+
"AuthenticationFailedError",
|
|
41
|
+
"EncryptionError",
|
|
42
|
+
|
|
43
|
+
# Masking
|
|
44
|
+
"Masker",
|
|
45
|
+
"MaskingConfig",
|
|
46
|
+
|
|
47
|
+
# Blind Index
|
|
48
|
+
"BlindIndexer",
|
|
49
|
+
|
|
50
|
+
# Audit
|
|
51
|
+
"AuditLogger",
|
|
52
|
+
"ConsoleAuditLogger",
|
|
53
|
+
"NullAuditLogger",
|
|
54
|
+
|
|
55
|
+
# Telemetry
|
|
56
|
+
"TelemetryClient",
|
|
57
|
+
|
|
58
|
+
# Storage
|
|
59
|
+
"TLSVerifier",
|
|
60
|
+
"MySqlAdapter",
|
|
61
|
+
"PostgresAdapter",
|
|
62
|
+
]
|