fix: CRUD endpoint return format - remove json.dumps, use widgettype format

This commit is contained in:
yumoqing 2026-07-03 14:51:19 +08:00
parent 57f683671e
commit 12af8e9ac8
25455 changed files with 7660591 additions and 0 deletions

28
alipay_priv.pem Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCJHRwndZ5KgGu2
I5Q3/SkcDrdq59UOeWy5F0rz0GVujfz2/pWNqNcym+IDyrUoxFiYcYbqsu3IKeBU
PXIy4WIhjP++qnd+tKQvOUltxtC21Wpxh60HwFxqUnecC/szgSQEHGJOnHwAH0xX
tBf0MbtlOWxefeHYrVIb3nK9FYRzK0b7g/n35QZ8TYlKVLUhoBakqFQfTmQQFwoT
hu/1WiTwt+E8Gkixd83bMVl4Y6YXbyslIXcuG3WA43FnylgkutvbbkO8NpoZzwIr
Px8wD3wgxUqpuqbfOjXeHvPyInUzGKtuRxYNmW+b1+0ERKTSNsMm50T+Jehq6gK2
qGT1k5ydAgMBAAECggEABkxPrRb/qge+FYQK3IuEu4+IKKFKLbuxcnW5xqXtktIe
KtuaKQNMEedhJAVypChosrqRlO7vxyr37UapRoxdwpFvHztF+Tb497ECSMhCHAkv
i37M7uHiHNbO5wcR3IAeabtCtL5cCnFlmKhiv/UXg4MgvDJnZlmHv6n3IUJUxClz
3Cxnbt3C66Vbl1ES9vtu9obbMm3W3oFGH+7zJItVQyWa4uYBnAyOICTncT5tMR9k
gWuXITrt/cB9+PAJa7NZsPORPxHygV4bbo+7OH6sBLh1c+Rcm3oSNyejkzRaKFO2
tWUcsyFvIUd/h61BMG123mBWT4XgPo0pTCBkfPohDQKBgQC4fNRz6DSjT3OgF9+7
fLhU+58ED+UtMWKBbKx+PZZfaumxWf8ZbKeLanrnxkCWIr7aVyVl567gq5I5lvN3
jSIDM9A/hgJqFJ8wJ0sW8Q2Fv+loLxANgf8XboSpcy8uADPO7r83D/UhuseHy42L
vQ0ex8WoH0V39PeqBHqcjbZMAwKBgQC+Qz+PFLfcWfvoLQr2aGhe4AQmFSmM5szb
xntkEcD0Dj/34kHOdbKfTThOwo+X8gf3nPcA2WWz3ytQPhZQueNHsR6qcJwzI9WU
yULwnS9Ukdu6bHO74D+1ehM2jZVc2s2V58b2hr5yNz3Z/tlv9txttESBhyCi4bcO
zLzhxeUi3wKBgQCN0sDMHc0hYnnDr7a5/eYCxrB2wfVvKZDNaAquvY+06I6gXUwD
cojWX1P+i2SpRiqr1OSWE2ZXpu2xQf8Gf8OO7K0BuHZwsEu0C/DowQShNmgrREq1
56J/k+F+FmNFnLg3M0hh/u12MY0kMnIs43eLmw2y8d9ImVQvKmRLp5FlmwKBgEiD
tOvBh7nSCfKZiD4V2QGf+7TQCAANzzJMWabwJUxfSf4eG9qmfSe99KIAAV51/pdf
Gb0XHm4JtqZko3itAHTIitmHBeFv3O1SL9Mo9WsUFFzfDNUkSOPP3RbDq5OySPzD
U8+N13QMneRB/3lu6uBc/mcnq0apJG3dlneuRwCdAoGAYZsNbg84qE5o9Jy9dZG8
mTSoS7H/hFZR0XFx3ur6YIBVQ5Ajr//jJinItxMuqV/TEeMdMBJ9DrN+osgPahmq
KNzovtG8spGMbssXY6yMQtM0RPeI+/16TZiWcScnkYQ7QfkwWBRbvQgjUhE6E5Sn
v+Sp46nTaBhBn6iKNVJrhhE=
-----END PRIVATE KEY-----

28
alipay_pub.pem Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCmBNz4GpYlwpIy
7uhXTYpCy125vcGltsMjDr7xNehDSkwrQZYOfHoCALE8o1hTEeAXaZN/wls6AEUT
o4i2KB+g3EXDNtm298zydpaWyh8HDhLkzsPeVxT2t2BE6vsusa5/IeQWmnjfU4Un
erSee+EHkrimzAkCLezynOeR69hobkZzhFfPvDm3ur79wJcttRmwbeF0fM6Nvsx2
CY5f1g9ZQb5UY0tfsN7qNFR/Hm6f5Du4nIAt7CwVUheCrjvvh8dByNJBpmSJfqOI
BipzbBDWTQm0s8+d29noUU/rMRAwBfAToG73nCpJoiFLlvw+DCjR4y/FtE5wgHXm
a1wCl1MdAgMBAAECggEAHfpe1EYouqTJtXzCY5FS2ADU6cdEAmJgFiKBhBjR2eS+
oEj1iaQce+QYHPT56/YcWt3rjnRP+Mc3sfYjp5DTNT7RMhDje1B/p4CWbKAOvj1i
WAKmB6390RcHwSoVNTdMZRR/lT1LejggoSJdHwkLd0ydHzFUpxoX4S9H+Wd26lRE
UiMDZuytWdJaW+xDdHTLrgO7m2bgp7qA1QAekEodsMDSorPgw8sNx7o5v0ZruYZi
SXKx6V1zhjFtTcWjCQgV51+4h6NQdjkG5aEyrrdV1hl7uqJMFRHt5EkczD9y/m7g
jdmufhD0TLYbubSop3tBy68S9c6Hat6LTEFJsnwogQKBgQDoi6sGQPI/+tUbNFFH
n0XqbYhOZKD8J3sTW3Qtmo0rAZgtHVtzpgSs2+X836Qit5RghQA+GPX4lwbBoG3h
MjOjxET6YEk15pnzeiqQrPhxJgNSc05DigQTjQg7OgtP8AELvQc63kuJ97A3Ivol
KMEmqWI0VVybCrsDgXssaCAb8QKBgQC2w3owPrQT0ORWgmFDVwyquPrpkVdBk+1w
sE29hban9/3ykmVDgYS0Iyji0VvcBmD+SxUGavyVzKuRbxo4anOdjZMTH8yLaCZ4
RWiCMpIoM9QrB89my++X14V0n+wucvHromTYYdbewku5ReUV0Ivr/HDquCx+4vtD
3fAv3i3F7QKBgQCYPJdCCNKOwA8zOBTd5o9G4V4StB4P9WjFS2HLWRqBxRFyt31f
QJhe8bamzWIOuFASv/9gp8afb3+k0vocK1lTJPJjVxWWi9jNZHTpMdOTf2c9Wu8p
l/kDM5jn7R/qvRxyKtXI3C5nrBdYgTVxjjSkss7vo9J0TZoQuXuBnskmgQKBgFa0
J9yJcr7P4/OSiPf8bRr1BLwX4nBO8F78lPTrYXsQMF6KyxWadU1MPNJWBiE8uXkK
P6A60zdx0Jb/QU4wWkcNag+xj0U3lMCMFQdnXGVMKUR8wQ0AhNrhOQPZ9p8WkuR5
tyPcTqaBQJFVsleGB0teCGeiFiHgJtnMiWz8F3UFAoGAQCHHLm5UY0KR71eSiF/Z
RjcfuEy1KIi8IN2QGRWoonghWdtZiGhx/PeieaOVLs9XMR1uX+mLG1G9lKSVNdxs
S+y7engCTTS4JbkWN5Hv+LoXKv0y8As9e3ddk+OEO5iiW1ZyTyhrFCek2Xl8dSbq
aWHluS2LQFVNlDX5I1lTeuI=
-----END PRIVATE KEY-----

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

19
check_bricks_perms.py Normal file
View File

@ -0,0 +1,19 @@
import asyncio
from sqlor.dbpools import DBPools
from appPublic.jsonConfig import getConfig
async def main():
config = getConfig('.')
db = DBPools(config.databases)
async with db.sqlorContext('sage') as sor:
perms = await sor.sqlExe(
"select p.path from permission p inner join rolepermission rp on p.id=rp.permid where rp.roleid='any' and p.path like ${path}$",
{'path': '/bricks/%'}
)
print(f'Found {len(perms)} bricks paths with any role:')
for p in perms[:15]:
print(f' {p.path}')
if len(perms) > 15:
print(f' ... and {len(perms)-15} more')
asyncio.get_event_loop().run_until_complete(main())

132
conf/config.json Executable file
View File

@ -0,0 +1,132 @@
{
"password_key":"!@#$%^&*(*&^%$QWERTYUIqwertyui234567",
"logopath": "$[workdir]$/conf/logo.png",
"woa_handler_id":"woa_subscribe_type",
{
"hot_reload": {
"enabled": true,
"interval": 5
}
},
"logger":{
"name":"sage",
"levelname":"warning",
"logfile":"$[workdir]$/logs/sage.log"
},
"tpacs":{
"cnprod":{
"get_tpac_balance_url": "https://www.opencomputing.cn/cntoai/get_user_balance.dspy",
"tpac_accounting_url": "https://www.opencomputing.cn/cntoai/process_user_billing.dspy"
},
"ncmatchdemo":{
"get_tpac_balance_url": "https://www.ncmatch.cn/cntoai/get_user_balance.dspy",
"tpac_accounting_url": "https://www.ncmatch.cn/cntoai/process_user_billing.dspy"
},
"cndemo": {
"get_tpac_balance_url": "https://dev.opencomputing.cn/cntoai/get_user_balance.dspy",
"tpac_accounting_url": "https://dev.opencomputing.cn/cntoai/process_user_billing.dspy"
}
},
"pay":{
"alipay":{
"public_key_file":"$[workdir]$/conf/alipay/public.txt",
"private_key_file":"$[workdir]$/conf/alipay/private.txt",
"appid":"2021005111636494",
"callback":"https://sage.opencomputing.cn/api/callback/alipay"
},
"paypal":{
"mode":"sandbox",
"client_id":"myid",
"client_secret":"mysecret",
"return_url":"ret_url",
"cancel_url":"cancel_url"
}
},
"skills_path": "$[workdir]$/skills",
"filesroot":"$[workdir]$/files",
"databases":{
"sage":{
"driver":"mysql",
"kwargs":{
"user":"test",
"db":"sage",
"password":"SS+C1MDMJrslBwGzYIv3nQ==",
"charset": "utf8mb4",
"host":"db"
}
}
},
"zmq_url": "tcp://127.0.0.1:5555",
"website":{
"paths":[
["$[workdir]$/wwwroot",""]
],
"client_max_size":1000000000,
"host":"0.0.0.0",
"port":9080,
"coding":"utf-8",
"ssl_gg":{
"crtfile":"$[workdir]$/conf/www.bsppo.com.pem",
"keyfile":"$[workdir]$/conf/www.bsppo.com.key"
},
"indexes":[
"index.html",
"index.tmpl",
"index.ui",
"index.dspy",
"index.md"
],
"startswiths":[
{
"leading":"/idfile",
"registerfunction":"idfile"
},{
"leading":"/i18n_getmsgs",
"registerfunction":"i18n"
}
],
"processors":[
[".ws","ws"],
[".wss","ws"],
[".xterm","xterm"],
[".proxy","proxy"],
[".llm", "llm"],
[".llms", "llms"],
[".llma", "llma"],
[".xlsxds","xlsxds"],
[".sqlds","sqlds"],
[".tmpl.js","tmpl"],
[".tmpl.css","tmpl"],
[".html.tmpl","tmpl"],
[".bcrud", "bricks_crud"],
[".tmpl","tmpl"],
[".app","app"],
[".bui","bui"],
[".ui","bui"],
[".dspy","dspy"],
[".md","md"]
],
"rsakey":{
"privatekey":"$[workdir]$/conf/rsa_private_key.pem",
"publickey":"$[workdir]$/conf/rsa_public_key.pem"
},
"session_max_time":3000,
"session_issue_time":2500,
"session_redis":{
"url":"redis://127.0.0.1:6379"
}
},
"langMapping":{
"zh-Hans-CN":"zh-cn",
"zh-CN":"zh-cn",
"en-us":"en",
"en-US":"en"
},
"module_cache":{
"rbac":true,
"pricing":true,
"uapi":true
}
}

3440442
logs/backend_accounting.log Normal file

File diff suppressed because it is too large Load Diff

866685
logs/sage.log Normal file

File diff suppressed because it is too large Load Diff

4
logs/sage_startup.log Normal file
View File

@ -0,0 +1,4 @@
model path=/home/hermesai/repos/sage/py3/lib/python3.10/site-packages/checklang/lid.176.ftz
reuse_port= True
======== Running on http://0.0.0.0:9180 ========
(Press CTRL+C to quit)

0
logs/sage_worker_0.log Normal file
View File

0
logs/sage_worker_1.log Normal file
View File

0
logs/sage_worker_2.log Normal file
View File

0
logs/sage_worker_3.log Normal file
View File

28
merchant_private_key.pem Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDXTTNYz/VOr6KV
a74kO1Ivj30YiQ9xxASJYxpH51gtHRXO2HUKO7VVArnyMbqWEBvSdSBI/mDCoxhm
TMVxt752VzngPYhGm6M5cFXlzCDJmodnyNEjWrQjTwOZ49mSNXyhSCLzpzAs9Prx
Q6NpltYz+FFs2K9DAWkns0C4Ke0vMd5H0/Cs9pjWsQVSi1TW0bj876xrouU+4jsO
hK+WxA8sBsCdus7iuSkHjimDVYcVde/+N/WFSunY8Et5lb1mueSIL3d8EYucshF2
ZN93CqcvnEiVAycGaZqWakwgQWrtKzaVNSgq1npdycCkhy2qkwoMBk/1Ls4ZzkQW
fQc+eiBFAgMBAAECggEACF22mUStB1uDZmnJkxM/B7Wvd1M0GqHMSO5lG6Ndfy56
WQ96+zFqXWnkTqLCDLy5gaPaSk8GjlAG50q9miqfdKFbdvkAVGx0NKVgOrRQ5D4x
KF/arvrPG/Dt3Rf7R1dbhwTZK6POfaC5wF0P4Rviw1UEQCxQ7lPRGzrRUMnh4b7s
q3ceJ58wY3LB4UND0DLCMwh23XjyVPNOy3fnJ4f5sJSh9ddCcZVheNZ6YvQmucio
WPdWKUXV3phPxO6YGfIqcaNdkSUFkpQywCitmiuAcK/LqUmHV9S8CMpHodzk/U8U
BWQyq79h3imrkydssnEBhi2EYhpJcugjwA+0I8T3TQKBgQDik4ez5lLeACznCS1D
ZNHCpJFVqwVNW+VmdF9nCgyRDCixwUbBwg6fHmJiAyG4LZnsSaRQhtbTwP8Q1wnk
xefPcCFEacwkbyD/zbfsAWNYUAdnP5DB0bDOULjSP5NlMdgYfM86d99mhWRGpx1m
VSwTIeBNGGBokoivY07T5y4yFwKBgQDzQthecCwu3I2YV+3fjtBAtx47xwxP+weN
VNpowT0cJ/Uf7FB6A2P2t/A0fPOarcbuVMROdcdEeScszFQhmJxnBb0YLfotdK6M
42FHX7+dQ812Kh7+6h+mV1qzGllVeAFqur79C3uwq/MvPHaZxLwSzV+tSupjUUUx
cLUGszUGAwKBgQDaIx9rXDw77/9LD9K8J7yroLUrvVOFfwwE79VJ5qrimsozGNl+
gc6B80bVBh7Yq06d5uiDfs4lYJIxLFciIkdjt5jPvOwFx9gFb5G7bjqvM51tEg3U
DIYknCLUiNDnhG2AZek9aVtz4MkCHLJ5a1bbtKm2j9mB1FI0SXADI3eeUQKBgQDh
JcA/ABFUuhtvogpu/K5xB0s7Rop1yECAJcYUaK3Xzn/IsR73HwY5hpsS6YdKZYaW
dexPNiFdlciVZPSFN8uiaqROqddAlRstGRKjTdJ6ixOyR1/yzdzHR1iSJlQCkBS3
pOo6KJOtvChTUuHuhjEQMfdY29q+W6zwCoHyFpF/4wKBgQDiYcg8wpceWpGA1rbf
miY/tysjRe4KnFRr/4QSfIlhxubHyTuteviI92TemLWQzBmZ1iK0AimLDUGawulf
Qrnuz53SLznQs4gNoUHuP4V+0W5BFuWy0CHzoxS2fRSUNSWhdJgBJTsSpC9q+IVW
eXfGkqt1kXKZ9JP5Hjnz1FBCTg==
-----END PRIVATE KEY-----

9
merchant_public_key.pem Normal file
View File

@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA100zWM/1Tq+ilWu+JDtS
L499GIkPccQEiWMaR+dYLR0Vzth1Cju1VQK58jG6lhAb0nUgSP5gwqMYZkzFcbe+
dlc54D2IRpujOXBV5cwgyZqHZ8jRI1q0I08DmePZkjV8oUgi86cwLPT68UOjaZbW
M/hRbNivQwFpJ7NAuCntLzHeR9PwrPaY1rEFUotU1tG4/O+sa6LlPuI7DoSvlsQP
LAbAnbrO4rkpB44pg1WHFXXv/jf1hUrp2PBLeZW9ZrnkiC93fBGLnLIRdmTfdwqn
L5xIlQMnBmmalmpMIEFq7Ss2lTUoKtZ6XcnApIctqpMKDAZP9S7OGc5EFn0HPnog
RQIDAQAB
-----END PUBLIC KEY-----

68
migrate_llm_catelog.py Normal file
View File

@ -0,0 +1,68 @@
import asyncio
from sqlor.dbpools import DBPools
from appPublic.jsonConfig import getConfig
from appPublic.uniqueID import getID
async def migrate():
config = getConfig('.')
db = DBPools(config.databases)
# sage数据库
dbname = 'sage'
async with db.sqlorContext(dbname) as sor:
# 1. Create table if not exists
print("Creating llm_catalog_rel table...")
create_sql = """
CREATE TABLE IF NOT EXISTS llm_catalog_rel (
id VARCHAR(32) NOT NULL PRIMARY KEY,
llmid VARCHAR(32) NOT NULL,
llmcatelogid VARCHAR(32) NOT NULL,
INDEX idx_llm (llmid),
INDEX idx_catelog (llmcatelogid)
)
"""
try:
await sor.sqlExe(create_sql, {})
print("Table llm_catalog_rel created or exists.")
except Exception as e:
print(f"Create table warning: {e}")
# 2. Migrate data
print("Migrating data...")
sql = "select id, llmcatelogid from llm where llmcatelogid is not null and llmcatelogid != ''"
rows = await sor.sqlExe(sql, {})
print(f"Found {len(rows)} records to migrate.")
migrated = 0
for r in rows:
new_id = getID()
data = {
'id': new_id,
'llmid': r['id'],
'llmcatelogid': r['llmcatelogid']
}
try:
await sor.C('llm_catalog_rel', data)
migrated += 1
except Exception as e:
print(f"Insert error for {r['id']}: {e}")
print(f"Migration complete. Migrated {migrated} records.")
# 3. Drop column
print("Dropping column llmcatelogid from llm...")
try:
await sor.sqlExe("alter table llm drop column llmcatelogid", {})
print("Column dropped.")
except Exception as e:
print(f"Drop column error: {e}")
return True
if __name__ == '__main__':
success = asyncio.get_event_loop().run_until_complete(migrate())
if success:
print('Migration complete.')
else:
print('Migration failed.')

28
pay_private_key.pem Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDLwRhu06ULipoH
eO89TdCMUiGsafCqzbLlCVDxRcHXLZV4fiNQAwVLonYHZnlNq/kYzJbsXWyqz+FF
RanbD47JSPlMPGZOoYZ2ANVLQIk8OD9RfWjuDcw/0RtjmiaPnqgRZluNU7gvWYEF
+JBFTHiGUKdopuR5rVctq37b64azB6XsGRmQfvmuoG2bW/SIngnI1ReBR9W3Jhf6
lFG3EaW6VaW12JbgbHGC+UwjzlzQYJgeaKOyCLXvo6fGnqZ1dgQy/Fs5YmGX6emT
VO6t+Sgh1ipJeWl3192g+ntLzkokjtjsUw1UVXkPMCOsuo8tVN7upgK+ubDtMv5P
pPxAWYuzAgMBAAECggEAFgFE0r9KbVcq2xC9VwkUM1CxcKNBCdP3nz26Kfx8epvi
hHtW8/lc3+DBT3uf29AYBwzIEJSRu6wsv474+6llTylxkcFaKTbPmedCzILr71Qs
c8VlXi72S+luRFEDG3KpOGEuFQghdaz8aWPWrO1H0ksGnB+eFY1aGMVoiMwZ0DQb
asXW52rbuS/fpC5cg3ydsz6icDHyb/J1Zqp/UeHTL36Wl6pg+CDcKeYIWJ4tb//F
IGW4xvN3s49HqhtYK0VUNTP3dyabyLb9VQFLuAEJpdjZHQgzeqgHugRv1RVGzIls
SX2lRJz2e13W6Zp/TNtBKYfOaNLsHG4O4wawpkvmzQKBgQDiYvVLe+HwRgEIZciB
q6Jo9E8D3BCar3Wl6AFyNqePI32XaYazJwbXt4Ir9VRExFAL0gFfe8BWlk3ZJSvl
I6orE9Wc0J5/qHGasim4Jhs8YQhBj3sEo964RCgM88Aj5aQAsgQ0LtM3u9kcwju/
c5mXEYyzwBrodbPm6Tz8ZTFOJQKBgQDmaD8nlYkJPP4zgTSvKCZnWBuCa35mn7TV
ZqD0mUNzdE3ySClVORxV3AxBOQaDV8cJFqGWz3NfSBtzthUe/NpUI2IDWYFNp2SO
2eNcV0Oiq9m1LXiGZfO4AMui+0iALm2e+ArVqjewVc5QsPiuY4aztci1IcPH0jJi
Dm2CRuKu9wKBgDIa5uGLDKmqRMZACM2yWCLUl7xp837ZALf0joVh1VoX588gOwDh
zWDnK7dg+AK0VGcZVtZ0RFCluZsq3/k6GIqqPCgWAE6O0H4Fmrg4LuUBMNuZzwdq
4Xt1Ekwzkr4fMFo7DDUke/kk6Vu1HZY1FrRZ3QNXrFzw2B1uV+Ig33XFAoGAHWM4
gu0AwIvmBF27gYfGdjH3uEfLpH1ETF+9sdUGlGhGNNvdYcBaC914Nq12VjRQ76jS
TXECTyncToLv6LbphgfJTZIR+vyZx9qktDdxKgNvTjuRftrsHhED6DLSyX6ifr82
apA+cCBRo1sfLOcG3E8YXXoEBa2avYUHlLFD4nsCgYB/7t/ZukC100AInglfUW68
QXSNZTm7hk7N3mdZ83KQ5FarihdNWOAixy/0I0KMgr8QDDzDj8rlcODl0hLlyJta
0D3nb94Kzq86TFjX3t9vSfXJnGzIqhFY63QEegOcGuALGH3fp6GQUV7rUty831q/
XbjVeIOQP4Rbda60fSDAYg==
-----END PRIVATE KEY-----

247
py3/bin/Activate.ps1 Normal file
View File

@ -0,0 +1,247 @@
<#
.Synopsis
Activate a Python virtual environment for the current PowerShell session.
.Description
Pushes the python executable for a virtual environment to the front of the
$Env:PATH environment variable and sets the prompt to signify that you are
in a Python virtual environment. Makes use of the command line switches as
well as the `pyvenv.cfg` file values present in the virtual environment.
.Parameter VenvDir
Path to the directory that contains the virtual environment to activate. The
default value for this is the parent of the directory that the Activate.ps1
script is located within.
.Parameter Prompt
The prompt prefix to display when this virtual environment is activated. By
default, this prompt is the name of the virtual environment folder (VenvDir)
surrounded by parentheses and followed by a single space (ie. '(.venv) ').
.Example
Activate.ps1
Activates the Python virtual environment that contains the Activate.ps1 script.
.Example
Activate.ps1 -Verbose
Activates the Python virtual environment that contains the Activate.ps1 script,
and shows extra information about the activation as it executes.
.Example
Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
Activates the Python virtual environment located in the specified location.
.Example
Activate.ps1 -Prompt "MyPython"
Activates the Python virtual environment that contains the Activate.ps1 script,
and prefixes the current prompt with the specified string (surrounded in
parentheses) while the virtual environment is active.
.Notes
On Windows, it may be required to enable this Activate.ps1 script by setting the
execution policy for the user. You can do this by issuing the following PowerShell
command:
PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
For more information on Execution Policies:
https://go.microsoft.com/fwlink/?LinkID=135170
#>
Param(
[Parameter(Mandatory = $false)]
[String]
$VenvDir,
[Parameter(Mandatory = $false)]
[String]
$Prompt
)
<# Function declarations --------------------------------------------------- #>
<#
.Synopsis
Remove all shell session elements added by the Activate script, including the
addition of the virtual environment's Python executable from the beginning of
the PATH variable.
.Parameter NonDestructive
If present, do not remove this function from the global namespace for the
session.
#>
function global:deactivate ([switch]$NonDestructive) {
# Revert to original values
# The prior prompt:
if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
}
# The prior PYTHONHOME:
if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
}
# The prior PATH:
if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
Remove-Item -Path Env:_OLD_VIRTUAL_PATH
}
# Just remove the VIRTUAL_ENV altogether:
if (Test-Path -Path Env:VIRTUAL_ENV) {
Remove-Item -Path env:VIRTUAL_ENV
}
# Just remove VIRTUAL_ENV_PROMPT altogether.
if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
Remove-Item -Path env:VIRTUAL_ENV_PROMPT
}
# Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
}
# Leave deactivate function in the global namespace if requested:
if (-not $NonDestructive) {
Remove-Item -Path function:deactivate
}
}
<#
.Description
Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
given folder, and returns them in a map.
For each line in the pyvenv.cfg file, if that line can be parsed into exactly
two strings separated by `=` (with any amount of whitespace surrounding the =)
then it is considered a `key = value` line. The left hand string is the key,
the right hand is the value.
If the value starts with a `'` or a `"` then the first and last character is
stripped from the value before being captured.
.Parameter ConfigDir
Path to the directory that contains the `pyvenv.cfg` file.
#>
function Get-PyVenvConfig(
[String]
$ConfigDir
) {
Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
# Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
$pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
# An empty map will be returned if no config file is found.
$pyvenvConfig = @{ }
if ($pyvenvConfigPath) {
Write-Verbose "File exists, parse `key = value` lines"
$pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
$pyvenvConfigContent | ForEach-Object {
$keyval = $PSItem -split "\s*=\s*", 2
if ($keyval[0] -and $keyval[1]) {
$val = $keyval[1]
# Remove extraneous quotations around a string value.
if ("'""".Contains($val.Substring(0, 1))) {
$val = $val.Substring(1, $val.Length - 2)
}
$pyvenvConfig[$keyval[0]] = $val
Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
}
}
}
return $pyvenvConfig
}
<# Begin Activate script --------------------------------------------------- #>
# Determine the containing directory of this script
$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
$VenvExecDir = Get-Item -Path $VenvExecPath
Write-Verbose "Activation script is located in path: '$VenvExecPath'"
Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
# Set values required in priority: CmdLine, ConfigFile, Default
# First, get the location of the virtual environment, it might not be
# VenvExecDir if specified on the command line.
if ($VenvDir) {
Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
}
else {
Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
$VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
Write-Verbose "VenvDir=$VenvDir"
}
# Next, read the `pyvenv.cfg` file to determine any required value such
# as `prompt`.
$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
# Next, set the prompt from the command line, or the config file, or
# just use the name of the virtual environment folder.
if ($Prompt) {
Write-Verbose "Prompt specified as argument, using '$Prompt'"
}
else {
Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
$Prompt = $pyvenvCfg['prompt'];
}
else {
Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)"
Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
$Prompt = Split-Path -Path $venvDir -Leaf
}
}
Write-Verbose "Prompt = '$Prompt'"
Write-Verbose "VenvDir='$VenvDir'"
# Deactivate any currently active virtual environment, but leave the
# deactivate function in place.
deactivate -nondestructive
# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
# that there is an activated venv.
$env:VIRTUAL_ENV = $VenvDir
if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
Write-Verbose "Setting prompt to '$Prompt'"
# Set the prompt to include the env name
# Make sure _OLD_VIRTUAL_PROMPT is global
function global:_OLD_VIRTUAL_PROMPT { "" }
Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
function global:prompt {
Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
_OLD_VIRTUAL_PROMPT
}
$env:VIRTUAL_ENV_PROMPT = $Prompt
}
# Clear PYTHONHOME
if (Test-Path -Path Env:PYTHONHOME) {
Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
Remove-Item -Path Env:PYTHONHOME
}
# Add the venv to the PATH
Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"

Binary file not shown.

Binary file not shown.

69
py3/bin/activate Normal file
View File

@ -0,0 +1,69 @@
# This file must be used with "source bin/activate" *from bash*
# you cannot run it directly
deactivate () {
# reset old environment variables
if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
PATH="${_OLD_VIRTUAL_PATH:-}"
export PATH
unset _OLD_VIRTUAL_PATH
fi
if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
export PYTHONHOME
unset _OLD_VIRTUAL_PYTHONHOME
fi
# This should detect bash and zsh, which have a hash command that must
# be called to get it to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
hash -r 2> /dev/null
fi
if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
PS1="${_OLD_VIRTUAL_PS1:-}"
export PS1
unset _OLD_VIRTUAL_PS1
fi
unset VIRTUAL_ENV
unset VIRTUAL_ENV_PROMPT
if [ ! "${1:-}" = "nondestructive" ] ; then
# Self destruct!
unset -f deactivate
fi
}
# unset irrelevant variables
deactivate nondestructive
VIRTUAL_ENV=/home/hermesai/repos/sage/py3
export VIRTUAL_ENV
_OLD_VIRTUAL_PATH="$PATH"
PATH="$VIRTUAL_ENV/"bin":$PATH"
export PATH
# unset PYTHONHOME if set
# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
# could use `if (set -u; : $PYTHONHOME) ;` in bash
if [ -n "${PYTHONHOME:-}" ] ; then
_OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
unset PYTHONHOME
fi
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
_OLD_VIRTUAL_PS1="${PS1:-}"
PS1='(py3) '"${PS1:-}"
export PS1
VIRTUAL_ENV_PROMPT='(py3) '
export VIRTUAL_ENV_PROMPT
fi
# This should detect bash and zsh, which have a hash command that must
# be called to get it to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
hash -r 2> /dev/null
fi

26
py3/bin/activate.csh Normal file
View File

@ -0,0 +1,26 @@
# This file must be used with "source bin/activate.csh" *from csh*.
# You cannot run it directly.
# Created by Davide Di Blasi <davidedb@gmail.com>.
# Ported to Python 3.3 venv by Andrew Svetlov <andrew.svetlov@gmail.com>
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate'
# Unset irrelevant variables.
deactivate nondestructive
setenv VIRTUAL_ENV /home/hermesai/repos/sage/py3
set _OLD_VIRTUAL_PATH="$PATH"
setenv PATH "$VIRTUAL_ENV/"bin":$PATH"
set _OLD_VIRTUAL_PROMPT="$prompt"
if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
set prompt = '(py3) '"$prompt"
setenv VIRTUAL_ENV_PROMPT '(py3) '
endif
alias pydoc python -m pydoc
rehash

69
py3/bin/activate.fish Normal file
View File

@ -0,0 +1,69 @@
# This file must be used with "source <venv>/bin/activate.fish" *from fish*
# (https://fishshell.com/); you cannot run it directly.
function deactivate -d "Exit virtual environment and return to normal shell environment"
# reset old environment variables
if test -n "$_OLD_VIRTUAL_PATH"
set -gx PATH $_OLD_VIRTUAL_PATH
set -e _OLD_VIRTUAL_PATH
end
if test -n "$_OLD_VIRTUAL_PYTHONHOME"
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
set -e _OLD_VIRTUAL_PYTHONHOME
end
if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
set -e _OLD_FISH_PROMPT_OVERRIDE
# prevents error when using nested fish instances (Issue #93858)
if functions -q _old_fish_prompt
functions -e fish_prompt
functions -c _old_fish_prompt fish_prompt
functions -e _old_fish_prompt
end
end
set -e VIRTUAL_ENV
set -e VIRTUAL_ENV_PROMPT
if test "$argv[1]" != "nondestructive"
# Self-destruct!
functions -e deactivate
end
end
# Unset irrelevant variables.
deactivate nondestructive
set -gx VIRTUAL_ENV /home/hermesai/repos/sage/py3
set -gx _OLD_VIRTUAL_PATH $PATH
set -gx PATH "$VIRTUAL_ENV/"bin $PATH
# Unset PYTHONHOME if set.
if set -q PYTHONHOME
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
set -e PYTHONHOME
end
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
# fish uses a function instead of an env var to generate the prompt.
# Save the current fish_prompt function as the function _old_fish_prompt.
functions -c fish_prompt _old_fish_prompt
# With the original prompt function renamed, we can override with our own.
function fish_prompt
# Save the return status of the last command.
set -l old_status $status
# Output the venv prompt; color taken from the blue of the Python logo.
printf "%s%s%s" (set_color 4B8BBE) '(py3) ' (set_color normal)
# Restore the return status of the previous command.
echo "exit $old_status" | .
# Output the original/"old" prompt.
_old_fish_prompt
end
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
set -gx VIRTUAL_ENV_PROMPT '(py3) '
end

8
py3/bin/dbloader Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from sqlor.dbloader import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/dbpassword Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from sqlor.dbpassword import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/distro Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from distro.distro import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/dotenv Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from dotenv.__main__ import cli
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(cli())

8
py3/bin/f2py Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from numpy.f2py.f2py2e import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/futurize Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from libfuturize.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/html2text Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from html2text.cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/httpx Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from httpx import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/json2ddl Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from xls2ddl.json2ddl import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/json2xlsx Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from xls2ddl.json2xlsx import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

41
py3/bin/jsondiff Executable file
View File

@ -0,0 +1,41 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
from __future__ import print_function
import sys
import json
import jsonpatch
import argparse
parser = argparse.ArgumentParser(description='Diff two JSON files')
parser.add_argument('FILE1', type=argparse.FileType('r'))
parser.add_argument('FILE2', type=argparse.FileType('r'))
parser.add_argument('--indent', type=int, default=None,
help='Indent output by n spaces')
parser.add_argument('-u', '--preserve-unicode', action='store_true',
help='Output Unicode character as-is without using Code Point')
parser.add_argument('-v', '--version', action='version',
version='%(prog)s ' + jsonpatch.__version__)
def main():
try:
diff_files()
except KeyboardInterrupt:
sys.exit(1)
def diff_files():
""" Diffs two JSON files and prints a patch """
args = parser.parse_args()
doc1 = json.load(args.FILE1)
doc2 = json.load(args.FILE2)
patch = jsonpatch.make_patch(doc1, doc2)
if patch.patch:
print(json.dumps(patch.patch, indent=args.indent, ensure_ascii=not(args.preserve_unicode)))
sys.exit(1)
if __name__ == "__main__":
main()

107
py3/bin/jsonpatch Executable file
View File

@ -0,0 +1,107 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import sys
import os.path
import json
import jsonpatch
import tempfile
import argparse
parser = argparse.ArgumentParser(
description='Apply a JSON patch on a JSON file')
parser.add_argument('ORIGINAL', type=argparse.FileType('r'),
help='Original file')
parser.add_argument('PATCH', type=argparse.FileType('r'),
nargs='?', default=sys.stdin,
help='Patch file (read from stdin if omitted)')
parser.add_argument('--indent', type=int, default=None,
help='Indent output by n spaces')
parser.add_argument('-b', '--backup', action='store_true',
help='Back up ORIGINAL if modifying in-place')
parser.add_argument('-i', '--in-place', action='store_true',
help='Modify ORIGINAL in-place instead of to stdout')
parser.add_argument('-v', '--version', action='version',
version='%(prog)s ' + jsonpatch.__version__)
parser.add_argument('-u', '--preserve-unicode', action='store_true',
help='Output Unicode character as-is without using Code Point')
def main():
try:
patch_files()
except KeyboardInterrupt:
sys.exit(1)
def patch_files():
""" Diffs two JSON files and prints a patch """
args = parser.parse_args()
doc = json.load(args.ORIGINAL)
patch = json.load(args.PATCH)
result = jsonpatch.apply_patch(doc, patch)
if args.in_place:
dirname = os.path.abspath(os.path.dirname(args.ORIGINAL.name))
try:
# Attempt to replace the file atomically. We do this by
# creating a temporary file in the same directory as the
# original file so we can atomically move the new file over
# the original later. (This is done in the same directory
# because atomic renames do not work across mount points.)
fd, pathname = tempfile.mkstemp(dir=dirname)
fp = os.fdopen(fd, 'w')
atomic = True
except OSError:
# We failed to create the temporary file for an atomic
# replace, so fall back to non-atomic mode by backing up
# the original (if desired) and writing a new file.
if args.backup:
os.rename(args.ORIGINAL.name, args.ORIGINAL.name + '.orig')
fp = open(args.ORIGINAL.name, 'w')
atomic = False
else:
# Since we're not replacing the original file in-place, write
# the modified JSON to stdout instead.
fp = sys.stdout
# By this point we have some sort of file object we can write the
# modified JSON to.
json.dump(result, fp, indent=args.indent, ensure_ascii=not(args.preserve_unicode))
fp.write('\n')
if args.in_place:
# Close the new file. If we aren't replacing atomically, this
# is our last step, since everything else is already in place.
fp.close()
if atomic:
try:
# Complete the atomic replace by linking the original
# to a backup (if desired), fixing up the permissions
# on the temporary file, and moving it into place.
if args.backup:
os.link(args.ORIGINAL.name, args.ORIGINAL.name + '.orig')
os.chmod(pathname, os.stat(args.ORIGINAL.name).st_mode)
os.rename(pathname, args.ORIGINAL.name)
except OSError:
# In the event we could not actually do the atomic
# replace, unlink the original to move it out of the
# way and finally move the temporary file into place.
os.unlink(args.ORIGINAL.name)
os.rename(pathname, args.ORIGINAL.name)
if __name__ == "__main__":
main()

66
py3/bin/jsonpointer Executable file
View File

@ -0,0 +1,66 @@
#!/home/hermesai/repos/sage/py3/bin/python3
import argparse
import json
import sys
import jsonpointer
parser = argparse.ArgumentParser(
description='Resolve a JSON pointer on JSON files')
# Accept pointer as argument or as file
ptr_group = parser.add_mutually_exclusive_group(required=True)
ptr_group.add_argument('-f', '--pointer-file', type=argparse.FileType('r'),
nargs='?',
help='File containing a JSON pointer expression')
ptr_group.add_argument('POINTER', type=str, nargs='?',
help='A JSON pointer expression')
parser.add_argument('FILE', type=argparse.FileType('r'), nargs='+',
help='Files for which the pointer should be resolved')
parser.add_argument('--indent', type=int, default=None,
help='Indent output by n spaces')
parser.add_argument('-v', '--version', action='version',
version='%(prog)s ' + jsonpointer.__version__)
def main():
try:
resolve_files()
except KeyboardInterrupt:
sys.exit(1)
def parse_pointer(args):
if args.POINTER:
ptr = args.POINTER
elif args.pointer_file:
ptr = args.pointer_file.read().strip()
else:
parser.print_usage()
sys.exit(1)
return ptr
def resolve_files():
""" Resolve a JSON pointer on JSON files """
args = parser.parse_args()
ptr = parse_pointer(args)
for f in args.FILE:
doc = json.load(f)
try:
result = jsonpointer.resolve_pointer(doc, ptr)
print(json.dumps(result, indent=args.indent))
except jsonpointer.JsonPointerException as e:
print('Could not resolve pointer: %s' % str(e), file=sys.stderr)
if __name__ == "__main__":
main()

8
py3/bin/markdown-it Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from markdown_it.cli.parse import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/mobiunpack Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from mobi.kindleunpack import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/natpmp-client.py Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from natpmp.natpmp_client import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/normalizer Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from charset_normalizer.cli import cli_detect
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(cli_detect())

8
py3/bin/numpy-config Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from numpy._configtool import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/pasteurize Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from libpasteurize.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/pip Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/pip3 Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/pip3.10 Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/pybind11-config Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pybind11.__main__ import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/pygmentize Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pygments.cmdline import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/pymupdf Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pymupdf.__main__ import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/pyrsa-decrypt Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from rsa.cli import decrypt
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(decrypt())

8
py3/bin/pyrsa-encrypt Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from rsa.cli import encrypt
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(encrypt())

8
py3/bin/pyrsa-keygen Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from rsa.cli import keygen
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(keygen())

8
py3/bin/pyrsa-priv2pub Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from rsa.util import private_to_public
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(private_to_public())

8
py3/bin/pyrsa-sign Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from rsa.cli import sign
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(sign())

8
py3/bin/pyrsa-verify Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from rsa.cli import verify
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(verify())

8
py3/bin/pytesseract Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pytesseract.pytesseract import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

1
py3/bin/python Symbolic link
View File

@ -0,0 +1 @@
python3

1
py3/bin/python3 Symbolic link
View File

@ -0,0 +1 @@
/usr/bin/python3

1
py3/bin/python3.10 Symbolic link
View File

@ -0,0 +1 @@
python3

8
py3/bin/qr Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from qrcode.console_scripts import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

410
py3/bin/runxlrd.py Executable file
View File

@ -0,0 +1,410 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# Copyright (c) 2005-2012 Stephen John Machin, Lingfo Pty Ltd
# This script is part of the xlrd package, which is released under a
# BSD-style licence.
from __future__ import print_function
cmd_doc = """
Commands:
2rows Print the contents of first and last row in each sheet
3rows Print the contents of first, second and last row in each sheet
bench Same as "show", but doesn't print -- for profiling
biff_count[1] Print a count of each type of BIFF record in the file
biff_dump[1] Print a dump (char and hex) of the BIFF records in the file
fonts hdr + print a dump of all font objects
hdr Mini-overview of file (no per-sheet information)
hotshot Do a hotshot profile run e.g. ... -f1 hotshot bench bigfile*.xls
labels Dump of sheet.col_label_ranges and ...row... for each sheet
name_dump Dump of each object in book.name_obj_list
names Print brief information for each NAME record
ov Overview of file
profile Like "hotshot", but uses cProfile
show Print the contents of all rows in each sheet
version[0] Print versions of xlrd and Python and exit
xfc Print "XF counts" and cell-type counts -- see code for details
[0] means no file arg
[1] means only one file arg i.e. no glob.glob pattern
"""
options = None
if __name__ == "__main__":
import xlrd
import sys
import time
import glob
import traceback
import gc
from xlrd.timemachine import xrange, REPR
class LogHandler(object):
def __init__(self, logfileobj):
self.logfileobj = logfileobj
self.fileheading = None
self.shown = 0
def setfileheading(self, fileheading):
self.fileheading = fileheading
self.shown = 0
def write(self, text):
if self.fileheading and not self.shown:
self.logfileobj.write(self.fileheading)
self.shown = 1
self.logfileobj.write(text)
null_cell = xlrd.empty_cell
def show_row(bk, sh, rowx, colrange, printit):
if bk.ragged_rows:
colrange = range(sh.row_len(rowx))
if not colrange: return
if printit: print()
if bk.formatting_info:
for colx, ty, val, cxfx in get_row_data(bk, sh, rowx, colrange):
if printit:
print("cell %s%d: type=%d, data: %r, xfx: %s"
% (xlrd.colname(colx), rowx+1, ty, val, cxfx))
else:
for colx, ty, val, _unused in get_row_data(bk, sh, rowx, colrange):
if printit:
print("cell %s%d: type=%d, data: %r" % (xlrd.colname(colx), rowx+1, ty, val))
def get_row_data(bk, sh, rowx, colrange):
result = []
dmode = bk.datemode
ctys = sh.row_types(rowx)
cvals = sh.row_values(rowx)
for colx in colrange:
cty = ctys[colx]
cval = cvals[colx]
if bk.formatting_info:
cxfx = str(sh.cell_xf_index(rowx, colx))
else:
cxfx = ''
if cty == xlrd.XL_CELL_DATE:
try:
showval = xlrd.xldate_as_tuple(cval, dmode)
except xlrd.XLDateError as e:
showval = "%s:%s" % (type(e).__name__, e)
cty = xlrd.XL_CELL_ERROR
elif cty == xlrd.XL_CELL_ERROR:
showval = xlrd.error_text_from_code.get(cval, '<Unknown error code 0x%02x>' % cval)
else:
showval = cval
result.append((colx, cty, showval, cxfx))
return result
def bk_header(bk):
print()
print("BIFF version: %s; datemode: %s"
% (xlrd.biff_text_from_num[bk.biff_version], bk.datemode))
print("codepage: %r (encoding: %s); countries: %r"
% (bk.codepage, bk.encoding, bk.countries))
print("Last saved by: %r" % bk.user_name)
print("Number of data sheets: %d" % bk.nsheets)
print("Use mmap: %d; Formatting: %d; On demand: %d"
% (bk.use_mmap, bk.formatting_info, bk.on_demand))
print("Ragged rows: %d" % bk.ragged_rows)
if bk.formatting_info:
print("FORMATs: %d, FONTs: %d, XFs: %d"
% (len(bk.format_list), len(bk.font_list), len(bk.xf_list)))
if not options.suppress_timing:
print("Load time: %.2f seconds (stage 1) %.2f seconds (stage 2)"
% (bk.load_time_stage_1, bk.load_time_stage_2))
print()
def show_fonts(bk):
print("Fonts:")
for x in xrange(len(bk.font_list)):
font = bk.font_list[x]
font.dump(header='== Index %d ==' % x, indent=4)
def show_names(bk, dump=0):
bk_header(bk)
if bk.biff_version < 50:
print("Names not extracted in this BIFF version")
return
nlist = bk.name_obj_list
print("Name list: %d entries" % len(nlist))
for nobj in nlist:
if dump:
nobj.dump(sys.stdout,
header="\n=== Dump of name_obj_list[%d] ===" % nobj.name_index)
else:
print("[%d]\tName:%r macro:%r scope:%d\n\tresult:%r\n"
% (nobj.name_index, nobj.name, nobj.macro, nobj.scope, nobj.result))
def print_labels(sh, labs, title):
if not labs:return
for rlo, rhi, clo, chi in labs:
print("%s label range %s:%s contains:"
% (title, xlrd.cellname(rlo, clo), xlrd.cellname(rhi-1, chi-1)))
for rx in xrange(rlo, rhi):
for cx in xrange(clo, chi):
print(" %s: %r" % (xlrd.cellname(rx, cx), sh.cell_value(rx, cx)))
def show_labels(bk):
# bk_header(bk)
hdr = 0
for shx in range(bk.nsheets):
sh = bk.sheet_by_index(shx)
clabs = sh.col_label_ranges
rlabs = sh.row_label_ranges
if clabs or rlabs:
if not hdr:
bk_header(bk)
hdr = 1
print("sheet %d: name = %r; nrows = %d; ncols = %d" %
(shx, sh.name, sh.nrows, sh.ncols))
print_labels(sh, clabs, 'Col')
print_labels(sh, rlabs, 'Row')
if bk.on_demand: bk.unload_sheet(shx)
def show(bk, nshow=65535, printit=1):
bk_header(bk)
if 0:
rclist = xlrd.sheet.rc_stats.items()
rclist = sorted(rclist)
print("rc stats")
for k, v in rclist:
print("0x%04x %7d" % (k, v))
if options.onesheet:
try:
shx = int(options.onesheet)
except ValueError:
shx = bk.sheet_by_name(options.onesheet).number
shxrange = [shx]
else:
shxrange = range(bk.nsheets)
# print("shxrange", list(shxrange))
for shx in shxrange:
sh = bk.sheet_by_index(shx)
nrows, ncols = sh.nrows, sh.ncols
colrange = range(ncols)
anshow = min(nshow, nrows)
print("sheet %d: name = %s; nrows = %d; ncols = %d" %
(shx, REPR(sh.name), sh.nrows, sh.ncols))
if nrows and ncols:
# Beat the bounds
for rowx in xrange(nrows):
nc = sh.row_len(rowx)
if nc:
sh.row_types(rowx)[nc-1]
sh.row_values(rowx)[nc-1]
sh.cell(rowx, nc-1)
for rowx in xrange(anshow-1):
if not printit and rowx % 10000 == 1 and rowx > 1:
print("done %d rows" % (rowx-1,))
show_row(bk, sh, rowx, colrange, printit)
if anshow and nrows:
show_row(bk, sh, nrows-1, colrange, printit)
print()
if bk.on_demand: bk.unload_sheet(shx)
def count_xfs(bk):
bk_header(bk)
for shx in range(bk.nsheets):
sh = bk.sheet_by_index(shx)
nrows = sh.nrows
print("sheet %d: name = %r; nrows = %d; ncols = %d" %
(shx, sh.name, sh.nrows, sh.ncols))
# Access all xfindexes to force gathering stats
type_stats = [0, 0, 0, 0, 0, 0, 0]
for rowx in xrange(nrows):
for colx in xrange(sh.row_len(rowx)):
xfx = sh.cell_xf_index(rowx, colx)
assert xfx >= 0
cty = sh.cell_type(rowx, colx)
type_stats[cty] += 1
print("XF stats", sh._xf_index_stats)
print("type stats", type_stats)
print()
if bk.on_demand: bk.unload_sheet(shx)
def main(cmd_args):
import optparse
global options
usage = "\n%prog [options] command [input-file-patterns]\n" + cmd_doc
oparser = optparse.OptionParser(usage)
oparser.add_option(
"-l", "--logfilename",
default="",
help="contains error messages")
oparser.add_option(
"-v", "--verbosity",
type="int", default=0,
help="level of information and diagnostics provided")
oparser.add_option(
"-m", "--mmap",
type="int", default=-1,
help="1: use mmap; 0: don't use mmap; -1: accept heuristic")
oparser.add_option(
"-e", "--encoding",
default="",
help="encoding override")
oparser.add_option(
"-f", "--formatting",
type="int", default=0,
help="0 (default): no fmt info\n"
"1: fmt info (all cells)\n",
)
oparser.add_option(
"-g", "--gc",
type="int", default=0,
help="0: auto gc enabled; 1: auto gc disabled, manual collect after each file; 2: no gc")
oparser.add_option(
"-s", "--onesheet",
default="",
help="restrict output to this sheet (name or index)")
oparser.add_option(
"-u", "--unnumbered",
action="store_true", default=0,
help="omit line numbers or offsets in biff_dump")
oparser.add_option(
"-d", "--on-demand",
action="store_true", default=0,
help="load sheets on demand instead of all at once")
oparser.add_option(
"-t", "--suppress-timing",
action="store_true", default=0,
help="don't print timings (diffs are less messy)")
oparser.add_option(
"-r", "--ragged-rows",
action="store_true", default=0,
help="open_workbook(..., ragged_rows=True)")
options, args = oparser.parse_args(cmd_args)
if len(args) == 1 and args[0] in ("version", ):
pass
elif len(args) < 2:
oparser.error("Expected at least 2 args, found %d" % len(args))
cmd = args[0]
xlrd_version = getattr(xlrd, "__VERSION__", "unknown; before 0.5")
if cmd == 'biff_dump':
xlrd.dump(args[1], unnumbered=options.unnumbered)
sys.exit(0)
if cmd == 'biff_count':
xlrd.count_records(args[1])
sys.exit(0)
if cmd == 'version':
print("xlrd: %s, from %s" % (xlrd_version, xlrd.__file__))
print("Python:", sys.version)
sys.exit(0)
if options.logfilename:
logfile = LogHandler(open(options.logfilename, 'w'))
else:
logfile = sys.stdout
mmap_opt = options.mmap
mmap_arg = xlrd.USE_MMAP
if mmap_opt in (1, 0):
mmap_arg = mmap_opt
elif mmap_opt != -1:
print('Unexpected value (%r) for mmap option -- assuming default' % mmap_opt)
fmt_opt = options.formatting | (cmd in ('xfc', ))
gc_mode = options.gc
if gc_mode:
gc.disable()
for pattern in args[1:]:
for fname in glob.glob(pattern):
print("\n=== File: %s ===" % fname)
if logfile != sys.stdout:
logfile.setfileheading("\n=== File: %s ===\n" % fname)
if gc_mode == 1:
n_unreachable = gc.collect()
if n_unreachable:
print("GC before open:", n_unreachable, "unreachable objects")
try:
t0 = time.time()
bk = xlrd.open_workbook(
fname,
verbosity=options.verbosity, logfile=logfile,
use_mmap=mmap_arg,
encoding_override=options.encoding,
formatting_info=fmt_opt,
on_demand=options.on_demand,
ragged_rows=options.ragged_rows,
)
t1 = time.time()
if not options.suppress_timing:
print("Open took %.2f seconds" % (t1-t0,))
except xlrd.XLRDError as e:
print("*** Open failed: %s: %s" % (type(e).__name__, e))
continue
except KeyboardInterrupt:
print("*** KeyboardInterrupt ***")
traceback.print_exc(file=sys.stdout)
sys.exit(1)
except BaseException as e:
print("*** Open failed: %s: %s" % (type(e).__name__, e))
traceback.print_exc(file=sys.stdout)
continue
t0 = time.time()
if cmd == 'hdr':
bk_header(bk)
elif cmd == 'ov': # OverView
show(bk, 0)
elif cmd == 'show': # all rows
show(bk)
elif cmd == '2rows': # first row and last row
show(bk, 2)
elif cmd == '3rows': # first row, 2nd row and last row
show(bk, 3)
elif cmd == 'bench':
show(bk, printit=0)
elif cmd == 'fonts':
bk_header(bk)
show_fonts(bk)
elif cmd == 'names': # named reference list
show_names(bk)
elif cmd == 'name_dump': # named reference list
show_names(bk, dump=1)
elif cmd == 'labels':
show_labels(bk)
elif cmd == 'xfc':
count_xfs(bk)
else:
print("*** Unknown command <%s>" % cmd)
sys.exit(1)
del bk
if gc_mode == 1:
n_unreachable = gc.collect()
if n_unreachable:
print("GC post cmd:", fname, "->", n_unreachable, "unreachable objects")
if not options.suppress_timing:
t1 = time.time()
print("\ncommand took %.2f seconds\n" % (t1-t0,))
return None
av = sys.argv[1:]
if not av:
main(av)
firstarg = av[0].lower()
if firstarg == "hotshot":
import hotshot
import hotshot.stats
av = av[1:]
prof_log_name = "XXXX.prof"
prof = hotshot.Profile(prof_log_name)
# benchtime, result = prof.runcall(main, *av)
result = prof.runcall(main, *(av, ))
print("result", repr(result))
prof.close()
stats = hotshot.stats.load(prof_log_name)
stats.strip_dirs()
stats.sort_stats('time', 'calls')
stats.print_stats(20)
elif firstarg == "profile":
import cProfile
av = av[1:]
cProfile.run('main(av)', 'YYYY.prof')
import pstats
p = pstats.Stats('YYYY.prof')
p.strip_dirs().sort_stats('cumulative').print_stats(30)
else:
main(av)

8
py3/bin/spacy Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from spacy.cli import setup_cli
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(setup_cli())

8
py3/bin/tqdm Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from tqdm.cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/typer Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from typer.cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

79
py3/bin/vba_extract.py Executable file
View File

@ -0,0 +1,79 @@
#!/home/hermesai/repos/sage/py3/bin/python3
##############################################################################
#
# vba_extract - A simple utility to extract a vbaProject.bin binary from an
# Excel 2007+ xlsm file for insertion into an XlsxWriter file.
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2013-2025, John McNamara, jmcnamara@cpan.org
#
import sys
from zipfile import BadZipFile, ZipFile
def extract_file(xlsm_zip, filename):
# Extract a single file from an Excel xlsm macro file.
data = xlsm_zip.read("xl/" + filename)
# Write the data to a local file.
file = open(filename, "wb")
file.write(data)
file.close()
# The VBA project file and project signature file we want to extract.
vba_filename = "vbaProject.bin"
vba_signature_filename = "vbaProjectSignature.bin"
# Get the xlsm file name from the commandline.
if len(sys.argv) > 1:
xlsm_file = sys.argv[1]
else:
print(
"\nUtility to extract a vbaProject.bin binary from an Excel 2007+ "
"xlsm macro file for insertion into an XlsxWriter file.\n"
"If the macros are digitally signed, extracts also a vbaProjectSignature.bin "
"file.\n"
"\n"
"See: https://xlsxwriter.readthedocs.io/working_with_macros.html\n"
"\n"
"Usage: vba_extract file.xlsm\n"
)
sys.exit()
try:
# Open the Excel xlsm file as a zip file.
xlsm_zip = ZipFile(xlsm_file, "r")
# Read the xl/vbaProject.bin file.
extract_file(xlsm_zip, vba_filename)
print(f"Extracted: {vba_filename}")
if "xl/" + vba_signature_filename in xlsm_zip.namelist():
extract_file(xlsm_zip, vba_signature_filename)
print(f"Extracted: {vba_signature_filename}")
except IOError as e:
print(f"File error: {str(e)}")
sys.exit()
except KeyError as e:
# Usually when there isn't a xl/vbaProject.bin member in the file.
print(f"File error: {str(e)}")
print(f"File may not be an Excel xlsm macro file: '{xlsm_file}'")
sys.exit()
except BadZipFile as e:
# Usually if the file is an xls file and not an xlsm file.
print(f"File error: {str(e)}: '{xlsm_file}'")
print("File may not be an Excel xlsm macro file.")
sys.exit()
except Exception as e:
# Catch any other exceptions.
print(f"File error: {str(e)}")
sys.exit()

8
py3/bin/weasel Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from weasel.cli import app
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(app())

8
py3/bin/wheel Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from wheel._commands import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/xls2ddl Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from xls2ddl.xls2ddl import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
py3/bin/xls2ui Executable file
View File

@ -0,0 +1,8 @@
#!/home/hermesai/repos/sage/py3/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from xls2ddl.xls2ui import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View File

@ -0,0 +1,164 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
/* Greenlet object interface */
#ifndef Py_GREENLETOBJECT_H
#define Py_GREENLETOBJECT_H
#include <Python.h>
#ifdef __cplusplus
extern "C" {
#endif
/* This is deprecated and undocumented. It does not change. */
#define GREENLET_VERSION "1.0.0"
#ifndef GREENLET_MODULE
#define implementation_ptr_t void*
#endif
typedef struct _greenlet {
PyObject_HEAD
PyObject* weakreflist;
PyObject* dict;
implementation_ptr_t pimpl;
} PyGreenlet;
#define PyGreenlet_Check(op) (op && PyObject_TypeCheck(op, &PyGreenlet_Type))
/* C API functions */
/* Total number of symbols that are exported */
#define PyGreenlet_API_pointers 12
#define PyGreenlet_Type_NUM 0
#define PyExc_GreenletError_NUM 1
#define PyExc_GreenletExit_NUM 2
#define PyGreenlet_New_NUM 3
#define PyGreenlet_GetCurrent_NUM 4
#define PyGreenlet_Throw_NUM 5
#define PyGreenlet_Switch_NUM 6
#define PyGreenlet_SetParent_NUM 7
#define PyGreenlet_MAIN_NUM 8
#define PyGreenlet_STARTED_NUM 9
#define PyGreenlet_ACTIVE_NUM 10
#define PyGreenlet_GET_PARENT_NUM 11
#ifndef GREENLET_MODULE
/* This section is used by modules that uses the greenlet C API */
static void** _PyGreenlet_API = NULL;
# define PyGreenlet_Type \
(*(PyTypeObject*)_PyGreenlet_API[PyGreenlet_Type_NUM])
# define PyExc_GreenletError \
((PyObject*)_PyGreenlet_API[PyExc_GreenletError_NUM])
# define PyExc_GreenletExit \
((PyObject*)_PyGreenlet_API[PyExc_GreenletExit_NUM])
/*
* PyGreenlet_New(PyObject *args)
*
* greenlet.greenlet(run, parent=None)
*/
# define PyGreenlet_New \
(*(PyGreenlet * (*)(PyObject * run, PyGreenlet * parent)) \
_PyGreenlet_API[PyGreenlet_New_NUM])
/*
* PyGreenlet_GetCurrent(void)
*
* greenlet.getcurrent()
*/
# define PyGreenlet_GetCurrent \
(*(PyGreenlet * (*)(void)) _PyGreenlet_API[PyGreenlet_GetCurrent_NUM])
/*
* PyGreenlet_Throw(
* PyGreenlet *greenlet,
* PyObject *typ,
* PyObject *val,
* PyObject *tb)
*
* g.throw(...)
*/
# define PyGreenlet_Throw \
(*(PyObject * (*)(PyGreenlet * self, \
PyObject * typ, \
PyObject * val, \
PyObject * tb)) \
_PyGreenlet_API[PyGreenlet_Throw_NUM])
/*
* PyGreenlet_Switch(PyGreenlet *greenlet, PyObject *args)
*
* g.switch(*args, **kwargs)
*/
# define PyGreenlet_Switch \
(*(PyObject * \
(*)(PyGreenlet * greenlet, PyObject * args, PyObject * kwargs)) \
_PyGreenlet_API[PyGreenlet_Switch_NUM])
/*
* PyGreenlet_SetParent(PyObject *greenlet, PyObject *new_parent)
*
* g.parent = new_parent
*/
# define PyGreenlet_SetParent \
(*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \
_PyGreenlet_API[PyGreenlet_SetParent_NUM])
/*
* PyGreenlet_GetParent(PyObject* greenlet)
*
* return greenlet.parent;
*
* This could return NULL even if there is no exception active.
* If it does not return NULL, you are responsible for decrementing the
* reference count.
*/
# define PyGreenlet_GetParent \
(*(PyGreenlet* (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_GET_PARENT_NUM])
/*
* deprecated, undocumented alias.
*/
# define PyGreenlet_GET_PARENT PyGreenlet_GetParent
# define PyGreenlet_MAIN \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_MAIN_NUM])
# define PyGreenlet_STARTED \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_STARTED_NUM])
# define PyGreenlet_ACTIVE \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_ACTIVE_NUM])
/* Macro that imports greenlet and initializes C API */
/* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we
keep the older definition to be sure older code that might have a copy of
the header still works. */
# define PyGreenlet_Import() \
{ \
_PyGreenlet_API = (void**)PyCapsule_Import("greenlet._C_API", 0); \
}
#endif /* GREENLET_MODULE */
#ifdef __cplusplus
}
#endif
#endif /* !Py_GREENLETOBJECT_H */

View File

@ -0,0 +1,235 @@
# -*- coding: utf-8 -*-
#
# Cipher/AES.py : AES
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
import sys
from Crypto.Cipher import _create_cipher
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
c_size_t, c_uint8_ptr)
from Crypto.Util import _cpu_features
from Crypto.Random import get_random_bytes
MODE_ECB = 1 #: Electronic Code Book (:ref:`ecb_mode`)
MODE_CBC = 2 #: Cipher-Block Chaining (:ref:`cbc_mode`)
MODE_CFB = 3 #: Cipher Feedback (:ref:`cfb_mode`)
MODE_OFB = 5 #: Output Feedback (:ref:`ofb_mode`)
MODE_CTR = 6 #: Counter mode (:ref:`ctr_mode`)
MODE_OPENPGP = 7 #: OpenPGP mode (:ref:`openpgp_mode`)
MODE_CCM = 8 #: Counter with CBC-MAC (:ref:`ccm_mode`)
MODE_EAX = 9 #: :ref:`eax_mode`
MODE_SIV = 10 #: Synthetic Initialization Vector (:ref:`siv_mode`)
MODE_GCM = 11 #: Galois Counter Mode (:ref:`gcm_mode`)
MODE_OCB = 12 #: Offset Code Book (:ref:`ocb_mode`)
MODE_KW = 13 #: Key Wrap (:ref:`kw_mode`)
MODE_KWP = 14 #: Key Wrap with Padding (:ref:`kwp_mode`)
_cproto = """
int AES_start_operation(const uint8_t key[],
size_t key_len,
void **pResult);
int AES_encrypt(const void *state,
const uint8_t *in,
uint8_t *out,
size_t data_len);
int AES_decrypt(const void *state,
const uint8_t *in,
uint8_t *out,
size_t data_len);
int AES_stop_operation(void *state);
"""
# Load portable AES
_raw_aes_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_aes",
_cproto)
# Try to load AES with AES NI instructions
try:
_raw_aesni_lib = None
if _cpu_features.have_aes_ni():
_raw_aesni_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_aesni",
_cproto.replace("AES",
"AESNI"))
# _raw_aesni may not have been compiled in
except OSError:
pass
def _create_base_cipher(dict_parameters):
"""This method instantiates and returns a handle to a low-level
base cipher. It will absorb named parameters in the process."""
use_aesni = dict_parameters.pop("use_aesni", True)
try:
key = dict_parameters.pop("key")
except KeyError:
raise TypeError("Missing 'key' parameter")
if len(key) not in key_size:
raise ValueError("Incorrect AES key length (%d bytes)" % len(key))
if use_aesni and _raw_aesni_lib:
start_operation = _raw_aesni_lib.AESNI_start_operation
stop_operation = _raw_aesni_lib.AESNI_stop_operation
else:
start_operation = _raw_aes_lib.AES_start_operation
stop_operation = _raw_aes_lib.AES_stop_operation
cipher = VoidPointer()
result = start_operation(c_uint8_ptr(key),
c_size_t(len(key)),
cipher.address_of())
if result:
raise ValueError("Error %X while instantiating the AES cipher"
% result)
return SmartPointer(cipher.get(), stop_operation)
def _derive_Poly1305_key_pair(key, nonce):
"""Derive a tuple (r, s, nonce) for a Poly1305 MAC.
If nonce is ``None``, a new 16-byte nonce is generated.
"""
if len(key) != 32:
raise ValueError("Poly1305 with AES requires a 32-byte key")
if nonce is None:
nonce = get_random_bytes(16)
elif len(nonce) != 16:
raise ValueError("Poly1305 with AES requires a 16-byte nonce")
s = new(key[:16], MODE_ECB).encrypt(nonce)
return key[16:], s, nonce
def new(key, mode, *args, **kwargs):
"""Create a new AES cipher.
Args:
key(bytes/bytearray/memoryview):
The secret key to use in the symmetric cipher.
It must be 16 (*AES-128)*, 24 (*AES-192*) or 32 (*AES-256*) bytes long.
For ``MODE_SIV`` only, it doubles to 32, 48, or 64 bytes.
mode (a ``MODE_*`` constant):
The chaining mode to use for encryption or decryption.
If in doubt, use ``MODE_EAX``.
Keyword Args:
iv (bytes/bytearray/memoryview):
(Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``,
and ``MODE_OPENPGP`` modes).
The initialization vector to use for encryption or decryption.
For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 16 bytes long.
For ``MODE_OPENPGP`` mode only,
it must be 16 bytes long for encryption
and 18 bytes for decryption (in the latter case, it is
actually the *encrypted* IV which was prefixed to the ciphertext).
If not provided, a random byte string is generated (you must then
read its value with the :attr:`iv` attribute).
nonce (bytes/bytearray/memoryview):
(Only applicable for ``MODE_CCM``, ``MODE_EAX``, ``MODE_GCM``,
``MODE_SIV``, ``MODE_OCB``, and ``MODE_CTR``).
A value that must never be reused for any other encryption done
with this key (except possibly for ``MODE_SIV``, see below).
For ``MODE_EAX``, ``MODE_GCM`` and ``MODE_SIV`` there are no
restrictions on its length (recommended: **16** bytes).
For ``MODE_CCM``, its length must be in the range **[7..13]**.
Bear in mind that with CCM there is a trade-off between nonce
length and maximum message size. Recommendation: **11** bytes.
For ``MODE_OCB``, its length must be in the range **[1..15]**
(recommended: **15**).
For ``MODE_CTR``, its length must be in the range **[0..15]**
(recommended: **8**).
For ``MODE_SIV``, the nonce is optional, if it is not specified,
then no nonce is being used, which renders the encryption
deterministic.
If not provided, for modes other than ``MODE_SIV``, a random
byte string of the recommended length is used (you must then
read its value with the :attr:`nonce` attribute).
segment_size (integer):
(Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext
are segmented in. It must be a multiple of 8.
If not specified, it will be assumed to be 8.
mac_len (integer):
(Only ``MODE_EAX``, ``MODE_GCM``, ``MODE_OCB``, ``MODE_CCM``)
Length of the authentication tag, in bytes.
It must be even and in the range **[4..16]**.
The recommended value (and the default, if not specified) is **16**.
msg_len (integer):
(Only ``MODE_CCM``). Length of the message to (de)cipher.
If not specified, ``encrypt`` must be called with the entire message.
Similarly, ``decrypt`` can only be called once.
assoc_len (integer):
(Only ``MODE_CCM``). Length of the associated data.
If not specified, all associated data is buffered internally,
which may represent a problem for very large messages.
initial_value (integer or bytes/bytearray/memoryview):
(Only ``MODE_CTR``).
The initial value for the counter. If not present, the cipher will
start counting from 0. The value is incremented by one for each block.
The counter number is encoded in big endian mode.
counter (object):
(Only ``MODE_CTR``).
Instance of ``Crypto.Util.Counter``, which allows full customization
of the counter block. This parameter is incompatible to both ``nonce``
and ``initial_value``.
use_aesni: (boolean):
Use Intel AES-NI hardware extensions (default: use if available).
Returns:
an AES object, of the applicable mode.
"""
kwargs["add_aes_modes"] = True
return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs)
# Size of a data block (in bytes)
block_size = 16
# Size of a key (in bytes)
key_size = (16, 24, 32)

View File

@ -0,0 +1,156 @@
from typing import Dict, Optional, Tuple, Union, overload
from typing_extensions import Literal
Buffer=bytes|bytearray|memoryview
from Crypto.Cipher._mode_ecb import EcbMode
from Crypto.Cipher._mode_cbc import CbcMode
from Crypto.Cipher._mode_cfb import CfbMode
from Crypto.Cipher._mode_ofb import OfbMode
from Crypto.Cipher._mode_ctr import CtrMode
from Crypto.Cipher._mode_openpgp import OpenPgpMode
from Crypto.Cipher._mode_ccm import CcmMode
from Crypto.Cipher._mode_eax import EaxMode
from Crypto.Cipher._mode_gcm import GcmMode
from Crypto.Cipher._mode_siv import SivMode
from Crypto.Cipher._mode_ocb import OcbMode
MODE_ECB: Literal[1]
MODE_CBC: Literal[2]
MODE_CFB: Literal[3]
MODE_OFB: Literal[5]
MODE_CTR: Literal[6]
MODE_OPENPGP: Literal[7]
MODE_CCM: Literal[8]
MODE_EAX: Literal[9]
MODE_SIV: Literal[10]
MODE_GCM: Literal[11]
MODE_OCB: Literal[12]
# MODE_ECB
@overload
def new(key: Buffer,
mode: Literal[1],
use_aesni : bool = ...) -> \
EcbMode: ...
# MODE_CBC
@overload
def new(key: Buffer,
mode: Literal[2],
iv : Optional[Buffer] = ...,
use_aesni : bool = ...) -> \
CbcMode: ...
@overload
def new(key: Buffer,
mode: Literal[2],
IV : Optional[Buffer] = ...,
use_aesni : bool = ...) -> \
CbcMode: ...
# MODE_CFB
@overload
def new(key: Buffer,
mode: Literal[3],
iv : Optional[Buffer] = ...,
segment_size : int = ...,
use_aesni : bool = ...) -> \
CfbMode: ...
@overload
def new(key: Buffer,
mode: Literal[3],
IV : Optional[Buffer] = ...,
segment_size : int = ...,
use_aesni : bool = ...) -> \
CfbMode: ...
# MODE_OFB
@overload
def new(key: Buffer,
mode: Literal[5],
iv : Optional[Buffer] = ...,
use_aesni : bool = ...) -> \
OfbMode: ...
@overload
def new(key: Buffer,
mode: Literal[5],
IV : Optional[Buffer] = ...,
use_aesni : bool = ...) -> \
OfbMode: ...
# MODE_CTR
@overload
def new(key: Buffer,
mode: Literal[6],
nonce : Optional[Buffer] = ...,
initial_value : Union[int, Buffer] = ...,
counter : Dict = ...,
use_aesni : bool = ...) -> \
CtrMode: ...
# MODE_OPENPGP
@overload
def new(key: Buffer,
mode: Literal[7],
iv : Optional[Buffer] = ...,
use_aesni : bool = ...) -> \
OpenPgpMode: ...
@overload
def new(key: Buffer,
mode: Literal[7],
IV : Optional[Buffer] = ...,
use_aesni : bool = ...) -> \
OpenPgpMode: ...
# MODE_CCM
@overload
def new(key: Buffer,
mode: Literal[8],
nonce : Optional[Buffer] = ...,
mac_len : int = ...,
assoc_len : int = ...,
use_aesni : bool = ...) -> \
CcmMode: ...
# MODE_EAX
@overload
def new(key: Buffer,
mode: Literal[9],
nonce : Optional[Buffer] = ...,
mac_len : int = ...,
use_aesni : bool = ...) -> \
EaxMode: ...
# MODE_GCM
@overload
def new(key: Buffer,
mode: Literal[10],
nonce : Optional[Buffer] = ...,
use_aesni : bool = ...) -> \
SivMode: ...
# MODE_SIV
@overload
def new(key: Buffer,
mode: Literal[11],
nonce : Optional[Buffer] = ...,
mac_len : int = ...,
use_aesni : bool = ...) -> \
GcmMode: ...
# MODE_OCB
@overload
def new(key: Buffer,
mode: Literal[12],
nonce : Optional[Buffer] = ...,
mac_len : int = ...,
use_aesni : bool = ...) -> \
OcbMode: ...
block_size: int
key_size: Tuple[int, int, int]

View File

@ -0,0 +1,175 @@
# -*- coding: utf-8 -*-
#
# Cipher/ARC2.py : ARC2.py
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
"""
Module's constants for the modes of operation supported with ARC2:
:var MODE_ECB: :ref:`Electronic Code Book (ECB) <ecb_mode>`
:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) <cbc_mode>`
:var MODE_CFB: :ref:`Cipher FeedBack (CFB) <cfb_mode>`
:var MODE_OFB: :ref:`Output FeedBack (OFB) <ofb_mode>`
:var MODE_CTR: :ref:`CounTer Mode (CTR) <ctr_mode>`
:var MODE_OPENPGP: :ref:`OpenPGP Mode <openpgp_mode>`
:var MODE_EAX: :ref:`EAX Mode <eax_mode>`
"""
import sys
from Crypto.Cipher import _create_cipher
from Crypto.Util.py3compat import byte_string
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
c_size_t, c_uint8_ptr)
_raw_arc2_lib = load_pycryptodome_raw_lib(
"Crypto.Cipher._raw_arc2",
"""
int ARC2_start_operation(const uint8_t key[],
size_t key_len,
size_t effective_key_len,
void **pResult);
int ARC2_encrypt(const void *state,
const uint8_t *in,
uint8_t *out,
size_t data_len);
int ARC2_decrypt(const void *state,
const uint8_t *in,
uint8_t *out,
size_t data_len);
int ARC2_stop_operation(void *state);
"""
)
def _create_base_cipher(dict_parameters):
"""This method instantiates and returns a handle to a low-level
base cipher. It will absorb named parameters in the process."""
try:
key = dict_parameters.pop("key")
except KeyError:
raise TypeError("Missing 'key' parameter")
effective_keylen = dict_parameters.pop("effective_keylen", 1024)
if len(key) not in key_size:
raise ValueError("Incorrect ARC2 key length (%d bytes)" % len(key))
if not (40 <= effective_keylen <= 1024):
raise ValueError("'effective_key_len' must be at least 40 and no larger than 1024 "
"(not %d)" % effective_keylen)
start_operation = _raw_arc2_lib.ARC2_start_operation
stop_operation = _raw_arc2_lib.ARC2_stop_operation
cipher = VoidPointer()
result = start_operation(c_uint8_ptr(key),
c_size_t(len(key)),
c_size_t(effective_keylen),
cipher.address_of())
if result:
raise ValueError("Error %X while instantiating the ARC2 cipher"
% result)
return SmartPointer(cipher.get(), stop_operation)
def new(key, mode, *args, **kwargs):
"""Create a new RC2 cipher.
:param key:
The secret key to use in the symmetric cipher.
Its length can vary from 5 to 128 bytes; the actual search space
(and the cipher strength) can be reduced with the ``effective_keylen`` parameter.
:type key: bytes, bytearray, memoryview
:param mode:
The chaining mode to use for encryption or decryption.
:type mode: One of the supported ``MODE_*`` constants
:Keyword Arguments:
* **iv** (*bytes*, *bytearray*, *memoryview*) --
(Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``,
and ``MODE_OPENPGP`` modes).
The initialization vector to use for encryption or decryption.
For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long.
For ``MODE_OPENPGP`` mode only,
it must be 8 bytes long for encryption
and 10 bytes for decryption (in the latter case, it is
actually the *encrypted* IV which was prefixed to the ciphertext).
If not provided, a random byte string is generated (you must then
read its value with the :attr:`iv` attribute).
* **nonce** (*bytes*, *bytearray*, *memoryview*) --
(Only applicable for ``MODE_EAX`` and ``MODE_CTR``).
A value that must never be reused for any other encryption done
with this key.
For ``MODE_EAX`` there are no
restrictions on its length (recommended: **16** bytes).
For ``MODE_CTR``, its length must be in the range **[0..7]**.
If not provided for ``MODE_EAX``, a random byte string is generated (you
can read it back via the ``nonce`` attribute).
* **effective_keylen** (*integer*) --
Optional. Maximum strength in bits of the actual key used by the ARC2 algorithm.
If the supplied ``key`` parameter is longer (in bits) of the value specified
here, it will be weakened to match it.
If not specified, no limitation is applied.
* **segment_size** (*integer*) --
(Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext
are segmented in. It must be a multiple of 8.
If not specified, it will be assumed to be 8.
* **mac_len** : (*integer*) --
(Only ``MODE_EAX``)
Length of the authentication tag, in bytes.
It must be no longer than 8 (default).
* **initial_value** : (*integer*) --
(Only ``MODE_CTR``). The initial value for the counter within
the counter block. By default it is **0**.
:Return: an ARC2 object, of the applicable mode.
"""
return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs)
MODE_ECB = 1
MODE_CBC = 2
MODE_CFB = 3
MODE_OFB = 5
MODE_CTR = 6
MODE_OPENPGP = 7
MODE_EAX = 9
# Size of a data block (in bytes)
block_size = 8
# Size of a key (in bytes)
key_size = range(5, 128 + 1)

View File

@ -0,0 +1,35 @@
from typing import Union, Dict, Iterable, Optional
Buffer = bytes|bytearray|memoryview
from Crypto.Cipher._mode_ecb import EcbMode
from Crypto.Cipher._mode_cbc import CbcMode
from Crypto.Cipher._mode_cfb import CfbMode
from Crypto.Cipher._mode_ofb import OfbMode
from Crypto.Cipher._mode_ctr import CtrMode
from Crypto.Cipher._mode_openpgp import OpenPgpMode
from Crypto.Cipher._mode_eax import EaxMode
ARC2Mode = int
MODE_ECB: ARC2Mode
MODE_CBC: ARC2Mode
MODE_CFB: ARC2Mode
MODE_OFB: ARC2Mode
MODE_CTR: ARC2Mode
MODE_OPENPGP: ARC2Mode
MODE_EAX: ARC2Mode
def new(key: Buffer,
mode: ARC2Mode,
iv : Optional[Buffer] = ...,
IV : Optional[Buffer] = ...,
nonce : Optional[Buffer] = ...,
segment_size : int = ...,
mac_len : int = ...,
initial_value : Union[int, Buffer] = ...,
counter : Dict = ...) -> \
Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ...
block_size: int
key_size: Iterable[int]

View File

@ -0,0 +1,136 @@
# -*- coding: utf-8 -*-
#
# Cipher/ARC4.py : ARC4
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer,
create_string_buffer, get_raw_buffer,
SmartPointer, c_size_t, c_uint8_ptr)
_raw_arc4_lib = load_pycryptodome_raw_lib("Crypto.Cipher._ARC4", """
int ARC4_stream_encrypt(void *rc4State, const uint8_t in[],
uint8_t out[], size_t len);
int ARC4_stream_init(uint8_t *key, size_t keylen,
void **pRc4State);
int ARC4_stream_destroy(void *rc4State);
""")
class ARC4Cipher:
"""ARC4 cipher object. Do not create it directly. Use
:func:`Crypto.Cipher.ARC4.new` instead.
"""
def __init__(self, key, *args, **kwargs):
"""Initialize an ARC4 cipher object
See also `new()` at the module level."""
if len(args) > 0:
ndrop = args[0]
args = args[1:]
else:
ndrop = kwargs.pop('drop', 0)
if len(key) not in key_size:
raise ValueError("Incorrect ARC4 key length (%d bytes)" %
len(key))
self._state = VoidPointer()
result = _raw_arc4_lib.ARC4_stream_init(c_uint8_ptr(key),
c_size_t(len(key)),
self._state.address_of())
if result != 0:
raise ValueError("Error %d while creating the ARC4 cipher"
% result)
self._state = SmartPointer(self._state.get(),
_raw_arc4_lib.ARC4_stream_destroy)
if ndrop > 0:
# This is OK even if the cipher is used for decryption,
# since encrypt and decrypt are actually the same thing
# with ARC4.
self.encrypt(b'\x00' * ndrop)
self.block_size = 1
self.key_size = len(key)
def encrypt(self, plaintext):
"""Encrypt a piece of data.
:param plaintext: The data to encrypt, of any size.
:type plaintext: bytes, bytearray, memoryview
:returns: the encrypted byte string, of equal length as the
plaintext.
"""
ciphertext = create_string_buffer(len(plaintext))
result = _raw_arc4_lib.ARC4_stream_encrypt(self._state.get(),
c_uint8_ptr(plaintext),
ciphertext,
c_size_t(len(plaintext)))
if result:
raise ValueError("Error %d while encrypting with RC4" % result)
return get_raw_buffer(ciphertext)
def decrypt(self, ciphertext):
"""Decrypt a piece of data.
:param ciphertext: The data to decrypt, of any size.
:type ciphertext: bytes, bytearray, memoryview
:returns: the decrypted byte string, of equal length as the
ciphertext.
"""
try:
return self.encrypt(ciphertext)
except ValueError as e:
raise ValueError(str(e).replace("enc", "dec"))
def new(key, *args, **kwargs):
"""Create a new ARC4 cipher.
:param key:
The secret key to use in the symmetric cipher.
Its length must be in the range ``[1..256]``.
The recommended length is 16 bytes.
:type key: bytes, bytearray, memoryview
:Keyword Arguments:
* *drop* (``integer``) --
The amount of bytes to discard from the initial part of the keystream.
In fact, such part has been found to be distinguishable from random
data (while it shouldn't) and also correlated to key.
The recommended value is 3072_ bytes. The default value is 0.
:Return: an `ARC4Cipher` object
.. _3072: http://eprint.iacr.org/2002/067.pdf
"""
return ARC4Cipher(key, *args, **kwargs)
# Size of a data block (in bytes)
block_size = 1
# Size of a key (in bytes)
key_size = range(1, 256+1)

View File

@ -0,0 +1,16 @@
from typing import Any, Union, Iterable
Buffer = bytes|bytearray|memoryview
class ARC4Cipher:
block_size: int
key_size: int
def __init__(self, key: Buffer, *args: Any, **kwargs: Any) -> None: ...
def encrypt(self, plaintext: Buffer) -> bytes: ...
def decrypt(self, ciphertext: Buffer) -> bytes: ...
def new(key: Buffer, drop : int = ...) -> ARC4Cipher: ...
block_size: int
key_size: Iterable[int]

View File

@ -0,0 +1,159 @@
# -*- coding: utf-8 -*-
#
# Cipher/Blowfish.py : Blowfish
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
"""
Module's constants for the modes of operation supported with Blowfish:
:var MODE_ECB: :ref:`Electronic Code Book (ECB) <ecb_mode>`
:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) <cbc_mode>`
:var MODE_CFB: :ref:`Cipher FeedBack (CFB) <cfb_mode>`
:var MODE_OFB: :ref:`Output FeedBack (OFB) <ofb_mode>`
:var MODE_CTR: :ref:`CounTer Mode (CTR) <ctr_mode>`
:var MODE_OPENPGP: :ref:`OpenPGP Mode <openpgp_mode>`
:var MODE_EAX: :ref:`EAX Mode <eax_mode>`
"""
import sys
from Crypto.Cipher import _create_cipher
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer, c_size_t,
c_uint8_ptr)
_raw_blowfish_lib = load_pycryptodome_raw_lib(
"Crypto.Cipher._raw_blowfish",
"""
int Blowfish_start_operation(const uint8_t key[],
size_t key_len,
void **pResult);
int Blowfish_encrypt(const void *state,
const uint8_t *in,
uint8_t *out,
size_t data_len);
int Blowfish_decrypt(const void *state,
const uint8_t *in,
uint8_t *out,
size_t data_len);
int Blowfish_stop_operation(void *state);
"""
)
def _create_base_cipher(dict_parameters):
"""This method instantiates and returns a smart pointer to
a low-level base cipher. It will absorb named parameters in
the process."""
try:
key = dict_parameters.pop("key")
except KeyError:
raise TypeError("Missing 'key' parameter")
if len(key) not in key_size:
raise ValueError("Incorrect Blowfish key length (%d bytes)" % len(key))
start_operation = _raw_blowfish_lib.Blowfish_start_operation
stop_operation = _raw_blowfish_lib.Blowfish_stop_operation
void_p = VoidPointer()
result = start_operation(c_uint8_ptr(key),
c_size_t(len(key)),
void_p.address_of())
if result:
raise ValueError("Error %X while instantiating the Blowfish cipher"
% result)
return SmartPointer(void_p.get(), stop_operation)
def new(key, mode, *args, **kwargs):
"""Create a new Blowfish cipher
:param key:
The secret key to use in the symmetric cipher.
Its length can vary from 5 to 56 bytes.
:type key: bytes, bytearray, memoryview
:param mode:
The chaining mode to use for encryption or decryption.
:type mode: One of the supported ``MODE_*`` constants
:Keyword Arguments:
* **iv** (*bytes*, *bytearray*, *memoryview*) --
(Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``,
and ``MODE_OPENPGP`` modes).
The initialization vector to use for encryption or decryption.
For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long.
For ``MODE_OPENPGP`` mode only,
it must be 8 bytes long for encryption
and 10 bytes for decryption (in the latter case, it is
actually the *encrypted* IV which was prefixed to the ciphertext).
If not provided, a random byte string is generated (you must then
read its value with the :attr:`iv` attribute).
* **nonce** (*bytes*, *bytearray*, *memoryview*) --
(Only applicable for ``MODE_EAX`` and ``MODE_CTR``).
A value that must never be reused for any other encryption done
with this key.
For ``MODE_EAX`` there are no
restrictions on its length (recommended: **16** bytes).
For ``MODE_CTR``, its length must be in the range **[0..7]**.
If not provided for ``MODE_EAX``, a random byte string is generated (you
can read it back via the ``nonce`` attribute).
* **segment_size** (*integer*) --
(Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext
are segmented in. It must be a multiple of 8.
If not specified, it will be assumed to be 8.
* **mac_len** : (*integer*) --
(Only ``MODE_EAX``)
Length of the authentication tag, in bytes.
It must be no longer than 8 (default).
* **initial_value** : (*integer*) --
(Only ``MODE_CTR``). The initial value for the counter within
the counter block. By default it is **0**.
:Return: a Blowfish object, of the applicable mode.
"""
return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs)
MODE_ECB = 1
MODE_CBC = 2
MODE_CFB = 3
MODE_OFB = 5
MODE_CTR = 6
MODE_OPENPGP = 7
MODE_EAX = 9
# Size of a data block (in bytes)
block_size = 8
# Size of a key (in bytes)
key_size = range(4, 56 + 1)

View File

@ -0,0 +1,35 @@
from typing import Union, Dict, Iterable, Optional
Buffer = bytes|bytearray|memoryview
from Crypto.Cipher._mode_ecb import EcbMode
from Crypto.Cipher._mode_cbc import CbcMode
from Crypto.Cipher._mode_cfb import CfbMode
from Crypto.Cipher._mode_ofb import OfbMode
from Crypto.Cipher._mode_ctr import CtrMode
from Crypto.Cipher._mode_openpgp import OpenPgpMode
from Crypto.Cipher._mode_eax import EaxMode
BlowfishMode = int
MODE_ECB: BlowfishMode
MODE_CBC: BlowfishMode
MODE_CFB: BlowfishMode
MODE_OFB: BlowfishMode
MODE_CTR: BlowfishMode
MODE_OPENPGP: BlowfishMode
MODE_EAX: BlowfishMode
def new(key: Buffer,
mode: BlowfishMode,
iv : Optional[Buffer] = ...,
IV : Optional[Buffer] = ...,
nonce : Optional[Buffer] = ...,
segment_size : int = ...,
mac_len : int = ...,
initial_value : Union[int, Buffer] = ...,
counter : Dict = ...) -> \
Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ...
block_size: int
key_size: Iterable[int]

View File

@ -0,0 +1,159 @@
# -*- coding: utf-8 -*-
#
# Cipher/CAST.py : CAST
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
"""
Module's constants for the modes of operation supported with CAST:
:var MODE_ECB: :ref:`Electronic Code Book (ECB) <ecb_mode>`
:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) <cbc_mode>`
:var MODE_CFB: :ref:`Cipher FeedBack (CFB) <cfb_mode>`
:var MODE_OFB: :ref:`Output FeedBack (OFB) <ofb_mode>`
:var MODE_CTR: :ref:`CounTer Mode (CTR) <ctr_mode>`
:var MODE_OPENPGP: :ref:`OpenPGP Mode <openpgp_mode>`
:var MODE_EAX: :ref:`EAX Mode <eax_mode>`
"""
import sys
from Crypto.Cipher import _create_cipher
from Crypto.Util.py3compat import byte_string
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
c_size_t, c_uint8_ptr)
_raw_cast_lib = load_pycryptodome_raw_lib(
"Crypto.Cipher._raw_cast",
"""
int CAST_start_operation(const uint8_t key[],
size_t key_len,
void **pResult);
int CAST_encrypt(const void *state,
const uint8_t *in,
uint8_t *out,
size_t data_len);
int CAST_decrypt(const void *state,
const uint8_t *in,
uint8_t *out,
size_t data_len);
int CAST_stop_operation(void *state);
""")
def _create_base_cipher(dict_parameters):
"""This method instantiates and returns a handle to a low-level
base cipher. It will absorb named parameters in the process."""
try:
key = dict_parameters.pop("key")
except KeyError:
raise TypeError("Missing 'key' parameter")
if len(key) not in key_size:
raise ValueError("Incorrect CAST key length (%d bytes)" % len(key))
start_operation = _raw_cast_lib.CAST_start_operation
stop_operation = _raw_cast_lib.CAST_stop_operation
cipher = VoidPointer()
result = start_operation(c_uint8_ptr(key),
c_size_t(len(key)),
cipher.address_of())
if result:
raise ValueError("Error %X while instantiating the CAST cipher"
% result)
return SmartPointer(cipher.get(), stop_operation)
def new(key, mode, *args, **kwargs):
"""Create a new CAST cipher
:param key:
The secret key to use in the symmetric cipher.
Its length can vary from 5 to 16 bytes.
:type key: bytes, bytearray, memoryview
:param mode:
The chaining mode to use for encryption or decryption.
:type mode: One of the supported ``MODE_*`` constants
:Keyword Arguments:
* **iv** (*bytes*, *bytearray*, *memoryview*) --
(Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``,
and ``MODE_OPENPGP`` modes).
The initialization vector to use for encryption or decryption.
For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long.
For ``MODE_OPENPGP`` mode only,
it must be 8 bytes long for encryption
and 10 bytes for decryption (in the latter case, it is
actually the *encrypted* IV which was prefixed to the ciphertext).
If not provided, a random byte string is generated (you must then
read its value with the :attr:`iv` attribute).
* **nonce** (*bytes*, *bytearray*, *memoryview*) --
(Only applicable for ``MODE_EAX`` and ``MODE_CTR``).
A value that must never be reused for any other encryption done
with this key.
For ``MODE_EAX`` there are no
restrictions on its length (recommended: **16** bytes).
For ``MODE_CTR``, its length must be in the range **[0..7]**.
If not provided for ``MODE_EAX``, a random byte string is generated (you
can read it back via the ``nonce`` attribute).
* **segment_size** (*integer*) --
(Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext
are segmented in. It must be a multiple of 8.
If not specified, it will be assumed to be 8.
* **mac_len** : (*integer*) --
(Only ``MODE_EAX``)
Length of the authentication tag, in bytes.
It must be no longer than 8 (default).
* **initial_value** : (*integer*) --
(Only ``MODE_CTR``). The initial value for the counter within
the counter block. By default it is **0**.
:Return: a CAST object, of the applicable mode.
"""
return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs)
MODE_ECB = 1
MODE_CBC = 2
MODE_CFB = 3
MODE_OFB = 5
MODE_CTR = 6
MODE_OPENPGP = 7
MODE_EAX = 9
# Size of a data block (in bytes)
block_size = 8
# Size of a key (in bytes)
key_size = range(5, 16 + 1)

View File

@ -0,0 +1,35 @@
from typing import Union, Dict, Iterable, Optional
Buffer = bytes|bytearray|memoryview
from Crypto.Cipher._mode_ecb import EcbMode
from Crypto.Cipher._mode_cbc import CbcMode
from Crypto.Cipher._mode_cfb import CfbMode
from Crypto.Cipher._mode_ofb import OfbMode
from Crypto.Cipher._mode_ctr import CtrMode
from Crypto.Cipher._mode_openpgp import OpenPgpMode
from Crypto.Cipher._mode_eax import EaxMode
CASTMode = int
MODE_ECB: CASTMode
MODE_CBC: CASTMode
MODE_CFB: CASTMode
MODE_OFB: CASTMode
MODE_CTR: CASTMode
MODE_OPENPGP: CASTMode
MODE_EAX: CASTMode
def new(key: Buffer,
mode: CASTMode,
iv : Optional[Buffer] = ...,
IV : Optional[Buffer] = ...,
nonce : Optional[Buffer] = ...,
segment_size : int = ...,
mac_len : int = ...,
initial_value : Union[int, Buffer] = ...,
counter : Dict = ...) -> \
Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ...
block_size: int
key_size : Iterable[int]

View File

@ -0,0 +1,291 @@
# ===================================================================
#
# Copyright (c) 2014, Legrandin <helderijs@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
from Crypto.Random import get_random_bytes
from Crypto.Util.py3compat import _copy_bytes
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
create_string_buffer,
get_raw_buffer, VoidPointer,
SmartPointer, c_size_t,
c_uint8_ptr, c_ulong,
is_writeable_buffer)
_raw_chacha20_lib = load_pycryptodome_raw_lib("Crypto.Cipher._chacha20",
"""
int chacha20_init(void **pState,
const uint8_t *key,
size_t keySize,
const uint8_t *nonce,
size_t nonceSize);
int chacha20_destroy(void *state);
int chacha20_encrypt(void *state,
const uint8_t in[],
uint8_t out[],
size_t len);
int chacha20_seek(void *state,
unsigned long block_high,
unsigned long block_low,
unsigned offset);
int hchacha20( const uint8_t key[32],
const uint8_t nonce16[16],
uint8_t subkey[32]);
""")
def _HChaCha20(key, nonce):
assert(len(key) == 32)
assert(len(nonce) == 16)
subkey = bytearray(32)
result = _raw_chacha20_lib.hchacha20(
c_uint8_ptr(key),
c_uint8_ptr(nonce),
c_uint8_ptr(subkey))
if result:
raise ValueError("Error %d when deriving subkey with HChaCha20" % result)
return subkey
class ChaCha20Cipher(object):
"""ChaCha20 (or XChaCha20) cipher object.
Do not create it directly. Use :py:func:`new` instead.
:var nonce: The nonce with length 8, 12 or 24 bytes
:vartype nonce: bytes
"""
block_size = 1
def __init__(self, key, nonce):
"""Initialize a ChaCha20/XChaCha20 cipher object
See also `new()` at the module level."""
self.nonce = _copy_bytes(None, None, nonce)
# XChaCha20 requires a key derivation with HChaCha20
# See 2.3 in https://tools.ietf.org/html/draft-arciszewski-xchacha-03
if len(nonce) == 24:
key = _HChaCha20(key, nonce[:16])
nonce = b'\x00' * 4 + nonce[16:]
self._name = "XChaCha20"
else:
self._name = "ChaCha20"
nonce = self.nonce
self._next = ("encrypt", "decrypt")
self._state = VoidPointer()
result = _raw_chacha20_lib.chacha20_init(
self._state.address_of(),
c_uint8_ptr(key),
c_size_t(len(key)),
nonce,
c_size_t(len(nonce)))
if result:
raise ValueError("Error %d instantiating a %s cipher" % (result,
self._name))
self._state = SmartPointer(self._state.get(),
_raw_chacha20_lib.chacha20_destroy)
def encrypt(self, plaintext, output=None):
"""Encrypt a piece of data.
Args:
plaintext(bytes/bytearray/memoryview): The data to encrypt, of any size.
Keyword Args:
output(bytes/bytearray/memoryview): The location where the ciphertext
is written to. If ``None``, the ciphertext is returned.
Returns:
If ``output`` is ``None``, the ciphertext is returned as ``bytes``.
Otherwise, ``None``.
"""
if "encrypt" not in self._next:
raise TypeError("Cipher object can only be used for decryption")
self._next = ("encrypt",)
return self._encrypt(plaintext, output)
def _encrypt(self, plaintext, output):
"""Encrypt without FSM checks"""
if output is None:
ciphertext = create_string_buffer(len(plaintext))
else:
ciphertext = output
if not is_writeable_buffer(output):
raise TypeError("output must be a bytearray or a writeable memoryview")
if len(plaintext) != len(output):
raise ValueError("output must have the same length as the input"
" (%d bytes)" % len(plaintext))
result = _raw_chacha20_lib.chacha20_encrypt(
self._state.get(),
c_uint8_ptr(plaintext),
c_uint8_ptr(ciphertext),
c_size_t(len(plaintext)))
if result:
raise ValueError("Error %d while encrypting with %s" % (result, self._name))
if output is None:
return get_raw_buffer(ciphertext)
else:
return None
def decrypt(self, ciphertext, output=None):
"""Decrypt a piece of data.
Args:
ciphertext(bytes/bytearray/memoryview): The data to decrypt, of any size.
Keyword Args:
output(bytes/bytearray/memoryview): The location where the plaintext
is written to. If ``None``, the plaintext is returned.
Returns:
If ``output`` is ``None``, the plaintext is returned as ``bytes``.
Otherwise, ``None``.
"""
if "decrypt" not in self._next:
raise TypeError("Cipher object can only be used for encryption")
self._next = ("decrypt",)
try:
return self._encrypt(ciphertext, output)
except ValueError as e:
raise ValueError(str(e).replace("enc", "dec"))
def seek(self, position):
"""Seek to a certain position in the key stream.
If you want to seek to a certain block,
use ``seek(block_number * 64)``.
Args:
position (integer):
The absolute position within the key stream, in bytes.
"""
block_number, offset = divmod(position, 64)
block_low = block_number & 0xFFFFFFFF
block_high = block_number >> 32
result = _raw_chacha20_lib.chacha20_seek(
self._state.get(),
c_ulong(block_high),
c_ulong(block_low),
offset
)
if result:
raise ValueError("Error %d while seeking with %s" % (result, self._name))
def _derive_Poly1305_key_pair(key, nonce):
"""Derive a tuple (r, s, nonce) for a Poly1305 MAC.
If nonce is ``None``, a new 12-byte nonce is generated.
"""
if len(key) != 32:
raise ValueError("Poly1305 with ChaCha20 requires a 32-byte key")
if nonce is None:
padded_nonce = nonce = get_random_bytes(12)
elif len(nonce) == 8:
# See RFC7538, 2.6: [...] ChaCha20 as specified here requires a 96-bit
# nonce. So if the provided nonce is only 64-bit, then the first 32
# bits of the nonce will be set to a constant number.
# This will usually be zero, but for protocols with multiple senders it may be
# different for each sender, but should be the same for all
# invocations of the function with the same key by a particular
# sender.
padded_nonce = b'\x00\x00\x00\x00' + nonce
elif len(nonce) == 12:
padded_nonce = nonce
else:
raise ValueError("Poly1305 with ChaCha20 requires an 8- or 12-byte nonce")
rs = new(key=key, nonce=padded_nonce).encrypt(b'\x00' * 32)
return rs[:16], rs[16:], nonce
def new(**kwargs):
"""Create a new ChaCha20 or XChaCha20 cipher
Keyword Args:
key (bytes/bytearray/memoryview): The secret key to use.
It must be 32 bytes long.
nonce (bytes/bytearray/memoryview): A mandatory value that
must never be reused for any other encryption
done with this key.
For ChaCha20, it must be 8 or 12 bytes long.
For XChaCha20, it must be 24 bytes long.
If not provided, 8 bytes will be randomly generated
(you can find them back in the ``nonce`` attribute).
:Return: a :class:`Crypto.Cipher.ChaCha20.ChaCha20Cipher` object
"""
try:
key = kwargs.pop("key")
except KeyError as e:
raise TypeError("Missing parameter %s" % e)
nonce = kwargs.pop("nonce", None)
if nonce is None:
nonce = get_random_bytes(8)
if len(key) != 32:
raise ValueError("ChaCha20/XChaCha20 key must be 32 bytes long")
if len(nonce) not in (8, 12, 24):
raise ValueError("Nonce must be 8/12 bytes(ChaCha20) or 24 bytes (XChaCha20)")
if kwargs:
raise TypeError("Unknown parameters: " + str(kwargs))
return ChaCha20Cipher(key, nonce)
# Size of a data block (in bytes)
block_size = 1
# Size of a key (in bytes)
key_size = 32

View File

@ -0,0 +1,25 @@
from typing import Union, overload, Optional
Buffer = bytes|bytearray|memoryview
def _HChaCha20(key: Buffer, nonce: Buffer) -> bytearray: ...
class ChaCha20Cipher:
block_size: int
nonce: bytes
def __init__(self, key: Buffer, nonce: Buffer) -> None: ...
@overload
def encrypt(self, plaintext: Buffer) -> bytes: ...
@overload
def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ...
@overload
def decrypt(self, plaintext: Buffer) -> bytes: ...
@overload
def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ...
def seek(self, position: int) -> None: ...
def new(key: Buffer, nonce: Optional[Buffer] = ...) -> ChaCha20Cipher: ...
block_size: int
key_size: int

View File

@ -0,0 +1,334 @@
# ===================================================================
#
# Copyright (c) 2018, Helder Eijs <helderijs@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
from binascii import unhexlify
from Crypto.Cipher import ChaCha20
from Crypto.Cipher.ChaCha20 import _HChaCha20
from Crypto.Hash import Poly1305, BLAKE2s
from Crypto.Random import get_random_bytes
from Crypto.Util.number import long_to_bytes
from Crypto.Util.py3compat import _copy_bytes, bord
from Crypto.Util._raw_api import is_buffer
def _enum(**enums):
return type('Enum', (), enums)
_CipherStatus = _enum(PROCESSING_AUTH_DATA=1,
PROCESSING_CIPHERTEXT=2,
PROCESSING_DONE=3)
class ChaCha20Poly1305Cipher(object):
"""ChaCha20-Poly1305 and XChaCha20-Poly1305 cipher object.
Do not create it directly. Use :py:func:`new` instead.
:var nonce: The nonce with length 8, 12 or 24 bytes
:vartype nonce: byte string
"""
def __init__(self, key, nonce):
"""Initialize a ChaCha20-Poly1305 AEAD cipher object
See also `new()` at the module level."""
self._next = ("update", "encrypt", "decrypt", "digest",
"verify")
self._authenticator = Poly1305.new(key=key, nonce=nonce, cipher=ChaCha20)
self._cipher = ChaCha20.new(key=key, nonce=nonce)
self._cipher.seek(64) # Block counter starts at 1
self._len_aad = 0
self._len_ct = 0
self._mac_tag = None
self._status = _CipherStatus.PROCESSING_AUTH_DATA
def update(self, data):
"""Protect the associated data.
Associated data (also known as *additional authenticated data* - AAD)
is the piece of the message that must stay in the clear, while
still allowing the receiver to verify its integrity.
An example is packet headers.
The associated data (possibly split into multiple segments) is
fed into :meth:`update` before any call to :meth:`decrypt` or :meth:`encrypt`.
If there is no associated data, :meth:`update` is not called.
:param bytes/bytearray/memoryview assoc_data:
A piece of associated data. There are no restrictions on its size.
"""
if "update" not in self._next:
raise TypeError("update() method cannot be called")
self._len_aad += len(data)
self._authenticator.update(data)
def _pad_aad(self):
assert(self._status == _CipherStatus.PROCESSING_AUTH_DATA)
if self._len_aad & 0x0F:
self._authenticator.update(b'\x00' * (16 - (self._len_aad & 0x0F)))
self._status = _CipherStatus.PROCESSING_CIPHERTEXT
def encrypt(self, plaintext, output=None):
"""Encrypt a piece of data.
Args:
plaintext(bytes/bytearray/memoryview): The data to encrypt, of any size.
Keyword Args:
output(bytes/bytearray/memoryview): The location where the ciphertext
is written to. If ``None``, the ciphertext is returned.
Returns:
If ``output`` is ``None``, the ciphertext is returned as ``bytes``.
Otherwise, ``None``.
"""
if "encrypt" not in self._next:
raise TypeError("encrypt() method cannot be called")
if self._status == _CipherStatus.PROCESSING_AUTH_DATA:
self._pad_aad()
self._next = ("encrypt", "digest")
result = self._cipher.encrypt(plaintext, output=output)
self._len_ct += len(plaintext)
if output is None:
self._authenticator.update(result)
else:
self._authenticator.update(output)
return result
def decrypt(self, ciphertext, output=None):
"""Decrypt a piece of data.
Args:
ciphertext(bytes/bytearray/memoryview): The data to decrypt, of any size.
Keyword Args:
output(bytes/bytearray/memoryview): The location where the plaintext
is written to. If ``None``, the plaintext is returned.
Returns:
If ``output`` is ``None``, the plaintext is returned as ``bytes``.
Otherwise, ``None``.
"""
if "decrypt" not in self._next:
raise TypeError("decrypt() method cannot be called")
if self._status == _CipherStatus.PROCESSING_AUTH_DATA:
self._pad_aad()
self._next = ("decrypt", "verify")
self._len_ct += len(ciphertext)
self._authenticator.update(ciphertext)
return self._cipher.decrypt(ciphertext, output=output)
def _compute_mac(self):
"""Finalize the cipher (if not done already) and return the MAC."""
if self._mac_tag:
assert(self._status == _CipherStatus.PROCESSING_DONE)
return self._mac_tag
assert(self._status != _CipherStatus.PROCESSING_DONE)
if self._status == _CipherStatus.PROCESSING_AUTH_DATA:
self._pad_aad()
if self._len_ct & 0x0F:
self._authenticator.update(b'\x00' * (16 - (self._len_ct & 0x0F)))
self._status = _CipherStatus.PROCESSING_DONE
self._authenticator.update(long_to_bytes(self._len_aad, 8)[::-1])
self._authenticator.update(long_to_bytes(self._len_ct, 8)[::-1])
self._mac_tag = self._authenticator.digest()
return self._mac_tag
def digest(self):
"""Compute the *binary* authentication tag (MAC).
:Return: the MAC tag, as 16 ``bytes``.
"""
if "digest" not in self._next:
raise TypeError("digest() method cannot be called")
self._next = ("digest",)
return self._compute_mac()
def hexdigest(self):
"""Compute the *printable* authentication tag (MAC).
This method is like :meth:`digest`.
:Return: the MAC tag, as a hexadecimal string.
"""
return "".join(["%02x" % bord(x) for x in self.digest()])
def verify(self, received_mac_tag):
"""Validate the *binary* authentication tag (MAC).
The receiver invokes this method at the very end, to
check if the associated data (if any) and the decrypted
messages are valid.
:param bytes/bytearray/memoryview received_mac_tag:
This is the 16-byte *binary* MAC, as received from the sender.
:Raises ValueError:
if the MAC does not match. The message has been tampered with
or the key is incorrect.
"""
if "verify" not in self._next:
raise TypeError("verify() cannot be called"
" when encrypting a message")
self._next = ("verify",)
secret = get_random_bytes(16)
self._compute_mac()
mac1 = BLAKE2s.new(digest_bits=160, key=secret,
data=self._mac_tag)
mac2 = BLAKE2s.new(digest_bits=160, key=secret,
data=received_mac_tag)
if mac1.digest() != mac2.digest():
raise ValueError("MAC check failed")
def hexverify(self, hex_mac_tag):
"""Validate the *printable* authentication tag (MAC).
This method is like :meth:`verify`.
:param string hex_mac_tag:
This is the *printable* MAC.
:Raises ValueError:
if the MAC does not match. The message has been tampered with
or the key is incorrect.
"""
self.verify(unhexlify(hex_mac_tag))
def encrypt_and_digest(self, plaintext):
"""Perform :meth:`encrypt` and :meth:`digest` in one step.
:param plaintext: The data to encrypt, of any size.
:type plaintext: bytes/bytearray/memoryview
:return: a tuple with two ``bytes`` objects:
- the ciphertext, of equal length as the plaintext
- the 16-byte MAC tag
"""
return self.encrypt(plaintext), self.digest()
def decrypt_and_verify(self, ciphertext, received_mac_tag):
"""Perform :meth:`decrypt` and :meth:`verify` in one step.
:param ciphertext: The piece of data to decrypt.
:type ciphertext: bytes/bytearray/memoryview
:param bytes received_mac_tag:
This is the 16-byte *binary* MAC, as received from the sender.
:return: the decrypted data (as ``bytes``)
:raises ValueError:
if the MAC does not match. The message has been tampered with
or the key is incorrect.
"""
plaintext = self.decrypt(ciphertext)
self.verify(received_mac_tag)
return plaintext
def new(**kwargs):
"""Create a new ChaCha20-Poly1305 or XChaCha20-Poly1305 AEAD cipher.
:keyword key: The secret key to use. It must be 32 bytes long.
:type key: byte string
:keyword nonce:
A value that must never be reused for any other encryption
done with this key.
For ChaCha20-Poly1305, it must be 8 or 12 bytes long.
For XChaCha20-Poly1305, it must be 24 bytes long.
If not provided, 12 ``bytes`` will be generated randomly
(you can find them back in the ``nonce`` attribute).
:type nonce: bytes, bytearray, memoryview
:Return: a :class:`Crypto.Cipher.ChaCha20.ChaCha20Poly1305Cipher` object
"""
try:
key = kwargs.pop("key")
except KeyError as e:
raise TypeError("Missing parameter %s" % e)
if len(key) != 32:
raise ValueError("Key must be 32 bytes long")
nonce = kwargs.pop("nonce", None)
if nonce is None:
nonce = get_random_bytes(12)
if len(nonce) in (8, 12):
chacha20_poly1305_nonce = nonce
elif len(nonce) == 24:
key = _HChaCha20(key, nonce[:16])
chacha20_poly1305_nonce = b'\x00\x00\x00\x00' + nonce[16:]
else:
raise ValueError("Nonce must be 8, 12 or 24 bytes long")
if not is_buffer(nonce):
raise TypeError("nonce must be bytes, bytearray or memoryview")
if kwargs:
raise TypeError("Unknown parameters: " + str(kwargs))
cipher = ChaCha20Poly1305Cipher(key, chacha20_poly1305_nonce)
cipher.nonce = _copy_bytes(None, None, nonce)
return cipher
# Size of a key (in bytes)
key_size = 32

View File

@ -0,0 +1,28 @@
from typing import Union, Tuple, overload, Optional
Buffer = bytes|bytearray|memoryview
class ChaCha20Poly1305Cipher:
nonce: bytes
def __init__(self, key: Buffer, nonce: Buffer) -> None: ...
def update(self, data: Buffer) -> None: ...
@overload
def encrypt(self, plaintext: Buffer) -> bytes: ...
@overload
def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ...
@overload
def decrypt(self, plaintext: Buffer) -> bytes: ...
@overload
def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def verify(self, received_mac_tag: Buffer) -> None: ...
def hexverify(self, received_mac_tag: str) -> None: ...
def encrypt_and_digest(self, plaintext: Buffer) -> Tuple[bytes, bytes]: ...
def decrypt_and_verify(self, ciphertext: Buffer, received_mac_tag: Buffer) -> bytes: ...
def new(key: Buffer, nonce: Optional[Buffer] = ...) -> ChaCha20Poly1305Cipher: ...
block_size: int
key_size: int

View File

@ -0,0 +1,158 @@
# -*- coding: utf-8 -*-
#
# Cipher/DES.py : DES
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
"""
Module's constants for the modes of operation supported with Single DES:
:var MODE_ECB: :ref:`Electronic Code Book (ECB) <ecb_mode>`
:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) <cbc_mode>`
:var MODE_CFB: :ref:`Cipher FeedBack (CFB) <cfb_mode>`
:var MODE_OFB: :ref:`Output FeedBack (OFB) <ofb_mode>`
:var MODE_CTR: :ref:`CounTer Mode (CTR) <ctr_mode>`
:var MODE_OPENPGP: :ref:`OpenPGP Mode <openpgp_mode>`
:var MODE_EAX: :ref:`EAX Mode <eax_mode>`
"""
import sys
from Crypto.Cipher import _create_cipher
from Crypto.Util.py3compat import byte_string
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
c_size_t, c_uint8_ptr)
_raw_des_lib = load_pycryptodome_raw_lib(
"Crypto.Cipher._raw_des",
"""
int DES_start_operation(const uint8_t key[],
size_t key_len,
void **pResult);
int DES_encrypt(const void *state,
const uint8_t *in,
uint8_t *out,
size_t data_len);
int DES_decrypt(const void *state,
const uint8_t *in,
uint8_t *out,
size_t data_len);
int DES_stop_operation(void *state);
""")
def _create_base_cipher(dict_parameters):
"""This method instantiates and returns a handle to a low-level
base cipher. It will absorb named parameters in the process."""
try:
key = dict_parameters.pop("key")
except KeyError:
raise TypeError("Missing 'key' parameter")
if len(key) != key_size:
raise ValueError("Incorrect DES key length (%d bytes)" % len(key))
start_operation = _raw_des_lib.DES_start_operation
stop_operation = _raw_des_lib.DES_stop_operation
cipher = VoidPointer()
result = start_operation(c_uint8_ptr(key),
c_size_t(len(key)),
cipher.address_of())
if result:
raise ValueError("Error %X while instantiating the DES cipher"
% result)
return SmartPointer(cipher.get(), stop_operation)
def new(key, mode, *args, **kwargs):
"""Create a new DES cipher.
:param key:
The secret key to use in the symmetric cipher.
It must be 8 byte long. The parity bits will be ignored.
:type key: bytes/bytearray/memoryview
:param mode:
The chaining mode to use for encryption or decryption.
:type mode: One of the supported ``MODE_*`` constants
:Keyword Arguments:
* **iv** (*byte string*) --
(Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``,
and ``MODE_OPENPGP`` modes).
The initialization vector to use for encryption or decryption.
For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long.
For ``MODE_OPENPGP`` mode only,
it must be 8 bytes long for encryption
and 10 bytes for decryption (in the latter case, it is
actually the *encrypted* IV which was prefixed to the ciphertext).
If not provided, a random byte string is generated (you must then
read its value with the :attr:`iv` attribute).
* **nonce** (*byte string*) --
(Only applicable for ``MODE_EAX`` and ``MODE_CTR``).
A value that must never be reused for any other encryption done
with this key.
For ``MODE_EAX`` there are no
restrictions on its length (recommended: **16** bytes).
For ``MODE_CTR``, its length must be in the range **[0..7]**.
If not provided for ``MODE_EAX``, a random byte string is generated (you
can read it back via the ``nonce`` attribute).
* **segment_size** (*integer*) --
(Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext
are segmented in. It must be a multiple of 8.
If not specified, it will be assumed to be 8.
* **mac_len** : (*integer*) --
(Only ``MODE_EAX``)
Length of the authentication tag, in bytes.
It must be no longer than 8 (default).
* **initial_value** : (*integer*) --
(Only ``MODE_CTR``). The initial value for the counter within
the counter block. By default it is **0**.
:Return: a DES object, of the applicable mode.
"""
return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs)
MODE_ECB = 1
MODE_CBC = 2
MODE_CFB = 3
MODE_OFB = 5
MODE_CTR = 6
MODE_OPENPGP = 7
MODE_EAX = 9
# Size of a data block (in bytes)
block_size = 8
# Size of a key (in bytes)
key_size = 8

View File

@ -0,0 +1,35 @@
from typing import Union, Dict, Iterable, Optional
Buffer = bytes|bytearray|memoryview
from Crypto.Cipher._mode_ecb import EcbMode
from Crypto.Cipher._mode_cbc import CbcMode
from Crypto.Cipher._mode_cfb import CfbMode
from Crypto.Cipher._mode_ofb import OfbMode
from Crypto.Cipher._mode_ctr import CtrMode
from Crypto.Cipher._mode_openpgp import OpenPgpMode
from Crypto.Cipher._mode_eax import EaxMode
DESMode = int
MODE_ECB: DESMode
MODE_CBC: DESMode
MODE_CFB: DESMode
MODE_OFB: DESMode
MODE_CTR: DESMode
MODE_OPENPGP: DESMode
MODE_EAX: DESMode
def new(key: Buffer,
mode: DESMode,
iv : Optional[Buffer] = ...,
IV : Optional[Buffer] = ...,
nonce : Optional[Buffer] = ...,
segment_size : int = ...,
mac_len : int = ...,
initial_value : Union[int, Buffer] = ...,
counter : Dict = ...) -> \
Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ...
block_size: int
key_size: int

View File

@ -0,0 +1,187 @@
# -*- coding: utf-8 -*-
#
# Cipher/DES3.py : DES3
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
"""
Module's constants for the modes of operation supported with Triple DES:
:var MODE_ECB: :ref:`Electronic Code Book (ECB) <ecb_mode>`
:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) <cbc_mode>`
:var MODE_CFB: :ref:`Cipher FeedBack (CFB) <cfb_mode>`
:var MODE_OFB: :ref:`Output FeedBack (OFB) <ofb_mode>`
:var MODE_CTR: :ref:`CounTer Mode (CTR) <ctr_mode>`
:var MODE_OPENPGP: :ref:`OpenPGP Mode <openpgp_mode>`
:var MODE_EAX: :ref:`EAX Mode <eax_mode>`
"""
import sys
from Crypto.Cipher import _create_cipher
from Crypto.Util.py3compat import byte_string, bchr, bord, bstr
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
c_size_t)
_raw_des3_lib = load_pycryptodome_raw_lib(
"Crypto.Cipher._raw_des3",
"""
int DES3_start_operation(const uint8_t key[],
size_t key_len,
void **pResult);
int DES3_encrypt(const void *state,
const uint8_t *in,
uint8_t *out,
size_t data_len);
int DES3_decrypt(const void *state,
const uint8_t *in,
uint8_t *out,
size_t data_len);
int DES3_stop_operation(void *state);
""")
def adjust_key_parity(key_in):
"""Set the parity bits in a TDES key.
:param key_in: the TDES key whose bits need to be adjusted
:type key_in: byte string
:returns: a copy of ``key_in``, with the parity bits correctly set
:rtype: byte string
:raises ValueError: if the TDES key is not 16 or 24 bytes long
:raises ValueError: if the TDES key degenerates into Single DES
"""
def parity_byte(key_byte):
parity = 1
for i in range(1, 8):
parity ^= (key_byte >> i) & 1
return (key_byte & 0xFE) | parity
if len(key_in) not in key_size:
raise ValueError("Not a valid TDES key")
key_out = b"".join([ bchr(parity_byte(bord(x))) for x in key_in ])
if key_out[:8] == key_out[8:16] or key_out[-16:-8] == key_out[-8:]:
raise ValueError("Triple DES key degenerates to single DES")
return key_out
def _create_base_cipher(dict_parameters):
"""This method instantiates and returns a handle to a low-level base cipher.
It will absorb named parameters in the process."""
try:
key_in = dict_parameters.pop("key")
except KeyError:
raise TypeError("Missing 'key' parameter")
key = adjust_key_parity(bstr(key_in))
start_operation = _raw_des3_lib.DES3_start_operation
stop_operation = _raw_des3_lib.DES3_stop_operation
cipher = VoidPointer()
result = start_operation(key,
c_size_t(len(key)),
cipher.address_of())
if result:
raise ValueError("Error %X while instantiating the TDES cipher"
% result)
return SmartPointer(cipher.get(), stop_operation)
def new(key, mode, *args, **kwargs):
"""Create a new Triple DES cipher.
:param key:
The secret key to use in the symmetric cipher.
It must be 16 or 24 byte long. The parity bits will be ignored.
:type key: bytes/bytearray/memoryview
:param mode:
The chaining mode to use for encryption or decryption.
:type mode: One of the supported ``MODE_*`` constants
:Keyword Arguments:
* **iv** (*bytes*, *bytearray*, *memoryview*) --
(Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``,
and ``MODE_OPENPGP`` modes).
The initialization vector to use for encryption or decryption.
For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long.
For ``MODE_OPENPGP`` mode only,
it must be 8 bytes long for encryption
and 10 bytes for decryption (in the latter case, it is
actually the *encrypted* IV which was prefixed to the ciphertext).
If not provided, a random byte string is generated (you must then
read its value with the :attr:`iv` attribute).
* **nonce** (*bytes*, *bytearray*, *memoryview*) --
(Only applicable for ``MODE_EAX`` and ``MODE_CTR``).
A value that must never be reused for any other encryption done
with this key.
For ``MODE_EAX`` there are no
restrictions on its length (recommended: **16** bytes).
For ``MODE_CTR``, its length must be in the range **[0..7]**.
If not provided for ``MODE_EAX``, a random byte string is generated (you
can read it back via the ``nonce`` attribute).
* **segment_size** (*integer*) --
(Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext
are segmented in. It must be a multiple of 8.
If not specified, it will be assumed to be 8.
* **mac_len** : (*integer*) --
(Only ``MODE_EAX``)
Length of the authentication tag, in bytes.
It must be no longer than 8 (default).
* **initial_value** : (*integer*) --
(Only ``MODE_CTR``). The initial value for the counter within
the counter block. By default it is **0**.
:Return: a Triple DES object, of the applicable mode.
"""
return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs)
MODE_ECB = 1
MODE_CBC = 2
MODE_CFB = 3
MODE_OFB = 5
MODE_CTR = 6
MODE_OPENPGP = 7
MODE_EAX = 9
# Size of a data block (in bytes)
block_size = 8
# Size of a key (in bytes)
key_size = (16, 24)

View File

@ -0,0 +1,37 @@
from typing import Union, Dict, Tuple, Optional
Buffer = bytes|bytearray|memoryview
from Crypto.Cipher._mode_ecb import EcbMode
from Crypto.Cipher._mode_cbc import CbcMode
from Crypto.Cipher._mode_cfb import CfbMode
from Crypto.Cipher._mode_ofb import OfbMode
from Crypto.Cipher._mode_ctr import CtrMode
from Crypto.Cipher._mode_openpgp import OpenPgpMode
from Crypto.Cipher._mode_eax import EaxMode
def adjust_key_parity(key_in: bytes) -> bytes: ...
DES3Mode = int
MODE_ECB: DES3Mode
MODE_CBC: DES3Mode
MODE_CFB: DES3Mode
MODE_OFB: DES3Mode
MODE_CTR: DES3Mode
MODE_OPENPGP: DES3Mode
MODE_EAX: DES3Mode
def new(key: Buffer,
mode: DES3Mode,
iv : Optional[Buffer] = ...,
IV : Optional[Buffer] = ...,
nonce : Optional[Buffer] = ...,
segment_size : int = ...,
mac_len : int = ...,
initial_value : Union[int, Buffer] = ...,
counter : Dict = ...) -> \
Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ...
block_size: int
key_size: Tuple[int, int]

View File

@ -0,0 +1,231 @@
# -*- coding: utf-8 -*-
#
# Cipher/PKCS1_OAEP.py : PKCS#1 OAEP
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
from Crypto.Signature.pss import MGF1
import Crypto.Hash.SHA1
from Crypto.Util.py3compat import _copy_bytes
import Crypto.Util.number
from Crypto.Util.number import ceil_div, bytes_to_long, long_to_bytes
from Crypto.Util.strxor import strxor
from Crypto import Random
from ._pkcs1_oaep_decode import oaep_decode
class PKCS1OAEP_Cipher:
"""Cipher object for PKCS#1 v1.5 OAEP.
Do not create directly: use :func:`new` instead."""
def __init__(self, key, hashAlgo, mgfunc, label, randfunc):
"""Initialize this PKCS#1 OAEP cipher object.
:Parameters:
key : an RSA key object
If a private half is given, both encryption and decryption are possible.
If a public half is given, only encryption is possible.
hashAlgo : hash object
The hash function to use. This can be a module under `Crypto.Hash`
or an existing hash object created from any of such modules. If not specified,
`Crypto.Hash.SHA1` is used.
mgfunc : callable
A mask generation function that accepts two parameters: a string to
use as seed, and the lenth of the mask to generate, in bytes.
If not specified, the standard MGF1 consistent with ``hashAlgo`` is used (a safe choice).
label : bytes/bytearray/memoryview
A label to apply to this particular encryption. If not specified,
an empty string is used. Specifying a label does not improve
security.
randfunc : callable
A function that returns random bytes.
:attention: Modify the mask generation function only if you know what you are doing.
Sender and receiver must use the same one.
"""
self._key = key
if hashAlgo:
self._hashObj = hashAlgo
else:
self._hashObj = Crypto.Hash.SHA1
if mgfunc:
self._mgf = mgfunc
else:
self._mgf = lambda x, y: MGF1(x, y, self._hashObj)
self._label = _copy_bytes(None, None, label)
self._randfunc = randfunc
def can_encrypt(self):
"""Legacy function to check if you can call :meth:`encrypt`.
.. deprecated:: 3.0"""
return self._key.can_encrypt()
def can_decrypt(self):
"""Legacy function to check if you can call :meth:`decrypt`.
.. deprecated:: 3.0"""
return self._key.can_decrypt()
def encrypt(self, message):
"""Encrypt a message with PKCS#1 OAEP.
:param message:
The message to encrypt, also known as plaintext. It can be of
variable length, but not longer than the RSA modulus (in bytes)
minus 2, minus twice the hash output size.
For instance, if you use RSA 2048 and SHA-256, the longest message
you can encrypt is 190 byte long.
:type message: bytes/bytearray/memoryview
:returns: The ciphertext, as large as the RSA modulus.
:rtype: bytes
:raises ValueError:
if the message is too long.
"""
# See 7.1.1 in RFC3447
modBits = Crypto.Util.number.size(self._key.n)
k = ceil_div(modBits, 8) # Convert from bits to bytes
hLen = self._hashObj.digest_size
mLen = len(message)
# Step 1b
ps_len = k - mLen - 2 * hLen - 2
if ps_len < 0:
raise ValueError("Plaintext is too long.")
# Step 2a
lHash = self._hashObj.new(self._label).digest()
# Step 2b
ps = b'\x00' * ps_len
# Step 2c
db = lHash + ps + b'\x01' + _copy_bytes(None, None, message)
# Step 2d
ros = self._randfunc(hLen)
# Step 2e
dbMask = self._mgf(ros, k-hLen-1)
# Step 2f
maskedDB = strxor(db, dbMask)
# Step 2g
seedMask = self._mgf(maskedDB, hLen)
# Step 2h
maskedSeed = strxor(ros, seedMask)
# Step 2i
em = b'\x00' + maskedSeed + maskedDB
# Step 3a (OS2IP)
em_int = bytes_to_long(em)
# Step 3b (RSAEP)
m_int = self._key._encrypt(em_int)
# Step 3c (I2OSP)
c = long_to_bytes(m_int, k)
return c
def decrypt(self, ciphertext):
"""Decrypt a message with PKCS#1 OAEP.
:param ciphertext: The encrypted message.
:type ciphertext: bytes/bytearray/memoryview
:returns: The original message (plaintext).
:rtype: bytes
:raises ValueError:
if the ciphertext has the wrong length, or if decryption
fails the integrity check (in which case, the decryption
key is probably wrong).
:raises TypeError:
if the RSA key has no private half (i.e. you are trying
to decrypt using a public key).
"""
# See 7.1.2 in RFC3447
modBits = Crypto.Util.number.size(self._key.n)
k = ceil_div(modBits, 8) # Convert from bits to bytes
hLen = self._hashObj.digest_size
# Step 1b and 1c
if len(ciphertext) != k or k < hLen+2:
raise ValueError("Ciphertext with incorrect length.")
# Step 2a (O2SIP)
ct_int = bytes_to_long(ciphertext)
# Step 2b (RSADP) and step 2c (I2OSP)
em = self._key._decrypt_to_bytes(ct_int)
# Step 3a
lHash = self._hashObj.new(self._label).digest()
# y must be 0, but we MUST NOT check it here in order not to
# allow attacks like Manger's (http://dl.acm.org/citation.cfm?id=704143)
maskedSeed = em[1:hLen+1]
maskedDB = em[hLen+1:]
# Step 3c
seedMask = self._mgf(maskedDB, hLen)
# Step 3d
seed = strxor(maskedSeed, seedMask)
# Step 3e
dbMask = self._mgf(seed, k-hLen-1)
# Step 3f
db = strxor(maskedDB, dbMask)
# Step 3b + 3g
res = oaep_decode(em, lHash, db)
if res <= 0:
raise ValueError("Incorrect decryption.")
# Step 4
return db[res:]
def new(key, hashAlgo=None, mgfunc=None, label=b'', randfunc=None):
"""Return a cipher object :class:`PKCS1OAEP_Cipher`
that can be used to perform PKCS#1 OAEP encryption or decryption.
:param key:
The key object to use to encrypt or decrypt the message.
Decryption is only possible with a private RSA key.
:type key: RSA key object
:param hashAlgo:
The hash function to use. This can be a module under `Crypto.Hash`
or an existing hash object created from any of such modules.
If not specified, `Crypto.Hash.SHA1` is used.
:type hashAlgo: hash object
:param mgfunc:
A mask generation function that accepts two parameters: a string to
use as seed, and the lenth of the mask to generate, in bytes.
If not specified, the standard MGF1 consistent with ``hashAlgo`` is used (a safe choice).
:type mgfunc: callable
:param label:
A label to apply to this particular encryption. If not specified,
an empty string is used. Specifying a label does not improve
security.
:type label: bytes/bytearray/memoryview
:param randfunc:
A function that returns random bytes.
The default is `Random.get_random_bytes`.
:type randfunc: callable
"""
if randfunc is None:
randfunc = Random.get_random_bytes
return PKCS1OAEP_Cipher(key, hashAlgo, mgfunc, label, randfunc)

View File

@ -0,0 +1,35 @@
from typing import Optional, Union, Callable, Any, overload
from typing_extensions import Protocol
from Crypto.PublicKey.RSA import RsaKey
class HashLikeClass(Protocol):
digest_size : int
def new(self, data: Optional[bytes] = ...) -> Any: ...
class HashLikeModule(Protocol):
digest_size : int
@staticmethod
def new(data: Optional[bytes] = ...) -> Any: ...
HashLike = Union[HashLikeClass, HashLikeModule]
Buffer = Union[bytes, bytearray, memoryview]
class PKCS1OAEP_Cipher:
def __init__(self,
key: RsaKey,
hashAlgo: HashLike,
mgfunc: Callable[[bytes, int], bytes],
label: Buffer,
randfunc: Callable[[int], bytes]) -> None: ...
def can_encrypt(self) -> bool: ...
def can_decrypt(self) -> bool: ...
def encrypt(self, message: Buffer) -> bytes: ...
def decrypt(self, ciphertext: Buffer) -> bytes: ...
def new(key: RsaKey,
hashAlgo: Optional[HashLike] = ...,
mgfunc: Optional[Callable[[bytes, int], bytes]] = ...,
label: Optional[Buffer] = ...,
randfunc: Optional[Callable[[int], bytes]] = ...) -> PKCS1OAEP_Cipher: ...

View File

@ -0,0 +1,189 @@
# -*- coding: utf-8 -*-
#
# Cipher/PKCS1-v1_5.py : PKCS#1 v1.5
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
__all__ = ['new', 'PKCS115_Cipher']
from Crypto import Random
from Crypto.Util.number import bytes_to_long, long_to_bytes
from Crypto.Util.py3compat import bord, is_bytes, _copy_bytes
from ._pkcs1_oaep_decode import pkcs1_decode
class PKCS115_Cipher:
"""This cipher can perform PKCS#1 v1.5 RSA encryption or decryption.
Do not instantiate directly. Use :func:`Crypto.Cipher.PKCS1_v1_5.new` instead."""
def __init__(self, key, randfunc):
"""Initialize this PKCS#1 v1.5 cipher object.
:Parameters:
key : an RSA key object
If a private half is given, both encryption and decryption are possible.
If a public half is given, only encryption is possible.
randfunc : callable
Function that returns random bytes.
"""
self._key = key
self._randfunc = randfunc
def can_encrypt(self):
"""Return True if this cipher object can be used for encryption."""
return self._key.can_encrypt()
def can_decrypt(self):
"""Return True if this cipher object can be used for decryption."""
return self._key.can_decrypt()
def encrypt(self, message):
"""Produce the PKCS#1 v1.5 encryption of a message.
This function is named ``RSAES-PKCS1-V1_5-ENCRYPT``, and it is specified in
`section 7.2.1 of RFC8017
<https://tools.ietf.org/html/rfc8017#page-28>`_.
:param message:
The message to encrypt, also known as plaintext. It can be of
variable length, but not longer than the RSA modulus (in bytes) minus 11.
:type message: bytes/bytearray/memoryview
:Returns: A byte string, the ciphertext in which the message is encrypted.
It is as long as the RSA modulus (in bytes).
:Raises ValueError:
If the RSA key length is not sufficiently long to deal with the given
message.
"""
# See 7.2.1 in RFC8017
k = self._key.size_in_bytes()
mLen = len(message)
# Step 1
if mLen > k - 11:
raise ValueError("Plaintext is too long.")
# Step 2a
ps = []
while len(ps) != k - mLen - 3:
new_byte = self._randfunc(1)
if bord(new_byte[0]) == 0x00:
continue
ps.append(new_byte)
ps = b"".join(ps)
# Step 2b
em = b'\x00\x02' + ps + b'\x00' + _copy_bytes(None, None, message)
# Step 3a (OS2IP)
em_int = bytes_to_long(em)
# Step 3b (RSAEP)
m_int = self._key._encrypt(em_int)
# Step 3c (I2OSP)
c = long_to_bytes(m_int, k)
return c
def decrypt(self, ciphertext, sentinel, expected_pt_len=0):
r"""Decrypt a PKCS#1 v1.5 ciphertext.
This is the function ``RSAES-PKCS1-V1_5-DECRYPT`` specified in
`section 7.2.2 of RFC8017
<https://tools.ietf.org/html/rfc8017#page-29>`_.
Args:
ciphertext (bytes/bytearray/memoryview):
The ciphertext that contains the message to recover.
sentinel (any type):
The object to return whenever an error is detected.
expected_pt_len (integer):
The length the plaintext is known to have, or 0 if unknown.
Returns (byte string):
It is either the original message or the ``sentinel`` (in case of an error).
.. warning::
PKCS#1 v1.5 decryption is intrinsically vulnerable to timing
attacks (see `Bleichenbacher's`__ attack).
**Use PKCS#1 OAEP instead**.
This implementation attempts to mitigate the risk
with some constant-time constructs.
However, they are not sufficient by themselves: the type of protocol you
implement and the way you handle errors make a big difference.
Specifically, you should make it very hard for the (malicious)
party that submitted the ciphertext to quickly understand if decryption
succeeded or not.
To this end, it is recommended that your protocol only encrypts
plaintexts of fixed length (``expected_pt_len``),
that ``sentinel`` is a random byte string of the same length,
and that processing continues for as long
as possible even if ``sentinel`` is returned (i.e. in case of
incorrect decryption).
.. __: https://dx.doi.org/10.1007/BFb0055716
"""
# See 7.2.2 in RFC8017
k = self._key.size_in_bytes()
# Step 1
if len(ciphertext) != k:
raise ValueError("Ciphertext with incorrect length (not %d bytes)" % k)
# Step 2a (O2SIP)
ct_int = bytes_to_long(ciphertext)
# Step 2b (RSADP) and Step 2c (I2OSP)
em = self._key._decrypt_to_bytes(ct_int)
# Step 3 (not constant time when the sentinel is not a byte string)
output = bytes(bytearray(k))
if not is_bytes(sentinel) or len(sentinel) > k:
size = pkcs1_decode(em, b'', expected_pt_len, output)
if size < 0:
return sentinel
else:
return output[size:]
# Step 3 (somewhat constant time)
size = pkcs1_decode(em, sentinel, expected_pt_len, output)
return output[size:]
def new(key, randfunc=None):
"""Create a cipher for performing PKCS#1 v1.5 encryption or decryption.
:param key:
The key to use to encrypt or decrypt the message. This is a `Crypto.PublicKey.RSA` object.
Decryption is only possible if *key* is a private RSA key.
:type key: RSA key object
:param randfunc:
Function that return random bytes.
The default is :func:`Crypto.Random.get_random_bytes`.
:type randfunc: callable
:returns: A cipher object `PKCS115_Cipher`.
"""
if randfunc is None:
randfunc = Random.get_random_bytes
return PKCS115_Cipher(key, randfunc)

View File

@ -0,0 +1,20 @@
from typing import Callable, Union, Any, Optional, TypeVar
from Crypto.PublicKey.RSA import RsaKey
Buffer = Union[bytes, bytearray, memoryview]
T = TypeVar('T')
class PKCS115_Cipher:
def __init__(self,
key: RsaKey,
randfunc: Callable[[int], bytes]) -> None: ...
def can_encrypt(self) -> bool: ...
def can_decrypt(self) -> bool: ...
def encrypt(self, message: Buffer) -> bytes: ...
def decrypt(self, ciphertext: Buffer,
sentinel: T,
expected_pt_len: Optional[int] = ...) -> Union[bytes, T]: ...
def new(key: RsaKey,
randfunc: Optional[Callable[[int], bytes]] = ...) -> PKCS115_Cipher: ...

View File

@ -0,0 +1,167 @@
# -*- coding: utf-8 -*-
#
# Cipher/Salsa20.py : Salsa20 stream cipher (http://cr.yp.to/snuffle.html)
#
# Contributed by Fabrizio Tarizzo <fabrizio@fabriziotarizzo.org>.
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
from Crypto.Util.py3compat import _copy_bytes
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
create_string_buffer,
get_raw_buffer, VoidPointer,
SmartPointer, c_size_t,
c_uint8_ptr, is_writeable_buffer)
from Crypto.Random import get_random_bytes
_raw_salsa20_lib = load_pycryptodome_raw_lib("Crypto.Cipher._Salsa20",
"""
int Salsa20_stream_init(uint8_t *key, size_t keylen,
uint8_t *nonce, size_t nonce_len,
void **pSalsaState);
int Salsa20_stream_destroy(void *salsaState);
int Salsa20_stream_encrypt(void *salsaState,
const uint8_t in[],
uint8_t out[], size_t len);
""")
class Salsa20Cipher:
"""Salsa20 cipher object. Do not create it directly. Use :py:func:`new`
instead.
:var nonce: The nonce with length 8
:vartype nonce: byte string
"""
def __init__(self, key, nonce):
"""Initialize a Salsa20 cipher object
See also `new()` at the module level."""
if len(key) not in key_size:
raise ValueError("Incorrect key length for Salsa20 (%d bytes)" % len(key))
if len(nonce) != 8:
raise ValueError("Incorrect nonce length for Salsa20 (%d bytes)" %
len(nonce))
self.nonce = _copy_bytes(None, None, nonce)
self._state = VoidPointer()
result = _raw_salsa20_lib.Salsa20_stream_init(
c_uint8_ptr(key),
c_size_t(len(key)),
c_uint8_ptr(nonce),
c_size_t(len(nonce)),
self._state.address_of())
if result:
raise ValueError("Error %d instantiating a Salsa20 cipher")
self._state = SmartPointer(self._state.get(),
_raw_salsa20_lib.Salsa20_stream_destroy)
self.block_size = 1
self.key_size = len(key)
def encrypt(self, plaintext, output=None):
"""Encrypt a piece of data.
Args:
plaintext(bytes/bytearray/memoryview): The data to encrypt, of any size.
Keyword Args:
output(bytes/bytearray/memoryview): The location where the ciphertext
is written to. If ``None``, the ciphertext is returned.
Returns:
If ``output`` is ``None``, the ciphertext is returned as ``bytes``.
Otherwise, ``None``.
"""
if output is None:
ciphertext = create_string_buffer(len(plaintext))
else:
ciphertext = output
if not is_writeable_buffer(output):
raise TypeError("output must be a bytearray or a writeable memoryview")
if len(plaintext) != len(output):
raise ValueError("output must have the same length as the input"
" (%d bytes)" % len(plaintext))
result = _raw_salsa20_lib.Salsa20_stream_encrypt(
self._state.get(),
c_uint8_ptr(plaintext),
c_uint8_ptr(ciphertext),
c_size_t(len(plaintext)))
if result:
raise ValueError("Error %d while encrypting with Salsa20" % result)
if output is None:
return get_raw_buffer(ciphertext)
else:
return None
def decrypt(self, ciphertext, output=None):
"""Decrypt a piece of data.
Args:
ciphertext(bytes/bytearray/memoryview): The data to decrypt, of any size.
Keyword Args:
output(bytes/bytearray/memoryview): The location where the plaintext
is written to. If ``None``, the plaintext is returned.
Returns:
If ``output`` is ``None``, the plaintext is returned as ``bytes``.
Otherwise, ``None``.
"""
try:
return self.encrypt(ciphertext, output=output)
except ValueError as e:
raise ValueError(str(e).replace("enc", "dec"))
def new(key, nonce=None):
"""Create a new Salsa20 cipher
:keyword key: The secret key to use. It must be 16 or 32 bytes long.
:type key: bytes/bytearray/memoryview
:keyword nonce:
A value that must never be reused for any other encryption
done with this key. It must be 8 bytes long.
If not provided, a random byte string will be generated (you can read
it back via the ``nonce`` attribute of the returned object).
:type nonce: bytes/bytearray/memoryview
:Return: a :class:`Crypto.Cipher.Salsa20.Salsa20Cipher` object
"""
if nonce is None:
nonce = get_random_bytes(8)
return Salsa20Cipher(key, nonce)
# Size of a data block (in bytes)
block_size = 1
# Size of a key (in bytes)
key_size = (16, 32)

View File

@ -0,0 +1,26 @@
from typing import Union, Tuple, Optional, overload, Optional
Buffer = bytes|bytearray|memoryview
class Salsa20Cipher:
nonce: bytes
block_size: int
key_size: int
def __init__(self,
key: Buffer,
nonce: Buffer) -> None: ...
@overload
def encrypt(self, plaintext: Buffer) -> bytes: ...
@overload
def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ...
@overload
def decrypt(self, plaintext: Buffer) -> bytes: ...
@overload
def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ...
def new(key: Buffer, nonce: Optional[Buffer] = ...) -> Salsa20Cipher: ...
block_size: int
key_size: Tuple[int, int]

Binary file not shown.

View File

@ -0,0 +1,131 @@
# ===================================================================
#
# Copyright (c) 2019, Legrandin <helderijs@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
import sys
from Crypto.Cipher import _create_cipher
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer, c_size_t,
c_uint8_ptr, c_uint)
_raw_blowfish_lib = load_pycryptodome_raw_lib(
"Crypto.Cipher._raw_eksblowfish",
"""
int EKSBlowfish_start_operation(const uint8_t key[],
size_t key_len,
const uint8_t salt[16],
size_t salt_len,
unsigned cost,
unsigned invert,
void **pResult);
int EKSBlowfish_encrypt(const void *state,
const uint8_t *in,
uint8_t *out,
size_t data_len);
int EKSBlowfish_decrypt(const void *state,
const uint8_t *in,
uint8_t *out,
size_t data_len);
int EKSBlowfish_stop_operation(void *state);
"""
)
def _create_base_cipher(dict_parameters):
"""This method instantiates and returns a smart pointer to
a low-level base cipher. It will absorb named parameters in
the process."""
try:
key = dict_parameters.pop("key")
salt = dict_parameters.pop("salt")
cost = dict_parameters.pop("cost")
except KeyError as e:
raise TypeError("Missing EKSBlowfish parameter: " + str(e))
invert = dict_parameters.pop("invert", True)
if len(key) not in key_size:
raise ValueError("Incorrect EKSBlowfish key length (%d bytes)" % len(key))
start_operation = _raw_blowfish_lib.EKSBlowfish_start_operation
stop_operation = _raw_blowfish_lib.EKSBlowfish_stop_operation
void_p = VoidPointer()
result = start_operation(c_uint8_ptr(key),
c_size_t(len(key)),
c_uint8_ptr(salt),
c_size_t(len(salt)),
c_uint(cost),
c_uint(int(invert)),
void_p.address_of())
if result:
raise ValueError("Error %X while instantiating the EKSBlowfish cipher"
% result)
return SmartPointer(void_p.get(), stop_operation)
def new(key, mode, salt, cost, invert):
"""Create a new EKSBlowfish cipher
Args:
key (bytes, bytearray, memoryview):
The secret key to use in the symmetric cipher.
Its length can vary from 0 to 72 bytes.
mode (one of the supported ``MODE_*`` constants):
The chaining mode to use for encryption or decryption.
salt (bytes, bytearray, memoryview):
The salt that bcrypt uses to thwart rainbow table attacks
cost (integer):
The complexity factor in bcrypt
invert (bool):
If ``False``, in the inner loop use ``ExpandKey`` first over the salt
and then over the key, as defined in
the `original bcrypt specification <https://www.usenix.org/legacy/events/usenix99/provos/provos_html/node4.html>`_.
If ``True``, reverse the order, as in the first implementation of
`bcrypt` in OpenBSD.
:Return: an EKSBlowfish object
"""
kwargs = { 'salt':salt, 'cost':cost, 'invert':invert }
return _create_cipher(sys.modules[__name__], key, mode, **kwargs)
MODE_ECB = 1
# Size of a data block (in bytes)
block_size = 8
# Size of a key (in bytes)
key_size = range(0, 72 + 1)

View File

@ -0,0 +1,15 @@
from typing import Union, Iterable
from Crypto.Cipher._mode_ecb import EcbMode
MODE_ECB: int
Buffer = Union[bytes, bytearray, memoryview]
def new(key: Buffer,
mode: int,
salt: Buffer,
cost: int) -> EcbMode: ...
block_size: int
key_size: Iterable[int]

Some files were not shown because too many files have changed in this diff Show More