secrets-plus 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.
@@ -0,0 +1,75 @@
1
+ Metadata-Version: 2.4
2
+ Name: secrets-plus
3
+ Version: 0.1.0
4
+ Summary: Windows BCrypt 加密安全随机数C扩展,与secrets接口完全一致
5
+ Author: Tevend_geven
6
+ Author-email: yanxiao_feng2013@163.com
7
+ License: MIT
8
+ Platform: Windows
9
+ Classifier: Programming Language :: C
10
+ Classifier: Programming Language :: Python :: 3.7
11
+ Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Operating System :: Microsoft :: Windows
17
+ Classifier: Topic :: Security :: Cryptography
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Requires-Python: >=3.7
20
+ Description-Content-Type: text/markdown
21
+ Dynamic: author
22
+ Dynamic: author-email
23
+ Dynamic: classifier
24
+ Dynamic: description
25
+ Dynamic: description-content-type
26
+ Dynamic: license
27
+ Dynamic: platform
28
+ Dynamic: requires-python
29
+ Dynamic: summary
30
+
31
+ # token-gen-win
32
+ Windows平台专用高性能C扩展,基于系统原生 **BCrypt API** 实现加密安全随机数,完整复刻Python标准库 `secrets` 常用接口,性能优于原生Python实现。
33
+
34
+ ## 平台限制
35
+ **仅支持 Windows 系统**
36
+ Linux / macOS 无系统BCrypt依赖库,无法编译、安装。
37
+
38
+ ## 功能列表
39
+ 完全对齐标准库 secrets 接口:
40
+ - `token_bytes()`:生成随机字节串
41
+ - `token_hex()`:生成十六进制随机令牌
42
+ - `token_urlsafe()`:生成URL安全随机令牌
43
+ - `randbelow()`:生成指定上界安全随机整数
44
+ - `randbits()`:生成指定比特位随机数
45
+ - `choice()`:从序列随机选取元素
46
+ - `shuffle()`:原地随机打乱序列
47
+
48
+ ## 安装方式
49
+ ```bash
50
+ pip install token-gen
51
+ ```
52
+
53
+ ## 快速使用
54
+ ```python
55
+ import token_gen
56
+
57
+ # 生成各类安全令牌
58
+ print(token_gen.token_urlsafe())
59
+ print(token_gen.token_hex(16))
60
+ print(token_gen.token_bytes(32))
61
+
62
+ # 随机数工具
63
+ print(token_gen.randbelow(1000))
64
+ print(token_gen.randbits(12))
65
+
66
+ # 序列操作
67
+ lst = [1,2,3,4,5]
68
+ print(token_gen.choice(lst))
69
+ token_gen.shuffle(lst)
70
+ print(lst)
71
+ ```
72
+
73
+ ## 注意事项
74
+ 1. 基于栈分配实现,不支持超大长度随机数生成(建议单次长度不超过1024),避免栈溢出
75
+ 2. 长期后台运行存在轻微BCrypt句柄残留,短期脚本使用无任何影响
@@ -0,0 +1,45 @@
1
+ # token-gen-win
2
+ Windows平台专用高性能C扩展,基于系统原生 **BCrypt API** 实现加密安全随机数,完整复刻Python标准库 `secrets` 常用接口,性能优于原生Python实现。
3
+
4
+ ## 平台限制
5
+ **仅支持 Windows 系统**
6
+ Linux / macOS 无系统BCrypt依赖库,无法编译、安装。
7
+
8
+ ## 功能列表
9
+ 完全对齐标准库 secrets 接口:
10
+ - `token_bytes()`:生成随机字节串
11
+ - `token_hex()`:生成十六进制随机令牌
12
+ - `token_urlsafe()`:生成URL安全随机令牌
13
+ - `randbelow()`:生成指定上界安全随机整数
14
+ - `randbits()`:生成指定比特位随机数
15
+ - `choice()`:从序列随机选取元素
16
+ - `shuffle()`:原地随机打乱序列
17
+
18
+ ## 安装方式
19
+ ```bash
20
+ pip install token-gen
21
+ ```
22
+
23
+ ## 快速使用
24
+ ```python
25
+ import token_gen
26
+
27
+ # 生成各类安全令牌
28
+ print(token_gen.token_urlsafe())
29
+ print(token_gen.token_hex(16))
30
+ print(token_gen.token_bytes(32))
31
+
32
+ # 随机数工具
33
+ print(token_gen.randbelow(1000))
34
+ print(token_gen.randbits(12))
35
+
36
+ # 序列操作
37
+ lst = [1,2,3,4,5]
38
+ print(token_gen.choice(lst))
39
+ token_gen.shuffle(lst)
40
+ print(lst)
41
+ ```
42
+
43
+ ## 注意事项
44
+ 1. 基于栈分配实现,不支持超大长度随机数生成(建议单次长度不超过1024),避免栈溢出
45
+ 2. 长期后台运行存在轻微BCrypt句柄残留,短期脚本使用无任何影响
@@ -0,0 +1,3 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,75 @@
1
+ Metadata-Version: 2.4
2
+ Name: secrets-plus
3
+ Version: 0.1.0
4
+ Summary: Windows BCrypt 加密安全随机数C扩展,与secrets接口完全一致
5
+ Author: Tevend_geven
6
+ Author-email: yanxiao_feng2013@163.com
7
+ License: MIT
8
+ Platform: Windows
9
+ Classifier: Programming Language :: C
10
+ Classifier: Programming Language :: Python :: 3.7
11
+ Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Operating System :: Microsoft :: Windows
17
+ Classifier: Topic :: Security :: Cryptography
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Requires-Python: >=3.7
20
+ Description-Content-Type: text/markdown
21
+ Dynamic: author
22
+ Dynamic: author-email
23
+ Dynamic: classifier
24
+ Dynamic: description
25
+ Dynamic: description-content-type
26
+ Dynamic: license
27
+ Dynamic: platform
28
+ Dynamic: requires-python
29
+ Dynamic: summary
30
+
31
+ # token-gen-win
32
+ Windows平台专用高性能C扩展,基于系统原生 **BCrypt API** 实现加密安全随机数,完整复刻Python标准库 `secrets` 常用接口,性能优于原生Python实现。
33
+
34
+ ## 平台限制
35
+ **仅支持 Windows 系统**
36
+ Linux / macOS 无系统BCrypt依赖库,无法编译、安装。
37
+
38
+ ## 功能列表
39
+ 完全对齐标准库 secrets 接口:
40
+ - `token_bytes()`:生成随机字节串
41
+ - `token_hex()`:生成十六进制随机令牌
42
+ - `token_urlsafe()`:生成URL安全随机令牌
43
+ - `randbelow()`:生成指定上界安全随机整数
44
+ - `randbits()`:生成指定比特位随机数
45
+ - `choice()`:从序列随机选取元素
46
+ - `shuffle()`:原地随机打乱序列
47
+
48
+ ## 安装方式
49
+ ```bash
50
+ pip install token-gen
51
+ ```
52
+
53
+ ## 快速使用
54
+ ```python
55
+ import token_gen
56
+
57
+ # 生成各类安全令牌
58
+ print(token_gen.token_urlsafe())
59
+ print(token_gen.token_hex(16))
60
+ print(token_gen.token_bytes(32))
61
+
62
+ # 随机数工具
63
+ print(token_gen.randbelow(1000))
64
+ print(token_gen.randbits(12))
65
+
66
+ # 序列操作
67
+ lst = [1,2,3,4,5]
68
+ print(token_gen.choice(lst))
69
+ token_gen.shuffle(lst)
70
+ print(lst)
71
+ ```
72
+
73
+ ## 注意事项
74
+ 1. 基于栈分配实现,不支持超大长度随机数生成(建议单次长度不超过1024),避免栈溢出
75
+ 2. 长期后台运行存在轻微BCrypt句柄残留,短期脚本使用无任何影响
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ setup.py
4
+ token_gen.c
5
+ secrets_plus.egg-info/PKG-INFO
6
+ secrets_plus.egg-info/SOURCES.txt
7
+ secrets_plus.egg-info/dependency_links.txt
8
+ secrets_plus.egg-info/not-zip-safe
9
+ secrets_plus.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ secplus
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,40 @@
1
+ from setuptools import setup, Extension
2
+ import pathlib
3
+
4
+ HERE = pathlib.Path(__file__).parent
5
+ README = (HERE / "README.md").read_text(encoding="utf-8")
6
+
7
+ ext_module = Extension(
8
+ name="secplus",
9
+ sources=["token_gen.c"],
10
+ libraries=["bcrypt"],
11
+ extra_compile_args=["/O2", "/GL"],
12
+ extra_link_args=["/LTCG"],
13
+ )
14
+
15
+ setup(
16
+ name="secrets-plus", # PyPI包名
17
+ version="0.1.0",
18
+ description="Windows BCrypt 加密安全随机数C扩展,与secrets接口完全一致",
19
+ long_description=README,
20
+ long_description_content_type="text/markdown",
21
+ author="Tevend_geven",
22
+ author_email="yanxiao_feng2013@163.com",
23
+ license="MIT",
24
+ ext_modules=[ext_module],
25
+ zip_safe=False,
26
+ python_requires=">=3.7",
27
+ platforms=["Windows"],
28
+ classifiers=[
29
+ "Programming Language :: C",
30
+ "Programming Language :: Python :: 3.7",
31
+ "Programming Language :: Python :: 3.8",
32
+ "Programming Language :: Python :: 3.9",
33
+ "Programming Language :: Python :: 3.10",
34
+ "Programming Language :: Python :: 3.11",
35
+ "Programming Language :: Python :: 3.12",
36
+ "Operating System :: Microsoft :: Windows",
37
+ "Topic :: Security :: Cryptography",
38
+ "License :: OSI Approved :: MIT License",
39
+ ],
40
+ )
@@ -0,0 +1,284 @@
1
+ #define PY_SSIZE_T_CLEAN
2
+ #include <Python.h>
3
+ #include <stdint.h>
4
+ #include <windows.h>
5
+ #include <bcrypt.h>
6
+ #include <string.h>
7
+
8
+ static int global_init_done = 0;
9
+ static BCRYPT_ALG_HANDLE hAlg = NULL;
10
+ static CRITICAL_SECTION cs_rand;
11
+ static char char_map[64];
12
+ #define CHAR_TOTAL 64
13
+
14
+ static void crypto_random(uint8_t* buf, size_t len) {
15
+ BCryptGenRandom(hAlg, buf, (ULONG)len, 0);
16
+ }
17
+
18
+ static uint64_t bytes_to_u64(const uint8_t* b) {
19
+ uint64_t res = 0;
20
+ res |= (uint64_t)b[0] << 0;
21
+ res |= (uint64_t)b[1] << 8;
22
+ res |= (uint64_t)b[2] << 16;
23
+ res |= (uint64_t)b[3] << 24;
24
+ res |= (uint64_t)b[4] << 32;
25
+ res |= (uint64_t)b[5] << 40;
26
+ res |= (uint64_t)b[6] << 48;
27
+ res |= (uint64_t)b[7] << 56;
28
+ return res;
29
+ }
30
+
31
+ static void safe_global_init(void) {
32
+ EnterCriticalSection(&cs_rand);
33
+ if (!global_init_done) {
34
+ BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, NULL, 0);
35
+ for (int v = 0; v < CHAR_TOTAL; v++) {
36
+ if (v < 10)
37
+ char_map[v] = '0' + v;
38
+ else if (v < 36)
39
+ char_map[v] = 'A' + (v - 10);
40
+ else if (v < 62)
41
+ char_map[v] = 'a' + (v - 36);
42
+ else if (v == 62)
43
+ char_map[v] = '_';
44
+ else
45
+ char_map[v] = '-';
46
+ }
47
+ global_init_done = 1;
48
+ }
49
+ LeaveCriticalSection(&cs_rand);
50
+ }
51
+
52
+ // ������ȡָ������ԭʼ����ֽڣ��ײ㹫����װ
53
+ static void get_raw_bytes(size_t n, uint8_t* out) {
54
+ safe_global_init();
55
+ crypto_random(out, n);
56
+ }
57
+
58
+ // ====================== ���� secrets ��׼�ӿ� ======================
59
+ // 1. token_bytes(n=None)
60
+ static PyObject* py_token_bytes(PyObject* self, PyObject* args, PyObject* kwargs) {
61
+ PyObject* n_obj = Py_None;
62
+ static const char* kwlist[] = {"n", NULL};
63
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", (char**)kwlist, &n_obj))
64
+ return NULL;
65
+
66
+ Py_ssize_t n;
67
+ if (n_obj == Py_None)
68
+ n = 32;
69
+ else if (!PyNumber_Check(n_obj)) {
70
+ PyErr_SetString(PyExc_TypeError, "n must be integer or None");
71
+ return NULL;
72
+ }
73
+ else {
74
+ n = PyNumber_AsSsize_t(n_obj, PyExc_OverflowError);
75
+ if (PyErr_Occurred()) return NULL;
76
+ if (n <= 0) {
77
+ PyErr_SetString(PyExc_ValueError, "n must be positive");
78
+ return NULL;
79
+ }
80
+ }
81
+
82
+ uint8_t* buf = (uint8_t*)alloca(n);
83
+ get_raw_bytes((size_t)n, buf);
84
+ return PyBytes_FromStringAndSize((char*)buf, n);
85
+ }
86
+
87
+ // 2. token_hex(n=None)
88
+ static PyObject* py_token_hex(PyObject* self, PyObject* args, PyObject* kwargs) {
89
+ PyObject* n_obj = Py_None;
90
+ static const char* kwlist[] = {"n", NULL};
91
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", (char**)kwlist, &n_obj))
92
+ return NULL;
93
+
94
+ Py_ssize_t n;
95
+ if (n_obj == Py_None)
96
+ n = 16;
97
+ else {
98
+ n = PyNumber_AsSsize_t(n_obj, PyExc_OverflowError);
99
+ if (PyErr_Occurred()) return NULL;
100
+ if (n <= 0) {
101
+ PyErr_SetString(PyExc_ValueError, "n must be positive");
102
+ return NULL;
103
+ }
104
+ }
105
+
106
+ uint8_t* raw = (uint8_t*)alloca(n);
107
+ get_raw_bytes((size_t)n, raw);
108
+ size_t hex_len = (size_t)n * 2;
109
+ char* hex_buf = (char*)alloca(hex_len + 1);
110
+ static const char hex_table[] = "0123456789abcdef";
111
+
112
+ for (Py_ssize_t i = 0; i < n; i++) {
113
+ uint8_t b = raw[i];
114
+ hex_buf[i*2] = hex_table[(b >> 4) & 0x0F];
115
+ hex_buf[i*2+1] = hex_table[b & 0x0F];
116
+ }
117
+ hex_buf[hex_len] = '\0';
118
+ return PyUnicode_FromStringAndSize(hex_buf, hex_len);
119
+ }
120
+
121
+ // 3. token_urlsafe(n=None)
122
+ static PyObject* py_token_urlsafe(PyObject* self, PyObject* args, PyObject* kwargs) {
123
+ PyObject* n_obj = Py_None;
124
+ static const char* kwlist[] = {"n", NULL};
125
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", (char**)kwlist, &n_obj))
126
+ return NULL;
127
+
128
+ Py_ssize_t n;
129
+ if (n_obj == Py_None)
130
+ n = 32;
131
+ else {
132
+ n = PyNumber_AsSsize_t(n_obj, PyExc_OverflowError);
133
+ if (PyErr_Occurred()) return NULL;
134
+ if (n <= 0) {
135
+ PyErr_SetString(PyExc_ValueError, "n must be positive");
136
+ return NULL;
137
+ }
138
+ }
139
+
140
+ size_t raw_len = (size_t)n;
141
+ uint8_t* raw = (uint8_t*)alloca(raw_len);
142
+ get_raw_bytes(raw_len, raw);
143
+
144
+ // Base64 urlsafe ���룬ȥ�����=����A-Za-z0-9-_
145
+ static const char b64_table[] =
146
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
147
+ size_t out_chars = ((raw_len * 8) + 5) / 6;
148
+ char* out_buf = (char*)alloca(out_chars + 1);
149
+ size_t pos = 0;
150
+
151
+ for (size_t i = 0; i < raw_len; i += 3) {
152
+ uint32_t triple = raw[i] << 16;
153
+ if (i + 1 < raw_len) triple |= raw[i+1] << 8;
154
+ if (i + 2 < raw_len) triple |= raw[i+2];
155
+
156
+ out_buf[pos++] = b64_table[(triple >> 18) & 0x3F];
157
+ out_buf[pos++] = b64_table[(triple >> 12) & 0x3F];
158
+ if (i + 1 < raw_len)
159
+ out_buf[pos++] = b64_table[(triple >> 6) & 0x3F];
160
+ if (i + 2 < raw_len)
161
+ out_buf[pos++] = b64_table[triple & 0x3F];
162
+ }
163
+ out_buf[out_chars] = '\0';
164
+ return PyUnicode_FromStringAndSize(out_buf, out_chars);
165
+ }
166
+
167
+ // 4. randbelow(exclusive_upper_bound)
168
+ static PyObject* py_randbelow(PyObject* self, PyObject* args, PyObject* kwargs) {
169
+ PyObject* upper;
170
+ static const char* kwlist[] = {"exclusive_upper_bound", NULL};
171
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", (char**)kwlist, &upper))
172
+ return NULL;
173
+
174
+ uint64_t bound = PyLong_AsUnsignedLongLong(upper);
175
+ if (PyErr_Occurred()) return NULL;
176
+ if (bound <= 1) {
177
+ PyErr_SetString(PyExc_ValueError, "bound must be greater than 1");
178
+ return NULL;
179
+ }
180
+
181
+ uint8_t rand_buf[8];
182
+ get_raw_bytes(8, rand_buf);
183
+ uint64_t r = bytes_to_u64(rand_buf);
184
+ uint64_t res = r % bound;
185
+ return PyLong_FromUnsignedLongLong(res);
186
+ }
187
+
188
+ // 5. randbits(k)
189
+ static PyObject* py_randbits(PyObject* self, PyObject* args, PyObject* kwargs) {
190
+ int k;
191
+ static const char* kwlist[] = {"k", NULL};
192
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", (char**)kwlist, &k))
193
+ return NULL;
194
+ if (k <= 0) {
195
+ PyErr_SetString(PyExc_ValueError, "k must be positive integer");
196
+ return NULL;
197
+ }
198
+
199
+ size_t bytes_need = ((size_t)k + 7) / 8;
200
+ uint8_t* buf = (uint8_t*)alloca(bytes_need);
201
+ get_raw_bytes(bytes_need, buf);
202
+ uint64_t val = 0;
203
+ for (size_t i = 0; i < bytes_need; i++)
204
+ val = (val << 8) | buf[i];
205
+ val &= ((1ULL << k) - 1);
206
+ return PyLong_FromUnsignedLongLong(val);
207
+ }
208
+
209
+ // 6. choice(seq)
210
+ static PyObject* py_choice(PyObject* self, PyObject* args, PyObject* kwargs) {
211
+ PyObject* seq;
212
+ static const char* kwlist[] = {"seq", NULL};
213
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", (char**)kwlist, &seq))
214
+ return NULL;
215
+
216
+ Py_ssize_t len = PySequence_Length(seq);
217
+ if (len <= 0) {
218
+ PyErr_SetString(PyExc_IndexError, "empty sequence");
219
+ return NULL;
220
+ }
221
+
222
+ uint8_t r_buf[8];
223
+ get_raw_bytes(8, r_buf);
224
+ uint64_t r = bytes_to_u64(r_buf);
225
+ Py_ssize_t idx = (Py_ssize_t)(r % (uint64_t)len);
226
+ return PySequence_GetItem(seq, idx);
227
+ }
228
+
229
+ // 7. shuffle(x) ԭ�ش���
230
+ static PyObject* py_shuffle(PyObject* self, PyObject* args, PyObject* kwargs) {
231
+ PyObject* x;
232
+ static const char* kwlist[] = {"x", NULL};
233
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", (char**)kwlist, &x))
234
+ return NULL;
235
+
236
+ Py_ssize_t n = PySequence_Length(x);
237
+ if (n <= 1) Py_RETURN_NONE;
238
+
239
+ // Fisher-Yates ϴ��
240
+ for (Py_ssize_t i = n - 1; i > 0; i--) {
241
+ uint8_t r_buf[8];
242
+ get_raw_bytes(8, r_buf);
243
+ uint64_t r = bytes_to_u64(r_buf);
244
+ Py_ssize_t j = (Py_ssize_t)(r % (uint64_t)(i + 1));
245
+ PyObject* a = PySequence_GetItem(x, i);
246
+ PyObject* b = PySequence_GetItem(x, j);
247
+ PySequence_SetItem(x, i, b);
248
+ PySequence_SetItem(x, j, a);
249
+ Py_XDECREF(a);
250
+ Py_XDECREF(b);
251
+ }
252
+ Py_RETURN_NONE;
253
+ }
254
+
255
+ static PyMethodDef TokenMethods[] = {
256
+ {"token_bytes", py_token_bytes, METH_VARARGS|METH_KEYWORDS,
257
+ "token_bytes(n=None) -> bytes\nCryptographically secure random bytes"},
258
+ {"token_hex", py_token_hex, METH_VARARGS|METH_KEYWORDS,
259
+ "token_hex(n=None) -> str\nHex encoded secure token"},
260
+ {"token_urlsafe", py_token_urlsafe, METH_VARARGS|METH_KEYWORDS,
261
+ "token_urlsafe(n=None) -> str\nURL-safe base64 token (A-Za-z0-9_-) "},
262
+ {"randbelow", py_randbelow, METH_VARARGS|METH_KEYWORDS,
263
+ "randbelow(exclusive_upper_bound) -> int\nSecure random integer [0, bound)"},
264
+ {"randbits", py_randbits, METH_VARARGS|METH_KEYWORDS,
265
+ "randbits(k) -> int\nSecure integer with k random bits"},
266
+ {"choice", py_choice, METH_VARARGS|METH_KEYWORDS,
267
+ "choice(seq) -> object\nSecure random pick from sequence"},
268
+ {"shuffle", py_shuffle, METH_VARARGS|METH_KEYWORDS,
269
+ "shuffle(x) -> None\nIn-place secure Fisher-Yates shuffle"},
270
+ {NULL, NULL, 0, NULL}
271
+ };
272
+
273
+ static struct PyModuleDef tokenmodule = {
274
+ PyModuleDef_HEAD_INIT,
275
+ "token_gen",
276
+ NULL,
277
+ -1,
278
+ TokenMethods
279
+ };
280
+
281
+ PyMODINIT_FUNC PyInit_token_gen(void) {
282
+ InitializeCriticalSection(&cs_rand);
283
+ return PyModule_Create(&tokenmodule);
284
+ }