mirror of
https://github.com/TeamPGM/tgcrypto.git
synced 2024-11-28 18:19:24 +00:00
171 lines
4.6 KiB
Markdown
171 lines
4.6 KiB
Markdown
# TgCrypto
|
|
|
|
<img src="https://i.imgur.com/JyxrStE.png" width="160" align="right">
|
|
|
|
> Fast and Portable Telegram Crypto Library for Python
|
|
|
|
**TgCrypto** is a Telegram Crypto Library written in C89 as a Python extension. It is designed to be portable, fast, easy
|
|
to install and use. TgCrypto is intended for [Pyrogram](https://github.com/pyrogram/pyrogram) and implements the crypto
|
|
algorithms Telegram requires, namely:
|
|
|
|
- **`AES256-IGE`** - used in [MTProto v2.0](https://core.telegram.org/mtproto).
|
|
- **`AES256-CTR`** - used for [CDN encrypted files](https://core.telegram.org/cdn).
|
|
- **`AES256-CBC`** - used for [encrypted passport credentials](https://core.telegram.org/passport).
|
|
|
|
Python [wheels are available](https://pypi.org/project/TgCrypto/#files) for hassle-free installations; they are
|
|
automatically built and tested using Travis CI for Linux (i686, x86_64, AArch64), Windows (32-bit, 64-bit) and macOS
|
|
(x86_64).
|
|
|
|
Even though TgCrypto is primarily intended for use with Pyrogram, you are free and welcome to use it for any other
|
|
Python project too, as it's shipped as standalone package.
|
|
|
|
More info: https://docs.pyrogram.org/topics/tgcrypto
|
|
|
|
## Requirements
|
|
|
|
- Python 3.6 or higher.
|
|
|
|
## Installation
|
|
|
|
``` bash
|
|
$ pip3 install -U tgcrypto
|
|
```
|
|
|
|
## API
|
|
|
|
TgCrypto API consists of these six methods:
|
|
|
|
```python
|
|
def ige256_encrypt(data: bytes, key: bytes, iv: bytes) -> bytes: ...
|
|
def ige256_decrypt(data: bytes, key: bytes, iv: bytes) -> bytes: ...
|
|
|
|
def ctr256_encrypt(data: bytes, key: bytes, iv: bytes, state: bytes) -> bytes: ...
|
|
def ctr256_decrypt(data: bytes, key: bytes, iv: bytes, state: bytes) -> bytes: ...
|
|
|
|
def cbc256_encrypt(data: bytes, key: bytes, iv: bytes) -> bytes: ...
|
|
def cbc256_decrypt(data: bytes, key: bytes, iv: bytes) -> bytes: ...
|
|
```
|
|
|
|
## Usage
|
|
|
|
### IGE Mode
|
|
|
|
**Note**: Data must be padded to match a multiple of the block size (16 bytes).
|
|
|
|
``` python
|
|
import os
|
|
|
|
import tgcrypto
|
|
|
|
data = os.urandom(10 * 1024 * 1024 + 7) # 10 MB of random data + 7 bytes to show padding
|
|
key = os.urandom(32) # Random Key
|
|
iv = os.urandom(32) # Random IV
|
|
|
|
# Pad with zeroes: -7 % 16 = 9
|
|
data += bytes(-len(data) % 16)
|
|
|
|
ige_encrypted = tgcrypto.ige256_encrypt(data, key, iv)
|
|
ige_decrypted = tgcrypto.ige256_decrypt(ige_encrypted, key, iv)
|
|
|
|
print(data == ige_decrypted) # True
|
|
```
|
|
|
|
### CTR Mode (single chunk)
|
|
|
|
``` python
|
|
import os
|
|
|
|
import tgcrypto
|
|
|
|
data = os.urandom(10 * 1024 * 1024) # 10 MB of random data
|
|
|
|
key = os.urandom(32) # Random Key
|
|
|
|
enc_iv = bytearray(os.urandom(16)) # Random IV
|
|
dec_iv = enc_iv.copy() # Keep a copy for decryption
|
|
|
|
ctr_encrypted = tgcrypto.ctr256_encrypt(data, key, enc_iv, bytes(1))
|
|
ctr_decrypted = tgcrypto.ctr256_decrypt(ctr_encrypted, key, dec_iv, bytes(1))
|
|
|
|
print(data == ctr_decrypted) # True
|
|
```
|
|
|
|
### CTR Mode (stream)
|
|
|
|
``` python
|
|
import os
|
|
from io import BytesIO
|
|
|
|
import tgcrypto
|
|
|
|
data = BytesIO(os.urandom(10 * 1024 * 1024)) # 10 MB of random data
|
|
|
|
key = os.urandom(32) # Random Key
|
|
|
|
enc_iv = bytearray(os.urandom(16)) # Random IV
|
|
dec_iv = enc_iv.copy() # Keep a copy for decryption
|
|
|
|
enc_state = bytes(1) # Encryption state, starts from 0
|
|
dec_state = bytes(1) # Decryption state, starts from 0
|
|
|
|
encrypted_data = BytesIO() # Encrypted data buffer
|
|
decrypted_data = BytesIO() # Decrypted data buffer
|
|
|
|
while True:
|
|
chunk = data.read(1024)
|
|
|
|
if not chunk:
|
|
break
|
|
|
|
# Write 1K encrypted bytes into the encrypted data buffer
|
|
encrypted_data.write(tgcrypto.ctr256_encrypt(chunk, key, enc_iv, enc_state))
|
|
|
|
# Reset position. We need to read it now
|
|
encrypted_data.seek(0)
|
|
|
|
while True:
|
|
chunk = encrypted_data.read(1024)
|
|
|
|
if not chunk:
|
|
break
|
|
|
|
# Write 1K decrypted bytes into the decrypted data buffer
|
|
decrypted_data.write(tgcrypto.ctr256_decrypt(chunk, key, dec_iv, dec_state))
|
|
|
|
print(data.getvalue() == decrypted_data.getvalue()) # True
|
|
```
|
|
|
|
### CBC Mode
|
|
|
|
**Note**: Data must be padded to match a multiple of the block size (16 bytes).
|
|
|
|
``` python
|
|
import os
|
|
|
|
import tgcrypto
|
|
|
|
data = os.urandom(10 * 1024 * 1024 + 7) # 10 MB of random data + 7 bytes to show padding
|
|
key = os.urandom(32) # Random Key
|
|
|
|
enc_iv = bytearray(os.urandom(16)) # Random IV
|
|
dec_iv = enc_iv.copy() # Keep a copy for decryption
|
|
|
|
# Pad with zeroes: -7 % 16 = 9
|
|
data += bytes(-len(data) % 16)
|
|
|
|
cbc_encrypted = tgcrypto.cbc256_encrypt(data, key, enc_iv)
|
|
cbc_decrypted = tgcrypto.cbc256_decrypt(cbc_encrypted, key, dec_iv)
|
|
|
|
print(data == cbc_decrypted) # True
|
|
```
|
|
|
|
## Testing
|
|
|
|
1. Clone this repository: `git clone https://github.com/pyrogram/tgcrypto`.
|
|
2. Enter the directory: `cd tgcrypto`.
|
|
3. Run tests: `python3 setup.py test`.
|
|
|
|
## License
|
|
|
|
[LGPLv3+](COPYING.lesser) © 2017-2020 [Dan](https://github.com/delivrance)
|