├── .dockerignore ├── .gitignore ├── .pre-commit-config.yaml ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── VERSION ├── appveyor.yml ├── appveyor ├── install.ps1 └── run_with_env.cmd ├── bin ├── run-example-django.sh └── run-test.sh ├── docker-compose-test.yml ├── docker ├── Dockerfile └── Dockerfile_3_12_plus ├── example └── django │ ├── Dockerfile │ ├── README.md │ └── pye_web │ ├── app_pye │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── management │ │ ├── __init__.py │ │ └── commands │ │ │ ├── __init__.py │ │ │ └── echo.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ └── views.py │ ├── manage.py │ ├── pye_web │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py │ └── requirements.txt ├── flake8.cfg ├── meson.build ├── meson.options ├── meson_utility ├── dist_cleanup.sh ├── gen_secret_key.py └── pyconcrete.pth ├── pyecli ├── pyproject.toml ├── src ├── __init__.py ├── config.py ├── pyconcrete │ ├── __init__.py │ └── version.py ├── pyconcrete_exe │ └── pyconcrete_exe.c └── pyconcrete_ext │ ├── include_win │ └── stdint.h │ ├── openaes │ ├── CHANGELOG │ ├── CMakeLists.txt │ ├── LICENSE │ ├── README │ ├── VERSION │ ├── inc │ │ ├── oaes_base64.h │ │ ├── oaes_common.h │ │ ├── oaes_config.h │ │ └── oaes_lib.h │ ├── src │ │ ├── isaac │ │ │ ├── rand.c │ │ │ ├── rand.h │ │ │ └── standard.h │ │ ├── oaes.c │ │ ├── oaes_base64.c │ │ └── oaes_lib.c │ └── test │ │ ├── test_encrypt.c │ │ ├── test_keys.c │ │ ├── test_performance.c │ │ └── vt_aes.c │ ├── pyconcrete.c │ ├── pyconcrete.h │ └── pyconcrete_module.c └── tests ├── README.md ├── __init__.py ├── conftest.py ├── exe_testcases ├── test_basic__main__module │ ├── expected.yaml │ └── main.py ├── test_basic_function_call │ ├── expected.yaml │ └── main.py ├── test_basic_name_be__main__ │ ├── expected.yaml │ └── main.py ├── test_basic_raise_exception │ ├── expected.yaml │ └── main.py ├── test_import_sub_module │ ├── expected.yaml │ ├── main.py │ └── sub_module │ │ ├── __init__.py │ │ └── foo.py ├── test_issue_98_multiprocessing │ ├── expected.yaml │ └── main.py ├── test_relative_import_sub_module │ ├── expected.yaml │ ├── main.py │ └── sub_module │ │ ├── __init__.py │ │ ├── bar.py │ │ └── foo.py ├── test_relative_import_sub_module2 │ ├── expected.yaml │ ├── main.py │ └── parent │ │ ├── __init__.py │ │ ├── child │ │ ├── __init__.py │ │ └── child_foo.py │ │ ├── parent_bar.py │ │ └── parent_foo.py ├── test_sys_exit │ ├── expected.yaml │ └── main.py └── test_threading │ ├── expected.yaml │ └── main.py ├── fixtures ├── __init__.py └── sample_module │ ├── __init__.py │ ├── main.py │ └── relative_import │ ├── __init__.py │ ├── main.py │ ├── sub_module │ ├── __init__.py │ └── module_cmd.py │ └── util.py ├── requirements.txt ├── shell_tools.py ├── test_cli.py ├── test_customize_ext.py ├── test_encoding.py ├── test_encryption.py ├── test_exe.py └── test_exe_testcases.py /.dockerignore: -------------------------------------------------------------------------------- 1 | .pip-cache/* 2 | build/* 3 | dist/* 4 | 5 | .python-version 6 | 7 | **/*.pyc 8 | **/*.pye 9 | **/*.so 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .pypirc 2 | *.pyc 3 | *.pye 4 | *.so 5 | .idea/* 6 | .vscode/* 7 | build/* 8 | dist/* 9 | vagrant/.vagrant/* 10 | venv/* 11 | 12 | src/pyconcrete/_pyconcrete.so 13 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | default_stages: [commit, push] 2 | fail_fast: false 3 | repos: 4 | - repo: https://github.com/pre-commit/pre-commit-hooks 5 | rev: v4.6.0 6 | hooks: 7 | - id: end-of-file-fixer 8 | - id: trailing-whitespace 9 | 10 | - repo: https://github.com/pycqa/isort 11 | rev: 5.13.2 12 | hooks: 13 | - id: isort 14 | 15 | - repo: https://github.com/psf/black 16 | rev: 24.4.2 17 | hooks: 18 | - id: black 19 | language_version: python3 20 | 21 | - repo: https://github.com/pycqa/flake8 22 | rev: '7.0.0' 23 | hooks: 24 | - id: flake8 25 | args: 26 | - --config 27 | - flake8.cfg 28 | additional_dependencies: 29 | - flake8-tidy-imports 30 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | sudo: required 3 | 4 | matrix: 5 | include: 6 | - python: "3.5" 7 | env: PY_VER=3.5 8 | dist: xenial 9 | 10 | - python: "3.6" 11 | env: PY_VER=3.6 12 | dist: xenial 13 | 14 | - python: "3.7" 15 | env: PY_VER=3.7 16 | dist: xenial 17 | 18 | - python: "3.8" 19 | env: PY_VER=3.8 20 | dist: xenial 21 | 22 | before_install: 23 | - sudo apt-get install -y python-software-properties 24 | - sudo add-apt-repository -y ppa:deadsnakes/ppa 25 | - sudo apt-get update 26 | - sudo apt-get install -y python$PY_VER-dev 27 | 28 | #install: 29 | # - pip install -r requirements.txt 30 | 31 | script: 32 | - python$PY_VER pyecli test 33 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Pyconcrete Changelog 2 | 3 | ## 1.0.1 (2025-??-??) 4 | 5 | ### Features 6 | * Support to assign customized file extension. Which default is .pye https://github.com/Falldog/pyconcrete/pull/115 7 | 8 | ### Bug fixes 9 | * Fix return code should not be 0 when python script is exception https://github.com/Falldog/pyconcrete/pull/114 10 | 11 | 12 | 13 | ## 1.0.0 (2025-02-23) 14 | 15 | ### Features 16 | * Build-system migrate to `meson-python` 17 | * Migrate `setup.py` to `pyproject.toml` 18 | * Migrate test framework to pytest 19 | * Support python 3.11 3.12, 3.13 20 | 21 | ### Breaking Changes 22 | * No longer support python versions earlier than 3.6 23 | * Assign passphrase by argument when pip installation, rather than assign env 24 | * Pip installation passphrase naming be `passphrase` 25 | * Rename `pyconcrete-admin.py` to `pyecli` 26 | 27 | 28 | 29 | ## 0.15.2 (2025-02-17) 30 | 31 | ### Features 32 | * Migrate PyeLoader from meta_path to path_hook https://github.com/Falldog/pyconcrete/pull/108 33 | 34 | ### Bug fixes 35 | * Fix django example Dockerfile get-pip.py for python 3.6 compatability https://github.com/Falldog/pyconcrete/pull/100 36 | 37 | 38 | 39 | ## 0.15.1 (2022-02-28) 40 | 41 | ### Bug fixes 42 | * Fix passphrase secret_key generation issue. https://github.com/Falldog/pyconcrete/issues/73 43 | * Remove installation default passphrase. https://github.com/Falldog/pyconcrete/issues/58 44 | * Update pip installation passphrase env name to `PYCONCRETE_PASSPHRASE` 45 | 46 | 47 | 48 | ## 0.14.1 (2022-02-13) 49 | 50 | ### Bug fixes 51 | * Fix pip installation issue 52 | 53 | 54 | 55 | ## 0.14.0 (2022-01-29) 56 | 57 | ### Features 58 | * Support python 3.9 & 3.10 59 | 60 | 61 | 62 | ## 0.13.0 (2021-09-28) 63 | 64 | ### Features 65 | * Support python 3.8 66 | 67 | ### Bug fixes 68 | * Fix pyconcrete.exe PY_Finalize exception issue https://github.com/Falldog/pyconcrete/issues/71 69 | * Fix threading global variable issue https://github.com/Falldog/pyconcrete/issues/61 70 | * Fix python 3.7 link issue on Mac 71 | 72 | 73 | 74 | ## 0.12.1 (2018-09-15) 75 | 76 | ### Features 77 | * Support python 3.7 78 | * pyconcrete-admin support ignore file pattern https://github.com/Falldog/pyconcrete/pull/24 79 | * pyconcrete-admin support multiple source files https://github.com/Falldog/pyconcrete/pull/43 80 | 81 | ### Bug fixes 82 | * Fix double release memory issue https://github.com/Falldog/pyconcrete/pull/37 83 | 84 | 85 | 86 | ## 0.11.3 (2017-10-07) 87 | 88 | ### Features 89 | * Support windows build with AppVeyor 90 | 91 | ### Bug fixes 92 | * Fix several windows build issues 93 | 94 | 95 | 96 | ## 0.11.1 (2017-07-31) 97 | 98 | ### Features 99 | * Support full encryption by pyconcrete(exe) for execute .pye as main script 100 | 101 | ### Bug fixes 102 | * Fix python3 support compatible issue 103 | * Fix Travis.ci unit test silent exception issue 104 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DEFAULT_TEST_PY_VER = 3.10 2 | PY_VERSIONS = 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3 | 4 | .PHONY: help test attach 5 | 6 | help: 7 | @printf "Usage: make [OPTION]\n" 8 | @printf "\n" 9 | @printf "test-all\n" 10 | @printf "test [version: 3.7|3.8|3.9|3.10|...]\n" 11 | @printf "attach [version: 3.7|3.8|3.9|3.10|...]\n" 12 | @printf "run-example-django\n" 13 | @printf "build-dist\n" 14 | @printf "upload-dist\n" 15 | @printf "upload-dist-for-test\n" 16 | @printf "install {ENV: PASSPHRASE=}\n" 17 | @printf "testpypi-install {ENV: VERSION= PASSPHRASE=}\n" 18 | 19 | 20 | clean: 21 | find . -type f -name "*.pyc" -exec rm -f {} \; 22 | 23 | test: 24 | VER="$(filter-out $@,$(MAKECMDGOALS))"; \ 25 | if [ -z "$$VER" ]; then \ 26 | VER="$(DEFAULT_TEST_PY_VER)"; \ 27 | fi; \ 28 | \ 29 | PY_VER=$$VER ./bin/run-test.sh 30 | 31 | test-all : 32 | for ver in $(PY_VERSIONS); do \ 33 | PY_VER=$$ver ./bin/run-test.sh || exit 1; \ 34 | done 35 | 36 | attach: 37 | VER="$(filter-out $@,$(MAKECMDGOALS))"; \ 38 | if [ -z "$$VER" ]; then \ 39 | VER="$(DEFAULT_TEST_PY_VER)"; \ 40 | fi; \ 41 | \ 42 | PY_VER=$$VER ./bin/run-test.sh attach 43 | 44 | run-example-django: 45 | ./bin/run-example-django.sh 46 | 47 | install: 48 | python3 -m pip install \ 49 | --no-cache-dir \ 50 | -v \ 51 | . \ 52 | -Csetup-args="-Dpassphrase=$(PASSPHRASE)" 53 | 54 | build-dist: 55 | rm -rf dist/ 56 | if [ -z "$$(git status --porcelain --untracked-files=no)" ]; then \ 57 | python -m build --sdist -Csetup-args="-Dpassphrase=__DUMMY__" ; \ 58 | else \ 59 | echo "Please stash your local modification before build dist ..."; \ 60 | fi; 61 | 62 | upload-dist: 63 | twine upload dist/* 64 | 65 | upload-dist-for-test: 66 | twine upload -r testpypi dist/* 67 | 68 | testpypi-install: 69 | python3 -m pip install \ 70 | --index-url https://test.pypi.org/simple/ \ 71 | --extra-index-url https://pypi.org/simple/ \ 72 | --no-cache-dir \ 73 | pyconcrete==$(VERSION) \ 74 | -Csetup-args="-Dpassphrase=$(PASSPHRASE)" 75 | 76 | # prevent error when assign extra argument for target 77 | %: 78 | @: 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | pyconcrete 2 | ============== 3 | [![Travis](https://img.shields.io/travis/Falldog/pyconcrete.svg?label=travis)](https://travis-ci.org/Falldog/pyconcrete) 4 | [![AppVeyor](https://img.shields.io/appveyor/ci/Falldog/pyconcrete.svg?label=appveyor)](https://ci.appveyor.com/project/Falldog/pyconcrete) 5 | [![PyPI Version](https://img.shields.io/pypi/v/pyconcrete.svg)](https://pypi.python.org/pypi/pyconcrete) 6 | [![PyPI PyVersion](https://img.shields.io/pypi/pyversions/pyconcrete.svg)](https://pypi.python.org/pypi/pyconcrete) 7 | [![PyPI License](https://img.shields.io/pypi/l/pyconcrete.svg)](https://pypi.python.org/pypi/pyconcrete) 8 | 9 | Protect your python script, encrypt .pyc to .pye and decrypt when import it 10 | 11 | -------------- 12 | 13 | 14 | Protect python script work flow 15 | -------------- 16 | * Build the execution `pyconcrete` and read the `MAIN.pye` which encrypted by your passphrase. 17 | * pyconcrete will decrypt the source file and then launch python interpreter to do the normal python behavior. 18 | * pyconcrete will hook import module 19 | * when your script do `import MODULE`, pyconcrete import hook will try to find `MODULE.pye` first 20 | and then decrypt `MODULE.pye` via `_pyconcrete.pyd` and execute decrypted data (as .pyc content) 21 | * encrypt & decrypt secret key record in `_pyconcrete.pyd` (like DLL or SO) 22 | the secret key would be hide in binary code, can't see it directly in HEX view 23 | 24 | 25 | Encryption 26 | -------------- 27 | * only support AES 128 bit now 28 | * encrypt & decrypt by library OpenAES 29 | 30 | 31 | Compatibility 32 | -------------- 33 | Pyconcrete has transitioned to using [meson-python](https://github.com/mesonbuild/meson-python) as its build backend 34 | starting from version 1.0.0. This provides a more powerful build mechanism and supports newer Python versions. 35 | 36 | For older Python support: 37 | * Pyconcrete versions prior to 0.15.2 only support up to Python 3.10. 38 | * If you need support for Python 3.6 or Python 2.7, please use versions before 0.15.2. 39 | * Pyconcrete no longer supports Python versions earlier than 3.6. 40 | 41 | 42 | Requirements 43 | -------------- 44 | For unix base 45 | * apt: pkg-config, build-essential, python{version}-dev 46 | * pip: 23.1+ 47 | 48 | 49 | Installation 50 | -------------- 51 | Due to security considerations, you must provide a passphrase to create a secret key for encrypting Python scripts: 52 | * The same passphrase will generate the same secret key. 53 | * Pre-built packages are not provided, so users must build the package yourself. 54 | 55 | Build Process 56 | * Pyconcrete relies on Meson to compile the C extension. 57 | * The installation process will add a `pyconcrete.pth` file to your `site-packages`, enabling `sitecustomize.py` to automatically import Pyconcrete. 58 | 59 | ### pip 60 | * Need to config the passphrase for installation. And only pip 23.1+ support passing argument via `-C` or `--config-settings`. 61 | * Remember to assign `--no-cache-dir` to avoid use pip's cached package which already built by old passphrase. 62 | ```sh 63 | $ pip install pyconcrete \ 64 | --no-cache-dir \ 65 | --config-settings=setup-args="-Dpassphrase=" 66 | ``` 67 | 68 | * Available arguments. Setup by `--config-settings=setup-args="-D="` 69 | * `passphrase`: (Mandatory) To generate secret key for encryption. 70 | * `ext`: Able to assign customized encrypted file extension. Which default is `.pye`. 71 | 72 | Usage 73 | -------------- 74 | 75 | ### Full encrypted 76 | * convert all of your `.py` to `*.pye` 77 | ```sh 78 | $ pyecli compile --pye -s= 79 | $ pyecli compile --pye -s= 80 | $ pyecli compile --pye -s= -e= 81 | ``` 82 | 83 | * remove `*.py` `*.pyc` or copy `*.pye` to other folder 84 | * *main*.py encrypted as *main*.pye, it can't be executed by normal `python`. 85 | You must use `pyconcrete` to process the *main*.pye script. 86 | `pyconcrete`(*exe*) will be installed in your system path (ex: /usr/local/bin) 87 | 88 | ```sh 89 | pyconcrete main.pye 90 | src/*.pye # your libs 91 | ``` 92 | 93 | 94 | ### Partial encrypted (pyconcrete as lib) -> (DEPRECATED and not Safe) 95 | * import pyconcrete in your main script 96 | * project layout 97 | ```sh 98 | main.py # import pyconcrete and your lib 99 | pyconcrete/* # put pyconcrete lib in project root, keep it as original files 100 | src/*.pye # your libs 101 | ``` 102 | 103 | 104 | Test 105 | -------------- 106 | * test in local 107 | ```sh 108 | $ pytest tests 109 | ``` 110 | 111 | * test in docker environment 112 | ```sh 113 | $ make test 114 | ``` 115 | 116 | * test in docker environment for specific python version 117 | ```sh 118 | $ make test 3.10 119 | ``` 120 | 121 | Example 122 | -------------- 123 | 124 | [Django with pyconcrete](example/django) 125 | 126 | 127 | ### Reference 128 | https://matthew-brett.github.io/pydagogue/python_msvc.html 129 | https://github.com/cython/cython/wiki/CythonExtensionsOnWindows 130 | 131 | 132 | Announcement 133 | -------------- 134 | pyconcrete is an experimental project, there is always a way to decrypt .pye files, but pyconcrete just make it harder. 135 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.0.0 2 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # reference from https://github.com/cython/cython/blob/master/appveyor.yml 2 | 3 | image: 4 | - Visual Studio 2015 5 | 6 | environment: 7 | 8 | global: 9 | # SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the 10 | # /E:ON and /V:ON options are not enabled in the batch script interpreter 11 | # See: https://stackoverflow.com/questions/11267463/compiling-python-modules-on-windows-x64/13751649#13751649 12 | WITH_ENV: "cmd /E:ON /V:ON /C .\\appveyor\\run_with_env.cmd" 13 | 14 | 15 | matrix: 16 | - PYTHON: "C:\\Python35" 17 | PYTHON_VERSION: "3.5.x" 18 | PYTHON_ARCH: "32" 19 | 20 | - PYTHON: "C:\\Python35-x64" 21 | PYTHON_VERSION: "3.5.x" 22 | PYTHON_ARCH: "64" 23 | 24 | - PYTHON: "C:\\Python36" 25 | PYTHON_VERSION: "3.6.x" 26 | PYTHON_ARCH: "32" 27 | 28 | - PYTHON: "C:\\Python36-x64" 29 | PYTHON_VERSION: "3.6.x" 30 | PYTHON_ARCH: "64" 31 | 32 | - PYTHON: "C:\\Python37" 33 | PYTHON_VERSION: "3.7.x" 34 | PYTHON_ARCH: "32" 35 | 36 | - PYTHON: "C:\\Python37-x64" 37 | PYTHON_VERSION: "3.7.x" 38 | PYTHON_ARCH: "64" 39 | 40 | - PYTHON: "C:\\Python38" 41 | PYTHON_VERSION: "3.8.x" 42 | PYTHON_ARCH: "32" 43 | 44 | - PYTHON: "C:\\Python38-x64" 45 | PYTHON_VERSION: "3.8.x" 46 | PYTHON_ARCH: "64" 47 | 48 | init: 49 | - "ECHO Python %PYTHON_VERSION% (%PYTHON_ARCH%bit) from %PYTHON%" 50 | 51 | install: 52 | - "powershell appveyor\\install.ps1" 53 | - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" 54 | - "python --version" 55 | - "pip --version" 56 | - "wheel version" 57 | - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" 58 | # Upgrade to the latest version of pip to avoid it displaying warnings 59 | # about it being out of date. 60 | - "python -m pip install --disable-pip-version-check --user --upgrade pip" 61 | - "pip --version" 62 | 63 | build: off 64 | 65 | test_script: 66 | - "python -m pip install --disable-pip-version-check --user -r test\\requirements.txt" 67 | - "%WITH_ENV% python pyecli test" 68 | -------------------------------------------------------------------------------- /appveyor/install.ps1: -------------------------------------------------------------------------------- 1 | # Sample script to install Python and pip under Windows 2 | # Authors: Olivier Grisel and Kyle Kastner 3 | # License: CC0 1.0 Universal: https://creativecommons.org/publicdomain/zero/1.0/ 4 | 5 | $PYTHON_BASE_URL = "https://www.python.org/ftp/python/" 6 | $GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py" 7 | $GET_PIP_PATH = "C:\get-pip.py" 8 | 9 | $DOWNLOADS = "C:\Downloads\Cython" 10 | 11 | 12 | function Download ($url, $filename, $destdir) { 13 | if ($destdir) { 14 | $item = New-Item $destdir -ItemType directory -Force 15 | $destdir = $item.FullName 16 | } else { 17 | $destdir = $pwd.Path 18 | } 19 | $filepath = Join-Path $destdir $filename 20 | if (Test-Path $filepath) { 21 | Write-Host "Reusing" $filename "from" $destdir 22 | return $filepath 23 | } 24 | Write-Host "Downloading" $filename "from" $url 25 | $webclient = New-Object System.Net.WebClient 26 | foreach($i in 1..3) { 27 | try { 28 | $webclient.DownloadFile($url, $filepath) 29 | Write-Host "File saved at" $filepath 30 | return $filepath 31 | } 32 | Catch [Exception] { 33 | Start-Sleep 1 34 | } 35 | } 36 | Write-Host "Failed to download" $filename "from" $url 37 | return $null 38 | } 39 | 40 | 41 | function InstallPython ($python_version, $architecture, $python_home) { 42 | Write-Host "Installing Python $python_version ($architecture-bit) to $python_home" 43 | if (Test-Path $python_home) { 44 | Write-Host $python_home "already exists, skipping." 45 | return 46 | } 47 | $py_major = $python_version[0]; $py_minor = $python_version[2] 48 | $installer_exe = ($py_major + $py_minor) -as [int] -ge 35 49 | if ($installer_exe) { 50 | $arch_suffix = @{"32"="";"64"="-amd64"}[$architecture] 51 | $dl_filename = "python-" + $python_version + $arch_suffix + ".exe" 52 | $filename = "python-" + $py_major + "." + $py_minor + $arch_suffix + ".exe" 53 | } else { 54 | $arch_suffix = @{"32"="";"64"=".amd64"}[$architecture] 55 | $dl_filename = "python-" + $python_version + $arch_suffix + ".msi" 56 | $filename = "python-" + $py_major + "." + $py_minor + $arch_suffix + ".msi" 57 | } 58 | $url = $PYTHON_BASE_URL + $python_version + "/" + $dl_filename 59 | $filepath = Download $url $filename $DOWNLOADS 60 | Write-Host "Installing" $filename "to" $python_home 61 | if ($installer_exe) { 62 | $prog = "$filepath" 63 | $args = "/quiet TargetDir=$python_home" 64 | } else { 65 | $prog = "msiexec.exe" 66 | $args = "/quiet /qn /i $filepath TARGETDIR=$python_home" 67 | } 68 | Write-Host $prog $args 69 | Start-Process -FilePath $prog -ArgumentList $args -Wait 70 | Write-Host "Python $python_version ($architecture-bit) installation complete" 71 | } 72 | 73 | 74 | function InstallPip ($python_home) { 75 | $python_path = Join-Path $python_home "python.exe" 76 | $pip_path = Join-Path $python_home "Scripts\pip.exe" 77 | if (Test-Path $pip_path) { 78 | Write-Host "Upgrading pip" 79 | $args = "-m pip.__main__ install --upgrade pip" 80 | Write-Host "Executing:" $python_path $args 81 | Start-Process -FilePath $python_path -ArgumentList $args -Wait 82 | Write-Host "pip upgrade complete" 83 | } else { 84 | Write-Host "Installing pip" 85 | $webclient = New-Object System.Net.WebClient 86 | $webclient.DownloadFile($GET_PIP_URL, $GET_PIP_PATH) 87 | Write-Host "Executing:" $python_path $GET_PIP_PATH 88 | Start-Process -FilePath $python_path -ArgumentList "$GET_PIP_PATH" -Wait 89 | Write-Host "pip installation complete" 90 | } 91 | } 92 | 93 | 94 | function InstallPipPackage ($python_home, $package) { 95 | $pip_path = Join-Path $python_home "Scripts\pip.exe" 96 | Write-Host "Installing/Upgrading $package" 97 | $args = "install --upgrade $package" 98 | Write-Host "Executing:" $pip_path $args 99 | Start-Process -FilePath $pip_path -ArgumentList $args -Wait 100 | Write-Host "$package install/upgrade complete" 101 | } 102 | 103 | function main () { 104 | $full_version = $env:PYTHON_VERSION + ".0" 105 | InstallPython $full_version $env:PYTHON_ARCH $env:PYTHON 106 | InstallPip $env:PYTHON 107 | InstallPipPackage $env:PYTHON setuptools 108 | InstallPipPackage $env:PYTHON wheel 109 | } 110 | 111 | main 112 | -------------------------------------------------------------------------------- /appveyor/run_with_env.cmd: -------------------------------------------------------------------------------- 1 | :: Author: Lisandro Dalcin 2 | :: Contact: dalcinl@gmail.com 3 | :: Credits: Olivier Grisel and Kyle Kastner 4 | @ECHO OFF 5 | 6 | SET COMMAND_TO_RUN=%* 7 | 8 | SET PYTHON_VERSION_MAJOR=%PYTHON_VERSION:~0,1% 9 | SET PYTHON_VERSION_MINOR=%PYTHON_VERSION:~2,1% 10 | 11 | SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows 12 | IF %PYTHON_VERSION_MAJOR% == 2 SET WIN_SDK_VERSION="v7.0" 13 | IF %PYTHON_VERSION_MAJOR% == 3 SET WIN_SDK_VERSION="v7.1" 14 | 15 | IF %PYTHON_ARCH% == 64 SET USE_WIN_SDK=1 16 | IF %PYTHON_VERSION_MAJOR% EQU 3 IF %PYTHON_VERSION_MINOR% GEQ 5 SET USE_WIN_SDK=0 17 | IF %PYTHON_VERSION_MAJOR% GTR 3 SET USE_WIN_SDK=0 18 | if %PYTHON_ARCH% == 32 SET USE_WIN_SDK=0 19 | 20 | IF %USE_WIN_SDK% == 1 ( 21 | ECHO Configuring Windows SDK %WIN_SDK_VERSION% for %PYTHON_ARCH% bit architecture 22 | SET DISTUTILS_USE_SDK=1 23 | SET MSSdk=1 24 | "%WIN_SDK_ROOT%\%WIN_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WIN_SDK_VERSION% 25 | "%WIN_SDK_ROOT%\%WIN_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release 26 | ECHO Executing: %COMMAND_TO_RUN% 27 | CALL %COMMAND_TO_RUN% || EXIT 1 28 | ) ELSE ( 29 | ECHO Using default MSVC build environment for %PYTHON_ARCH% bit architecture 30 | ECHO Executing: %COMMAND_TO_RUN% 31 | CALL %COMMAND_TO_RUN% || EXIT 1 32 | ) 33 | -------------------------------------------------------------------------------- /bin/run-example-django.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -ex 4 | 5 | PORT=${PORT:="5151"} 6 | 7 | declare -xr REPO_ROOT=$( cd "$( dirname "${BASH_SOURCE[0]}" )/../" && pwd ) 8 | 9 | cd ${REPO_ROOT} 10 | 11 | docker build \ 12 | -t falldog/example-django \ 13 | -f example/django/Dockerfile \ 14 | . 15 | 16 | echo "Django testing website running at http://127.0.0.1:${PORT}" 17 | docker run \ 18 | --rm \ 19 | -p ${PORT}:80 \ 20 | --name pyconcrete-example-django \ 21 | falldog/example-django 22 | -------------------------------------------------------------------------------- /bin/run-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -ex 4 | 5 | PY_VER=${PY_VER:="3.10"} 6 | TEST_VERBOSE=${TEST_VERBOSE:=""} 7 | 8 | 9 | declare -xr REPO_ROOT=$( cd "$( dirname "${BASH_SOURCE[0]}" )/../" && pwd ) 10 | declare -xr PIP_CACHE=${REPO_ROOT}/.pip-cache 11 | 12 | mkdir -p ${PIP_CACHE} 13 | cd "${REPO_ROOT}" 14 | 15 | build() { 16 | ver=$1 17 | service="pye${ver}" 18 | 19 | docker-compose -f docker-compose-test.yml build ${service} 20 | } 21 | 22 | run_test() { 23 | ver=$1 24 | docker run \ 25 | --rm \ 26 | -t \ 27 | -e TEST_PYE_PERFORMANCE_COUNT=1 \ 28 | -e TEST_VERBOSE=${TEST_VERBOSE} \ 29 | --mount="type=bind,source=${REPO_ROOT}/,target=/code" \ 30 | --mount="type=bind,source=${PIP_CACHE}/,target=/root/.cache/pip/" \ 31 | falldog/pyconcrete-tester:${ver} \ 32 | \ 33 | /bin/bash -c \ 34 | " \ 35 | pip list && \ 36 | pytest tests \ 37 | " 38 | } 39 | 40 | attach_for_test() { 41 | ver=$1 42 | docker run \ 43 | --rm \ 44 | -it \ 45 | -e TEST_PYE_PERFORMANCE_COUNT=1 \ 46 | --mount="type=bind,source=${REPO_ROOT}/,target=/code" \ 47 | --mount="type=bind,source=${PIP_CACHE}/,target=/root/.cache/pip/" \ 48 | falldog/pyconcrete-tester:${ver} \ 49 | /bin/bash 50 | } 51 | 52 | 53 | 54 | case $1 in 55 | attach) 56 | build ${PY_VER} 57 | attach_for_test "${PY_VER}" 58 | ;; 59 | *) 60 | build ${PY_VER} 61 | run_test "${PY_VER}" 62 | ;; 63 | esac 64 | -------------------------------------------------------------------------------- /docker-compose-test.yml: -------------------------------------------------------------------------------- 1 | services: 2 | # meson-python not support python3.6, drop the support 3 | # pye3.6: 4 | # build: 5 | # context: . 6 | # dockerfile: ./docker/Dockerfile_3_6 7 | # args: 8 | # PY_VER: "3.6" 9 | # image: falldog/pyconcrete-tester:3.6 10 | 11 | pye3.7: 12 | build: 13 | context: . 14 | dockerfile: ./docker/Dockerfile 15 | args: 16 | PY_VER: "3.7" 17 | image: falldog/pyconcrete-tester:3.7 18 | 19 | pye3.8: 20 | build: 21 | context: . 22 | dockerfile: ./docker/Dockerfile 23 | args: 24 | PY_VER: "3.8" 25 | image: falldog/pyconcrete-tester:3.8 26 | 27 | pye3.9: 28 | build: 29 | context: . 30 | dockerfile: ./docker/Dockerfile 31 | args: 32 | PY_VER: "3.9" 33 | image: falldog/pyconcrete-tester:3.9 34 | 35 | pye3.10: 36 | build: 37 | context: . 38 | dockerfile: ./docker/Dockerfile 39 | args: 40 | PY_VER: "3.10" 41 | image: falldog/pyconcrete-tester:3.10 42 | 43 | pye3.11: 44 | build: 45 | context: . 46 | dockerfile: ./docker/Dockerfile 47 | args: 48 | PY_VER: "3.11" 49 | image: falldog/pyconcrete-tester:3.11 50 | 51 | pye3.12: 52 | build: 53 | context: . 54 | dockerfile: ./docker/Dockerfile_3_12_plus 55 | args: 56 | PY_VER: "3.12" 57 | image: falldog/pyconcrete-tester:3.12 58 | 59 | pye3.13: 60 | build: 61 | context: . 62 | dockerfile: ./docker/Dockerfile_3_12_plus 63 | args: 64 | PY_VER: "3.13" 65 | image: falldog/pyconcrete-tester:3.13 66 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | LABEL maintainer=falldog 3 | 4 | ARG DEBIAN_FRONTEND=noninteractive 5 | ARG PY_VER=3.10 6 | 7 | RUN set -ex \ 8 | && apt-get update \ 9 | && apt-get install -y --no-install-recommends \ 10 | # debug utility 11 | vim \ 12 | less \ 13 | \ 14 | curl \ 15 | build-essential \ 16 | software-properties-common \ 17 | python3-distutils \ 18 | gpg-agent \ 19 | \ 20 | && rm -rf /var/lib/apt/lists/* 21 | 22 | RUN set -ex \ 23 | && add-apt-repository ppa:deadsnakes/ppa \ 24 | && apt-get update \ 25 | && apt-get install -y --no-install-recommends \ 26 | python${PY_VER} \ 27 | python${PY_VER}-dev \ 28 | python${PY_VER}-distutils \ 29 | pkg-config \ 30 | \ 31 | && rm -rf /var/lib/apt/lists/* 32 | 33 | # install pip 34 | RUN if [ "${PY_VER}" = "3.7" ] ; then \ 35 | curl https://bootstrap.pypa.io/pip/3.7/get-pip.py | python3.7 ; \ 36 | else \ 37 | curl https://bootstrap.pypa.io/get-pip.py | python${PY_VER} ; \ 38 | fi 39 | 40 | RUN set -ex \ 41 | && mkdir -p /code/tests \ 42 | && ln -sf /usr/bin/python${PY_VER} /usr/bin/python 43 | 44 | COPY tests/requirements.txt /code/tests 45 | RUN set -ex \ 46 | && python${PY_VER} -m pip install --no-cache-dir -r /code/tests/requirements.txt 47 | 48 | WORKDIR /code 49 | -------------------------------------------------------------------------------- /docker/Dockerfile_3_12_plus: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | LABEL maintainer=falldog 3 | 4 | ARG DEBIAN_FRONTEND=noninteractive 5 | ARG PY_VER=3.12 6 | 7 | RUN set -ex \ 8 | && apt-get update \ 9 | && apt-get install -y --no-install-recommends \ 10 | # debug utility 11 | vim \ 12 | less \ 13 | \ 14 | curl \ 15 | build-essential \ 16 | software-properties-common \ 17 | python3-distutils \ 18 | gpg \ 19 | gpg-agent \ 20 | \ 21 | && DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install tzdata \ 22 | && add-apt-repository -y ppa:deadsnakes/ppa \ 23 | && rm -rf /var/lib/apt/lists/* 24 | 25 | RUN set -ex \ 26 | && apt-get update \ 27 | && apt-get install -y --no-install-recommends \ 28 | python${PY_VER} \ 29 | python${PY_VER}-dev \ 30 | pkg-config \ 31 | \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | \ 34 | && curl https://bootstrap.pypa.io/get-pip.py | python${PY_VER} 35 | 36 | RUN set -ex \ 37 | && mkdir -p /code/tests \ 38 | && ln -sf /usr/bin/python${PY_VER} /usr/bin/python 39 | 40 | COPY tests/requirements.txt /code/tests 41 | RUN set -ex \ 42 | && python${PY_VER} -m pip install --no-cache-dir -r /code/tests/requirements.txt 43 | 44 | WORKDIR /code 45 | -------------------------------------------------------------------------------- /example/django/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | LABEL maintainer=falldog 3 | 4 | ARG PY_VER=3.10 5 | ARG PASSPHRASE=TEST_FOR_DJANGO 6 | 7 | RUN set -ex \ 8 | && apt-get update \ 9 | && apt-get install -y --no-install-recommends \ 10 | # debug utility 11 | vim \ 12 | less \ 13 | \ 14 | curl \ 15 | build-essential \ 16 | software-properties-common \ 17 | python3-distutils \ 18 | pkg-config \ 19 | \ 20 | && rm -rf /var/lib/apt/lists/* 21 | 22 | RUN set -ex \ 23 | && apt-get update \ 24 | && apt-get install -y --no-install-recommends \ 25 | python${PY_VER} python${PY_VER}-dev \ 26 | \ 27 | && rm -rf /var/lib/apt/lists/* \ 28 | \ 29 | && curl https://bootstrap.pypa.io/get-pip.py | python${PY_VER} 30 | 31 | RUN set -ex \ 32 | && mkdir -p /code \ 33 | && mkdir -p /pyconcrete-code \ 34 | && ln -sf /usr/bin/python${PY_VER} /usr/bin/python 35 | 36 | # install pip requirements 37 | COPY example/django/pye_web/requirements.txt /code/ 38 | RUN pip install --no-cache-dir -r /code/requirements.txt 39 | 40 | # copy source code 41 | COPY example/django/pye_web/ \ 42 | /code/ 43 | COPY . \ 44 | /pyconcrete-code/ 45 | 46 | # install pyconcrete && compile .pye 47 | RUN set -ex \ 48 | && cd /pyconcrete-code/ \ 49 | && pip install --config-settings=setup-args=-Dpassphrase=${PASSPHARE} . \ 50 | && python pyecli compile \ 51 | --source=/code/ \ 52 | --pye \ 53 | --remove-py \ 54 | --remove-pyc \ 55 | -i wsgi.py manage.py 56 | 57 | WORKDIR /code 58 | 59 | CMD ["python", "manage.py", "runserver", "0.0.0.0:80"] 60 | -------------------------------------------------------------------------------- /example/django/README.md: -------------------------------------------------------------------------------- 1 | pyconcrete example for Django 2 | ============== 3 | 4 | 5 | Environment setup 6 | -------------- 7 | * install docker & execute below command to build and run 8 | ```bash 9 | $ ./bin/run-example-django.sh 10 | ``` 11 | * access `http://127.0.0.1:5151` by browser 12 | 13 | 14 | Environment 15 | -------------- 16 | * Docker, Ubuntu 22.04 17 | * Python 3.10 18 | * Django 2 19 | 20 | 21 | How the example working 22 | -------------- 23 | * django in docker listen port `5151` 24 | * install `pyconcrete` in system 25 | * django source code be encrypted in docker image, `/code/` 26 | * leave these two files as `.py`, and need add `import pyconcrete` at beginning 27 | * /code/pye_web/wsgi.py 28 | * /code/manage.py 29 | * (Note) docker image will cache source code by image layer, the example only for testing. In production, you need to make sure docker image will not cache the original .py source code. 30 | -------------------------------------------------------------------------------- /example/django/pye_web/app_pye/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Falldog/pyconcrete/5210bc2e47e1b4df3ebce120340b217a1016759f/example/django/pye_web/app_pye/__init__.py -------------------------------------------------------------------------------- /example/django/pye_web/app_pye/admin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.contrib import admin # noqa: F401 5 | 6 | # Register your models here. 7 | -------------------------------------------------------------------------------- /example/django/pye_web/app_pye/apps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.apps import AppConfig 5 | 6 | 7 | class PyeConfig(AppConfig): 8 | name = 'app_pye' 9 | -------------------------------------------------------------------------------- /example/django/pye_web/app_pye/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Falldog/pyconcrete/5210bc2e47e1b4df3ebce120340b217a1016759f/example/django/pye_web/app_pye/management/__init__.py -------------------------------------------------------------------------------- /example/django/pye_web/app_pye/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Falldog/pyconcrete/5210bc2e47e1b4df3ebce120340b217a1016759f/example/django/pye_web/app_pye/management/commands/__init__.py -------------------------------------------------------------------------------- /example/django/pye_web/app_pye/management/commands/echo.py: -------------------------------------------------------------------------------- 1 | from django.core.management import BaseCommand 2 | 3 | 4 | class Command(BaseCommand): 5 | def add_arguments(self, parser): 6 | super().add_arguments(parser) 7 | parser.add_argument('msg', nargs='+', help='echo message') 8 | 9 | def handle(self, *args, **options): 10 | msg = ' '.join(options['msg']) 11 | print(msg) 12 | -------------------------------------------------------------------------------- /example/django/pye_web/app_pye/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Falldog/pyconcrete/5210bc2e47e1b4df3ebce120340b217a1016759f/example/django/pye_web/app_pye/migrations/__init__.py -------------------------------------------------------------------------------- /example/django/pye_web/app_pye/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models # noqa: F401 5 | 6 | # Create your models here. 7 | -------------------------------------------------------------------------------- /example/django/pye_web/app_pye/tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.test import TestCase # noqa: F401 5 | 6 | # Create your tests here. 7 | -------------------------------------------------------------------------------- /example/django/pye_web/app_pye/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.shortcuts import render # noqa: F401 5 | 6 | # Create your views here. 7 | -------------------------------------------------------------------------------- /example/django/pye_web/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | import pyconcrete # noqa: F401 6 | 7 | if __name__ == "__main__": 8 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pye_web.settings") 9 | try: 10 | from django.core.management import execute_from_command_line 11 | except ImportError: 12 | # The above import may fail for some other reason. Ensure that the 13 | # issue is really that Django is missing to avoid masking other 14 | # exceptions on Python 2. 15 | try: 16 | import django # noqa: F401 17 | except ImportError: 18 | raise ImportError( 19 | "Couldn't import Django. Are you sure it's installed and " 20 | "available on your PYTHONPATH environment variable? Did you " 21 | "forget to activate a virtual environment?" 22 | ) 23 | raise 24 | execute_from_command_line(sys.argv) 25 | -------------------------------------------------------------------------------- /example/django/pye_web/pye_web/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Falldog/pyconcrete/5210bc2e47e1b4df3ebce120340b217a1016759f/example/django/pye_web/pye_web/__init__.py -------------------------------------------------------------------------------- /example/django/pye_web/pye_web/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for pye_web project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.11.5. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.11/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = 'f)t9o192lw#qsk9gow-778)wmxa4rn(rplcd@a(84neye_5320' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | 'django.contrib.admin', 35 | 'django.contrib.auth', 36 | 'django.contrib.contenttypes', 37 | 'django.contrib.sessions', 38 | 'django.contrib.messages', 39 | 'django.contrib.staticfiles', 40 | 'app_pye', 41 | ] 42 | 43 | MIDDLEWARE = [ 44 | 'django.middleware.security.SecurityMiddleware', 45 | 'django.contrib.sessions.middleware.SessionMiddleware', 46 | 'django.middleware.common.CommonMiddleware', 47 | 'django.middleware.csrf.CsrfViewMiddleware', 48 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 49 | 'django.contrib.messages.middleware.MessageMiddleware', 50 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 51 | ] 52 | 53 | ROOT_URLCONF = 'pye_web.urls' 54 | 55 | TEMPLATES = [ 56 | { 57 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 58 | 'DIRS': [], 59 | 'APP_DIRS': True, 60 | 'OPTIONS': { 61 | 'context_processors': [ 62 | 'django.template.context_processors.debug', 63 | 'django.template.context_processors.request', 64 | 'django.contrib.auth.context_processors.auth', 65 | 'django.contrib.messages.context_processors.messages', 66 | ], 67 | }, 68 | }, 69 | ] 70 | 71 | WSGI_APPLICATION = 'pye_web.wsgi.application' 72 | 73 | 74 | # Database 75 | # https://docs.djangoproject.com/en/1.11/ref/settings/#databases 76 | 77 | DATABASES = { 78 | 'default': { 79 | 'ENGINE': 'django.db.backends.sqlite3', 80 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 81 | } 82 | } 83 | 84 | 85 | # Password validation 86 | # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators 87 | 88 | AUTH_PASSWORD_VALIDATORS = [ 89 | { 90 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 91 | }, 92 | { 93 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 94 | }, 95 | { 96 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 97 | }, 98 | { 99 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 100 | }, 101 | ] 102 | 103 | 104 | # Internationalization 105 | # https://docs.djangoproject.com/en/1.11/topics/i18n/ 106 | 107 | LANGUAGE_CODE = 'en-us' 108 | 109 | TIME_ZONE = 'UTC' 110 | 111 | USE_I18N = True 112 | 113 | USE_L10N = True 114 | 115 | USE_TZ = True 116 | 117 | 118 | # Static files (CSS, JavaScript, Images) 119 | # https://docs.djangoproject.com/en/1.11/howto/static-files/ 120 | 121 | STATIC_URL = '/static/' 122 | -------------------------------------------------------------------------------- /example/django/pye_web/pye_web/urls.py: -------------------------------------------------------------------------------- 1 | """pye_web URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.11/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | 17 | from django.contrib import admin 18 | from django.urls import path 19 | 20 | urlpatterns = [ 21 | path(r'admin/', admin.site.urls), 22 | ] 23 | -------------------------------------------------------------------------------- /example/django/pye_web/pye_web/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for pye_web project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ 8 | """ 9 | # flake8: noqa 10 | 11 | import pyconcrete # isort:skip 12 | import os 13 | 14 | from django.core.wsgi import get_wsgi_application 15 | 16 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pye_web.settings") 17 | 18 | application = get_wsgi_application() 19 | -------------------------------------------------------------------------------- /example/django/pye_web/requirements.txt: -------------------------------------------------------------------------------- 1 | Django==5.0.6 2 | -------------------------------------------------------------------------------- /flake8.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | extend-ignore= 3 | # See https://github.com/PyCQA/pycodestyle/issues/373 4 | E203, 5 | # style related, follow black 6 | E501, 7 | # style related, follow black 8 | W503, 9 | max-line-length = 120 10 | per-file-ignores = 11 | # imported but unused 12 | __init__.py: F401 13 | max-complexity = 100 14 | 15 | select = E,F,W,I251 16 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'pyconcrete', 3 | 'c', 4 | meson_version: '>= 1.1', 5 | version: files('VERSION'), 6 | default_options: ['ext=.pye'], 7 | ) 8 | 9 | INSTALL_DIR = 'pyconcrete' 10 | PYCONCRETE_EXE_NAME = 'pyconcrete' 11 | BUILD_UTILITY_DIR = './meson_utility/' 12 | 13 | version = meson.project_version() 14 | 15 | # The python version will follow which user invoke menson-python 16 | # Such as `python -m pip install ...` or `python -m build ...` 17 | python_ins = import('python').find_installation(pure: false) 18 | python_ver = python_ins.language_version() 19 | python_exe_path = python_ins.full_path() 20 | python_dependency = python_ins.dependency(embed: true) 21 | 22 | macro_ext = '-D PYCONCRETE_EXT="@0@"'.format(get_option('ext')) 23 | macro_version = '-D PYCONCRETE_VERSION=@0@'.format(version) 24 | 25 | 26 | #---------------------------- 27 | # secret_key.h 28 | #---------------------------- 29 | 30 | passphrase = get_option('passphrase') 31 | if passphrase == '' 32 | error('Must assign a passphrase to build pyconcrete') 33 | endif 34 | 35 | gen_secret_key = custom_target( 36 | 'gen_secret_key', 37 | input: join_paths(BUILD_UTILITY_DIR, 'gen_secret_key.py'), 38 | output: 'secret_key.h', 39 | build_by_default: true, 40 | command: [python_exe_path, '@INPUT@', passphrase], 41 | ) 42 | 43 | 44 | #---------------------------- 45 | # _pyconcrete ext 46 | #---------------------------- 47 | 48 | ext_includes = [ 49 | './src/pyconcrete_ext/', 50 | './src/pyconcrete_ext/openaes/inc/', 51 | ] 52 | ext_srcs = [ 53 | './src/pyconcrete_ext/pyconcrete.c', 54 | './src/pyconcrete_ext/pyconcrete_module.c', 55 | './src/pyconcrete_ext/openaes/src/oaes_base64.c', 56 | './src/pyconcrete_ext/openaes/src/oaes_lib.c', 57 | ] 58 | python_ins.extension_module( 59 | '_pyconcrete', 60 | ext_srcs, 61 | c_args: [macro_ext], 62 | subdir: INSTALL_DIR, 63 | install: true, 64 | include_directories: ext_includes, 65 | ) 66 | 67 | python_ins.install_sources( 68 | [ 69 | 'src/pyconcrete/__init__.py', 70 | 'src/pyconcrete/version.py', 71 | 'VERSION', 72 | ], 73 | pure: false, 74 | subdir: INSTALL_DIR, 75 | ) 76 | 77 | python_ins.install_sources( 78 | join_paths(BUILD_UTILITY_DIR, 'pyconcrete.pth'), 79 | pure: false, 80 | # subdir: 81 | ) 82 | 83 | 84 | #---------------------------- 85 | # pyconcrete exe 86 | #---------------------------- 87 | 88 | exe_includes = [ 89 | './src/pyconcrete_exe/', 90 | './src/pyconcrete_ext/', 91 | './src/pyconcrete_ext/openaes/inc/', 92 | ] 93 | exe_srcs = [ 94 | './src/pyconcrete_exe/pyconcrete_exe.c', 95 | './src/pyconcrete_ext/pyconcrete.c', 96 | './src/pyconcrete_ext/openaes/src/oaes_base64.c', 97 | './src/pyconcrete_ext/openaes/src/oaes_lib.c', 98 | ] 99 | executable( 100 | PYCONCRETE_EXE_NAME, 101 | exe_srcs, 102 | c_args: [ 103 | macro_ext, 104 | macro_version, 105 | ], 106 | include_directories: exe_includes, 107 | dependencies: python_dependency, 108 | install: true, 109 | ) 110 | 111 | 112 | #---------------------------- 113 | # pyconcrete cli 114 | #---------------------------- 115 | 116 | # for install the executable cli scripts, we use bindir here. 117 | # meson-python will mapping `bindir`(meson) to `scripts`(python) 118 | # ref: 119 | # https://github.com/mesonbuild/meson-python/blob/0.17.1/mesonpy/__init__.py#L83 120 | # https://docs.python.org/3/library/sysconfig.html#installation-paths 121 | install_data( 122 | './pyecli', 123 | install_mode: 'rwxr-xr-x', 124 | install_dir: get_option('bindir'), 125 | ) 126 | 127 | 128 | #---------------------------- 129 | # sdist 130 | #---------------------------- 131 | 132 | # Meson dist not allow to config include/exclude file rules. 133 | # And it only clone the sources in .git revision, not including the uncommitted files in local. 134 | # So, we need to add dist_cleanup.sh to cleanup redundant files in dist/. 135 | meson.add_dist_script(join_paths(BUILD_UTILITY_DIR, 'dist_cleanup.sh')) 136 | -------------------------------------------------------------------------------- /meson.options: -------------------------------------------------------------------------------- 1 | option('passphrase', type: 'string', description: 'User-defined passphrase for secret key') 2 | option('ext', type: 'string', description: 'User-defined file extension, default is .pye') 3 | -------------------------------------------------------------------------------- /meson_utility/dist_cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DIST_DIR='meson-dist/pyconcrete-*' 4 | 5 | echo "clean up the dist files in '${DIST_DIR}'" 6 | 7 | # this script will be executed when do `python -m build --sdist` 8 | # and this will cleanup the meson staging folder 9 | 10 | set -ex 11 | 12 | rm -rf ${DIST_DIR}/appveyor/ 13 | rm -rf ${DIST_DIR}/bin/ 14 | rm -rf ${DIST_DIR}/docker/ 15 | rm -rf ${DIST_DIR}/example/ 16 | rm -rf ${DIST_DIR}/tests/ 17 | -------------------------------------------------------------------------------- /meson_utility/gen_secret_key.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Falldog Hsieh 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import hashlib 15 | import sys 16 | 17 | PY2 = sys.version_info.major < 3 18 | SECRET_HEADER_PATH = 'secret_key.h' 19 | 20 | 21 | def hash_key(key): 22 | if PY2: 23 | factor = sum([ord(s) for s in key]) 24 | else: 25 | factor = sum([s for s in key]) 26 | factor %= 128 27 | if factor < 16: 28 | factor += 16 29 | 30 | m = hashlib.md5() 31 | m.update(key) 32 | k = m.digest() 33 | 34 | return k, factor 35 | 36 | 37 | def create_secret_key_header(key, factor): 38 | # reference from - http://stackoverflow.com/questions/1356896/how-to-hide-a-string-in-binary-code 39 | # encrypt the secret key in binary code 40 | # avoid to easy read from HEX view 41 | key_val_lst = [] 42 | for i, k in enumerate(key): 43 | n = ord(k) if PY2 else k 44 | key_val_lst.append("(0x%X ^ (0x%X - %d))" % (n, factor, i)) 45 | key_val_code = ", ".join(key_val_lst) 46 | 47 | code = """ 48 | #define SECRET_NUM 0x%X 49 | #define SECRET_KEY_LEN %d 50 | static const unsigned char* GetSecretKey() 51 | { 52 | unsigned int i = 0; 53 | static unsigned char key[] = {%s, 0/* terminal char */}; 54 | static int is_encrypt = 1/*true*/; 55 | if( is_encrypt ) 56 | { 57 | for(i = 0 ; i < SECRET_KEY_LEN ; ++i) 58 | { 59 | key[i] = key[i] ^ (SECRET_NUM - i); 60 | } 61 | is_encrypt = 0/*false*/; 62 | } 63 | return key; 64 | } 65 | """ % ( 66 | factor, 67 | len(key), 68 | key_val_code, 69 | ) 70 | 71 | with open(SECRET_HEADER_PATH, 'w') as f: 72 | f.write(code) 73 | 74 | 75 | if __name__ == '__main__': 76 | passphrase = sys.argv[1] 77 | k, f = hash_key(passphrase.encode('utf8')) 78 | create_secret_key_header(k, f) 79 | -------------------------------------------------------------------------------- /meson_utility/pyconcrete.pth: -------------------------------------------------------------------------------- 1 | import pyconcrete 2 | -------------------------------------------------------------------------------- /pyecli: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright 2015 Falldog Hsieh 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import argparse 18 | import fnmatch 19 | import logging 20 | import os 21 | import py_compile 22 | import sys 23 | from os.path import abspath, dirname, exists, isdir, isfile, join, splitext 24 | 25 | CUR_DIR = dirname(abspath(__file__)) 26 | 27 | IGNORE_FILES = ['.', '..', '.git', '.svn', 'pyconcrete'] 28 | logger = logging.getLogger('pyconcrete') 29 | 30 | 31 | class PyConcreteError(Exception): 32 | pass 33 | 34 | 35 | class PyConcreteCli(object): 36 | def __init__(self): 37 | self.parser = None 38 | self.args = None 39 | self.parse_arg() 40 | self.verbose = False 41 | 42 | def parse_arg(self): 43 | """ 44 | Example: 45 | compile file/dir to .pye 46 | pyecli compile --source={file} --pye 47 | 48 | compile file/dir to .pyc 49 | pyecli compile --source={file} --pyc 50 | """ 51 | parser = argparse.ArgumentParser(description='PyConcreteCli') 52 | subparsers = parser.add_subparsers() 53 | 54 | # === compile === # 55 | parser_compile = subparsers.add_parser('compile', help='compile .pye') 56 | parser_compile.add_argument( 57 | '-s', 58 | '--source', 59 | dest='sources', 60 | default=None, 61 | nargs='+', 62 | help='specific the sources to process, source could be file/dir', 63 | ) 64 | parser_compile.add_argument('--pye', dest='pye', action='store_true', help='process on .pye') 65 | parser_compile.add_argument('--pyc', dest='pyc', action='store_true', help='process on .pyc') 66 | parser_compile.add_argument('-e', '--ext', dest='ext', default='.pye', help='file extension, default is .pye') 67 | parser_compile.add_argument( 68 | '--remove-py', dest='remove_py', action='store_true', help='remove .py after compile pye' 69 | ) 70 | parser_compile.add_argument( 71 | '--remove-pyc', dest='remove_pyc', action='store_true', help='remove .pyc after compile pye' 72 | ) 73 | parser_compile.add_argument( 74 | '-i', 75 | '--ignore-file-list', 76 | dest='ignore_file_list', 77 | metavar='filename', 78 | nargs='+', 79 | default=tuple(), 80 | help='ignore file name list', 81 | ) 82 | parser_compile.add_argument('-v', '--verbose', action='store_true', help='verbose mode') 83 | parser_compile.set_defaults(func=self.compile) 84 | 85 | if len(sys.argv) == 1: 86 | parser.print_help() 87 | 88 | else: 89 | try: 90 | args = parser.parse_args() 91 | self.verbose = getattr(args, 'verbose', False) 92 | args.func(args) 93 | except PyConcreteError as e: 94 | print('Error: ' + str(e)) 95 | sys.exit(1) 96 | 97 | def compile(self, args): 98 | if args.sources is None: 99 | raise PyConcreteError("arg: compile, need assign --source={file/dir} to process") 100 | if not args.pye and not args.pyc: 101 | raise PyConcreteError("arg: compile, need assign the type for compile to `pye` or `pyc`") 102 | 103 | for source in args.sources: 104 | if isfile(source): 105 | if not source.endswith('.py'): 106 | raise PyConcreteError("source file should end with .py") 107 | 108 | if args.pye: 109 | self._compile_pye_file(args, source) 110 | elif args.pyc: 111 | self._compile_pyc_file(args, source) 112 | 113 | elif isdir(source): 114 | self._compile_dir(args, source) 115 | 116 | def _get_ignore_patterns(self, args): 117 | patterns = [] 118 | for pat in args.ignore_file_list: 119 | if not pat.startswith("*"): 120 | if not pat.startswith(os.sep): 121 | pat = os.sep + pat 122 | pat = "*" + pat 123 | patterns.append(pat) 124 | return patterns 125 | 126 | def _compile_dir(self, args, folder): 127 | # ignore patterns 128 | patterns = self._get_ignore_patterns(args) 129 | for file in os.listdir(folder): 130 | fullpath = join(folder, file) 131 | if file in IGNORE_FILES or self._fnmatch(fullpath, patterns): 132 | continue 133 | 134 | if isdir(fullpath): 135 | self._compile_dir(args, fullpath) 136 | elif fullpath.endswith('.py'): 137 | if args.pye: 138 | self._compile_pye_file(args, fullpath) 139 | elif args.pyc: 140 | self._compile_pyc_file(args, fullpath) 141 | 142 | def _compile_pyc_file(self, args, py_file): 143 | filename, ext = splitext(py_file) 144 | pyc_file = filename + '.pyc' 145 | pyc_exists = exists(pyc_file) 146 | if not pyc_exists or os.stat(py_file).st_mtime != os.stat(pyc_file).st_mtime: 147 | py_compile.compile(py_file, cfile=pyc_file) 148 | if self.verbose: 149 | print('* create %s' % pyc_file) 150 | else: 151 | if self.verbose: 152 | print('* skip %s' % pyc_file) 153 | 154 | if args.remove_py: 155 | os.remove(py_file) 156 | 157 | def _compile_pye_file(self, args, py_file): 158 | """ 159 | if there is no .pyc file, compile .pyc first 160 | then compile .pye 161 | """ 162 | import pyconcrete 163 | 164 | filename, ext = splitext(py_file) 165 | pyc_file = filename + '.pyc' 166 | pye_file = filename + args.ext 167 | pyc_exists = exists(pyc_file) 168 | if not pyc_exists or os.stat(py_file).st_mtime != os.stat(pyc_file).st_mtime: 169 | py_compile.compile(py_file, cfile=pyc_file) 170 | if not exists(pye_file) or os.stat(py_file).st_mtime != os.stat(pye_file).st_mtime: 171 | pyconcrete.encrypt_file(pyc_file, pye_file) 172 | if self.verbose: 173 | print('* create %s' % pye_file) 174 | else: 175 | if self.verbose: 176 | print('* skip %s' % pye_file) 177 | 178 | # .pyc doesn't exists at beginning, remove it after .pye created 179 | if not pyc_exists or args.remove_pyc: 180 | os.remove(pyc_file) 181 | if args.remove_py: 182 | os.remove(py_file) 183 | 184 | @staticmethod 185 | def _fnmatch(name, patterns): 186 | """Test whether FILENAME matches PATTERN. 187 | 188 | Patterns are Unix shell style: 189 | * matches everything 190 | ? matches any single character 191 | [seq] matches any character in seq 192 | [!seq] matches any char not in seq 193 | """ 194 | return any(fnmatch.fnmatch(name, pat) for pat in patterns) 195 | 196 | 197 | if __name__ == '__main__': 198 | cli = PyConcreteCli() 199 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = 'pyconcrete' 3 | description = 'Protect your python script, encrypt .pyc to .pye and decrypt when import it' 4 | dynamic = ["version"] # it will provide by meson.build 5 | readme = 'README.md' 6 | license = {file = 'LICENSE'} 7 | authors = [ 8 | {name = 'Falldog', email = 'falldog7@gmail.com'}, 9 | ] 10 | classifiers = [ 11 | 'Development Status :: 5 - Production/Stable', 12 | 'Intended Audience :: Developers', 13 | 'Intended Audience :: System Administrators', 14 | 'Topic :: Software Development :: Build Tools', 15 | 'Topic :: Security', 16 | 'Topic :: Security :: Cryptography', 17 | 'Programming Language :: Python :: 3', 18 | 'Programming Language :: Python :: 3.7', 19 | 'Programming Language :: Python :: 3.8', 20 | 'Programming Language :: Python :: 3.9', 21 | 'Programming Language :: Python :: 3.10', 22 | 'Programming Language :: Python :: 3.11', 23 | 'Programming Language :: Python :: 3.12', 24 | 'Programming Language :: Python :: 3.13', 25 | 'Programming Language :: Python :: Implementation :: CPython', 26 | 'License :: OSI Approved :: Apache Software License', 27 | ] 28 | 29 | [project.optional-dependencies] 30 | test = [ 31 | "pytest==7.4.4", 32 | "virtualenv==20.26.6", 33 | ] 34 | 35 | [build-system] 36 | build-backend = 'mesonpy' 37 | requires = [ 38 | 'meson-python', 39 | 'meson >= 1.1.0', 40 | ] 41 | 42 | [tool.black] 43 | line-length = 120 44 | skip-string-normalization = true 45 | target-version = ['py39'] 46 | 47 | [tool.isort] 48 | profile = "black" 49 | line_length = 120 50 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Falldog/pyconcrete/5210bc2e47e1b4df3ebce120340b217a1016759f/src/__init__.py -------------------------------------------------------------------------------- /src/config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Create on : 2017/01/18 4 | # 5 | # @author : Falldog 6 | # 7 | from os.path import abspath, dirname, join, pardir 8 | 9 | PASSPHRASE_ENV = 'PYCONCRETE_PASSPHRASE' 10 | ROOT_DIR = abspath(join(dirname(__file__), pardir)) 11 | TEST_DIR = 'test' 12 | SRC_DIR = join('src') 13 | PY_SRC_DIR = join(SRC_DIR, 'pyconcrete') 14 | EXT_SRC_DIR = join(SRC_DIR, 'pyconcrete_ext') 15 | EXE_SRC_DIR = join(SRC_DIR, 'pyconcrete_exe') 16 | SECRET_HEADER_PATH = join(EXT_SRC_DIR, 'secret_key.h') 17 | -------------------------------------------------------------------------------- /src/pyconcrete/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright 2015 Falldog Hsieh 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import importlib 18 | import importlib.util 19 | import marshal 20 | import struct 21 | import sys 22 | from importlib._bootstrap_external import _get_supported_file_loaders 23 | from importlib.machinery import SOURCE_SUFFIXES, FileFinder, SourceFileLoader 24 | 25 | from . import _pyconcrete # noqa: E402 26 | 27 | __all__ = ["info"] 28 | 29 | _pyconcrete_module = _pyconcrete 30 | 31 | 32 | def decrypt_buffer(data): 33 | return _pyconcrete_module.decrypt_buffer(data) 34 | 35 | 36 | def encrypt_file(pyc_filepath, pye_filepath): 37 | return _pyconcrete_module.encrypt_file(pyc_filepath, pye_filepath) 38 | 39 | 40 | def info(): 41 | return _pyconcrete_module.info() 42 | 43 | 44 | def get_ext(): 45 | """get supported file extension, default should be .pye""" 46 | return _pyconcrete_module.get_ext() 47 | 48 | 49 | # We need to modify SOURCE_SUFFIXES, because it used in importlib.machinery.all_suffixes function which 50 | # called by inspect.getmodulename and we need to be able to detect the module name relative to .pye files 51 | # because .py can be deleted by us 52 | SOURCE_SUFFIXES.append(get_ext()) 53 | 54 | 55 | class PyeLoader(SourceFileLoader): 56 | @property 57 | def magic(self): 58 | if sys.version_info >= (3, 7): 59 | # reference python source code 60 | # python/Lib/importlib/_bootstrap_external.py _code_to_timestamp_pyc() & _code_to_hash_pyc() 61 | # MAGIC + HASH + TIMESTAMP + FILE_SIZE 62 | magic = 16 63 | elif sys.version_info >= (3, 3): 64 | # reference python source code 65 | # python/Lib/importlib/_bootstrap_external.py _code_to_bytecode() 66 | # MAGIC + TIMESTAMP + FILE_SIZE 67 | magic = 12 68 | else: 69 | # load pyc from memory 70 | # reference http://stackoverflow.com/questions/1830727/how-to-load-compiled-python-modules-from-memory 71 | # MAGIC + TIMESTAMP 72 | magic = 8 73 | return magic 74 | 75 | @staticmethod 76 | def _validate_version(data): 77 | magic = importlib.util.MAGIC_NUMBER 78 | ml = len(magic) 79 | if data[:ml] != magic: 80 | # convert little-endian byte string to unsigned short 81 | py_magic = struct.unpack(' 2 | #include 3 | #include "pyconcrete.h" 4 | 5 | #define STRINGIFY(x) #x 6 | #define TOSTRING(x) STRINGIFY(x) 7 | 8 | #define RET_OK 0 9 | #define RET_FAIL 1 10 | 11 | #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >=7 12 | #define MAGIC_OFFSET 16 13 | #elif PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >=3 14 | #define MAGIC_OFFSET 12 15 | #else 16 | #define MAGIC_OFFSET 8 17 | #endif 18 | 19 | 20 | int execPycContent(PyObject* pyc_content); 21 | int runFile(const char* filepath); 22 | 23 | 24 | int main(int argc, char *argv[]) 25 | { 26 | #if PY_MAJOR_VERSION >= 3 27 | int i, len; 28 | int ret = RET_OK; 29 | wchar_t** argv_ex = NULL; 30 | argv_ex = (wchar_t**) malloc(sizeof(wchar_t*) * argc); 31 | for(i=0 ; i= 2) 47 | { 48 | if(argc == 2 && (strncmp(argv[1], "-v", 3)==0 || strncmp(argv[1], "--version", 10)==0)) 49 | { 50 | printf("pyconcrete %s [Python %s]\n", TOSTRING(PYCONCRETE_VERSION), TOSTRING(PY_VERSION)); // defined by build-backend 51 | } 52 | else 53 | { 54 | PySys_SetArgv(argc-1, argv_ex+1); 55 | ret = runFile(argv[1]); 56 | } 57 | } 58 | 59 | PyGILState_Ensure(); 60 | 61 | if (PyErr_Occurred()) { 62 | ret = RET_FAIL; 63 | PyErr_Print(); 64 | } 65 | 66 | // reference mod_wsgi & uwsgi finalize steps 67 | // https://github.com/GrahamDumpleton/mod_wsgi/blob/develop/src/server/wsgi_interp.c 68 | // https://github.com/unbit/uwsgi/blob/master/plugins/python/python_plugin.c 69 | PyObject *module = PyImport_ImportModule("atexit"); 70 | Py_XDECREF(module); 71 | 72 | if (!PyImport_AddModule("dummy_threading")) { 73 | PyErr_Clear(); 74 | } 75 | 76 | Py_Finalize(); 77 | 78 | #if PY_MAJOR_VERSION >= 3 79 | for(i=0 ; i= 3 99 | PyObject* main_name = PyUnicode_FromString("__main__"); 100 | #else 101 | PyObject* main_name = PyBytes_FromString("__main__"); 102 | #endif 103 | 104 | // load compiled source from .pyc content 105 | py_marshal = PyImport_ImportModule("marshal"); 106 | py_marshal_loads = PyObject_GetAttrString(py_marshal, "loads"); 107 | 108 | content = PyBytes_AS_STRING(pyc_content); 109 | content_size = PyBytes_Size(pyc_content); 110 | 111 | pyc_content_wo_magic = PyBytes_FromStringAndSize(content+MAGIC_OFFSET, content_size-MAGIC_OFFSET); 112 | py_code = PyObject_CallFunctionObjArgs(py_marshal_loads, pyc_content_wo_magic, NULL); 113 | if(py_code == NULL && PyErr_Occurred() != NULL) 114 | { 115 | ret = RET_FAIL; 116 | PyErr_Print(); 117 | goto ERROR; 118 | } 119 | 120 | // setup global and exec loaded py_code 121 | PyDict_SetItemString(global, "__name__", main_name); 122 | PyDict_SetItemString(global, "__builtins__", PyEval_GetBuiltins()); 123 | PyEval_EvalCode(py_code, global, global); 124 | 125 | ERROR: 126 | Py_XDECREF(py_code); 127 | Py_XDECREF(global); 128 | Py_XDECREF(pyc_content_wo_magic); 129 | Py_XDECREF(py_marshal_loads); 130 | Py_XDECREF(py_marshal); 131 | return ret; 132 | } 133 | 134 | int runFile(const char* filepath) 135 | { 136 | FILE* src = NULL; 137 | char* content = NULL; 138 | int ret = RET_OK; 139 | size_t s, size; 140 | PyObject* py_content = NULL; 141 | PyObject* py_plaint_content = NULL; 142 | PyObject* py_args = NULL; 143 | 144 | src = fopen(filepath, "rb"); 145 | if(src == NULL) 146 | { 147 | return RET_FAIL; 148 | } 149 | 150 | // read & parse file 151 | { 152 | fseek(src, 0, SEEK_END); 153 | size = ftell(src); 154 | 155 | fseek(src, 0, SEEK_SET); 156 | content = malloc(size * sizeof(char)); 157 | s = fread(content, 1, size, src); 158 | if(s != size) 159 | { 160 | return RET_FAIL; 161 | } 162 | py_content = PyBytes_FromStringAndSize(content, size); 163 | py_args = PyTuple_New(1); 164 | PyTuple_SetItem(py_args, 0, py_content); 165 | py_plaint_content = fnDecryptBuffer(NULL, py_args); 166 | 167 | Py_DECREF(py_args); 168 | free(content); 169 | } 170 | fclose(src); 171 | 172 | ret = execPycContent(py_plaint_content); 173 | 174 | Py_DECREF(py_plaint_content); 175 | return ret; 176 | } 177 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/include_win/stdint.h: -------------------------------------------------------------------------------- 1 | 2 | // ISO C9x compliant stdint.h for Microsoft Visual Studio 3 | // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 4 | // 5 | // Copyright (c) 2006-2013 Alexander Chemeris 6 | // 7 | // Redistribution and use in source and binary forms, with or without 8 | // modification, are permitted provided that the following conditions are met: 9 | // 10 | // 1. Redistributions of source code must retain the above copyright notice, 11 | // this list of conditions and the following disclaimer. 12 | // 13 | // 2. Redistributions in binary form must reproduce the above copyright 14 | // notice, this list of conditions and the following disclaimer in the 15 | // documentation and/or other materials provided with the distribution. 16 | // 17 | // 3. Neither the name of the product nor the names of its contributors may 18 | // be used to endorse or promote products derived from this software 19 | // without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 22 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 23 | // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 24 | // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 27 | // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28 | // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 29 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 30 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | // 32 | /////////////////////////////////////////////////////////////////////////////// 33 | 34 | #ifndef _MSC_VER // [ 35 | #error "Use this header only with Microsoft Visual C++ compilers!" 36 | #endif // _MSC_VER ] 37 | 38 | #ifndef _MSC_STDINT_H_ // [ 39 | #define _MSC_STDINT_H_ 40 | 41 | #if _MSC_VER > 1000 42 | #pragma once 43 | #endif 44 | 45 | #if _MSC_VER >= 1600 // [ 46 | #include 47 | #else // ] _MSC_VER >= 1600 [ 48 | 49 | #include 50 | 51 | // For Visual Studio 6 in C++ mode and for many Visual Studio versions when 52 | // compiling for ARM we should wrap include with 'extern "C++" {}' 53 | // or compiler give many errors like this: 54 | // error C2733: second C linkage of overloaded function 'wmemchr' not allowed 55 | #ifdef __cplusplus 56 | extern "C" { 57 | #endif 58 | # include 59 | #ifdef __cplusplus 60 | } 61 | #endif 62 | 63 | // Define _W64 macros to mark types changing their size, like intptr_t. 64 | #ifndef _W64 65 | # if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 66 | # define _W64 __w64 67 | # else 68 | # define _W64 69 | # endif 70 | #endif 71 | 72 | 73 | // 7.18.1 Integer types 74 | 75 | // 7.18.1.1 Exact-width integer types 76 | 77 | // Visual Studio 6 and Embedded Visual C++ 4 doesn't 78 | // realize that, e.g. char has the same size as __int8 79 | // so we give up on __intX for them. 80 | #if (_MSC_VER < 1300) 81 | typedef signed char int8_t; 82 | typedef signed short int16_t; 83 | typedef signed int int32_t; 84 | typedef unsigned char uint8_t; 85 | typedef unsigned short uint16_t; 86 | typedef unsigned int uint32_t; 87 | #else 88 | typedef signed __int8 int8_t; 89 | typedef signed __int16 int16_t; 90 | typedef signed __int32 int32_t; 91 | typedef unsigned __int8 uint8_t; 92 | typedef unsigned __int16 uint16_t; 93 | typedef unsigned __int32 uint32_t; 94 | #endif 95 | typedef signed __int64 int64_t; 96 | typedef unsigned __int64 uint64_t; 97 | 98 | 99 | // 7.18.1.2 Minimum-width integer types 100 | typedef int8_t int_least8_t; 101 | typedef int16_t int_least16_t; 102 | typedef int32_t int_least32_t; 103 | typedef int64_t int_least64_t; 104 | typedef uint8_t uint_least8_t; 105 | typedef uint16_t uint_least16_t; 106 | typedef uint32_t uint_least32_t; 107 | typedef uint64_t uint_least64_t; 108 | 109 | // 7.18.1.3 Fastest minimum-width integer types 110 | typedef int8_t int_fast8_t; 111 | typedef int16_t int_fast16_t; 112 | typedef int32_t int_fast32_t; 113 | typedef int64_t int_fast64_t; 114 | typedef uint8_t uint_fast8_t; 115 | typedef uint16_t uint_fast16_t; 116 | typedef uint32_t uint_fast32_t; 117 | typedef uint64_t uint_fast64_t; 118 | 119 | // 7.18.1.4 Integer types capable of holding object pointers 120 | #ifdef _WIN64 // [ 121 | typedef signed __int64 intptr_t; 122 | typedef unsigned __int64 uintptr_t; 123 | #else // _WIN64 ][ 124 | typedef _W64 signed int intptr_t; 125 | typedef _W64 unsigned int uintptr_t; 126 | #endif // _WIN64 ] 127 | 128 | // 7.18.1.5 Greatest-width integer types 129 | typedef int64_t intmax_t; 130 | typedef uint64_t uintmax_t; 131 | 132 | 133 | // 7.18.2 Limits of specified-width integer types 134 | 135 | #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 136 | 137 | // 7.18.2.1 Limits of exact-width integer types 138 | #define INT8_MIN ((int8_t)_I8_MIN) 139 | #define INT8_MAX _I8_MAX 140 | #define INT16_MIN ((int16_t)_I16_MIN) 141 | #define INT16_MAX _I16_MAX 142 | #define INT32_MIN ((int32_t)_I32_MIN) 143 | #define INT32_MAX _I32_MAX 144 | #define INT64_MIN ((int64_t)_I64_MIN) 145 | #define INT64_MAX _I64_MAX 146 | #define UINT8_MAX _UI8_MAX 147 | #define UINT16_MAX _UI16_MAX 148 | #define UINT32_MAX _UI32_MAX 149 | #define UINT64_MAX _UI64_MAX 150 | 151 | // 7.18.2.2 Limits of minimum-width integer types 152 | #define INT_LEAST8_MIN INT8_MIN 153 | #define INT_LEAST8_MAX INT8_MAX 154 | #define INT_LEAST16_MIN INT16_MIN 155 | #define INT_LEAST16_MAX INT16_MAX 156 | #define INT_LEAST32_MIN INT32_MIN 157 | #define INT_LEAST32_MAX INT32_MAX 158 | #define INT_LEAST64_MIN INT64_MIN 159 | #define INT_LEAST64_MAX INT64_MAX 160 | #define UINT_LEAST8_MAX UINT8_MAX 161 | #define UINT_LEAST16_MAX UINT16_MAX 162 | #define UINT_LEAST32_MAX UINT32_MAX 163 | #define UINT_LEAST64_MAX UINT64_MAX 164 | 165 | // 7.18.2.3 Limits of fastest minimum-width integer types 166 | #define INT_FAST8_MIN INT8_MIN 167 | #define INT_FAST8_MAX INT8_MAX 168 | #define INT_FAST16_MIN INT16_MIN 169 | #define INT_FAST16_MAX INT16_MAX 170 | #define INT_FAST32_MIN INT32_MIN 171 | #define INT_FAST32_MAX INT32_MAX 172 | #define INT_FAST64_MIN INT64_MIN 173 | #define INT_FAST64_MAX INT64_MAX 174 | #define UINT_FAST8_MAX UINT8_MAX 175 | #define UINT_FAST16_MAX UINT16_MAX 176 | #define UINT_FAST32_MAX UINT32_MAX 177 | #define UINT_FAST64_MAX UINT64_MAX 178 | 179 | // 7.18.2.4 Limits of integer types capable of holding object pointers 180 | #ifdef _WIN64 // [ 181 | # define INTPTR_MIN INT64_MIN 182 | # define INTPTR_MAX INT64_MAX 183 | # define UINTPTR_MAX UINT64_MAX 184 | #else // _WIN64 ][ 185 | # define INTPTR_MIN INT32_MIN 186 | # define INTPTR_MAX INT32_MAX 187 | # define UINTPTR_MAX UINT32_MAX 188 | #endif // _WIN64 ] 189 | 190 | // 7.18.2.5 Limits of greatest-width integer types 191 | #define INTMAX_MIN INT64_MIN 192 | #define INTMAX_MAX INT64_MAX 193 | #define UINTMAX_MAX UINT64_MAX 194 | 195 | // 7.18.3 Limits of other integer types 196 | 197 | #ifdef _WIN64 // [ 198 | # define PTRDIFF_MIN _I64_MIN 199 | # define PTRDIFF_MAX _I64_MAX 200 | #else // _WIN64 ][ 201 | # define PTRDIFF_MIN _I32_MIN 202 | # define PTRDIFF_MAX _I32_MAX 203 | #endif // _WIN64 ] 204 | 205 | #define SIG_ATOMIC_MIN INT_MIN 206 | #define SIG_ATOMIC_MAX INT_MAX 207 | 208 | #ifndef SIZE_MAX // [ 209 | # ifdef _WIN64 // [ 210 | # define SIZE_MAX _UI64_MAX 211 | # else // _WIN64 ][ 212 | # define SIZE_MAX _UI32_MAX 213 | # endif // _WIN64 ] 214 | #endif // SIZE_MAX ] 215 | 216 | // WCHAR_MIN and WCHAR_MAX are also defined in 217 | #ifndef WCHAR_MIN // [ 218 | # define WCHAR_MIN 0 219 | #endif // WCHAR_MIN ] 220 | #ifndef WCHAR_MAX // [ 221 | # define WCHAR_MAX _UI16_MAX 222 | #endif // WCHAR_MAX ] 223 | 224 | #define WINT_MIN 0 225 | #define WINT_MAX _UI16_MAX 226 | 227 | #endif // __STDC_LIMIT_MACROS ] 228 | 229 | 230 | // 7.18.4 Limits of other integer types 231 | 232 | #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 233 | 234 | // 7.18.4.1 Macros for minimum-width integer constants 235 | 236 | #define INT8_C(val) val##i8 237 | #define INT16_C(val) val##i16 238 | #define INT32_C(val) val##i32 239 | #define INT64_C(val) val##i64 240 | 241 | #define UINT8_C(val) val##ui8 242 | #define UINT16_C(val) val##ui16 243 | #define UINT32_C(val) val##ui32 244 | #define UINT64_C(val) val##ui64 245 | 246 | // 7.18.4.2 Macros for greatest-width integer constants 247 | // These #ifndef's are needed to prevent collisions with . 248 | // Check out Issue 9 for the details. 249 | #ifndef INTMAX_C // [ 250 | # define INTMAX_C INT64_C 251 | #endif // INTMAX_C ] 252 | #ifndef UINTMAX_C // [ 253 | # define UINTMAX_C UINT64_C 254 | #endif // UINTMAX_C ] 255 | 256 | #endif // __STDC_CONSTANT_MACROS ] 257 | 258 | #endif // _MSC_VER >= 1600 ] 259 | 260 | #endif // _MSC_STDINT_H_ ] 261 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/openaes/CHANGELOG: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------- 2 | Nabil S. Al Ramli 3 | www.nalramli.com 4 | --------------------------------------------------------------------------- 5 | 6 | OpenAES-0.9.0 7 | ------------- 8 | * remove static OAES header from encrypted output 9 | * build: remove dependency on obselete malloc.h 10 | * oaes_base64: implement base64 algorithm 11 | * oaes: implement base64-enc and base64-dec commands 12 | * NOTE: oaes: enc and dec commands have been renamed to aes-enc and aes-dec 13 | * oaes: mdify --key option to only accept base64-encoded key_data 14 | * oaes: mdify --key option to enhance security if a longer key_data is entered 15 | * oaes: prevent overwriting existing files with the --out option 16 | 17 | OpenAES-0.8.1 18 | ------------- 19 | * implement gen-key 20 | * implement --key-file 21 | 22 | OpenAES-0.8.0 23 | ------------- 24 | * implement multi-threading to improve performance 25 | * allow the user to enter a key after starting 26 | * build: add Windows installer Visual Studio 2010 setup project with basic shell integration 27 | * build: modify oaes_lib to static or shared library 28 | 29 | OpenAES-0.7.0 30 | ------------- 31 | * implement oaes command line utility 32 | * defect: oaes_decrypt() does not have a way to tell if pad pattern is accidental 33 | 34 | OpenAES-0.6.0 35 | ------------- 36 | * add stepping pause to vt_aes 37 | 38 | OpenAES-0.5.0 39 | ------------- 40 | * defect: algorithm errors with ExpandKey for 192 bit and 256 bit keys 41 | 42 | OpenAES-0.4.0 43 | ------------- 44 | * add vt_aes test program 45 | * defect: algorithm errors with ShiftRows and MixColumns 46 | * OAES_DEBUG config to step through encryption and decryption 47 | * defect: test_performance crash when printing results 48 | * allow user to specify iv by passing it to oaes_set_option() 49 | * oaes_key_import_data() and oaes_key_export_data() to operate on key data directly 50 | * defect: Access violation in oaes_key_export() 51 | 52 | OpenAES-0.3.0 53 | ------------- 54 | * Add CMake support 55 | * platform independence fixes 56 | 57 | OpenAES-0.2.0 58 | ------------- 59 | * Add performance tests 60 | * Implement CBC mode in AES algorithm 61 | * Performance improvements in oaes_shift_rows() and oaes_inv_shift_rows() 62 | 63 | OpenAES-0.1.0 64 | ------------- 65 | * Implement AES algorithm 66 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/openaes/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------- 2 | # OpenAES License 3 | # --------------------------------------------------------------------------- 4 | # Copyright (c) 2013, Nabil S. Al Ramli, www.nalramli.com 5 | # All rights reserved. 6 | # 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions are met: 9 | # 10 | # - Redistributions of source code must retain the above copyright notice, 11 | # this list of conditions and the following disclaimer. 12 | # - Redistributions in binary form must reproduce the above copyright 13 | # notice, this list of conditions and the following disclaimer in the 14 | # documentation and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | # POSSIBILITY OF SUCH DAMAGE. 27 | # --------------------------------------------------------------------------- 28 | 29 | cmake_minimum_required (VERSION 2.8.0) 30 | 31 | project ( "oaes" ) 32 | 33 | include_directories ( 34 | ${CMAKE_CURRENT_SOURCE_DIR}/inc 35 | ${CMAKE_CURRENT_SOURCE_DIR}/src/isaac 36 | ) 37 | 38 | set (HDR 39 | ${CMAKE_CURRENT_SOURCE_DIR}/inc/oaes_common.h 40 | ${CMAKE_CURRENT_SOURCE_DIR}/inc/oaes_base64.h 41 | ${CMAKE_CURRENT_SOURCE_DIR}/inc/oaes_lib.h 42 | ) 43 | 44 | set (SRC_lib 45 | ${CMAKE_CURRENT_SOURCE_DIR}/src/oaes_base64.c 46 | ${CMAKE_CURRENT_SOURCE_DIR}/src/oaes_lib.c 47 | ${CMAKE_CURRENT_SOURCE_DIR}/src/isaac/rand.c 48 | ) 49 | 50 | set (HDR_lib 51 | ${CMAKE_CURRENT_SOURCE_DIR}/inc/oaes_config.h 52 | ${CMAKE_CURRENT_SOURCE_DIR}/src/isaac/rand.h 53 | ${CMAKE_CURRENT_SOURCE_DIR}/src/isaac/standard.h 54 | ) 55 | 56 | set (SRC_test_encrypt 57 | ${CMAKE_CURRENT_SOURCE_DIR}/test/test_encrypt.c 58 | ) 59 | 60 | set (SRC_test_keys 61 | ${CMAKE_CURRENT_SOURCE_DIR}/test/test_keys.c 62 | ) 63 | 64 | set (SRC_test_performance 65 | ${CMAKE_CURRENT_SOURCE_DIR}/test/test_performance.c 66 | ) 67 | 68 | set (SRC_vt_aes 69 | ${CMAKE_CURRENT_SOURCE_DIR}/test/vt_aes.c 70 | ) 71 | 72 | set (SRC_oaes 73 | ${CMAKE_CURRENT_SOURCE_DIR}/src/oaes.c 74 | ) 75 | 76 | add_library( oaes_lib ${SRC_lib} ${HDR_lib} ${HDR} ) 77 | add_executable( test_encrypt ${SRC_test_encrypt} ${HDR} ) 78 | add_executable( test_keys ${SRC_test_keys} ${HDR} ) 79 | add_executable( test_performance ${SRC_test_performance} ${HDR} ) 80 | add_executable( vt_aes ${SRC_vt_aes} ${HDR} ) 81 | add_executable( oaes ${SRC_oaes} ${HDR} ) 82 | 83 | target_link_libraries( test_encrypt oaes_lib ) 84 | target_link_libraries( test_keys oaes_lib ) 85 | target_link_libraries( test_performance oaes_lib ) 86 | target_link_libraries( vt_aes oaes_lib ) 87 | if( MSVC ) 88 | target_link_libraries( oaes oaes_lib ) 89 | else() 90 | target_link_libraries( oaes oaes_lib pthread ) 91 | endif() 92 | 93 | file( COPY 94 | "${CMAKE_CURRENT_SOURCE_DIR}/src/oaes_setup.vdproj" 95 | DESTINATION "${PROJECT_BINARY_DIR}" 96 | ) 97 | add_custom_target( oaes_setup_configure 98 | ALL 99 | ${CMAKE_COMMAND} -E copy_if_different 100 | "${CMAKE_CURRENT_SOURCE_DIR}/src/oaes_setup.vdproj" 101 | "${PROJECT_BINARY_DIR}" 102 | & 103 | ${CMAKE_COMMAND} -E copy_if_different 104 | "${CMAKE_CURRENT_SOURCE_DIR}/CHANGELOG" 105 | "${PROJECT_BINARY_DIR}" 106 | & 107 | ${CMAKE_COMMAND} -E copy_if_different 108 | "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" 109 | "${PROJECT_BINARY_DIR}" 110 | & 111 | ${CMAKE_COMMAND} -E copy_if_different 112 | "${CMAKE_CURRENT_SOURCE_DIR}/README" 113 | "${PROJECT_BINARY_DIR}" 114 | & 115 | ${CMAKE_COMMAND} -E copy_if_different 116 | "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" 117 | "${PROJECT_BINARY_DIR}" 118 | ) 119 | include_external_msproject( 120 | oaes_setup "${PROJECT_BINARY_DIR}/oaes_setup.vdproj" 121 | TYPE "8:{978C614F-708E-4E1A-B201-565925725DBA}" 122 | ) 123 | if( MSVC ) 124 | add_dependencies( oaes_setup oaes_setup_configure oaes ) 125 | endif() 126 | 127 | # set BUILD_SHARED_LIBS=1 to build oaes_lib shared library, or BUILD_SHARED_LIBS=0 to build static library 128 | if( BUILD_SHARED_LIBS ) 129 | set_property( 130 | TARGET "oaes_lib" "test_encrypt" "test_keys" "test_performance" "vt_aes" "oaes" 131 | APPEND PROPERTY COMPILE_DEFINITIONS OAES_SHARED=1 132 | ) 133 | else() 134 | set_property( 135 | TARGET "oaes_lib" "test_encrypt" "test_keys" "test_performance" "vt_aes" "oaes" 136 | APPEND PROPERTY COMPILE_DEFINITIONS OAES_STATIC=1 137 | ) 138 | endif() 139 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/openaes/LICENSE: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------- 2 | OpenAES Licence 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2012, Nabil S. Al Ramli, www.nalramli.com 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | - Redistributions of source code must retain the above copyright notice, 11 | this list of conditions and the following disclaimer. 12 | - Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | --------------------------------------------------------------------------- 28 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/openaes/README: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------- 2 | OpenAES-0.9.0 3 | Nabil S. Al Ramli 4 | www.nalramli.com 5 | --------------------------------------------------------------------------- 6 | 7 | License Terms 8 | ------------- 9 | 10 | --------------------------------------------------------------------------- 11 | OpenAES Licence 12 | --------------------------------------------------------------------------- 13 | Copyright (c) 2012, Nabil S. Al Ramli, www.nalramli.com 14 | All rights reserved. 15 | 16 | Redistribution and use in source and binary forms, with or without 17 | modification, are permitted provided that the following conditions are met: 18 | 19 | - Redistributions of source code must retain the above copyright notice, 20 | this list of conditions and the following disclaimer. 21 | - Redistributions in binary form must reproduce the above copyright 22 | notice, this list of conditions and the following disclaimer in the 23 | documentation and/or other materials provided with the distribution. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | POSSIBILITY OF SUCH DAMAGE. 36 | --------------------------------------------------------------------------- 37 | 38 | Introduction 39 | ------------ 40 | 41 | OpenAES is an open source implementation of the Advanced Encryption 42 | Standard. It is distributed as a portable, lightweight C library that can 43 | be easily integrated into applications. 44 | 45 | Compiling 46 | --------- 47 | 48 | OpenAES has been tested with the GCC as well as VC compilers. It is 49 | necessary to compile the source files located in ./src, and to add ./inc to 50 | the include paths. 51 | 52 | If you are building with OAES_HAVE_ISAAC defined (true by default), then 53 | you also need to link in the source files under ./src/isaac and also add 54 | ./src/isaac to the include paths. 55 | 56 | You may edit ./inc/oaes_config.h to modify build options. 57 | 58 | CMake 2.8.0 can be used to build the test programs on different platforms. 59 | 60 | In a Linux command line terminal type: 61 | 62 | cmake . 63 | make 64 | 65 | In Windows, in a Visual Studio command line window type: 66 | 67 | cmake . -G "NMake Makefiles" 68 | nmake 69 | 70 | Usage 71 | ----- 72 | 73 | oaes_lib usage is described in the header file ./inc/oaes_lib.h. 74 | 75 | The oaes command line application help manual can be obtained by using the 76 | --help command line options. 77 | 78 | The oaes_setup Windows installer integrates with the Windows shell. It can be 79 | used by right clicking a file in Windows Explorer and then selecting a 80 | subcommand from the OpenAES menu. 81 | 82 | Samples 83 | ------- 84 | 85 | Samples applications are provided in the /test folder. 86 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/openaes/VERSION: -------------------------------------------------------------------------------- 1 | OpenAES-0.9.0 2 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/openaes/inc/oaes_base64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * --------------------------------------------------------------------------- 3 | * OpenAES License 4 | * --------------------------------------------------------------------------- 5 | * Copyright (c) 2013, Nabil S. Al Ramli, www.nalramli.com 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * - Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * - Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | * --------------------------------------------------------------------------- 29 | */ 30 | 31 | #ifndef _OAES_BASE64_H 32 | #define _OAES_BASE64_H 33 | 34 | #include 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | OAES_API OAES_RET oaes_base64_encode( 41 | const uint8_t *in, size_t in_len, char *out, size_t *out_len ); 42 | 43 | OAES_API OAES_RET oaes_base64_decode( 44 | const char *in, size_t in_len, uint8_t *out, size_t *out_len ); 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #endif // _OAES_BASE64_H 51 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/openaes/inc/oaes_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * --------------------------------------------------------------------------- 3 | * OpenAES License 4 | * --------------------------------------------------------------------------- 5 | * Copyright (c) 2013, Nabil S. Al Ramli, www.nalramli.com 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * - Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * - Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | * --------------------------------------------------------------------------- 29 | */ 30 | 31 | #ifndef _OAES_COMMON_H 32 | #define _OAES_COMMON_H 33 | 34 | #include 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | #ifdef _WIN32 41 | # ifdef OAES_SHARED 42 | # ifdef oaes_lib_EXPORTS 43 | # define OAES_API __declspec(dllexport) 44 | # else 45 | # define OAES_API __declspec(dllimport) 46 | # endif 47 | # else 48 | # define OAES_API 49 | # endif 50 | #else 51 | # define OAES_API 52 | #endif // WIN32 53 | 54 | #define OAES_VERSION "0.9.0" 55 | 56 | typedef enum 57 | { 58 | OAES_RET_FIRST = 0, 59 | OAES_RET_SUCCESS = 0, 60 | OAES_RET_ERROR, 61 | OAES_RET_ARG1, 62 | OAES_RET_ARG2, 63 | OAES_RET_ARG3, 64 | OAES_RET_ARG4, 65 | OAES_RET_ARG5, 66 | OAES_RET_NOKEY, 67 | OAES_RET_MEM, 68 | OAES_RET_BUF, 69 | OAES_RET_HEADER, 70 | OAES_RET_COUNT 71 | } OAES_RET; 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif 76 | 77 | #endif // _OAES_COMMON_H 78 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/openaes/inc/oaes_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * --------------------------------------------------------------------------- 3 | * OpenAES License 4 | * --------------------------------------------------------------------------- 5 | * Copyright (c) 2012, Nabil S. Al Ramli, www.nalramli.com 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * - Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * - Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | * --------------------------------------------------------------------------- 29 | */ 30 | 31 | #ifndef _OAES_CONFIG_H 32 | #define _OAES_CONFIG_H 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | #ifndef OAES_HAVE_ISAAC 39 | //#define OAES_HAVE_ISAAC 1 40 | #endif // OAES_HAVE_ISAAC 41 | 42 | #ifndef OAES_DEBUG 43 | //#define OAES_DEBUG 0 44 | #endif // OAES_DEBUG 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #endif // _OAES_CONFIG_H 51 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/openaes/inc/oaes_lib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * --------------------------------------------------------------------------- 3 | * OpenAES License 4 | * --------------------------------------------------------------------------- 5 | * Copyright (c) 2013, Nabil S. Al Ramli, www.nalramli.com 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * - Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * - Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | * --------------------------------------------------------------------------- 29 | */ 30 | 31 | #ifndef _OAES_LIB_H 32 | #define _OAES_LIB_H 33 | 34 | #include 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | #ifdef _WIN32 41 | # ifdef OAES_SHARED 42 | # ifdef oaes_lib_EXPORTS 43 | # define OAES_API __declspec(dllexport) 44 | # else 45 | # define OAES_API __declspec(dllimport) 46 | # endif 47 | # else 48 | # define OAES_API 49 | # endif 50 | #else 51 | # define OAES_API 52 | #endif // WIN32 53 | 54 | #define OAES_BLOCK_SIZE 16 55 | 56 | typedef void OAES_CTX; 57 | 58 | /* 59 | * oaes_set_option() takes one of these values for its [option] parameter 60 | * some options accept either an optional or a required [value] parameter 61 | */ 62 | // no option 63 | #define OAES_OPTION_NONE 0 64 | // enable ECB mode, disable CBC mode 65 | #define OAES_OPTION_ECB 1 66 | // enable CBC mode, disable ECB mode 67 | // value is optional, may pass uint8_t iv[OAES_BLOCK_SIZE] to specify 68 | // the value of the initialization vector, iv 69 | #define OAES_OPTION_CBC 2 70 | 71 | #ifdef OAES_DEBUG 72 | typedef int ( * oaes_step_cb ) ( 73 | const uint8_t state[OAES_BLOCK_SIZE], 74 | const char * step_name, 75 | int step_count, 76 | void * user_data ); 77 | // enable state stepping mode 78 | // value is required, must pass oaes_step_cb to receive the state at each step 79 | #define OAES_OPTION_STEP_ON 4 80 | // disable state stepping mode 81 | #define OAES_OPTION_STEP_OFF 8 82 | #endif // OAES_DEBUG 83 | 84 | typedef uint16_t OAES_OPTION; 85 | 86 | /* 87 | * // usage: 88 | * 89 | * OAES_CTX * ctx = oaes_alloc(); 90 | * . 91 | * . 92 | * . 93 | * { 94 | * oaes_gen_key_xxx( ctx ); 95 | * { 96 | * oaes_key_export( ctx, _buf, &_buf_len ); 97 | * // or 98 | * oaes_key_export_data( ctx, _buf, &_buf_len );\ 99 | * } 100 | * } 101 | * // or 102 | * { 103 | * oaes_key_import( ctx, _buf, _buf_len ); 104 | * // or 105 | * oaes_key_import_data( ctx, _buf, _buf_len ); 106 | * } 107 | * . 108 | * . 109 | * . 110 | * oaes_encrypt( ctx, m, m_len, c, &c_len ); 111 | * . 112 | * . 113 | * . 114 | * oaes_decrypt( ctx, c, c_len, m, &m_len ); 115 | * . 116 | * . 117 | * . 118 | * oaes_free( &ctx ); 119 | */ 120 | 121 | OAES_API OAES_CTX * oaes_alloc(); 122 | 123 | OAES_API OAES_RET oaes_free( OAES_CTX ** ctx ); 124 | 125 | OAES_API OAES_RET oaes_set_option( OAES_CTX * ctx, 126 | OAES_OPTION option, const void * value ); 127 | 128 | OAES_API OAES_RET oaes_key_gen_128( OAES_CTX * ctx ); 129 | 130 | OAES_API OAES_RET oaes_key_gen_192( OAES_CTX * ctx ); 131 | 132 | OAES_API OAES_RET oaes_key_gen_256( OAES_CTX * ctx ); 133 | 134 | // export key with header information 135 | // set data == NULL to get the required data_len 136 | OAES_API OAES_RET oaes_key_export( OAES_CTX * ctx, 137 | uint8_t * data, size_t * data_len ); 138 | 139 | // directly export the data from key 140 | // set data == NULL to get the required data_len 141 | OAES_API OAES_RET oaes_key_export_data( OAES_CTX * ctx, 142 | uint8_t * data, size_t * data_len ); 143 | 144 | // import key with header information 145 | OAES_API OAES_RET oaes_key_import( OAES_CTX * ctx, 146 | const uint8_t * data, size_t data_len ); 147 | 148 | // directly import data into key 149 | OAES_API OAES_RET oaes_key_import_data( OAES_CTX * ctx, 150 | const uint8_t * data, size_t data_len ); 151 | 152 | // set c == NULL to get the required c_len 153 | OAES_API OAES_RET oaes_encrypt( OAES_CTX * ctx, 154 | const uint8_t * m, size_t m_len, uint8_t * c, size_t * c_len ); 155 | 156 | // set m == NULL to get the required m_len 157 | OAES_API OAES_RET oaes_decrypt( OAES_CTX * ctx, 158 | const uint8_t * c, size_t c_len, uint8_t * m, size_t * m_len ); 159 | 160 | OAES_API OAES_RET oaes_encrypt_block( 161 | OAES_CTX * ctx, uint8_t * c, size_t c_len ); 162 | OAES_API OAES_RET oaes_decrypt_block( 163 | OAES_CTX * ctx, uint8_t * c, size_t c_len ); 164 | 165 | // set buf == NULL to get the required buf_len 166 | OAES_API OAES_RET oaes_sprintf( 167 | char * buf, size_t * buf_len, const uint8_t * data, size_t data_len ); 168 | 169 | #ifdef __cplusplus 170 | } 171 | #endif 172 | 173 | #endif // _OAES_LIB_H 174 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/openaes/src/isaac/rand.c: -------------------------------------------------------------------------------- 1 | /* 2 | ------------------------------------------------------------------------------ 3 | rand.c: By Bob Jenkins. My random number generator, ISAAC. Public Domain. 4 | MODIFIED: 5 | 960327: Creation (addition of randinit, really) 6 | 970719: use context, not global variables, for internal state 7 | 980324: added main (ifdef'ed out), also rearranged randinit() 8 | 010626: Note that this is public domain 9 | ------------------------------------------------------------------------------ 10 | */ 11 | #ifndef STANDARD 12 | #include "standard.h" 13 | #endif 14 | #ifndef RAND 15 | #include "rand.h" 16 | #endif 17 | 18 | 19 | #define ind(mm,x) (*(ub4 *)((ub1 *)(mm) + ((x) & ((RANDSIZ-1)<<2)))) 20 | #define rngstep(mix,a,b,mm,m,m2,r,x) \ 21 | { \ 22 | x = *m; \ 23 | a = (a^(mix)) + *(m2++); \ 24 | *(m++) = y = ind(mm,x) + a + b; \ 25 | *(r++) = b = ind(mm,y>>RANDSIZL) + x; \ 26 | } 27 | 28 | void isaac(ctx) 29 | randctx *ctx; 30 | { 31 | register ub4 a,b,x,y,*m,*mm,*m2,*r,*mend; 32 | mm=ctx->randmem; r=ctx->randrsl; 33 | a = ctx->randa; b = ctx->randb + (++ctx->randc); 34 | for (m = mm, mend = m2 = m+(RANDSIZ/2); m>6 , a, b, mm, m, m2, r, x); 38 | rngstep( a<<2 , a, b, mm, m, m2, r, x); 39 | rngstep( a>>16, a, b, mm, m, m2, r, x); 40 | } 41 | for (m2 = mm; m2>6 , a, b, mm, m, m2, r, x); 45 | rngstep( a<<2 , a, b, mm, m, m2, r, x); 46 | rngstep( a>>16, a, b, mm, m, m2, r, x); 47 | } 48 | ctx->randb = b; ctx->randa = a; 49 | } 50 | 51 | 52 | #define mix(a,b,c,d,e,f,g,h) \ 53 | { \ 54 | a^=b<<11; d+=a; b+=c; \ 55 | b^=c>>2; e+=b; c+=d; \ 56 | c^=d<<8; f+=c; d+=e; \ 57 | d^=e>>16; g+=d; e+=f; \ 58 | e^=f<<10; h+=e; f+=g; \ 59 | f^=g>>4; a+=f; g+=h; \ 60 | g^=h<<8; b+=g; h+=a; \ 61 | h^=a>>9; c+=h; a+=b; \ 62 | } 63 | 64 | /* if (flag==TRUE), then use the contents of randrsl[] to initialize mm[]. */ 65 | void randinit(ctx, flag) 66 | randctx *ctx; 67 | word flag; 68 | { 69 | word i; 70 | ub4 a,b,c,d,e,f,g,h; 71 | ub4 *m,*r; 72 | ctx->randa = ctx->randb = ctx->randc = 0; 73 | m=ctx->randmem; 74 | r=ctx->randrsl; 75 | a=b=c=d=e=f=g=h=0x9e3779b9; /* the golden ratio */ 76 | 77 | for (i=0; i<4; ++i) /* scramble it */ 78 | { 79 | mix(a,b,c,d,e,f,g,h); 80 | } 81 | 82 | if (flag) 83 | { 84 | /* initialize using the contents of r[] as the seed */ 85 | for (i=0; irandcnt=RANDSIZ; /* prepare to use the first set of results */ 116 | } 117 | 118 | 119 | #ifdef NEVER 120 | int main() 121 | { 122 | ub4 i,j; 123 | randctx ctx; 124 | ctx.randa=ctx.randb=ctx.randc=(ub4)0; 125 | for (i=0; i<256; ++i) ctx.randrsl[i]=(ub4)0; 126 | randinit(&ctx, TRUE); 127 | for (i=0; i<2; ++i) 128 | { 129 | isaac(&ctx); 130 | for (j=0; j<256; ++j) 131 | { 132 | printf("%.8lx",ctx.randrsl[j]); 133 | if ((j&7)==7) printf("\n"); 134 | } 135 | } 136 | } 137 | #endif 138 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/openaes/src/isaac/rand.h: -------------------------------------------------------------------------------- 1 | /* 2 | ------------------------------------------------------------------------------ 3 | rand.h: definitions for a random number generator 4 | By Bob Jenkins, 1996, Public Domain 5 | MODIFIED: 6 | 960327: Creation (addition of randinit, really) 7 | 970719: use context, not global variables, for internal state 8 | 980324: renamed seed to flag 9 | 980605: recommend RANDSIZL=4 for noncryptography. 10 | 010626: note this is public domain 11 | ------------------------------------------------------------------------------ 12 | */ 13 | #ifndef STANDARD 14 | #include "standard.h" 15 | #endif 16 | 17 | #ifndef RAND 18 | #define RAND 19 | #define RANDSIZL (8) 20 | #define RANDSIZ (1<randcnt-- ? \ 51 | (isaac(r), (r)->randcnt=RANDSIZ-1, (r)->randrsl[(r)->randcnt]) : \ 52 | (r)->randrsl[(r)->randcnt]) 53 | 54 | #endif /* RAND */ 55 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/openaes/src/isaac/standard.h: -------------------------------------------------------------------------------- 1 | /* 2 | ------------------------------------------------------------------------------ 3 | Standard definitions and types, Bob Jenkins 4 | ------------------------------------------------------------------------------ 5 | */ 6 | #ifndef STANDARD 7 | # define STANDARD 8 | # ifndef STDIO 9 | # include 10 | # define STDIO 11 | # endif 12 | # ifndef STDDEF 13 | # include 14 | # define STDDEF 15 | # endif 16 | typedef unsigned long long ub8; 17 | #define UB8MAXVAL 0xffffffffffffffffLL 18 | #define UB8BITS 64 19 | typedef signed long long sb8; 20 | #define SB8MAXVAL 0x7fffffffffffffffLL 21 | typedef unsigned long int ub4; /* unsigned 4-byte quantities */ 22 | #define UB4MAXVAL 0xffffffff 23 | typedef signed long int sb4; 24 | #define UB4BITS 32 25 | #define SB4MAXVAL 0x7fffffff 26 | typedef unsigned short int ub2; 27 | #define UB2MAXVAL 0xffff 28 | #define UB2BITS 16 29 | typedef signed short int sb2; 30 | #define SB2MAXVAL 0x7fff 31 | typedef unsigned char ub1; 32 | #define UB1MAXVAL 0xff 33 | #define UB1BITS 8 34 | typedef signed char sb1; /* signed 1-byte quantities */ 35 | #define SB1MAXVAL 0x7f 36 | typedef int word; /* fastest type available */ 37 | 38 | #define bis(target,mask) ((target) |= (mask)) 39 | #define bic(target,mask) ((target) &= ~(mask)) 40 | #define bit(target,mask) ((target) & (mask)) 41 | #ifndef min 42 | # define min(a,b) (((a)<(b)) ? (a) : (b)) 43 | #endif /* min */ 44 | #ifndef max 45 | # define max(a,b) (((a)<(b)) ? (b) : (a)) 46 | #endif /* max */ 47 | #ifndef align 48 | # define align(a) (((ub4)a+(sizeof(void *)-1))&(~(sizeof(void *)-1))) 49 | #endif /* align */ 50 | #ifndef abs 51 | # define abs(a) (((a)>0) ? (a) : -(a)) 52 | #endif 53 | #define TRUE 1 54 | #define FALSE 0 55 | #define SUCCESS 0 /* 1 on VAX */ 56 | 57 | #endif /* STANDARD */ 58 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/openaes/src/oaes_base64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * --------------------------------------------------------------------------- 3 | * OpenAES License 4 | * --------------------------------------------------------------------------- 5 | * Copyright (c) 2013, Nabil S. Al Ramli, www.nalramli.com 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * - Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * - Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | * --------------------------------------------------------------------------- 29 | */ 30 | static const char _NR[] = { 31 | 0x4e,0x61,0x62,0x69,0x6c,0x20,0x53,0x2e,0x20, 32 | 0x41,0x6c,0x20,0x52,0x61,0x6d,0x6c,0x69,0x00 }; 33 | 34 | #include 35 | #include 36 | 37 | #include "oaes_config.h" 38 | #include "oaes_base64.h" 39 | 40 | static const char _oaes_base64_table[] = 41 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 42 | 43 | OAES_RET oaes_base64_encode( 44 | const uint8_t *in, size_t in_len, char *out, size_t *out_len) 45 | { 46 | size_t _i = 0, _j = 0; 47 | unsigned char _buf1[3]; 48 | unsigned char _buf2[4]; 49 | size_t _out_len_req = 4 * ( in_len / 3 + ( in_len % 3 ? 1 : 0 ) ) + 1; 50 | 51 | if( NULL == in || 0 == in_len || NULL == out_len ) 52 | return OAES_RET_ERROR; 53 | 54 | if( NULL == out ) 55 | { 56 | *out_len = _out_len_req; 57 | return OAES_RET_SUCCESS; 58 | } 59 | 60 | if( _out_len_req > *out_len ) 61 | return OAES_RET_ERROR; 62 | 63 | memset(out, 0, *out_len); 64 | *out_len = 0; 65 | while( in_len-- ) 66 | { 67 | _buf1[_i++] = *(in++); 68 | if( _i == 3 ) 69 | { 70 | _buf2[0] = (_buf1[0] & 0xfc) >> 2; 71 | _buf2[1] = ((_buf1[0] & 0x03) << 4) + ((_buf1[1] & 0xf0) >> 4); 72 | _buf2[2] = ((_buf1[1] & 0x0f) << 2) + ((_buf1[2] & 0xc0) >> 6); 73 | _buf2[3] = _buf1[2] & 0x3f; 74 | 75 | for( _i = 0; _i < 4; _i++ ) 76 | { 77 | *(out++) = _oaes_base64_table[_buf2[_i]]; 78 | (*out_len)++; 79 | } 80 | _i = 0; 81 | } 82 | } 83 | 84 | if( _i ) 85 | { 86 | for( _j = _i; _j < 3; _j++ ) 87 | _buf1[_j] = '\0'; 88 | 89 | _buf2[0] = (_buf1[0] & 0xfc) >> 2; 90 | _buf2[1] = ((_buf1[0] & 0x03) << 4) + ((_buf1[1] & 0xf0) >> 4); 91 | _buf2[2] = ((_buf1[1] & 0x0f) << 2) + ((_buf1[2] & 0xc0) >> 6); 92 | _buf2[3] = _buf1[2] & 0x3f; 93 | 94 | for( _j = 0; (_j < _i + 1); _j++ ) 95 | { 96 | *(out++) = _oaes_base64_table[_buf2[_j]]; 97 | (*out_len)++; 98 | } 99 | 100 | while( _i++ < 3 ) 101 | { 102 | *(out++) = '='; 103 | (*out_len)++; 104 | } 105 | } 106 | 107 | return OAES_RET_SUCCESS; 108 | 109 | } 110 | 111 | OAES_RET oaes_base64_decode( 112 | const char *in, size_t in_len, uint8_t *out, size_t *out_len ) 113 | { 114 | size_t _i = 0, _j = 0, _idx = 0; 115 | uint8_t _buf2[4], _buf1[3]; 116 | size_t _out_len_req = 3 * ( in_len / 4 + ( in_len % 4 ? 1 : 0 ) ); 117 | 118 | if( NULL == in || 0 == in_len || NULL == out_len ) 119 | return OAES_RET_ERROR; 120 | 121 | if( NULL == out ) 122 | { 123 | *out_len = _out_len_req; 124 | return OAES_RET_SUCCESS; 125 | } 126 | 127 | if( _out_len_req > *out_len ) 128 | return OAES_RET_ERROR; 129 | 130 | memset(out, 0, *out_len); 131 | *out_len = 0; 132 | while( in_len-- && strchr(_oaes_base64_table, in[_idx++]) ) 133 | { 134 | _buf2[_i++] = in[_idx - 1]; 135 | if( _i ==4 ) 136 | { 137 | for (_i = 0; _i < 4; _i++) 138 | _buf2[_i] = strchr(_oaes_base64_table, _buf2[_i]) - _oaes_base64_table; 139 | 140 | _buf1[0] = (_buf2[0] << 2) + ((_buf2[1] & 0x30) >> 4); 141 | _buf1[1] = ((_buf2[1] & 0xf) << 4) + ((_buf2[2] & 0x3c) >> 2); 142 | _buf1[2] = ((_buf2[2] & 0x3) << 6) + _buf2[3]; 143 | 144 | for( _i = 0; (_i < 3); _i++ ) 145 | { 146 | *(out++) = _buf1[_i]; 147 | (*out_len)++; 148 | } 149 | _i = 0; 150 | } 151 | } 152 | 153 | if( _i ) 154 | { 155 | for( _j = _i; _j <4; _j++ ) 156 | _buf2[_j] = 0; 157 | 158 | for( _j = 0; _j <4; _j++ ) 159 | _buf2[_j] = strchr(_oaes_base64_table, _buf2[_j]) - _oaes_base64_table; 160 | 161 | _buf1[0] = (_buf2[0] << 2) + ((_buf2[1] & 0x30) >> 4); 162 | _buf1[1] = ((_buf2[1] & 0xf) << 4) + ((_buf2[2] & 0x3c) >> 2); 163 | _buf1[2] = ((_buf2[2] & 0x3) << 6) + _buf2[3]; 164 | 165 | for( _j = 0; (_j < _i - 1); _j++ ) 166 | { 167 | *(out++) = _buf1[_j]; 168 | (*out_len)++; 169 | } 170 | } 171 | 172 | return OAES_RET_SUCCESS; 173 | } 174 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/openaes/test/test_encrypt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * --------------------------------------------------------------------------- 3 | * OpenAES License 4 | * --------------------------------------------------------------------------- 5 | * Copyright (c) 2012, Nabil S. Al Ramli, www.nalramli.com 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * - Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * - Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | * --------------------------------------------------------------------------- 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #include "oaes_lib.h" 36 | 37 | void usage(const char * exe_name) 38 | { 39 | if( NULL == exe_name ) 40 | return; 41 | 42 | printf( 43 | "Usage:\n" 44 | "\t%s [-ecb] [-key < 128 | 192 | 256 >] \n", 45 | exe_name 46 | ); 47 | } 48 | 49 | int main(int argc, char** argv) 50 | { 51 | size_t _i; 52 | OAES_CTX * ctx = NULL; 53 | uint8_t *_encbuf, *_decbuf; 54 | size_t _encbuf_len, _decbuf_len, _buf_len; 55 | char *_buf; 56 | short _is_ecb = 0; 57 | char * _text = NULL; 58 | int _key_len = 128; 59 | 60 | if( argc < 2 ) 61 | { 62 | usage( argv[0] ); 63 | return EXIT_FAILURE; 64 | } 65 | 66 | for( _i = 1; _i < argc; _i++ ) 67 | { 68 | int _found = 0; 69 | 70 | if( 0 == strcmp( argv[_i], "-ecb" ) ) 71 | { 72 | _found = 1; 73 | _is_ecb = 1; 74 | } 75 | 76 | if( 0 == strcmp( argv[_i], "-key" ) ) 77 | { 78 | _found = 1; 79 | _i++; // len 80 | if( _i >= argc ) 81 | { 82 | printf("Error: No value specified for '-%s'.\n", 83 | "key"); 84 | usage( argv[0] ); 85 | return EXIT_FAILURE; 86 | } 87 | _key_len = atoi( argv[_i] ); 88 | switch( _key_len ) 89 | { 90 | case 128: 91 | case 192: 92 | case 256: 93 | break; 94 | default: 95 | printf("Error: Invalid value [%d] specified for '-%s'.\n", 96 | _key_len, "key"); 97 | usage( argv[0] ); 98 | return EXIT_FAILURE; 99 | } 100 | } 101 | 102 | if( 0 == _found ) 103 | { 104 | if( _text ) 105 | { 106 | printf("Error: Invalid option '%s'.\n", argv[_i]); 107 | usage( argv[0] ); 108 | return EXIT_FAILURE; 109 | } 110 | else 111 | { 112 | _text = (char *) calloc(strlen( argv[_i] ) + 1, sizeof(char)); 113 | if( NULL == _text ) 114 | { 115 | printf("Error: Failed to allocate memory.\n", argv[_i]); 116 | return EXIT_FAILURE; 117 | } 118 | strcpy( _text, argv[_i] ); 119 | } 120 | } 121 | } 122 | 123 | if( NULL == _text ) 124 | { 125 | usage( argv[0] ); 126 | return EXIT_FAILURE; 127 | } 128 | 129 | oaes_sprintf( NULL, &_buf_len, 130 | (const uint8_t *)_text, strlen( _text ) ); 131 | _buf = (char *) calloc(_buf_len, sizeof(char)); 132 | printf( "\n***** plaintext *****\n" ); 133 | if( _buf ) 134 | { 135 | oaes_sprintf( _buf, &_buf_len, 136 | (const uint8_t *)_text, strlen( _text ) ); 137 | printf( "%s", _buf ); 138 | } 139 | printf( "\n**********************\n" ); 140 | free( _buf ); 141 | 142 | ctx = oaes_alloc(); 143 | if( NULL == ctx ) 144 | { 145 | printf("Error: Failed to initialize OAES.\n"); 146 | free( _text ); 147 | return EXIT_FAILURE; 148 | } 149 | if( _is_ecb ) 150 | if( OAES_RET_SUCCESS != oaes_set_option( ctx, OAES_OPTION_ECB, NULL ) ) 151 | printf("Error: Failed to set OAES options.\n"); 152 | switch( _key_len ) 153 | { 154 | case 128: 155 | if( OAES_RET_SUCCESS != oaes_key_gen_128(ctx) ) 156 | printf("Error: Failed to generate OAES %d bit key.\n", _key_len); 157 | break; 158 | case 192: 159 | if( OAES_RET_SUCCESS != oaes_key_gen_192(ctx) ) 160 | printf("Error: Failed to generate OAES %d bit key.\n", _key_len); 161 | break; 162 | case 256: 163 | if( OAES_RET_SUCCESS != oaes_key_gen_256(ctx) ) 164 | printf("Error: Failed to generate OAES %d bit key.\n", _key_len); 165 | break; 166 | default: 167 | break; 168 | } 169 | 170 | if( OAES_RET_SUCCESS != oaes_encrypt( ctx, 171 | (const uint8_t *)_text, strlen( _text ), NULL, &_encbuf_len ) ) 172 | printf("Error: Failed to retrieve required buffer size for encryption.\n"); 173 | _encbuf = (uint8_t *) calloc( _encbuf_len, sizeof(uint8_t) ); 174 | if( NULL == _encbuf ) 175 | { 176 | printf( "Error: Failed to allocate memory.\n" ); 177 | free( _text ); 178 | return EXIT_FAILURE; 179 | } 180 | if( OAES_RET_SUCCESS != oaes_encrypt( ctx, 181 | (const uint8_t *)_text, strlen( _text ), _encbuf, &_encbuf_len ) ) 182 | printf("Error: Encryption failed.\n"); 183 | 184 | if( OAES_RET_SUCCESS != oaes_decrypt( ctx, 185 | _encbuf, _encbuf_len, NULL, &_decbuf_len ) ) 186 | printf("Error: Failed to retrieve required buffer size for encryption.\n"); 187 | _decbuf = (uint8_t *) calloc( _decbuf_len, sizeof(uint8_t) ); 188 | if( NULL == _decbuf ) 189 | { 190 | printf( "Error: Failed to allocate memory.\n" ); 191 | free( _text ); 192 | free( _encbuf ); 193 | return EXIT_FAILURE; 194 | } 195 | if( OAES_RET_SUCCESS != oaes_decrypt( ctx, 196 | _encbuf, _encbuf_len, _decbuf, &_decbuf_len ) ) 197 | printf("Error: Decryption failed.\n"); 198 | 199 | if( OAES_RET_SUCCESS != oaes_free( &ctx ) ) 200 | printf("Error: Failed to uninitialize OAES.\n"); 201 | 202 | oaes_sprintf( NULL, &_buf_len, _encbuf, _encbuf_len ); 203 | _buf = (char *) calloc(_buf_len, sizeof(char)); 204 | printf( "\n***** cyphertext *****\n" ); 205 | if( _buf ) 206 | { 207 | oaes_sprintf( _buf, &_buf_len, _encbuf, _encbuf_len ); 208 | printf( "%s", _buf ); 209 | } 210 | printf( "\n**********************\n" ); 211 | free( _buf ); 212 | 213 | oaes_sprintf( NULL, &_buf_len, _decbuf, _decbuf_len ); 214 | _buf = (char *) calloc(_buf_len, sizeof( char)); 215 | printf( "\n***** plaintext *****\n" ); 216 | if( _buf ) 217 | { 218 | oaes_sprintf( _buf, &_buf_len, _decbuf, _decbuf_len ); 219 | printf( "%s", _buf ); 220 | } 221 | printf( "\n**********************\n\n" ); 222 | free( _buf ); 223 | 224 | free( _encbuf ); 225 | free( _decbuf ); 226 | free( _text ); 227 | 228 | return (EXIT_SUCCESS); 229 | } 230 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/openaes/test/test_keys.c: -------------------------------------------------------------------------------- 1 | /* 2 | * --------------------------------------------------------------------------- 3 | * OpenAES License 4 | * --------------------------------------------------------------------------- 5 | * Copyright (c) 2012, Nabil S. Al Ramli, www.nalramli.com 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * - Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * - Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | * --------------------------------------------------------------------------- 29 | */ 30 | 31 | #include 32 | #include 33 | 34 | #include "oaes_lib.h" 35 | 36 | /* 37 | * 38 | */ 39 | int main(int argc, char** argv) { 40 | 41 | OAES_CTX * ctx = NULL; 42 | uint8_t * _buf; 43 | size_t _data_len; 44 | FILE * f = NULL; 45 | OAES_RET _rc; 46 | 47 | if( NULL == ( ctx = oaes_alloc() ) ) 48 | { 49 | printf( "Error: Initialization failed.\n" ); 50 | return 1; 51 | } 52 | 53 | /* ************** Generate 128-bit key and export it ************** 54 | * ****************************************************************/ 55 | if( OAES_RET_SUCCESS != ( _rc = oaes_key_gen_128(ctx) ) ) 56 | { 57 | printf( "Error: Failed to generate 128-bit key [%d].\n", _rc ); 58 | oaes_free(&ctx); 59 | return 1; 60 | } 61 | 62 | if( OAES_RET_SUCCESS != ( _rc = oaes_key_export(ctx, NULL, &_data_len) ) ) 63 | { 64 | printf( "Error: Failed to retrieve key length [%d].\n", _rc ); 65 | oaes_free(&ctx); 66 | return 1; 67 | } 68 | 69 | _buf = (uint8_t *) calloc(_data_len, sizeof(uint8_t)); 70 | if( _buf ) 71 | { 72 | if( OAES_RET_SUCCESS != ( _rc = oaes_key_export(ctx, _buf, &_data_len) ) ) 73 | { 74 | printf("Error: Failed to export key [%d].\n", _rc); 75 | free(_buf); 76 | oaes_free(&ctx); 77 | return 1; 78 | } 79 | 80 | f = fopen( "key_128", "wb" ); 81 | if( f ) 82 | { 83 | fwrite(_buf, _data_len, sizeof(uint8_t), f); 84 | fclose(f); 85 | } 86 | free(_buf); 87 | } 88 | 89 | /* ************** Generate 192-bit key and export it ************** 90 | * ****************************************************************/ 91 | if( OAES_RET_SUCCESS != ( _rc = oaes_key_gen_192(ctx) ) ) 92 | { 93 | printf( "Error: Failed to generate 192-bit key [%d].\n", _rc ); 94 | oaes_free(&ctx); 95 | return 1; 96 | } 97 | 98 | if( OAES_RET_SUCCESS != ( _rc = oaes_key_export(ctx, NULL, &_data_len) ) ) 99 | { 100 | printf( "Error: Failed to retrieve key length [%d].\n", _rc ); 101 | oaes_free(&ctx); 102 | return 1; 103 | } 104 | 105 | _buf = (uint8_t *) calloc(_data_len, sizeof(uint8_t)); 106 | if( _buf ) 107 | { 108 | if( OAES_RET_SUCCESS != ( _rc = oaes_key_export(ctx, _buf, &_data_len) ) ) 109 | { 110 | printf("Error: Failed to export key [%d].\n", _rc); 111 | free(_buf); 112 | oaes_free(&ctx); 113 | return 1; 114 | } 115 | 116 | f = fopen("key_192", "wb"); 117 | if( f ) 118 | { 119 | fwrite(_buf, _data_len, sizeof(uint8_t), f); 120 | fclose(f); 121 | } 122 | free(_buf); 123 | } 124 | 125 | /* ************** Generate 256-bit key and export it ************** 126 | * ****************************************************************/ 127 | if( OAES_RET_SUCCESS != ( _rc = oaes_key_gen_256(ctx) ) ) 128 | { 129 | printf("Error: Failed to generate 256-bit key [%d].\n", _rc); 130 | oaes_free(&ctx); 131 | return 1; 132 | } 133 | 134 | if( OAES_RET_SUCCESS != ( _rc = oaes_key_export(ctx, NULL, &_data_len) ) ) 135 | { 136 | printf("Error: Failed to retrieve key length [%d].\n", _rc); 137 | oaes_free(&ctx); 138 | return 1; 139 | } 140 | 141 | _buf = (uint8_t *) calloc(_data_len, sizeof(uint8_t)); 142 | if( _buf ) 143 | { 144 | if( OAES_RET_SUCCESS != ( _rc = oaes_key_export(ctx, _buf, &_data_len) ) ) 145 | { 146 | printf("Error: Failed to export key [%d].\n", _rc); 147 | free(_buf); 148 | oaes_free(&ctx); 149 | return 1; 150 | } 151 | 152 | f = fopen("key_256", "wb"); 153 | if( f ) 154 | { 155 | fwrite(_buf, _data_len, sizeof(uint8_t), f); 156 | fclose(f); 157 | } 158 | free(_buf); 159 | } 160 | 161 | /* ********************** Import 128-bit key ********************** 162 | * ****************************************************************/ 163 | f = fopen("key_128", "rb"); 164 | if( f ) 165 | { 166 | fseek(f, 0L, SEEK_END); 167 | _data_len = ftell(f); 168 | fseek(f, 0L, SEEK_SET); 169 | _buf = (uint8_t *) calloc(_data_len, sizeof(uint8_t)); 170 | if( _buf ) 171 | { 172 | fread(_buf, _data_len, sizeof(uint8_t), f); 173 | 174 | if( OAES_RET_SUCCESS != 175 | ( _rc = oaes_key_import(ctx, _buf, _data_len) ) ) 176 | { 177 | printf( "Error: Failed to import key [%d].\n", _rc ); 178 | free(_buf); 179 | fclose(f); 180 | oaes_free(&ctx); 181 | return 1; 182 | } 183 | 184 | free(_buf); 185 | } 186 | fclose(f); 187 | } 188 | 189 | /* ********************** Import 192-bit key ********************** 190 | * ****************************************************************/ 191 | f = fopen("key_192", "rb"); 192 | if( f ) 193 | { 194 | fseek(f, 0L, SEEK_END); 195 | _data_len = ftell(f); 196 | fseek(f, 0L, SEEK_SET); 197 | _buf = (uint8_t *) calloc(_data_len, sizeof(uint8_t)); 198 | if( _buf ) 199 | { 200 | fread(_buf, _data_len, sizeof(uint8_t), f); 201 | 202 | if( OAES_RET_SUCCESS != 203 | ( _rc = oaes_key_import(ctx, _buf, _data_len) ) ) 204 | { 205 | printf("Error: Failed to import key [%d].\n", _rc); 206 | free(_buf); 207 | fclose(f); 208 | oaes_free(&ctx); 209 | return 1; 210 | } 211 | 212 | free(_buf); 213 | } 214 | fclose(f); 215 | } 216 | 217 | /* ********************** Import 256-bit key ********************** 218 | * ****************************************************************/ 219 | f = fopen("key_256", "rb"); 220 | if( f ) 221 | { 222 | fseek(f, 0L, SEEK_END); 223 | _data_len = ftell(f); 224 | fseek(f, 0L, SEEK_SET); 225 | _buf = (uint8_t *) calloc(_data_len, sizeof(uint8_t)); 226 | if( _buf ) 227 | { 228 | fread(_buf, _data_len, sizeof(uint8_t), f); 229 | 230 | if( OAES_RET_SUCCESS != 231 | ( _rc = oaes_key_import(ctx, _buf, _data_len) ) ) 232 | { 233 | printf("Error: Failed to import key [%d].\n", _rc); 234 | free(_buf); 235 | fclose(f); 236 | oaes_free(&ctx); 237 | return 1; 238 | } 239 | 240 | free(_buf); 241 | } 242 | fclose(f); 243 | } 244 | 245 | oaes_free(&ctx); 246 | 247 | return (EXIT_SUCCESS); 248 | } 249 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/openaes/test/test_performance.c: -------------------------------------------------------------------------------- 1 | /* 2 | * --------------------------------------------------------------------------- 3 | * OpenAES License 4 | * --------------------------------------------------------------------------- 5 | * Copyright (c) 2012, Nabil S. Al Ramli, www.nalramli.com 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * - Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * - Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | * --------------------------------------------------------------------------- 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "oaes_lib.h" 37 | 38 | void usage(const char * exe_name) 39 | { 40 | if( NULL == exe_name ) 41 | return; 42 | 43 | printf( 44 | "Usage:\n" 45 | "\t%s [-ecb] [-key < 128 | 192 | 256 >] [-data ]\n", 46 | exe_name 47 | ); 48 | } 49 | 50 | /* 51 | * 52 | */ 53 | int main(int argc, char** argv) { 54 | 55 | size_t _i, _j; 56 | time_t _time_start, _time_end; 57 | OAES_CTX * ctx = NULL; 58 | uint8_t *_encbuf, *_decbuf; 59 | size_t _encbuf_len, _decbuf_len; 60 | uint8_t _buf[1024 * 1024]; 61 | short _is_ecb = 0; 62 | int _key_len = 128; 63 | size_t _data_len = 64; 64 | 65 | for( _i = 1; _i < argc; _i++ ) 66 | { 67 | int _found = 0; 68 | 69 | if( 0 == strcmp( argv[_i], "-ecb" ) ) 70 | { 71 | _found = 1; 72 | _is_ecb = 1; 73 | } 74 | 75 | if( 0 == strcmp( argv[_i], "-key" ) ) 76 | { 77 | _found = 1; 78 | _i++; // key_len 79 | if( _i >= argc ) 80 | { 81 | printf("Error: No value specified for '-%s'.\n", 82 | "key"); 83 | usage( argv[0] ); 84 | return 1; 85 | } 86 | _key_len = atoi( argv[_i] ); 87 | switch( _key_len ) 88 | { 89 | case 128: 90 | case 192: 91 | case 256: 92 | break; 93 | default: 94 | printf("Error: Invalid value [%d] specified for '-%s'.\n", 95 | _key_len, "key"); 96 | usage( argv[0] ); 97 | return 1; 98 | } 99 | } 100 | 101 | if( 0 == strcmp( argv[_i], "-data" ) ) 102 | { 103 | _found = 1; 104 | _i++; // data_len 105 | if( _i >= argc ) 106 | { 107 | printf("Error: No value specified for '-%s'.\n", 108 | "data"); 109 | usage( argv[0] ); 110 | return 1; 111 | } 112 | _data_len = atoi( argv[_i] ); 113 | } 114 | 115 | if( 0 == _found ) 116 | { 117 | printf("Error: Invalid option '%s'.\n", argv[_i]); 118 | usage( argv[0] ); 119 | return 1; 120 | } 121 | } 122 | 123 | // generate random test data 124 | time( &_time_start ); 125 | srand( _time_start ); 126 | for( _i = 0; _i < 1024 * 1024; _i++ ) 127 | _buf[_i] = rand(); 128 | 129 | ctx = oaes_alloc(); 130 | if( NULL == ctx ) 131 | { 132 | printf("Error: Failed to initialize OAES.\n"); 133 | return EXIT_FAILURE; 134 | } 135 | if( _is_ecb ) 136 | if( OAES_RET_SUCCESS != oaes_set_option( ctx, OAES_OPTION_ECB, NULL ) ) 137 | printf("Error: Failed to set OAES options.\n"); 138 | switch( _key_len ) 139 | { 140 | case 128: 141 | if( OAES_RET_SUCCESS != oaes_key_gen_128(ctx) ) 142 | printf("Error: Failed to generate OAES %d bit key.\n", _key_len); 143 | break; 144 | case 192: 145 | if( OAES_RET_SUCCESS != oaes_key_gen_192(ctx) ) 146 | printf("Error: Failed to generate OAES %d bit key.\n", _key_len); 147 | break; 148 | case 256: 149 | if( OAES_RET_SUCCESS != oaes_key_gen_256(ctx) ) 150 | printf("Error: Failed to generate OAES %d bit key.\n", _key_len); 151 | break; 152 | default: 153 | break; 154 | } 155 | 156 | if( OAES_RET_SUCCESS != oaes_encrypt( ctx, 157 | (const uint8_t *)_buf, 1024 * 1024, NULL, &_encbuf_len ) ) 158 | printf("Error: Failed to retrieve required buffer size for encryption.\n"); 159 | _encbuf = (uint8_t *) calloc( _encbuf_len, sizeof( char ) ); 160 | if( NULL == _encbuf ) 161 | { 162 | printf( "Error: Failed to allocate memory.\n" ); 163 | return EXIT_FAILURE; 164 | } 165 | 166 | if( OAES_RET_SUCCESS != oaes_decrypt( ctx, 167 | _encbuf, _encbuf_len, NULL, &_decbuf_len ) ) 168 | printf("Error: Failed to retrieve required buffer size for encryption.\n"); 169 | _decbuf = (uint8_t *) calloc( _decbuf_len, sizeof( char ) ); 170 | if( NULL == _decbuf ) 171 | { 172 | free( _encbuf ); 173 | printf( "Error: Failed to allocate memory.\n" ); 174 | return EXIT_FAILURE; 175 | } 176 | 177 | time( &_time_start ); 178 | 179 | for( _i = 0; _i < _data_len; _i++ ) 180 | { 181 | if( OAES_RET_SUCCESS != oaes_encrypt( ctx, 182 | (const uint8_t *)_buf, 1024 * 1024, _encbuf, &_encbuf_len ) ) 183 | printf("Error: Encryption failed.\n"); 184 | if( OAES_RET_SUCCESS != oaes_decrypt( ctx, 185 | _encbuf, _encbuf_len, _decbuf, &_decbuf_len ) ) 186 | printf("Error: Decryption failed.\n"); 187 | } 188 | 189 | time( &_time_end ); 190 | printf( "Test encrypt and decrypt:\n\ttime: %lld seconds\n\tdata: %ld MB" 191 | "\n\tkey: %d bits\n\tmode: %s\n", 192 | _time_end - _time_start, _data_len, 193 | _key_len, _is_ecb? "EBC" : "CBC" ); 194 | free( _encbuf ); 195 | free( _decbuf ); 196 | if( OAES_RET_SUCCESS != oaes_free( &ctx ) ) 197 | printf("Error: Failed to uninitialize OAES.\n"); 198 | 199 | return (EXIT_SUCCESS); 200 | } 201 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/openaes/test/vt_aes.c: -------------------------------------------------------------------------------- 1 | /* 2 | * --------------------------------------------------------------------------- 3 | * OpenAES License 4 | * --------------------------------------------------------------------------- 5 | * Copyright (c) 2012, Nabil S. Al Ramli, www.nalramli.com 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * - Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * - Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | * --------------------------------------------------------------------------- 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #define OAES_DEBUG 1 36 | #include "oaes_lib.h" 37 | 38 | static int _is_step = 1; 39 | 40 | static int step_cb( 41 | const uint8_t state[OAES_BLOCK_SIZE], 42 | const char * step_name, 43 | int step_count, 44 | void * user_data ) 45 | { 46 | size_t _buf_len; 47 | char * _buf; 48 | 49 | 50 | if( NULL == state ) 51 | return 1; 52 | 53 | oaes_sprintf( NULL, &_buf_len, state, OAES_BLOCK_SIZE ); 54 | _buf = (char *) calloc( _buf_len, sizeof( char ) ); 55 | 56 | if( _buf ) 57 | { 58 | oaes_sprintf( _buf, &_buf_len, state, OAES_BLOCK_SIZE ); 59 | printf( "round[%2d].%-7s --> %s", step_count, step_name, _buf ); 60 | free( _buf ); 61 | } 62 | 63 | if( 1 == _is_step && '\n' != getchar( ) ) 64 | _is_step = 0; 65 | 66 | return 0; 67 | } 68 | 69 | static int to_binary(uint8_t * buf, size_t * buf_len, const char * data) 70 | { 71 | size_t _i, _buf_len_in; 72 | 73 | if( NULL == buf_len ) 74 | return 1; 75 | 76 | if( NULL == data ) 77 | return 1; 78 | 79 | _buf_len_in = *buf_len; 80 | *buf_len = strlen( data ) / 2; 81 | 82 | if( NULL == buf ) 83 | return 0; 84 | 85 | if( *buf_len > _buf_len_in ) 86 | return 1; 87 | 88 | memset( buf, 0, strlen( data ) / 2 ); 89 | 90 | // lookup ascii table 91 | for( _i = 0; _i < strlen( data ); _i++ ) 92 | { 93 | // 0-9 94 | if( data[_i] >= 0x30 && data[_i] <= 0x39 ) 95 | buf[_i / 2] += ( data[_i] - 0x30 ) << ( 4 * ( ( _i + 1 ) % 2 ) ) ; 96 | // a-f 97 | else if( data[_i] >= 0x41 && data[_i] <= 0x46 ) 98 | buf[_i / 2] += ( data[_i] - 0x37 ) << ( 4 * ( ( _i + 1 ) % 2 ) ); 99 | // A-F 100 | else if( data[_i] >= 0x61 && data[_i] <= 0x66 ) 101 | buf[_i / 2] += ( data[_i] - 0x57 ) << ( 4 * ( ( _i + 1 ) % 2 ) ); 102 | // invalid character 103 | else 104 | return 1; 105 | } 106 | 107 | return 0; 108 | } 109 | 110 | static void usage(const char * exe_name) 111 | { 112 | if( NULL == exe_name ) 113 | return; 114 | 115 | printf( 116 | "Usage:\n" 117 | " %s [-step] [-ecb] [[-key < 128 | 192 | 256 | key_data >] [-bin] \n", 118 | exe_name 119 | ); 120 | } 121 | 122 | int main(int argc, char** argv) 123 | { 124 | size_t _i; 125 | OAES_CTX * ctx = NULL; 126 | uint8_t *_encbuf, *_decbuf, *_key_data = NULL, *_bin_data = NULL; 127 | size_t _encbuf_len, _decbuf_len, _buf_len; 128 | size_t _key_data_len = 0, _bin_data_len = 0; 129 | char *_buf; 130 | short _is_ecb = 0, _is_bin = 0; 131 | char * _text = NULL, * _key_text = NULL; 132 | int _key_len = 128; 133 | 134 | if( argc < 2 ) 135 | { 136 | usage( argv[0] ); 137 | return EXIT_FAILURE; 138 | } 139 | 140 | for( _i = 1; _i < argc; _i++ ) 141 | { 142 | int _found = 0; 143 | 144 | if( 0 == strcmp( argv[_i], "-nostep" ) ) 145 | { 146 | _found = 1; 147 | _is_step = 0; 148 | } 149 | 150 | if( 0 == strcmp( argv[_i], "-ecb" ) ) 151 | { 152 | _found = 1; 153 | _is_ecb = 1; 154 | } 155 | 156 | if( 0 == strcmp( argv[_i], "-bin" ) ) 157 | { 158 | _found = 1; 159 | _is_bin = 1; 160 | } 161 | 162 | if( 0 == strcmp( argv[_i], "-key" ) ) 163 | { 164 | _found = 1; 165 | _i++; // len 166 | if( _i >= argc ) 167 | { 168 | printf("Error: No value specified for '-%s'.\n", 169 | "key"); 170 | usage( argv[0] ); 171 | return EXIT_FAILURE; 172 | } 173 | _key_len = atoi( argv[_i] ); 174 | switch( _key_len ) 175 | { 176 | case 128: 177 | case 192: 178 | case 256: 179 | break; 180 | default: 181 | _key_text = argv[_i]; 182 | if( to_binary( NULL, &_key_data_len, _key_text ) ) 183 | { 184 | printf( "Error: Invalid value [%s] specified for '-%s'.\n", 185 | argv[_i], "key" ); 186 | return EXIT_FAILURE; 187 | } 188 | switch( _key_data_len ) 189 | { 190 | case 16: 191 | case 24: 192 | case 32: 193 | break; 194 | default: 195 | printf("Error: key_data [%s] specified for '-%s' has an invalid " 196 | "size.\n", argv[_i], "key"); 197 | usage( argv[0] ); 198 | return EXIT_FAILURE; 199 | } 200 | } 201 | } 202 | 203 | if( 0 == _found ) 204 | { 205 | if( _text ) 206 | { 207 | printf("Error: Invalid option '%s'.\n", argv[_i]); 208 | usage( argv[0] ); 209 | return EXIT_FAILURE; 210 | } 211 | else 212 | { 213 | _text = argv[_i]; 214 | if( _is_bin && to_binary( NULL, &_bin_data_len, _text ) ) 215 | { 216 | printf( "Error: Invalid value [%s] specified for '-%s'.\n", 217 | argv[_i], "bin" ); 218 | return EXIT_FAILURE; 219 | } 220 | } 221 | } 222 | } 223 | 224 | if( NULL == _text ) 225 | { 226 | usage( argv[0] ); 227 | return EXIT_FAILURE; 228 | } 229 | 230 | if( _is_step ) 231 | printf( "\nEnabling step mode, press Return to step.\n\n" ); 232 | 233 | if( _is_bin ) 234 | { 235 | _bin_data = (uint8_t *) calloc(_bin_data_len, sizeof(uint8_t)); 236 | if( NULL == _bin_data ) 237 | { 238 | printf( "Error: Failed to allocate memory.\n" ); 239 | return EXIT_FAILURE; 240 | } 241 | if( to_binary( _bin_data, &_bin_data_len, _text ) ) 242 | { 243 | printf( "Error: Could not load data [%s].\n", _text); 244 | free( _bin_data ); 245 | return EXIT_FAILURE; 246 | } 247 | } 248 | else 249 | { 250 | oaes_sprintf( NULL, &_buf_len, (const uint8_t *)_text, strlen(_text)); 251 | _buf = (char *) calloc(_buf_len, sizeof(char)); 252 | printf( "\n***** plaintext *****\n" ); 253 | if( _buf ) 254 | { 255 | oaes_sprintf( _buf, &_buf_len, 256 | (const uint8_t *)_text, strlen( _text ) ); 257 | printf( "%s", _buf ); 258 | } 259 | printf( "\n**********************\n" ); 260 | free( _buf ); 261 | } 262 | 263 | ctx = oaes_alloc(); 264 | if( NULL == ctx ) 265 | { 266 | printf("Error: Failed to initialize OAES.\n"); 267 | if( _bin_data ) 268 | free( _bin_data ); 269 | return EXIT_FAILURE; 270 | } 271 | if( OAES_RET_SUCCESS != oaes_set_option( ctx, OAES_OPTION_STEP_ON, step_cb ) ) 272 | printf("Error: Failed to set OAES options.\n"); 273 | if( _is_ecb ) 274 | if( OAES_RET_SUCCESS != oaes_set_option( ctx, OAES_OPTION_ECB, NULL ) ) 275 | printf("Error: Failed to set OAES options.\n"); 276 | 277 | if( _key_text ) 278 | { 279 | _key_data = (uint8_t *) calloc(_key_data_len, sizeof(uint8_t)); 280 | if( NULL == _key_data ) 281 | { 282 | printf( "Error: Failed to allocate memory.\n" ); 283 | if( _bin_data ) 284 | free( _bin_data ); 285 | return EXIT_FAILURE; 286 | } 287 | if( to_binary( _key_data, &_key_data_len, _key_text ) ) 288 | { 289 | printf( "Error: Could not load key [%s].\n", _key_text); 290 | free( _key_data ); 291 | return EXIT_FAILURE; 292 | } 293 | oaes_key_import_data( ctx, _key_data, _key_data_len ); 294 | } 295 | else 296 | switch( _key_len ) 297 | { 298 | case 128: 299 | if( OAES_RET_SUCCESS != oaes_key_gen_128(ctx) ) 300 | printf("Error: Failed to generate OAES %d bit key.\n", _key_len); 301 | break; 302 | case 192: 303 | if( OAES_RET_SUCCESS != oaes_key_gen_192(ctx) ) 304 | printf("Error: Failed to generate OAES %d bit key.\n", _key_len); 305 | break; 306 | case 256: 307 | if( OAES_RET_SUCCESS != oaes_key_gen_256(ctx) ) 308 | printf("Error: Failed to generate OAES %d bit key.\n", _key_len); 309 | break; 310 | default: 311 | break; 312 | } 313 | 314 | if( _bin_data ) 315 | { 316 | if( OAES_RET_SUCCESS != oaes_encrypt( ctx, 317 | _bin_data, _bin_data_len, NULL, &_encbuf_len ) ) 318 | printf("Error: Failed to retrieve required buffer size for encryption.\n"); 319 | _encbuf = (uint8_t *) calloc(_encbuf_len, sizeof(uint8_t)); 320 | if( NULL == _encbuf ) 321 | { 322 | printf( "Error: Failed to allocate memory.\n" ); 323 | if( _key_data ) 324 | free( _key_data ); 325 | free( _bin_data ); 326 | return EXIT_FAILURE; 327 | } 328 | printf( "\n" ); 329 | if( OAES_RET_SUCCESS != oaes_encrypt( ctx, 330 | _bin_data, _bin_data_len, _encbuf, &_encbuf_len ) ) 331 | printf("Error: Encryption failed.\n"); 332 | printf( "\n**********************\n\n" ); 333 | } 334 | else 335 | { 336 | if( OAES_RET_SUCCESS != oaes_encrypt( ctx, 337 | (const uint8_t *)_text, strlen( _text ), NULL, &_encbuf_len ) ) 338 | printf("Error: Failed to retrieve required buffer size for encryption.\n"); 339 | _encbuf = (uint8_t *) calloc(_encbuf_len, sizeof(uint8_t)); 340 | if( NULL == _encbuf ) 341 | { 342 | printf( "Error: Failed to allocate memory.\n" ); 343 | if( _key_data ) 344 | free( _key_data ); 345 | return EXIT_FAILURE; 346 | } 347 | printf( "\n" ); 348 | if( OAES_RET_SUCCESS != oaes_encrypt( ctx, 349 | (const uint8_t *)_text, strlen( _text ), _encbuf, &_encbuf_len ) ) 350 | printf("Error: Encryption failed.\n"); 351 | printf( "\n**********************\n\n" ); 352 | } 353 | 354 | if( OAES_RET_SUCCESS != oaes_decrypt( ctx, 355 | _encbuf, _encbuf_len, NULL, &_decbuf_len ) ) 356 | printf("Error: Failed to retrieve required buffer size for encryption.\n"); 357 | _decbuf = (uint8_t *) calloc(_decbuf_len, sizeof(uint8_t)); 358 | if( NULL == _decbuf ) 359 | { 360 | printf( "Error: Failed to allocate memory.\n" ); 361 | if( _key_data ) 362 | free( _key_data ); 363 | if( _bin_data ) 364 | free( _bin_data ); 365 | free( _encbuf ); 366 | return EXIT_FAILURE; 367 | } 368 | if( OAES_RET_SUCCESS != oaes_decrypt( ctx, 369 | _encbuf, _encbuf_len, _decbuf, &_decbuf_len ) ) 370 | printf("Error: Decryption failed.\n"); 371 | 372 | if( OAES_RET_SUCCESS != oaes_free( &ctx ) ) 373 | printf("Error: Failed to uninitialize OAES.\n"); 374 | 375 | oaes_sprintf( NULL, &_buf_len, _encbuf, _encbuf_len ); 376 | _buf = (char *) calloc(_buf_len, sizeof(char)); 377 | printf( "\n***** cyphertext *****\n" ); 378 | if( _buf ) 379 | { 380 | oaes_sprintf( _buf, &_buf_len, _encbuf, _encbuf_len ); 381 | printf( "%s", _buf ); 382 | } 383 | printf( "\n**********************\n" ); 384 | free( _buf ); 385 | 386 | oaes_sprintf( NULL, &_buf_len, _decbuf, _decbuf_len ); 387 | _buf = (char *) calloc(_buf_len, sizeof(char)); 388 | printf( "\n***** plaintext *****\n" ); 389 | if( _buf ) 390 | { 391 | oaes_sprintf( _buf, &_buf_len, _decbuf, _decbuf_len ); 392 | printf( "%s", _buf ); 393 | } 394 | printf( "\n**********************\n\n" ); 395 | free( _buf ); 396 | 397 | free( _encbuf ); 398 | free( _decbuf ); 399 | if( _key_data ) 400 | free( _key_data ); 401 | if( _bin_data ) 402 | free( _bin_data ); 403 | 404 | return (EXIT_SUCCESS); 405 | } 406 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/pyconcrete.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2015 Falldog Hsieh 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | #define PY_SSIZE_T_CLEAN 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "oaes_lib.h" 22 | #include "secret_key.h" // auto generate at build time 23 | 24 | // #define SECRET_KEY_LEN %d // defined in secret_key.h 25 | #define AES_BLOCK_SIZE 16 26 | 27 | #if PY_MAJOR_VERSION >= 3 28 | #define IS_PY3K 29 | #endif 30 | 31 | const static unsigned int TRUE = 1; 32 | const static unsigned int FALSE = 0; 33 | 34 | PyObject* g_PyConcreteError = NULL; 35 | 36 | static void print_buffer(unsigned char* buf, int size) 37 | { 38 | int i = 0; 39 | printf("print buffer 0x%p(%d) ", buf, size); 40 | for(i=0 ; i plain_buf_size) 220 | { 221 | break; // the last block already decrypt 222 | } 223 | else 224 | { 225 | memcpy(cur_plain, cur_cipher, AES_BLOCK_SIZE); 226 | oaes_decrypt_block(key, cur_plain, AES_BLOCK_SIZE); 227 | 228 | cur_plain += AES_BLOCK_SIZE; 229 | cur_cipher += AES_BLOCK_SIZE; 230 | proc_size += AES_BLOCK_SIZE; 231 | } 232 | } 233 | 234 | // fill last fragment block 235 | if(padding_size < AES_BLOCK_SIZE) 236 | memcpy(cur_plain, last_block, AES_BLOCK_SIZE-padding_size); 237 | } 238 | KeyDestroy(&key); 239 | return py_plain_obj; 240 | } 241 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/pyconcrete.h: -------------------------------------------------------------------------------- 1 | #ifndef PYCONCRETE_H 2 | #define PYCONCRETE_H 3 | 4 | extern PyObject* g_PyConcreteError; 5 | 6 | PyObject * fnEncryptFile(PyObject* self, PyObject* args); 7 | PyObject * fnDecryptFile(PyObject* self, PyObject* args); 8 | PyObject * fnDecryptBuffer(PyObject* self, PyObject* args); 9 | 10 | #endif // PYCONCRETE_H 11 | -------------------------------------------------------------------------------- /src/pyconcrete_ext/pyconcrete_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "pyconcrete.h" // auto generate at build time 6 | 7 | // #define SECRET_KEY_LEN %d // defined in secret_key.h 8 | 9 | #if PY_MAJOR_VERSION >= 3 10 | #define IS_PY3K 11 | #endif 12 | 13 | #ifndef PYCONCRETE_EXT 14 | #define PYCONCRETE_EXT ".pye" 15 | #endif 16 | 17 | static PyObject * fnInfo(PyObject *self, PyObject* null) 18 | { 19 | return Py_BuildValue("s", "PyConcrete Info() AES 128bit"); 20 | } 21 | 22 | static PyObject * fnExt(PyObject *self, PyObject* null) 23 | { 24 | return Py_BuildValue("s", PYCONCRETE_EXT); 25 | } 26 | 27 | static PyMethodDef PyConcreteMethods[] = { 28 | {"info", fnInfo, METH_NOARGS, "Display PyConcrete info"}, 29 | {"get_ext", fnExt, METH_NOARGS, "PyConcrete file ext"}, 30 | {"encrypt_file", fnEncryptFile, METH_VARARGS, "Encrypt whole file"}, 31 | {"decrypt_file", fnDecryptFile, METH_VARARGS, "Decrypt whole file (not ready)"}, 32 | {"decrypt_buffer", fnDecryptBuffer, METH_VARARGS, "Decrypt buffer"}, 33 | {NULL, NULL, 0, NULL} /* Sentinel */ 34 | }; 35 | 36 | #if PY_MAJOR_VERSION >= 3 37 | static struct PyModuleDef PyConcreteMethodDef = { 38 | PyModuleDef_HEAD_INIT, 39 | "_pyconcrete", /* m_name */ 40 | NULL, /* m_doc */ 41 | -1, /* m_size */ 42 | PyConcreteMethods, /* m_methods */ 43 | NULL, /* m_reload */ 44 | NULL, /* m_traverse */ 45 | NULL, /* m_clear */ 46 | NULL, /* m_free */ 47 | }; 48 | #define INITERROR return NULL 49 | #else 50 | #define INITERROR return 51 | #endif 52 | 53 | 54 | #if PY_MAJOR_VERSION >= 3 55 | PyMODINIT_FUNC 56 | PyInit__pyconcrete(void) 57 | #else 58 | PyMODINIT_FUNC 59 | init_pyconcrete(void) 60 | #endif 61 | { 62 | PyObject* m = NULL; 63 | #if PY_MAJOR_VERSION >= 3 64 | m = PyModule_Create(&PyConcreteMethodDef); 65 | #else 66 | m = Py_InitModule("_pyconcrete", PyConcreteMethods); 67 | #endif 68 | if (m == NULL) 69 | INITERROR; 70 | 71 | g_PyConcreteError = PyErr_NewException("_pyconcrete.Error", NULL, NULL); 72 | Py_INCREF(g_PyConcreteError); 73 | PyModule_AddObject(m, "Error", g_PyConcreteError); 74 | 75 | #if PY_MAJOR_VERSION >= 3 76 | return m; 77 | #endif 78 | } 79 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # Pyconcrete Test 2 | 3 | 4 | ## Testing Environment 5 | 6 | Testing framework is `pytest`. 7 | 8 | How to run the test? 9 | ```shell 10 | $ pytest 11 | ``` 12 | 13 | 14 | Run test in docker, for testing different python version environment: 15 | ```shell 16 | $ make test 3.10 17 | ``` 18 | 19 | 20 | ## Testing Guideline 21 | There 2 parts for pyconcrete testing: 22 | 1. `pyecli` encryption behavior 23 | 2. pyconcrete exe, executable behavior 24 | 3. pyconcrete hook import path behavior 25 | 4. pyconcrete decrypt .pye behavior 26 | 27 | Avoid to pollute the testing environment, we avoid to change python default path_hook. 28 | So pyconcrete test doesn't import pyconcret module during testing. 29 | 30 | All of testcases will be executed by new process, such as `subprocess`. It will make sure the 31 | testing environment clear and not be pollution. 32 | 33 | For most of the general testing purpose. Put the testcases into `tests/exe_testcases/` to inspect the 34 | process return code and stdout to make sure the code execute as expected result. 35 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Falldog/pyconcrete/5210bc2e47e1b4df3ebce120340b217a1016759f/tests/__init__.py -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Falldog Hsieh 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import subprocess 15 | import sys 16 | from os.path import abspath, dirname, join 17 | 18 | import pytest 19 | 20 | ROOT_DIR = abspath(join(dirname(__file__), '..')) 21 | PASSPHRASE = 'TestPyconcrete' 22 | 23 | 24 | class Venv: 25 | def __init__(self, env_dir, pyconcrete_ext=None): 26 | self.executable = None 27 | self.bin_dir = None 28 | self.env_dir = env_dir 29 | self._pyconcrete_ext = pyconcrete_ext 30 | self.create() 31 | 32 | def create(self): 33 | subprocess.check_call([sys.executable, '-m', 'virtualenv', self.env_dir]) 34 | self.bin_dir = join(self.env_dir, 'bin') 35 | self.executable = join(self.bin_dir, 'python') 36 | self._ensure_pyconcrete_exist() 37 | 38 | def python(self, *args: [str]): 39 | return subprocess.check_output([self.executable, *args]).decode() 40 | 41 | def pip(self, *args: [str]): 42 | return self.python('-m', 'pip', *args) 43 | 44 | @property 45 | def pyconcrete_exe(self): 46 | self._ensure_pyconcrete_exist() 47 | return join(self.bin_dir, 'pyconcrete') 48 | 49 | def pyconcrete(self, *args: [str]): 50 | self._ensure_pyconcrete_exist() 51 | return subprocess.check_output([self.pyconcrete_exe, *args]).decode() 52 | 53 | def pyconcrete_cli(self, *args: [str]): 54 | self._ensure_pyconcrete_exist() 55 | cli_script = join(ROOT_DIR, 'pyecli') 56 | return subprocess.check_output([self.executable, cli_script, *args]).decode() 57 | 58 | def _ensure_pyconcrete_exist(self): 59 | proc = subprocess.run(f'{self.executable} -m pip list | grep -c pyconcrete', shell=True) 60 | pyconcrete_exist = bool(proc.returncode == 0) 61 | if not pyconcrete_exist: 62 | args = [ 63 | 'install', 64 | f'--config-settings=setup-args=-Dpassphrase={PASSPHRASE}', 65 | f'--config-settings=setup-args=-Dext={self._pyconcrete_ext}' if self._pyconcrete_ext else '', 66 | '--quiet', 67 | ROOT_DIR, 68 | ] 69 | args = [arg for arg in args if arg] # filter empty string 70 | self.pip(*args) 71 | 72 | 73 | class PyeCli: 74 | def __init__(self, venv: Venv): 75 | self._venv = venv 76 | self._tmp_dir = None 77 | self._module_name = None 78 | self._source_code = None 79 | 80 | def setup(self, tmp_dir, module_name): 81 | self._tmp_dir = tmp_dir 82 | self._module_name = module_name 83 | return self 84 | 85 | @property 86 | def tmp_dir(self): 87 | """tmp dir to do the encryption""" 88 | return self._tmp_dir 89 | 90 | def source_code(self, code): 91 | self._source_code = code 92 | return self 93 | 94 | def get_encrypt_path(self): 95 | assert self._module_name 96 | assert self._source_code 97 | 98 | py_module_path = join(self._tmp_dir, f'{self._module_name}.py') 99 | pye_module_path = join(self._tmp_dir, f'{self._module_name}.pye') 100 | with open(py_module_path, 'w') as f: 101 | f.write(self._source_code) 102 | 103 | self._venv.pyconcrete_cli('compile', '--remove-py', '--pye', '-s', py_module_path) 104 | 105 | return pye_module_path 106 | 107 | 108 | @pytest.fixture 109 | def pye_cli(venv: Venv): 110 | return PyeCli(venv) 111 | 112 | 113 | @pytest.fixture(scope='session') 114 | def venv(tmp_path_factory): 115 | return Venv(tmp_path_factory.mktemp('venv_')) 116 | 117 | 118 | @pytest.fixture 119 | def sample_module_path(): 120 | return join(ROOT_DIR, 'tests', 'fixtures', 'sample_module') 121 | 122 | 123 | @pytest.fixture 124 | def sample_import_sub_module_path(): 125 | return join(ROOT_DIR, 'tests', 'exe_testcases', 'test_import_sub_module') 126 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_basic__main__module/expected.yaml: -------------------------------------------------------------------------------- 1 | expected: 2 | return_code: 0 3 | stdout: "Hello World\n" 4 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_basic__main__module/main.py: -------------------------------------------------------------------------------- 1 | if __name__ == '__main__': 2 | print("Hello World") 3 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_basic_function_call/expected.yaml: -------------------------------------------------------------------------------- 1 | expected: 2 | return_code: 0 3 | stdout: "55\n" 4 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_basic_function_call/main.py: -------------------------------------------------------------------------------- 1 | def fibonacci(n): 2 | if n > 1: 3 | return fibonacci(n - 1) + fibonacci(n - 2) 4 | return n 5 | 6 | 7 | print(fibonacci(10)) 8 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_basic_name_be__main__/expected.yaml: -------------------------------------------------------------------------------- 1 | expected: 2 | return_code: 0 3 | stdout: "__main__\n" 4 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_basic_name_be__main__/main.py: -------------------------------------------------------------------------------- 1 | print(__name__) 2 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_basic_raise_exception/expected.yaml: -------------------------------------------------------------------------------- 1 | expected: 2 | return_code: 1 3 | is_ignore_stdout: True 4 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_basic_raise_exception/main.py: -------------------------------------------------------------------------------- 1 | raise Exception("Error") 2 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_import_sub_module/expected.yaml: -------------------------------------------------------------------------------- 1 | expected: 2 | return_code: 0 3 | stdout: "bar\n" 4 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_import_sub_module/main.py: -------------------------------------------------------------------------------- 1 | from sub_module import foo 2 | 3 | print(foo.name) 4 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_import_sub_module/sub_module/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Falldog/pyconcrete/5210bc2e47e1b4df3ebce120340b217a1016759f/tests/exe_testcases/test_import_sub_module/sub_module/__init__.py -------------------------------------------------------------------------------- /tests/exe_testcases/test_import_sub_module/sub_module/foo.py: -------------------------------------------------------------------------------- 1 | name = 'bar' 2 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_issue_98_multiprocessing/expected.yaml: -------------------------------------------------------------------------------- 1 | expected: 2 | return_code: 0 3 | stdout: "0\n1\n4\n9\n16\n" 4 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_issue_98_multiprocessing/main.py: -------------------------------------------------------------------------------- 1 | import multiprocessing 2 | 3 | 4 | def task_fn(arr): 5 | for i in arr: 6 | print(i**2) 7 | 8 | 9 | if __name__ == '__main__': 10 | args = range(5) 11 | ctx = multiprocessing.get_context('fork') 12 | p = ctx.Process(target=task_fn, args=(args,)) 13 | p.start() 14 | p.join() 15 | p.close() 16 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_relative_import_sub_module/expected.yaml: -------------------------------------------------------------------------------- 1 | expected: 2 | return_code: 0 3 | stdout: "20\n" 4 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_relative_import_sub_module/main.py: -------------------------------------------------------------------------------- 1 | from sub_module.bar import bar_value 2 | 3 | print(bar_value) 4 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_relative_import_sub_module/sub_module/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Falldog/pyconcrete/5210bc2e47e1b4df3ebce120340b217a1016759f/tests/exe_testcases/test_relative_import_sub_module/sub_module/__init__.py -------------------------------------------------------------------------------- /tests/exe_testcases/test_relative_import_sub_module/sub_module/bar.py: -------------------------------------------------------------------------------- 1 | from .foo import foo_value 2 | 3 | bar_value = foo_value + 10 4 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_relative_import_sub_module/sub_module/foo.py: -------------------------------------------------------------------------------- 1 | foo_value = 10 2 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_relative_import_sub_module2/expected.yaml: -------------------------------------------------------------------------------- 1 | expected: 2 | return_code: 0 3 | stdout: "120\n" 4 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_relative_import_sub_module2/main.py: -------------------------------------------------------------------------------- 1 | from parent.child import child_foo 2 | 3 | print(child_foo.child_foo_value) 4 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_relative_import_sub_module2/parent/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Falldog/pyconcrete/5210bc2e47e1b4df3ebce120340b217a1016759f/tests/exe_testcases/test_relative_import_sub_module2/parent/__init__.py -------------------------------------------------------------------------------- /tests/exe_testcases/test_relative_import_sub_module2/parent/child/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Falldog/pyconcrete/5210bc2e47e1b4df3ebce120340b217a1016759f/tests/exe_testcases/test_relative_import_sub_module2/parent/child/__init__.py -------------------------------------------------------------------------------- /tests/exe_testcases/test_relative_import_sub_module2/parent/child/child_foo.py: -------------------------------------------------------------------------------- 1 | from ..parent_bar import bar_value 2 | 3 | child_foo_value = bar_value + 100 4 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_relative_import_sub_module2/parent/parent_bar.py: -------------------------------------------------------------------------------- 1 | from .parent_foo import foo_value 2 | 3 | bar_value = foo_value + 10 4 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_relative_import_sub_module2/parent/parent_foo.py: -------------------------------------------------------------------------------- 1 | foo_value = 10 2 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_sys_exit/expected.yaml: -------------------------------------------------------------------------------- 1 | expected: 2 | return_code: 99 3 | stdout: "" 4 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_sys_exit/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | sys.exit(99) 4 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_threading/expected.yaml: -------------------------------------------------------------------------------- 1 | expected: 2 | return_code: 0 3 | stdout: "0 1 4 9 16\n" 4 | -------------------------------------------------------------------------------- /tests/exe_testcases/test_threading/main.py: -------------------------------------------------------------------------------- 1 | from threading import Thread 2 | 3 | try: 4 | from queue import Queue 5 | except: # noqa: E722 6 | from Queue import Queue 7 | 8 | 9 | def main(): 10 | # global Queue, Thread, sqrt 11 | q = Queue() 12 | worker = [] 13 | 14 | for i in range(5): 15 | t = Thread(target=sqrt, args=(q, i)) 16 | t.start() 17 | worker.append(t) 18 | 19 | for w in worker: 20 | w.join() 21 | 22 | res = [] 23 | while not q.empty(): 24 | res.append(q.get()) 25 | 26 | # sort the result 27 | print(' '.join(str(n) for n in sorted(res))) 28 | 29 | 30 | def sqrt(q, n): 31 | q.put(n * n) 32 | 33 | 34 | if __name__ == '__main__': 35 | main() 36 | -------------------------------------------------------------------------------- /tests/fixtures/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Falldog/pyconcrete/5210bc2e47e1b4df3ebce120340b217a1016759f/tests/fixtures/__init__.py -------------------------------------------------------------------------------- /tests/fixtures/sample_module/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Falldog/pyconcrete/5210bc2e47e1b4df3ebce120340b217a1016759f/tests/fixtures/sample_module/__init__.py -------------------------------------------------------------------------------- /tests/fixtures/sample_module/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | environ = os.environ 5 | path = sys.path 6 | -------------------------------------------------------------------------------- /tests/fixtures/sample_module/relative_import/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Falldog/pyconcrete/5210bc2e47e1b4df3ebce120340b217a1016759f/tests/fixtures/sample_module/relative_import/__init__.py -------------------------------------------------------------------------------- /tests/fixtures/sample_module/relative_import/main.py: -------------------------------------------------------------------------------- 1 | from . import util # noqa: F401 2 | 3 | data = 'main' 4 | -------------------------------------------------------------------------------- /tests/fixtures/sample_module/relative_import/sub_module/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Falldog/pyconcrete/5210bc2e47e1b4df3ebce120340b217a1016759f/tests/fixtures/sample_module/relative_import/sub_module/__init__.py -------------------------------------------------------------------------------- /tests/fixtures/sample_module/relative_import/sub_module/module_cmd.py: -------------------------------------------------------------------------------- 1 | data = 'sub-module' 2 | -------------------------------------------------------------------------------- /tests/fixtures/sample_module/relative_import/util.py: -------------------------------------------------------------------------------- 1 | data = 'util' 2 | -------------------------------------------------------------------------------- /tests/requirements.txt: -------------------------------------------------------------------------------- 1 | pytest==7.4.4 2 | virtualenv==20.26.6 3 | meson-python==0.17.1 4 | PyYAML==6.0.1 5 | -------------------------------------------------------------------------------- /tests/shell_tools.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Falldog Hsieh 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import os 15 | from os.path import join 16 | from pathlib import Path 17 | from typing import Union 18 | 19 | 20 | def touch(file_path): 21 | open(file_path, 'a').close() 22 | 23 | 24 | def make_py_packages(base_dir: str, child_path: str): 25 | children_paths = child_path.split('/') 26 | cur_dir = base_dir 27 | touch(join(cur_dir, '__init__.py')) 28 | for p in children_paths: 29 | if p == '': 30 | continue 31 | dir_path = join(cur_dir, p) 32 | os.makedirs(dir_path, exist_ok=True) 33 | touch(join(dir_path, '__init__.py')) 34 | cur_dir = dir_path 35 | return join(base_dir, child_path) 36 | 37 | 38 | def _tree_iter(dir_path: Union[str, Path], prefix: str = ''): 39 | """ 40 | A recursive generator, given a directory Path object 41 | will yield a visual tree structure line by line 42 | with each line prefixed by the same characters 43 | """ 44 | # prefix components 45 | space = ' ' 46 | branch = '│ ' 47 | # pointers 48 | tee = '├── ' 49 | last = '└── ' 50 | 51 | contents = list(dir_path.iterdir()) 52 | # contents each get pointers that are ├── with a final └── : 53 | pointers = [tee] * (len(contents) - 1) + [last] 54 | for pointer, path in zip(pointers, contents): 55 | yield prefix + pointer + path.name 56 | if path.is_dir(): # extend the prefix and recurse: 57 | extension = branch if pointer == tee else space 58 | # i.e. space because last, └── , above so no more | 59 | yield from _tree_iter(path, prefix=prefix + extension) 60 | 61 | 62 | def tree(dir_path: Union[str, Path], prefix: str = ''): 63 | """debug tool for dump folder structure as tree view""" 64 | dir_path = Path(dir_path) 65 | for line in _tree_iter(dir_path, prefix=prefix): 66 | print(line) 67 | -------------------------------------------------------------------------------- /tests/test_cli.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Falldog Hsieh 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import os 15 | import shutil 16 | from os.path import join 17 | 18 | import pytest 19 | 20 | from .shell_tools import touch 21 | 22 | YES = 'yes' 23 | NO = 'no' 24 | 25 | 26 | def test_cli__encrypt_single_file(venv, pye_cli, tmpdir, sample_module_path): 27 | # prepare 28 | source_file = join(tmpdir, 'm.py') 29 | encrypt_file = join(tmpdir, 'm.pye') 30 | 31 | with open(source_file, 'w') as f: 32 | f.write("""print('hello world')""") 33 | 34 | # execution 35 | venv.pyconcrete_cli('compile', f'--source={source_file}', '--pye') 36 | 37 | # validation 38 | assert os.path.exists(encrypt_file) 39 | 40 | 41 | def test_cli__encrypt_whole_folder(venv, pye_cli, tmpdir, sample_module_path): 42 | # prepare 43 | source_dir = join(tmpdir, 'sample_module') 44 | shutil.copytree(sample_module_path, source_dir) 45 | 46 | # execution 47 | venv.pyconcrete_cli('compile', f'--source={source_dir}', '--pye') 48 | 49 | # validation 50 | for root, dirs, files in os.walk(sample_module_path): 51 | for filename in files: 52 | source_file = str(join(root, filename)) 53 | source_relative_path = os.path.relpath(source_file, sample_module_path) 54 | py_file = join(source_dir, source_relative_path) 55 | pye_file = py_file + 'e' 56 | assert os.path.exists(pye_file) 57 | 58 | 59 | _f_main = 'main.pye' 60 | _f_ri__main = join('relative_import', 'main.pye') 61 | _f_ri__util = join('relative_import', 'util.pye') 62 | 63 | 64 | @pytest.mark.parametrize( 65 | "pattern,expect_result_map", 66 | [ 67 | (None, {_f_main: YES, _f_ri__main: YES, _f_ri__util: YES}), 68 | ("main.py", {_f_main: NO, _f_ri__main: NO, _f_ri__util: YES}), 69 | ("relative_import/*", {_f_main: YES, _f_ri__main: NO, _f_ri__util: NO}), 70 | ("relative_import/util.py", {_f_main: YES, _f_ri__main: YES, _f_ri__util: NO}), 71 | ("relative_import/main.py", {_f_main: YES, _f_ri__main: NO, _f_ri__util: YES}), 72 | ("main.py util.py", {_f_main: NO, _f_ri__main: NO, _f_ri__util: NO}), 73 | ], 74 | ) 75 | def test_cli__ignore_rule__in_deep_folder(venv, tmpdir, sample_module_path, pattern, expect_result_map): 76 | # prepare 77 | source_dir = join(tmpdir, 'sample_module') 78 | shutil.copytree(sample_module_path, source_dir) 79 | 80 | # execution 81 | ignore_args = [] 82 | if pattern is not None: 83 | ignore_args.append('-i') 84 | ignore_args.extend(pattern.split(' ')) 85 | venv.pyconcrete_cli('compile', f'--source={source_dir}', '--pye', *ignore_args) 86 | 87 | # validation 88 | for f, encrypted in expect_result_map.items(): 89 | if encrypted == YES: 90 | path = join(source_dir, f) 91 | assert os.path.exists(path), f"ignore pattern `{pattern}` fail on exist file `{f}` validation!" 92 | else: # encrypted == NO 93 | path = join(source_dir, f) 94 | assert not os.path.exists(path), f"ignore pattern `{pattern}` fail on non-exist file `{f}` validation!" 95 | 96 | 97 | _f_foo = 'foo.pye' 98 | _f_test1 = join('test1.pye') 99 | _f_test2 = join('test2.pye') 100 | _f_test3 = join('test3.pye') 101 | _f_test = join('test.pye') 102 | _f_a_test = join('a_test.pye') 103 | _f_b_test = join('b_test.pye') 104 | 105 | 106 | @pytest.mark.parametrize( 107 | "pattern,expect_result_map", 108 | [ 109 | ( 110 | None, 111 | {_f_foo: YES, _f_test1: YES, _f_test2: YES, _f_test3: YES, _f_test: YES, _f_a_test: YES, _f_b_test: YES}, 112 | ), 113 | ( 114 | "*/test.py", 115 | {_f_foo: YES, _f_test1: YES, _f_test2: YES, _f_test3: YES, _f_test: NO, _f_a_test: YES, _f_b_test: YES}, 116 | ), 117 | ( 118 | "/test.py", 119 | {_f_foo: YES, _f_test1: YES, _f_test2: YES, _f_test3: YES, _f_test: NO, _f_a_test: YES, _f_b_test: YES}, 120 | ), 121 | ( 122 | "test.py", 123 | {_f_foo: YES, _f_test1: YES, _f_test2: YES, _f_test3: YES, _f_test: NO, _f_a_test: YES, _f_b_test: YES}, 124 | ), 125 | ( 126 | "test?.py", 127 | {_f_foo: YES, _f_test1: NO, _f_test2: NO, _f_test3: NO, _f_test: YES, _f_a_test: YES, _f_b_test: YES}, 128 | ), 129 | ( 130 | "test[1,3].py", 131 | {_f_foo: YES, _f_test1: NO, _f_test2: YES, _f_test3: NO, _f_test: YES, _f_a_test: YES, _f_b_test: YES}, 132 | ), 133 | ( 134 | "test[!1,3].py", 135 | {_f_foo: YES, _f_test1: YES, _f_test2: NO, _f_test3: YES, _f_test: YES, _f_a_test: YES, _f_b_test: YES}, 136 | ), 137 | ], 138 | ) 139 | def test_cli__ignore_rule__in_same_folder(venv, pye_cli, tmpdir, pattern, expect_result_map): 140 | # prepare 141 | source_dir = tmpdir 142 | # create the files which list on parametrize 143 | for f, encrypted in expect_result_map.items(): 144 | name, ext = os.path.splitext(f) 145 | py_file = join(source_dir, f'{name}.py') 146 | touch(py_file) 147 | 148 | # execution 149 | ignore_args = [] 150 | if pattern is not None: 151 | ignore_args.append('-i') 152 | ignore_args.extend(pattern.split(' ')) 153 | venv.pyconcrete_cli('compile', f'--source={source_dir}', '--pye', *ignore_args) 154 | 155 | # validation 156 | for f, encrypted in expect_result_map.items(): 157 | if encrypted == YES: 158 | path = join(source_dir, f) 159 | assert os.path.exists(path), f"ignore pattern `{pattern}` fail on exist file `{f}` validation!" 160 | else: # encrypted == NO 161 | path = join(source_dir, f) 162 | assert not os.path.exists(path), f"ignore pattern `{pattern}` fail on non-exist file `{f}` validation!" 163 | -------------------------------------------------------------------------------- /tests/test_customize_ext.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Falldog Hsieh 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import shutil 15 | from os.path import exists, join 16 | 17 | import pytest 18 | 19 | from .conftest import Venv 20 | 21 | 22 | @pytest.mark.parametrize( 23 | "ext", 24 | [".pye", ".t", ".tw"], 25 | ) 26 | def test_customize_ext(tmp_path_factory, tmpdir, sample_import_sub_module_path, ext): 27 | """build the standalone virtualenv for different file extensions""" 28 | # prepare 29 | target_dir = join(tmpdir, 'for_ext_module') 30 | main_encrypted = join(target_dir, f'main{ext}') 31 | venv = Venv(tmp_path_factory.mktemp('venv_ext_'), pyconcrete_ext=ext) 32 | 33 | # compile to customized extension 34 | shutil.copytree(sample_import_sub_module_path, target_dir) 35 | venv.pyconcrete_cli( 36 | 'compile', 37 | f'--ext={ext}', 38 | f'--source={target_dir}', 39 | '--pye', 40 | '--remove-py', 41 | ) 42 | 43 | # verification (before) 44 | assert exists(main_encrypted) is True 45 | 46 | # execution 47 | output = venv.pyconcrete(main_encrypted) 48 | 49 | # verification (after) 50 | assert output == 'bar\n' 51 | -------------------------------------------------------------------------------- /tests/test_encoding.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Falldog Hsieh 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import pytest 15 | 16 | 17 | @pytest.mark.parametrize("text", ["早安", "¡Buenos días!", "おはようございます"]) 18 | def test_encoding(venv, pye_cli, tmpdir, text): 19 | # prepare 20 | pye_path = pye_cli.setup(tmpdir, 'test_encoding').source_code(f"print('{text}')").get_encrypt_path() 21 | 22 | # execution 23 | output = venv.pyconcrete(pye_path) 24 | output = output.strip() 25 | 26 | # verification 27 | assert output == text 28 | -------------------------------------------------------------------------------- /tests/test_encryption.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Falldog Hsieh 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | from os.path import join 15 | from subprocess import PIPE, Popen 16 | 17 | import pytest 18 | 19 | 20 | def _encrypt_plain_buffer_and_decrypt(venv, tmpdir, plain_buffer): 21 | """ 22 | pye_cli will always transform .py to .pyc and then encrypt it as .pye 23 | here want to test AES encryption, We should not convert it to .pyc. or it will chnage the text length to encryption. 24 | We try to encrypt by custom script to keep the text as original. 25 | """ 26 | executor_py = join(tmpdir, 'executor.py') 27 | plain_file = join(tmpdir, 'plain_buffer.text') 28 | encrypted_file = join(tmpdir, 'encrypted.text') 29 | 30 | # create executor py file 31 | with open(executor_py, "w") as f: 32 | executor_py_source = """ 33 | import sys 34 | import pyconcrete 35 | plain_buffer = sys.argv[1] 36 | encrypted = sys.argv[2] 37 | pyconcrete.encrypt_file(plain_buffer, encrypted) 38 | with open(encrypted, 'rb') as f: 39 | data = f.read() 40 | print(pyconcrete.decrypt_buffer(data).decode('utf-8')) 41 | """.strip() 42 | f.write(executor_py_source) 43 | 44 | # create plain file 45 | with open(plain_file, 'w') as f: 46 | f.write(plain_buffer) 47 | 48 | # run executor py file to encrypt as file and decrypt via buffer 49 | cmds = [venv.executable, executor_py, plain_file, encrypted_file] 50 | p = Popen(cmds, stdout=PIPE, stdin=PIPE, stderr=PIPE, text=True) 51 | stdout, stderr = p.communicate(input=plain_buffer) 52 | return stdout 53 | 54 | 55 | @pytest.mark.parametrize( 56 | "plain_buffer", 57 | [ 58 | # less than 1 AES block (16) 59 | "1", 60 | "12", 61 | "123", 62 | "12345", 63 | "12345678", 64 | # 1 AES block (16) 65 | "1234567890ABCDEF", 66 | # more than 1 AES block (16) 67 | "1234567890ABCDEF,\n" * 10, 68 | ], 69 | ) 70 | def test_encryption__aes_block_testing(venv, pye_cli, tmpdir, plain_buffer): 71 | # execution 72 | output = _encrypt_plain_buffer_and_decrypt(venv, tmpdir, plain_buffer) 73 | 74 | # verification 75 | assert output == (plain_buffer + '\n') # without output.strip() to make sure the output is exactly what we want 76 | -------------------------------------------------------------------------------- /tests/test_exe.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Falldog Hsieh 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import subprocess 15 | 16 | 17 | def test_exe__execute_an_non_exist_file(venv): 18 | return_code = subprocess.call([venv.pyconcrete_exe, 'non_existing_file.txt']) 19 | assert return_code == 1 20 | 21 | 22 | def test_exe__sys_path__should_contain_pye_file_dir(venv, pye_cli, tmpdir): 23 | # prepare 24 | pye_path = ( 25 | pye_cli.setup(tmpdir, 'test_sys_path') 26 | .source_code( 27 | """ 28 | import sys 29 | print('\\n'.join(sys.path)) 30 | """.strip() 31 | ) 32 | .get_encrypt_path() 33 | ) 34 | 35 | # execution 36 | output = venv.pyconcrete(pye_path) 37 | output = output.replace('\r\n', '\n') 38 | paths = output.split('\n') 39 | pye_file_dir = pye_cli.tmp_dir 40 | 41 | # verification 42 | assert pye_file_dir in paths, "the folder of pye-file should be contained in sys.path" 43 | 44 | 45 | def test_exe__sys_argv__first_arg_should_be_file_name(venv, pye_cli, tmpdir): 46 | # prepare 47 | pye_path = ( 48 | pye_cli.setup(tmpdir, 'test_sys_argv') 49 | .source_code( 50 | """ 51 | import sys 52 | print(" ".join(sys.argv)) 53 | """.strip() 54 | ) 55 | .get_encrypt_path() 56 | ) 57 | 58 | # execution 59 | output = venv.pyconcrete(pye_path) 60 | output = output.strip() 61 | 62 | # verification 63 | assert output == pye_path 64 | 65 | 66 | def test_exe__sys_argv__more_arguments(venv, pye_cli, tmpdir): 67 | # prepare 68 | pye_path = ( 69 | pye_cli.setup(tmpdir, 'test_sys_argv') 70 | .source_code( 71 | """ 72 | import sys 73 | print(" ".join(sys.argv)) 74 | """.strip() 75 | ) 76 | .get_encrypt_path() 77 | ) 78 | 79 | # execution 80 | output = venv.pyconcrete(pye_path, '-a', '-b', '-c') 81 | output = output.strip() 82 | 83 | # verification 84 | assert output == f'{pye_path} -a -b -c' 85 | 86 | 87 | def test_exe__import_pyconcrete__validate__file__(venv, pye_cli, tmpdir): 88 | # prepare 89 | pye_path = ( 90 | pye_cli.setup(tmpdir, 'test_import_pyconcrete') 91 | .source_code( 92 | """ 93 | import pyconcrete 94 | print(pyconcrete.__file__) 95 | """.strip() 96 | ) 97 | .get_encrypt_path() 98 | ) 99 | 100 | # execution 101 | output = venv.pyconcrete(pye_path) 102 | output = output.strip() 103 | pyconcrete__file__ = output 104 | 105 | # verification 106 | assert pyconcrete__file__.startswith(str(venv.env_dir)) 107 | -------------------------------------------------------------------------------- /tests/test_exe_testcases.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Falldog Hsieh 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import os 15 | import shutil 16 | import subprocess 17 | from dataclasses import dataclass 18 | from os.path import basename, isdir, join 19 | 20 | import pytest 21 | import yaml 22 | 23 | from .conftest import ROOT_DIR 24 | 25 | TEST_CASES_DIR = join(ROOT_DIR, 'tests', 'exe_testcases') 26 | MODULE_PREFIX = 'test_' 27 | MAIN_PY = 'main.py' 28 | MAIN_PYE = 'main.pye' 29 | EXPECTED_YAML = 'expected.yaml' 30 | 31 | 32 | @dataclass(frozen=True) 33 | class ExpectedConfig: 34 | return_code: int 35 | stdout: str 36 | is_ignore_stdout: bool 37 | 38 | 39 | def _is_valid_testcase_folder(sub_test_case_dir): 40 | module_path = sub_test_case_dir 41 | module_name = basename(module_path) 42 | 43 | if not isdir(module_path): 44 | return False 45 | if not module_name.startswith(MODULE_PREFIX): 46 | return False 47 | 48 | module_files = os.listdir(module_path) 49 | if (MAIN_PY not in module_files) or (EXPECTED_YAML not in module_files): 50 | return False 51 | 52 | return True 53 | 54 | 55 | def _discover_exe_testcases_folder() -> list: 56 | test_cases = [] 57 | for d in os.listdir(TEST_CASES_DIR): 58 | sub_test_case_dir = join(TEST_CASES_DIR, d) 59 | if _is_valid_testcase_folder(sub_test_case_dir): 60 | test_cases.append(sub_test_case_dir) 61 | return sorted(test_cases) 62 | 63 | 64 | def _read_expected_yaml(expected_yaml: str) -> ExpectedConfig: 65 | with open(join(expected_yaml), 'r') as f: 66 | data = yaml.safe_load(f) 67 | 68 | expected = data['expected'] 69 | config = ExpectedConfig( 70 | return_code=expected.get('return_code', 0), 71 | stdout=expected.get('stdout', ''), 72 | is_ignore_stdout=expected.get('is_ignore_stdout', False), 73 | ) 74 | return config 75 | 76 | 77 | @pytest.mark.parametrize( 78 | "sub_test_case_folder", 79 | _discover_exe_testcases_folder(), 80 | ) 81 | def test_exe__testcases(venv, tmpdir, sub_test_case_folder: str): 82 | """ 83 | Dynamic load testcases from tests/exe_testcases folder. 84 | 85 | Workflow process 86 | 1. Copy files to tmp dir 87 | 2. Encrypt .py to .pye 88 | 3. Execute main.pye by pyconcrete 89 | 4. Validate expected result by expected.yaml 90 | 91 | """ 92 | # prepare 93 | dest_dir = join(tmpdir, basename(sub_test_case_folder)) 94 | shutil.copytree(sub_test_case_folder, dest_dir) 95 | venv.pyconcrete_cli('compile', f'--source={dest_dir}', '--pye', '--remove-py', '--remove-pyc') 96 | 97 | # execution 98 | main_pye = join(dest_dir, MAIN_PYE) 99 | p = subprocess.Popen( 100 | [venv.pyconcrete_exe, main_pye], 101 | stdin=subprocess.DEVNULL, 102 | stdout=subprocess.PIPE, 103 | stderr=subprocess.STDOUT, 104 | ) 105 | output, error = p.communicate() 106 | output = output.decode() 107 | return_code = p.returncode 108 | 109 | # verification 110 | expected = _read_expected_yaml(join(dest_dir, EXPECTED_YAML)) 111 | 112 | assert type(expected.return_code) is int, f"type of `return_code` ({type(expected.return_code)}) is not int" 113 | assert expected.return_code == return_code 114 | 115 | if not expected.is_ignore_stdout: 116 | assert type(expected.stdout) is str, f"type of `stdout` ({type(expected.stdout)}) is not string" 117 | assert expected.stdout == output 118 | --------------------------------------------------------------------------------