Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ similar to `python3 -mcompileall -b` where `-b` does an in place compilation.
```python
from pyce import encrypt_path
encrypt_path('pyce/hello.pyc')
[('pyce/hello.pyce', '443df1d5f9914d13ed27950dd81aa2dd9d3b708be416c388f3226ad398d71a14')]
[('da78a5bfe655d01334d7121dc0f021de870dc11515424f528045eb5f29098504', 'd11d969ab1d345df86f4180db549f5ffc400da10d03d43e1fa93eae373199dae')]
```

Second, register your keys and try importing from the encrypted module or
package:

```python
from pyce import PYCEPathFinder
PYCEPathFinder.KEYS = {'pyce/hello.pyce' : '443df1d5f9914d13ed27950dd81aa2dd9d3b708be416c388f3226ad398d71a14'}
PYCEPathFinder.KEYS = {'da78a5bfe655d01334d7121dc0f021de870dc11515424f528045eb5f29098504': 'd11d969ab1d345df86f4180db549f5ffc400da10d03d43e1fa93eae373199dae'}

import sys
sys.meta_path.insert(0, PYCEPathFinder)
Expand Down
23 changes: 16 additions & 7 deletions pyce/_crypto.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
Example use:

>>> from pyce.crypto import encrypt_path, decryptf
>>> path, key = encrypt_path('pyce/hello.pyc')[0]
>>> print(decryptf(path, key))
>>> hash, key = encrypt_path('pyce/hello.pyc')[0]
>>> print(decryptf('pyce/hello.pyce', key))
"""


Expand Down Expand Up @@ -79,7 +79,7 @@ def encrypt_path(path: str, extensions: Set[str] = ENC_EXT, exclusions:
exclusions: files that should not be encrypted

Returns:
List of all paths and their encryption key
List of hashes of all encrypted files with their encryption key
"""
if exclusions is None:
exclusions = set()
Expand Down Expand Up @@ -118,8 +118,8 @@ def encrypt_path(path: str, extensions: Set[str] = ENC_EXT, exclusions:
data = openf.read()

# hash
hashv = srchash(data)
key = hashv.digest()
plaintext_hash = srchash(data)
key = plaintext_hash.digest()

# encrypt
cipher = Cipher(CIPHER(key), MODE(key[0:16]), backend=BACKEND)
Expand All @@ -131,12 +131,21 @@ def encrypt_path(path: str, extensions: Set[str] = ENC_EXT, exclusions:
openf.write(ciphertext)

# append HMAC
openf.write(hmac(key, ciphertext, HMAC_HS).digest())
ciphertext_hmac = hmac(key, ciphertext, HMAC_HS).digest()
openf.write(ciphertext_hmac)

new_absolute_path, ext = splitext(absolute_path)
new_absolute_path += ext + 'e'
rename(absolute_path, new_absolute_path)
manifest.append((new_absolute_path, hashv.hexdigest()))

# add the decryption key for this file together with a hash of its
# encrypted contents. The import mechanism will then look up the
# required key by producing this same hash again at runtime.
encrypted_data = ciphertext + ciphertext_hmac
ciphertext_hash = srchash(encrypted_data)
manifest.append(
(ciphertext_hash.hexdigest(), plaintext_hash.hexdigest())
)

return manifest

Expand Down
9 changes: 5 additions & 4 deletions pyce/_imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@
_classify_pyc)
from importlib.machinery import (FileFinder, ModuleSpec, PathFinder,
SourcelessFileLoader)
from os.path import normcase, relpath
from typing import Any, Dict, List, Optional, Tuple

from pyce._crypto import decrypt
from pyce._crypto import decrypt, srchash

# Globals
EXTENSIONS = ['.pyce']
Expand Down Expand Up @@ -69,8 +68,10 @@ def get_code(self, fullname: str) -> Any:
path = self.get_filename(fullname)
data = self.get_data(path)

# It is important to normalize path case for platforms like Windows
data = decrypt(data, PYCEPathFinder.KEYS[normcase(relpath(path))])
# Decrypt the code. Use a hash of the encrypted data to look up the
# required encryption key.
data_hash = srchash(data).hexdigest()
data = decrypt(data, PYCEPathFinder.KEYS[data_hash])

# Call _classify_pyc to do basic validation of the pyc but ignore the
# result. There's no source to check against.
Expand Down