rencrypt


Namerencrypt JSON
Version 1.0.7 PyPI version JSON
download
home_pageNone
SummaryA Python encryption library implemented in Rust. It supports AEAD with various ciphers. It uses multiple providers to handle encryption.
upload_time2024-06-22 03:15:23
maintainerNone
docs_urlNone
authorNone
requires_python>=3.7
licenseNone
keywords cryptography encryption security rust speed aead cipher
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # rencrypt

[![PyPI version](https://badge.fury.io/py/rencrypt.svg)](https://badge.fury.io/py/rencrypt)
[![CI](https://github.com/radumarias/rencrypt-python/actions/workflows/CI.yml/badge.svg)](https://github.com/radumarias/rencrypt-python/actions/workflows/CI.yml)

> [!WARNING]  
> **This crate hasn't been audited, but it's mostly a wrapper over several libs like `ring` (well known and audited library),`RustCrypto` (`AES-GCM` and `ChaCha20Poly1305` ciphers are audited) but also others which are NOT audited, so in principle at least the primitives should offer a similar level of security.**

A Python encryption library implemented in Rust. It supports `AEAD` with varius ciphers. It uses [ring](https://crates.io/crates/ring), [RustCrypto](https://crates.io/crates/aead) (and derivates), [sodiumoxide](https://crates.io/crates/sodiumoxide) and [orion](https://crates.io/crates/orion) to handle encryption.  
If offers slightly higher speed compared to other Python libs, especially for small chunks of data (especially the `Ring` provider with `AES-GCM` ciphers). The API also tries to be easy to use but it's more optimized for speed than usability.

So if you want to use a vast variaety of ciphers and/or achieve the highest possible encryption speed, consider giving it a try.

# Benchmark

Some benchmarks comparing it to [PyFLocker](https://github.com/arunanshub/pyflocker) which from my benchmarks is the fastest among other Python libs like `cryptography`, `NaCl` (`libsodium`), `PyCryptodome`.

## Buffer in memory

This is useful when you keep a buffer, set your plaintext/ciphertext in there, and then encrypt/decrypt in-place in that buffer. This is the most performant way to use it, because it does't copy any bytes nor allocate new memory.  
`rencrypt` is faster on small buffers, less than few MB, `PyFLocker` is comming closer for larger buffers.

**Encrypt seconds**  
![Encrypt buffer](https://github.com/radumarias/rencrypt-python/blob/main/resources/charts/encrypt.png?raw=true)

**Decrypt seconds**  
![Decrypt buffer](https://github.com/radumarias/rencrypt-python/blob/main/resources/charts/decrypt.png?raw=true)


**Block size and duration in seconds**

<table>
    <thead>
        <tr>
            <th>MB</th>
            <th>rencrypt<br>encrypt</th>
            <th>PyFLocker<br>encrypt</th>
            <th>rencrypt<br>decrypt</th>
            <th>PyFLocker<br>decrypt</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>0.03125</td>
            <td>0.00001</td>
            <td>0.00091</td>
            <td>0.00001</td>
            <td>0.00004</td>
        </tr>
        <tr>
            <td>0.0625</td>
            <td>0.00001</td>
            <td>0.00005</td>
            <td>0.00001</td>
            <td>0.00004</td>
        </tr>
        <tr>
            <td>0.125</td>
            <td>0.00002</td>
            <td>0.00005</td>
            <td>0.00003</td>
            <td>0.00005</td>
        </tr>
        <tr>
            <td>0.25</td>
            <td>0.00004</td>
            <td>0.00008</td>
            <td>0.00005</td>
            <td>0.00009</td>
        </tr>
        <tr>
            <td>0.5</td>
            <td>0.00010</td>
            <td>0.00014</td>
            <td>0.00011</td>
            <td>0.00015</td>
        </tr>
        <tr>
            <td>1</td>
            <td>0.00021</td>
            <td>0.00024</td>
            <td>0.00021</td>
            <td>0.00029</td>
        </tr>
        <tr>
            <td>2</td>
            <td>0.00043</td>
            <td>0.00052</td>
            <td>0.00044</td>
            <td>0.00058</td>
        </tr>
        <tr>
            <td>4</td>
            <td>0.00089</td>
            <td>0.00098</td>
            <td>0.00089</td>
            <td>0.00117</td>
        </tr>
        <tr>
            <td>8</td>
            <td>0.00184</td>
            <td>0.00190</td>
            <td>0.00192</td>
            <td>0.00323</td>
        </tr>
        <tr>
            <td>16</td>
            <td>0.00353</td>
            <td>0.00393</td>
            <td>0.00367</td>
            <td>0.00617</td>
        </tr>
        <tr>
            <td>32</td>
            <td>0.00678</td>
            <td>0.00748</td>
            <td>0.00749</td>
            <td>0.01348</td>
        </tr>
        <tr>
            <td>64</td>
            <td>0.01361</td>
            <td>0.01461</td>
            <td>0.01460</td>
            <td>0.02697</td>
        </tr>
        <tr>
            <td>128</td>
            <td>0.02923</td>
            <td>0.03027</td>
            <td>0.03134</td>
            <td>0.05410</td>
        </tr>
        <tr>
            <td>256</td>
            <td>0.06348</td>
            <td>0.06188</td>
            <td>0.06136</td>
            <td>0.10417</td>
        </tr>
        <tr>
            <td>512</td>
            <td>0.11782</td>
            <td>0.13463</td>
            <td>0.12090</td>
            <td>0.21114</td>
        </tr>
        <tr>
            <td>1024</td>
            <td>0.25001</td>
            <td>0.24953</td>
            <td>0.25377</td>
            <td>0.42581</td>
        </tr>
    </tbody>
</table>

## File

**Encrypt seconds**  
![Encrypt file](https://github.com/radumarias/rencrypt-python/blob/main/resources/charts/encrypt-file.png?raw=true)

 **Decrypt seconds**  
![Decrypt buffer](https://github.com/radumarias/rencrypt-python/blob/main/resources/charts/decrypt-file.png?raw=true)

**File size and duration in seconds**

<table>
    <thead>
        <tr>
            <th>MB</th>
            <th>rencrypt<br>encrypt</th>
            <th>PyFLocker<br>encrypt</th>
            <th>rencrypt<br>decrypt</th>
            <th>PyFLocker<br>decrypt</th>
        </tr>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>0.031251</td>
            <td>0.00010</td>
            <td>0.00280</td>
            <td>0.00004</td>
            <td>0.00479</td>
        </tr>
        <tr>
            <td>0.062501</td>
            <td>0.00009</td>
            <td>0.00218</td>
            <td>0.00005</td>
            <td>0.00143</td>
        </tr>
        <tr>
            <td>0.125</td>
            <td>0.00020</td>
            <td>0.00212</td>
            <td>0.00014</td>
            <td>0.00129</td>
        </tr>
        <tr>
            <td>0.25</td>
            <td>0.00034</td>
            <td>0.00232</td>
            <td>0.00020</td>
            <td>0.00165</td>
        </tr>
        <tr>
            <td>0.5</td>
            <td>0.00050</td>
            <td>0.00232</td>
            <td>0.00035</td>
            <td>0.00181</td>
        </tr>
        <tr>
            <td>1</td>
            <td>0.00087</td>
            <td>0.00356</td>
            <td>0.00065</td>
            <td>0.00248</td>
        </tr>
        <tr>
            <td>2</td>
            <td>0.00215</td>
            <td>0.00484</td>
            <td>0.00154</td>
            <td>0.00363</td>
        </tr>
        <tr>
            <td>4</td>
            <td>0.00361</td>
            <td>0.00765</td>
            <td>0.00301</td>
            <td>0.00736</td>
        </tr>
        <tr>
            <td>8</td>
            <td>0.00688</td>
            <td>0.01190</td>
            <td>0.00621</td>
            <td>0.00876</td>
        </tr>
        <tr>
            <td>16</td>
            <td>0.01503</td>
            <td>0.02097</td>
            <td>0.01202</td>
            <td>0.01583</td>
        </tr>
        <tr>
            <td>32</td>
            <td>0.02924</td>
            <td>0.03642</td>
            <td>0.02563</td>
            <td>0.02959</td>
        </tr>
        <tr>
            <td>64</td>
            <td>0.05737</td>
            <td>0.06473</td>
            <td>0.04431</td>
            <td>0.05287</td>
        </tr>
        <tr>
            <td>128</td>
            <td>0.11098</td>
            <td>0.12646</td>
            <td>0.08944</td>
            <td>0.09926</td>
        </tr>
        <tr>
            <td>256</td>
            <td>0.22964</td>
            <td>0.24716</td>
            <td>0.17402</td>
            <td>0.19420</td>
        </tr>
        <tr>
            <td>512</td>
            <td>0.43506</td>
            <td>0.46444</td>
            <td>0.38143</td>
            <td>0.38242</td>
        </tr>
        <tr>
            <td>1024</td>
            <td>0.97147</td>
            <td>0.95803</td>
            <td>0.78137</td>
            <td>0.87363</td>
        </tr>
        <tr>
            <td>2048</td>
            <td>2.07143</td>
            <td>2.10766</td>
            <td>1.69471</td>
            <td>2.99210</td>
        </tr>
        <tr>
            <td>4096</td>
            <td>4.85395</td>
            <td>4.69722</td>
            <td>5.40580</td>
            <td>8.73779</td>
        </tr>
        <tr>
            <td>8192</td>
            <td>10.76984</td>
            <td>11.76741</td>
            <td>10.29253</td>
            <td>21.00636</td>
        </tr>
        <tr>
            <td>16384</td>
            <td>21.84490</td>
            <td>26.27385</td>
            <td>39.56230</td>
            <td>43.55530</td>
        </tr>
    </tbody>
</table>

# Usage

There are two ways in which you can use the lib, the first one is a bit faster, the second offers a bit more flexible way to use it sacrificing a bit of performance.

1. **With a buffer in memory**: using `seal_in_place()`/`open_in_place()`, is useful when you keep a buffer (or have it from somewhere), set your plaintext/ciphertext in there, and then encrypt/decrypt in-place in that buffer. This is the most performant way to use it, because it does't copy any bytes nor allocate new memory.  
**The buffer has to be a `numpy array`**, so that it's easier for you to collect data with slices that reference to underlying data. This is because the whole buffer needs to be the size of ciphertext (which is plaintext_len + tag_len + nonce_len) but you may pass a slice of the buffer to a BufferedReader to `read_into()` the plaintext.  
If you can directly collect the data to that buffer, like `BufferedReader.read_into()`, **this is the preffered way to go**.
2. **From some bytes into the buffer**: using `seal_in_place_from()`/`open_in_place_from()`, when you have some arbitrary data that you want to work with. It will first copy those bytes to the buffer then do the operation in-place in the buffer. This is a bit slower, especially for large data, because it first needs to copy the bytes to the buffer.

`block_index`, `aad` and `nonce` are optional.

If `nonce` is not provided, on each encrypt operation (`seal_in_place*()`) it will generate a cryptographically secure random nonce using `ChaCha20`. You can also provide your own nonce, there is an example below.

# Security

- **The total number of invocations of the encryption functions (`seal_in_place*()`) shall not exceed `2^32`, including all nonce lengths and all instances of `Cipher` with the given key. Following this guideline, only `4,294,967,296` messages with random nonces can be encrypted under a given key. While this bound is high, it's possible to encounter in practice, and systems which might reach it should consider alternatives to purely random nonces, like a counter or a combination of a random nonce + counter.**
- **When encrypting more than one block you should provide `block_index` as it's more secure because it ensures the order of the blocks was not changed in ciphertext.**
- **When you encrypt files it's more secure to generate a random number per file and include that in AAD, this will prevent ciphertext blocks from being swapped between files.**
- **For security reasons it's a good practice to lock the memory with `mlock()` in which you keep sensitive data like passwords or encrryption keys, or any other plaintext sensitive content. Also it's important to zeroize the data when not used anymore.**  
- **In the case of [Copy-on-write fork](https://en.wikipedia.org/wiki/Copy-on-write) you need to zeroize the memory before forking the child process.**  

In the examples below you will see how to do it.

# Encryption providers and algorithms (ciphers)

You will notice in the examples we create the `Cipher` from something like this `cipher_meta = CipherMeta.Ring(RingAlgorithm.Aes256Gcm)`. The first part `CipherMeta.Ring` is the encryption provider. The last part is the algorithm for that provider, in this case `Aes256Gcm`. Each provier might expose specific algorithms.

## Providers

```rust
enum CipherMeta {
    Ring { alg: RingAlgorithm },
    RustCrypto { alg: RustCryptoAlgorithm },
    Sodiumoxide { alg: SodiumoxideAlgorithm },
    Orion { alg: OrionAlgorithm },
}
```

- `Ring`: Based on [ring](https://crates.io/crates/ring) crate. ring is focused on the implementation, testing, and optimization of a core set of cryptographic operations exposed via an easy-to-use (and hard-to-misuse) API. ring exposes a Rust API and is written in a hybrid of Rust, C, and assembly language.  
  Particular attention is being paid to making it easy to build and integrate ring into applications and higher-level frameworks, and to ensuring that ring works optimally on small devices, and eventually microcontrollers, to support Internet of Things (IoT) applications.  
  Most of the C and assembly language code in ring comes from BoringSSL, and BoringSSL is derived from OpenSSL. ring merges changes from BoringSSL regularly. Also, several changes that were developed for ring have been contributed to and integrated into BoringSSL.
- `RustCrypto`: Based on [RustCrypto](https://github.com/RustCrypto/AEADs) collection of Authenticated Encryption with Associated Data (AEAD) algorithms written in pure Rust. AEADs are high-level symmetric encryption primitives which defend against a wide range of potential attacks (i.e. IND-CCA3).
- `Sodiumoxide`: Based on [sodiumoxide](https://crates.io/crates/sodiumoxide) crate which aims to provide a type-safe and efficient Rust binding that's just as easy to use.  
  [`NaCl`](https://nacl.cr.yp.to) (pronounced "salt") is a new easy-to-use high-speed software library for network communication, encryption, decryption, signatures, etc. NaCl's goal is to provide all of the core operations needed to build higher-level cryptographic tools. Of course, other libraries already exist for these core operations. NaCl advances the state of the art by improving security, by improving usability, and by improving speed.  
  [Sodium](https://github.com/jedisct1/libsodium) is a portable, cross-compilable, installable, packageable fork of NaCl (based on the latest released upstream version nacl-20110221), with a compatible API.
- `Orion`: Based on [orion](https://crates.io/crates/orion) crate. Written in pure Rust, it aims to provide easy and usable crypto while trying to minimize the use of unsafe code. You can read more about Orion in the [wiki](https://github.com/orion-rs/orion/wiki).

## Algorithms

```rust
enum RingAlgorithm {
    ChaCha20Poly1305,
    Aes128Gcm,
    Aes256Gcm,
}
```

```rust
enum RustCryptoAlgorithm {
    ChaCha20Poly1305,
    XChaCha20Poly1305,
    Aes128Gcm,
    Aes256Gcm,
    Aes128GcmSiv,
    Aes256GcmSiv,
    Aes128Siv,
    Aes256Siv,
    Ascon128,
    Ascon128a,
    Ascon80pq,
    DeoxysI128,
    DeoxysI256,
    DeoxysII128,
    DeoxysII256,
    Aes128Eax,
    Aes256Eax,
}
```

```rust
enum SodiumoxideAlgorithm {
    ChaCha20Poly1305,
    ChaCha20Poly1305Ieft,
    XChaCha20Poly1305Ieft,
}
```

```rust
enum OrionAlgorithm {
    ChaCha20Poly1305,
    XChaCha20Poly1305,
}
```

## Audited

**Only for `Aes128Gcm`, `Aes256Gcm` and `ChaCha20Poly1305` with `Ring` and `RustCrypto` providers underlying crates have been audited.**

- [`Aes128Gcm`/`Aes256Gcm`](https://datatracker.ietf.org/doc/html/rfc5288): If you have hardware acceleration (e.g. `AES-NI`), then `AES-GCM` provides better performance. If you do not have a hardware acceleration, `AES-GCM` is either slower than `ChaCha20Poly1305`, or it leaks your encryption keys in cache timing. With `RustCrypto` provider the underlying `aes-gcm` has received one security audit by NCC Group, with no significant findings. With `Ring` provider the underlying `ring` crate was also audited.
- [`ChaCha20Poly1305`](https://en.wikipedia.org/wiki/ChaCha20-Poly1305): Is notable for being simple and fast when implemented in pure software. The underlying `ChaCha20` stream cipher uses a simple combination of `add`, `rotate`, and `XOR` instructions (a.k.a. `"ARX"`), and the `Poly1305` hash function is likewise extremely simple. With `RustCrypto` provider the underlying `chacha20poly1305` has received one security audit by NCC Group, with no significant findings. With `Ring` provider the underlying `ring` crtate was also audited.
  If you do not have a hardware acceleration, `ChaCha20Poly1305` is faster than `AES-GCM`.
  While it hasn't received approval from certain standards bodies (i.e. NIST) the algorithm is widely used and deployed. Notably it's mandatory to implement in the Transport Layer Security (TLS) protocol. The underlying `ChaCha20` cipher is also widely used as a cryptographically secure random number generator, including internal use by the Rust standard library.
- [`XChaCha20Poly1305`](https://en.wikipedia.org/wiki/ChaCha20-Poly1305#XChaCha20-Poly1305_%E2%80%93_extended_nonce_variant): A variant of `ChaCha20Poly1305` with an extended 192-bit (24-byte) nonce.

## Not audited

**USE AT YOUR OWN RISK!**

- [`Aes128GcmSiv` / `Aes256GcmSiv`](https://en.wikipedia.org/wiki/AES-GCM-SIV): Provides nonce reuse misuse resistance. Suitable as a general purpose symmetric encryption cipher, `AES-GCM-SIV` also removes many of the "sharp edges" of `AES-GCM`, providing significantly better security bounds while simultaneously eliminating the most catastrophic risks of nonce reuse that exist in `AES-GCM`. Decryption performance is equivalent to `AES-GCM`. Encryption is marginally slower.
- [`Aes128Siv` / `Aes256Siv`](https://github.com/miscreant/meta/wiki/AES-SIV): Cipher which also provides nonce reuse misuse resistance.
- [`Ascon128` / `Ascon128a` / `Ascon80pq`](https://ascon.iaik.tugraz.at): Designed to be lightweight and easy to implement, even with added countermeasures against side-channel attacks. Ascon has been selected as new standard for lightweight cryptography in the NIST Lightweight Cryptography competition (2019–2023). Ascon has also been selected as the primary choice for lightweight authenticated encryption in the final portfolio of the CAESAR competition (2014–2019).
- [`Deoxys`](https://sites.google.com/view/deoxyscipher): Based on a 128-bit lightweight ad-hoc tweakable block cipher. It may be used in two modes to handle nonce-respecting users (`Deoxys-I`) or nonce-reusing user (`Deoxys-II`). `Deoxys-II` has been selected as first choice for the "in-depth security" portfolio of the `CAESAR` competition.
- [`Aes128Eax` / `Aes256Eax`](https://en.wikipedia.org/wiki/EAX_mode): Designed with a two-pass scheme, one pass for achieving privacy and one for authenticity for each block. `EAX` mode was submitted on October 3, 2003, to the attention of NIST in order to replace `CCM` as standard `AEAD` mode of operation, since `CCM` mode lacks some desirable attributes of `EAX` and is more complex.
- For `Sodiumoxide` provider [`ChaCha20Poly1305`](https://libsodium.gitbook.io/doc/secret-key_cryptography/aead/chacha20-poly1305/original_chacha20-poly1305_construction): The original `ChaCha20-Poly1305` construction can safely encrypt a pratically unlimited number of messages with the same key, without any practical limit to the size of a message (up to ~ 2^64 bytes).
- For `Sodiumoxide` provider [`ChaChaCha20Poly1305Ieft`](https://libsodium.gitbook.io/doc/secret-key_cryptography/aead/chacha20-poly1305/ietf_chacha20-poly1305_construction): The IETF variant of the `ChaCha20-Poly1305` construction can safely encrypt a practically unlimited number of messages, but individual messages cannot exceed 64*(2^32)-64 bytes (approximatively 256 GB).

# Examples

You can see more in [examples](https://github.com/radumarias/rencrypt-python/tree/main/examples) directory and in [bench.py](https://github.com/radumarias/rencrypt-python/tree/main/bench.py) which has some benchmarks. Here are few simple examples:

## Encrypt and decrypt with a buffer in memory

`seal_in_place()`/`open_in_place()`

This is the most performant way to use it as it will not copy bytes to the buffer nor allocate new memory for plaintext and ciphertext.

```python
from rencrypt import Cipher, CipherMeta, RingAlgorithm
import os
from zeroize import zeroize1, mlock, munlock
import numpy as np


if __name__ == "__main__":
    try:
        # You can use also other algorithms like cipher_meta = CipherMeta.Ring(RingAlgorithm.ChaCha20Poly1305)`.
        cipher_meta = CipherMeta.Ring(RingAlgorithm.Aes256Gcm)
        key_len = cipher_meta.key_len()
        key = bytearray(key_len)
        # for security reasons we lock the memory of the key so it won't be swapped to disk
        mlock(key)
        cipher_meta.generate_key(key)
        # The key is copied and the input key is zeroized for security reasons.
        # The copied key will also be zeroized when the object is dropped.
        cipher = Cipher(cipher_meta, key)
        # it was zeroized we can unlock it
        munlock(key)

        # we create a buffer based on plaintext block len of 4096
        # the actual buffer needs to be a bit larger as the ciphertext also includes the tag and nonce
        plaintext_len = 4096
        ciphertext_len = cipher_meta.ciphertext_len(plaintext_len)
        buf = np.array([0] * ciphertext_len, dtype=np.uint8)
        # for security reasons we lock the memory of the buffer so it won't be swapped to disk, because it contains plaintext after decryption
        mlock(buf)

        aad = b"AAD"

        # put some plaintext in the buffer, it would be ideal if you can directly collect the data into the buffer without allocating new memory
        # but for the sake of example we will allocate and copy the data
        plaintext = bytearray(os.urandom(plaintext_len))
        # for security reasons we lock the memory of the plaintext so it won't be swapped to disk
        mlock(plaintext)
        # cipher.copy_slice is slighlty faster than buf[:plaintext_len] = plaintext, especially for large plaintext, because it copies the data in parallel
        # cipher.copy_slice takes bytes as input, cipher.copy_slice1 takes bytearray
        cipher.copy_slice(plaintext, buf)
        # encrypt it, this will encrypt in-place the data in the buffer
        print("encryping...")
        ciphertext_len = cipher.seal_in_place(buf, plaintext_len, 42, aad)
        cipertext = buf[:ciphertext_len]
        # you can do something with the ciphertext

        # decrypt it
        # if you need to copy ciphertext to buffer, we don't need to do it now as it's already in the buffer
        # cipher.copy_slice(ciphertext, buf[:len(ciphertext)])
        print("decryping...")
        plaintext_len = cipher.open_in_place(buf, ciphertext_len, 42, aad)
        plaintext2 = buf[:plaintext_len]
        # for security reasons we lock the memory of the plaintext so it won't be swapped to disk
        mlock(plaintext2)
        assert plaintext == plaintext2

    finally:
        # best practice, you should always zeroize the plaintext and keys after you are done with it (key will be zeroized when the enc object is dropped)
        zeroize1(plaintext)
        zeroize1(buf)

        munlock(buf)
        munlock(plaintext)

        print("bye!")
```

You can use other ciphers like `cipher_meta = CipherMeta.Ring(RingAlgorithm.ChaCha20Poly1305)`.

You can also provide your own nonce that you can generate based on your contraints.

```python
from rencrypt import Cipher, CipherMeta, RingAlgorithm
import os
from zeroize import zeroize1, mlock, munlock
import numpy as np


if __name__ == "__main__":
    try:
        # You can use also other algorithms like cipher_meta = CipherMeta.Ring(RingAlgorithm.ChaCha20Poly1305)`.
        cipher_meta = CipherMeta.Ring(RingAlgorithm.Aes256Gcm)
        key_len = cipher_meta.key_len()
        key = bytearray(key_len)
        # for security reasons we lock the memory of the key so it won't be swapped to disk
        mlock(key)
        cipher_meta.generate_key(key)
        # The key is copied and the input key is zeroized for security reasons.
        # The copied key will also be zeroized when the object is dropped.
        cipher = Cipher(cipher_meta, key)
        # it was zeroized we can unlock it
        munlock(key)

        # we create a buffer based on plaintext block len of 4096
        # the actual buffer needs to be a bit larger as the ciphertext also includes the tag and nonce
        plaintext_len = 4096
        ciphertext_len = cipher_meta.ciphertext_len(plaintext_len)
        buf = np.array([0] * ciphertext_len, dtype=np.uint8)
        # for security reasons we lock the memory of the buffer so it won't be swapped to disk, because it contains plaintext after decryption
        mlock(buf)

        aad = b"AAD"
        # create our own nonce
        nonce = os.urandom(cipher_meta.nonce_len())

        # put some plaintext in the buffer, it would be ideal if you can directly collect the data into the buffer without allocating new memory
        # but for the sake of example we will allocate and copy the data
        plaintext = bytearray(os.urandom(plaintext_len))
        # for security reasons we lock the memory of the plaintext so it won't be swapped to disk
        mlock(plaintext)
        # cipher.copy_slice is slighlty faster than buf[:plaintext_len] = plaintext, especially for large plaintext, because it copies the data in parallel
        # cipher.copy_slice takes bytes as input, cipher.copy_slice1 takes bytearray
        cipher.copy_slice(plaintext, buf)
        # encrypt it, this will encrypt in-place the data in the buffer
        # provide our own nonce
        print("encryping...")
        ciphertext_len = cipher.seal_in_place(buf, plaintext_len, 42, aad, nonce)
        cipertext = buf[:ciphertext_len]
        # you can do something with the ciphertext

        # decrypt it
        # if you need to copy ciphertext to buffer, we don't need to do it now as it's already in the buffer
        # cipher.copy_slice(ciphertext, buf[:len(ciphertext)])
        print("decryping...")
        plaintext_len = cipher.open_in_place(buf, ciphertext_len, 42, aad)
        plaintext2 = buf[:plaintext_len]
        # for security reasons we lock the memory of the plaintext so it won't be swapped to disk
        mlock(plaintext2)
        assert plaintext == plaintext2

    finally:
        # best practice, you should always zeroize the plaintext and keys after you are done with it (key will be zeroized when the enc object is dropped)
        zeroize1(plaintext)
        zeroize1(buf)

        munlock(buf)
        munlock(plaintext)

        print("bye!")
```

## Encrypt and decrypt a file

```python
import errno
import io
import os
from pathlib import Path
import shutil
from rencrypt import Cipher, CipherMeta, RingAlgorithm
import hashlib
from zeroize import zeroize1, mlock, munlock
import numpy as np


def read_file_in_chunks(file_path, buf):
    with open(file_path, "rb") as file:
        buffered_reader = io.BufferedReader(file, buffer_size=len(buf))
        while True:
            read = buffered_reader.readinto(buf)
            if read == 0:
                break
            yield read


def hash_file(file_path):
    hash_algo = hashlib.sha256()
    with open(file_path, "rb") as f:
        for chunk in iter(lambda: f.read(4096), b""):
            hash_algo.update(chunk)
    return hash_algo.hexdigest()


def compare_files_by_hash(file1, file2):
    return hash_file(file1) == hash_file(file2)


def silentremove(filename):
    try:
        os.remove(filename)
    except OSError as e:  # this would be "except OSError, e:" before Python 2.6
        if e.errno != errno.ENOENT:  # errno.ENOENT = no such file or directory
            raise  # re-raise exception if a different error occurred


def create_directory_in_home(dir_name):
    # Get the user's home directory
    home_dir = Path.home()

    # Create the full path for the new directory
    new_dir_path = home_dir / dir_name

    # Create the directory
    try:
        new_dir_path.mkdir(parents=True, exist_ok=True)
    except Exception as e:
        print(f"Error creating directory: {e}")

    return new_dir_path.absolute().__str__()


def create_file_with_size(file_path_str, size_in_bytes):
    with open(file_path_str, "wb") as f:
        for _ in range((size_in_bytes // 4096) + 1):
            f.write(os.urandom(min(4096, size_in_bytes)))
        f.flush()


def delete_dir(path):
    if os.path.exists(path):
        shutil.rmtree(path)
    else:
        print(f"Directory {path} does not exist.")


if __name__ == "__main__":
    try:
        tmp_dir = create_directory_in_home("rencrypt_tmp")
        fin = tmp_dir + "/" + "fin"
        fout = tmp_dir + "/" + "fout.enc"
        create_file_with_size(fin, 10 * 1024 * 1024)

        chunk_len = 256 * 1024

        # You can use also other algorithms like cipher_meta = CipherMeta.Ring(RingAlgorithm.ChaCha20Poly1305)`.
        cipher_meta = CipherMeta.Ring(RingAlgorithm.Aes256Gcm)
        key_len = cipher_meta.key_len()
        key = bytearray(key_len)
        # for security reasons we lock the memory of the key so it won't be swapped to disk
        mlock(key)
        cipher_meta.generate_key(key)
        # The key is copied and the input key is zeroized for security reasons.
        # The copied key will also be zeroized when the object is dropped.
        cipher = Cipher(cipher_meta, key)
        # it was zeroized we can unlock it
        munlock(key)

        plaintext_len = chunk_len
        ciphertext_len = cipher_meta.ciphertext_len(plaintext_len)
        buf = np.array([0] * ciphertext_len, dtype=np.uint8)
        mlock(buf)

        aad = b"AAD"

        # encrypt
        print("encryping...")
        with open(fout, "wb", buffering=plaintext_len) as file_out:
            i = 0
            for read in read_file_in_chunks(fin, buf[:plaintext_len]):
                ciphertext_len = cipher.seal_in_place(buf, read, i, aad)
                file_out.write(buf[:ciphertext_len])
                i += 1
            file_out.flush()

        # decrypt
        print("decryping...")
        tmp = fout + ".dec"
        with open(tmp, "wb", buffering=plaintext_len) as file_out:
            i = 0
            for read in read_file_in_chunks(fout, buf):
                plaintext_len2 = cipher.open_in_place(buf, read, i, aad)
                file_out.write(buf[:plaintext_len2])
                i += 1
            file_out.flush()

        assert compare_files_by_hash(fin, tmp)

        delete_dir(tmp_dir)

    finally:
        # best practice, you should always zeroize the plaintext and keys after you are done with it (key will be zeroized when the enc object is dropped)
        # buf will containt the last block plaintext so we need to zeroize it
        zeroize1(buf)

        munlock(buf)

    print("bye!")
```

## Encrypt and decrypt from some bytes into the buffer

`encrypt_from()`/`decrypt_from()`

This is a bit slower than handling data only via the buffer, especially for large plaintext, but there are situations when you can't directly collect the data to the buffer but have some data from somewhere else.

```python
from rencrypt import Cipher, CipherMeta, RingAlgorithm
import os
from zeroize import zeroize1, mlock, munlock
import numpy as np


if __name__ == "__main__":
    try:
        # You can use also other algorithms like cipher_meta = CipherMeta.Ring(RingAlgorithm.ChaCha20Poly1305)`.
        cipher_meta = CipherMeta.Ring(RingAlgorithm.Aes256Gcm)
        key_len = cipher_meta.key_len()
        key = bytearray(key_len)
        # for security reasons we lock the memory of the key so it won't be swapped to disk
        mlock(key)
        cipher_meta.generate_key(key)
        # The key is copied and the input key is zeroized for security reasons.
        # The copied key will also be zeroized when the object is dropped.
        cipher = Cipher(cipher_meta, key)
        # it was zeroized we can unlock it
        munlock(key)

        # we create a buffer based on plaintext block len of 4096
        # the actual buffer needs to be a bit larger as the ciphertext also includes the tag and nonce
        plaintext_len = 4096
        ciphertext_len = cipher_meta.ciphertext_len(plaintext_len)
        buf = np.array([0] * ciphertext_len, dtype=np.uint8)
        # for security reasons we lock the memory of the buffer so it won't be swapped to disk, because it contains plaintext after decryption
        mlock(buf)

        aad = b"AAD"

        plaintext = bytearray(os.urandom(plaintext_len))
        # for security reasons we lock the memory of the plaintext so it won't be swapped to disk
        mlock(plaintext)

        # encrypt it, after this will have the ciphertext in the buffer
        print("encryping...")
        ciphertext_len = cipher.seal_in_place_from(plaintext, buf, 42, aad)
        cipertext = bytes(buf[:ciphertext_len])

        # decrypt it
        print("decryping...")
        plaintext_len = cipher.open_in_place_from(cipertext, buf, 42, aad)
        plaintext2 = buf[:plaintext_len]
        # for security reasons we lock the memory of the plaintext so it won't be swapped to disk
        mlock(plaintext2)
        assert plaintext == plaintext2

    finally:
        # best practice, you should always zeroize the plaintext and keys after you are done with it (key will be zeroized when the enc object is dropped)
        zeroize1(plaintext)
        zeroize1(buf)

        munlock(buf)
        munlock(plaintext)

        print("bye!")
```

## Zeroing memory before forking child process

This mitigates the problems that appears on [Copy-on-write fork](https://en.wikipedia.org/wiki/Copy-on-write). You need to zeroize the data before forking the child process.

```python
import os
from zeroize import zeroize1, mlock, munlock


if __name__ == "__main__":
    try:
        # Maximum you can mlock is 4MB
        sensitive_data = bytearray(b"Sensitive Information")
        mlock(sensitive_data)

        print("Before zeroization:", sensitive_data)

        zeroize1(sensitive_data)
        print("After zeroization:", sensitive_data)

        # Forking after zeroization to ensure no sensitive data is copied
        pid = os.fork()
        if pid == 0:
            # This is the child process
            print("Child process memory after fork:", sensitive_data)
        else:
            # This is the parent process
            os.wait()  # Wait for the child process to exit
        
        print("all good, bye!")

    finally:
        # Unlock the memory
        print("unlocking memory")
        munlock(sensitive_data)
```

# Build from source

## Browser

[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/radumarias/rencrypt-python)

[![Open in Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/?repo=radumarias%2Frencrypt-python&ref=main)

## Geting sources from GitHub

Skip this if you're starting it in browser.

```bash
git clone https://github.com/radumarias/rencrypt-python && cd Cipher-python
```

## Compile and run

```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```

To configure your current shell, you need to source
the corresponding env file under $HOME/.cargo.
This is usually done by running one of the following (note the leading DOT):

```bash
. "$HOME/.cargo/env"
```

```bash
python -m venv .env
source .env/bin/activate
pip install -r requirements.txt
maturin develop --release
pytest
python examples/encrypt.py
python examples/encrypt_into.py
python examples/encrypt_from.py
python examples/encrypt_file.py
python benches/bench.py
```

# More benchmarks

## Different ways to use the lib

**Encrypt**  
![Encrypt buffer](https://github.com/radumarias/rencrypt-python/blob/main/resources/charts/encrypt-all.png?raw=true)

**Decrypt**  
 ![Decrypt buffer](https://github.com/radumarias/rencrypt-python/blob/main/resources/charts/decrypt-all.png?raw=true)

**Block size and duration in seconds**

<table>
    <thead>
        <tr>
            <td>MB</td>
            <td>rencrypt<br>encrypt</td>
            <td>PyFLocker<br>encrypt update_into</td>
            <td>rencrypt<br>encrypt_from</td>
            <td>PyFLocker<br>encrypt update</td>
            <td>rencrypt<br>decrypt</td>
            <td>PyFLocker<br>decrypt update_into</td>
            <td>rencrypt<br>decrypt_from</td>
            <td>
                <div>
                    <div>PyFLocker<br>decrypt update</div>
                </div>
            </td>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>0.03125</td>
            <td>0.00001</td>
            <td>0.00091</td>
            <td>0.00001</td>
            <td>0.00009</td>
            <td>0.00001</td>
            <td>0.00004</td>
            <td>0.00001</td>
            <td>0.00005</td>
        </tr>
        <tr>
            <td>0.0625</td>
            <td>0.00001</td>
            <td>0.00005</td>
            <td>0.00002</td>
            <td>0.00005</td>
            <td>0.00001</td>
            <td>0.00004</td>
            <td>0.00002</td>
            <td>0.00008</td>
        </tr>
        <tr>
            <td>0.125</td>
            <td>0.00002</td>
            <td>0.00005</td>
            <td>0.00003</td>
            <td>0.00011</td>
            <td>0.00003</td>
            <td>0.00005</td>
            <td>0.00003</td>
            <td>0.00013</td>
        </tr>
        <tr>
            <td>0.25</td>
            <td>0.00004</td>
            <td>0.00008</td>
            <td>0.00007</td>
            <td>0.00019</td>
            <td>0.00005</td>
            <td>0.00009</td>
            <td>0.00007</td>
            <td>0.00023</td>
        </tr>
        <tr>
            <td>0.5</td>
            <td>0.0001</td>
            <td>0.00014</td>
            <td>0.00015</td>
            <td>0.00035</td>
            <td>0.00011</td>
            <td>0.00015</td>
            <td>0.00014</td>
            <td>0.00043</td>
        </tr>
        <tr>
            <td>1</td>
            <td>0.00021</td>
            <td>0.00024</td>
            <td>0.0008</td>
            <td>0.00082</td>
            <td>0.00021</td>
            <td>0.00029</td>
            <td>0.00044</td>
            <td>0.00103</td>
        </tr>
        <tr>
            <td>2</td>
            <td>0.00043</td>
            <td>0.00052</td>
            <td>0.00082</td>
            <td>0.00147</td>
            <td>0.00044</td>
            <td>0.00058</td>
            <td>0.00089</td>
            <td>0.00176</td>
        </tr>
        <tr>
            <td>4</td>
            <td>0.00089</td>
            <td>0.00098</td>
            <td>0.00174</td>
            <td>0.00284</td>
            <td>0.00089</td>
            <td>0.00117</td>
            <td>0.0013</td>
            <td>0.0034</td>
        </tr>
        <tr>
            <td>8</td>
            <td>0.00184</td>
            <td>0.0019</td>
            <td>0.00263</td>
            <td>0.00523</td>
            <td>0.00192</td>
            <td>0.00323</td>
            <td>0.00283</td>
            <td>0.00571</td>
        </tr>
        <tr>
            <td>16</td>
            <td>0.00353</td>
            <td>0.00393</td>
            <td>0.00476</td>
            <td>0.0141</td>
            <td>0.00367</td>
            <td>0.00617</td>
            <td>0.00509</td>
            <td>0.01031</td>
        </tr>
        <tr>
            <td>32</td>
            <td>0.00678</td>
            <td>0.00748</td>
            <td>0.00904</td>
            <td>0.0244</td>
            <td>0.00749</td>
            <td>0.01348</td>
            <td>0.01014</td>
            <td>0.02543</td>
        </tr>
        <tr>
            <td>64</td>
            <td>0.01361</td>
            <td>0.01461</td>
            <td>0.01595</td>
            <td>0.05064</td>
            <td>0.0146</td>
            <td>0.02697</td>
            <td>0.0192</td>
            <td>0.05296</td>
        </tr>
        <tr>
            <td>128</td>
            <td>0.02923</td>
            <td>0.03027</td>
            <td>0.03343</td>
            <td>0.10362</td>
            <td>0.03134</td>
            <td>0.0541</td>
            <td>0.03558</td>
            <td>0.1138</td>
        </tr>
        <tr>
            <td>256</td>
            <td>0.06348</td>
            <td>0.06188</td>
            <td>0.07303</td>
            <td>0.20911</td>
            <td>0.06136</td>
            <td>0.10417</td>
            <td>0.07572</td>
            <td>0.20828</td>
        </tr>
        <tr>
            <td>512</td>
            <td>0.11782</td>
            <td>0.13463</td>
            <td>0.14283</td>
            <td>0.41929</td>
            <td>0.1209</td>
            <td>0.21114</td>
            <td>0.14434</td>
            <td>0.41463</td>
        </tr>
        <tr>
            <td>1024</td>
            <td>0.25001</td>
            <td>0.24953</td>
            <td>0.28912</td>
            <td>0.8237</td>
            <td>0.25377</td>
            <td>0.42581</td>
            <td>0.29795</td>
            <td>0.82588</td>
        </tr>
    </tbody>
</table>

## Speed throughput

`256KB` seems to be the sweet spot for buffer size that offers the max `MB/s` speed for encryption, on benchmarks that seem to be the case.
We performed `10.000` encryption operations for each size varying from `1KB` to `16MB`.

![Speed throughput](https://github.com/radumarias/rencrypt-python/blob/main/resources/charts/speed-throughput.png?raw=true)

| MB    | MB/s |
| ----- | ------- |
| 0.0009765625 | 1083 |
| 0.001953125 | 1580 |
| 0.00390625 | 2158 |
| 0.0078125 | 2873 |
| 0.015625 | 3348 |
| 0.03125 | 3731 |
| 0.0625 | 4053 |
| 0.125 | 4156 |
| <span style="color: red; font-weight: bold;">0.25</span> | <span style="color: red; font-weight: bold;">4247</span> |
| 0.5 | 4182 |
| 1.0 | 3490 |
| 2.0 | 3539 |
| 4.0 | 3684 |
| 8.0 | 3787 |
| 16.0 | 3924 |

# For the future

- Generating key from password (`KDF`)
- Maybe add support for `RSA` and `Elliptic-curve cryptography`
- Saving and loading keys from file

# Considerations

This lib hasn't been audited, but it wraps `ring` crate (well known and audited library) and `RustCrypto` (`AES-GCM` and `ChaCha20Poly1305` ciphers are audited), so in principle at least the primitives should offer a similar level of security.

# Contribute

Feel free to fork it, change and use it in any way that you want. If you build something interesting and feel like sharing pull requests are always appreciated.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache License, shall be dual-licensed as above, without any additional terms or conditions.

## How to contribute

1. Fork the repo
2. Make the changes in your fork
3. Add tests for your changes, if applicable
4. `cargo build --all --all-features` and fix any issues
5. `cargo fmt --all`, you can cnofigure your IDE to do this on save [RustRover](https://www.jetbrains.com/help/rust/rustfmt.html) and [VSCode](https://code.visualstudio.com/docs/languages/rust#_formatting)
6. `cargo check --all --all-features` and fix any errors and warnings
7. `cargo clippy --all --all-features` and fix any errors
8. `cargo test --all --all-features` and fix any issues
9. `cargo bench --all --all-features` and fix any issues
10. Create a PR
11. Monitor the checks (GitHub actions runned)
12. Respond to any comments
13. In the end ideally it will be merged to `main`


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "rencrypt",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": null,
    "keywords": "cryptography, encryption, security, rust, speed, aead, cipher",
    "author": null,
    "author_email": "Radu Marias <radumarias@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/ec/d1/be2039a3d6c351dfc0a8966a7625fb64973168004ccb667aceecdaf33318/rencrypt-1.0.7.tar.gz",
    "platform": null,
    "description": "# rencrypt\n\n[![PyPI version](https://badge.fury.io/py/rencrypt.svg)](https://badge.fury.io/py/rencrypt)\n[![CI](https://github.com/radumarias/rencrypt-python/actions/workflows/CI.yml/badge.svg)](https://github.com/radumarias/rencrypt-python/actions/workflows/CI.yml)\n\n> [!WARNING]  \n> **This crate hasn't been audited, but it's mostly a wrapper over several libs like `ring` (well known and audited library),`RustCrypto` (`AES-GCM` and `ChaCha20Poly1305` ciphers are audited) but also others which are NOT audited, so in principle at least the primitives should offer a similar level of security.**\n\nA Python encryption library implemented in Rust. It supports `AEAD` with varius ciphers. It uses [ring](https://crates.io/crates/ring), [RustCrypto](https://crates.io/crates/aead) (and derivates), [sodiumoxide](https://crates.io/crates/sodiumoxide) and [orion](https://crates.io/crates/orion) to handle encryption.  \nIf offers slightly higher speed compared to other Python libs, especially for small chunks of data (especially the `Ring` provider with `AES-GCM` ciphers). The API also tries to be easy to use but it's more optimized for speed than usability.\n\nSo if you want to use a vast variaety of ciphers and/or achieve the highest possible encryption speed, consider giving it a try.\n\n# Benchmark\n\nSome benchmarks comparing it to [PyFLocker](https://github.com/arunanshub/pyflocker) which from my benchmarks is the fastest among other Python libs like `cryptography`, `NaCl` (`libsodium`), `PyCryptodome`.\n\n## Buffer in memory\n\nThis is useful when you keep a buffer, set your plaintext/ciphertext in there, and then encrypt/decrypt in-place in that buffer. This is the most performant way to use it, because it does't copy any bytes nor allocate new memory.  \n`rencrypt` is faster on small buffers, less than few MB, `PyFLocker` is comming closer for larger buffers.\n\n**Encrypt seconds**  \n![Encrypt buffer](https://github.com/radumarias/rencrypt-python/blob/main/resources/charts/encrypt.png?raw=true)\n\n**Decrypt seconds**  \n![Decrypt buffer](https://github.com/radumarias/rencrypt-python/blob/main/resources/charts/decrypt.png?raw=true)\n\n\n**Block size and duration in seconds**\n\n<table>\n    <thead>\n        <tr>\n            <th>MB</th>\n            <th>rencrypt<br>encrypt</th>\n            <th>PyFLocker<br>encrypt</th>\n            <th>rencrypt<br>decrypt</th>\n            <th>PyFLocker<br>decrypt</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td>0.03125</td>\n            <td>0.00001</td>\n            <td>0.00091</td>\n            <td>0.00001</td>\n            <td>0.00004</td>\n        </tr>\n        <tr>\n            <td>0.0625</td>\n            <td>0.00001</td>\n            <td>0.00005</td>\n            <td>0.00001</td>\n            <td>0.00004</td>\n        </tr>\n        <tr>\n            <td>0.125</td>\n            <td>0.00002</td>\n            <td>0.00005</td>\n            <td>0.00003</td>\n            <td>0.00005</td>\n        </tr>\n        <tr>\n            <td>0.25</td>\n            <td>0.00004</td>\n            <td>0.00008</td>\n            <td>0.00005</td>\n            <td>0.00009</td>\n        </tr>\n        <tr>\n            <td>0.5</td>\n            <td>0.00010</td>\n            <td>0.00014</td>\n            <td>0.00011</td>\n            <td>0.00015</td>\n        </tr>\n        <tr>\n            <td>1</td>\n            <td>0.00021</td>\n            <td>0.00024</td>\n            <td>0.00021</td>\n            <td>0.00029</td>\n        </tr>\n        <tr>\n            <td>2</td>\n            <td>0.00043</td>\n            <td>0.00052</td>\n            <td>0.00044</td>\n            <td>0.00058</td>\n        </tr>\n        <tr>\n            <td>4</td>\n            <td>0.00089</td>\n            <td>0.00098</td>\n            <td>0.00089</td>\n            <td>0.00117</td>\n        </tr>\n        <tr>\n            <td>8</td>\n            <td>0.00184</td>\n            <td>0.00190</td>\n            <td>0.00192</td>\n            <td>0.00323</td>\n        </tr>\n        <tr>\n            <td>16</td>\n            <td>0.00353</td>\n            <td>0.00393</td>\n            <td>0.00367</td>\n            <td>0.00617</td>\n        </tr>\n        <tr>\n            <td>32</td>\n            <td>0.00678</td>\n            <td>0.00748</td>\n            <td>0.00749</td>\n            <td>0.01348</td>\n        </tr>\n        <tr>\n            <td>64</td>\n            <td>0.01361</td>\n            <td>0.01461</td>\n            <td>0.01460</td>\n            <td>0.02697</td>\n        </tr>\n        <tr>\n            <td>128</td>\n            <td>0.02923</td>\n            <td>0.03027</td>\n            <td>0.03134</td>\n            <td>0.05410</td>\n        </tr>\n        <tr>\n            <td>256</td>\n            <td>0.06348</td>\n            <td>0.06188</td>\n            <td>0.06136</td>\n            <td>0.10417</td>\n        </tr>\n        <tr>\n            <td>512</td>\n            <td>0.11782</td>\n            <td>0.13463</td>\n            <td>0.12090</td>\n            <td>0.21114</td>\n        </tr>\n        <tr>\n            <td>1024</td>\n            <td>0.25001</td>\n            <td>0.24953</td>\n            <td>0.25377</td>\n            <td>0.42581</td>\n        </tr>\n    </tbody>\n</table>\n\n## File\n\n**Encrypt seconds**  \n![Encrypt file](https://github.com/radumarias/rencrypt-python/blob/main/resources/charts/encrypt-file.png?raw=true)\n\n **Decrypt seconds**  \n![Decrypt buffer](https://github.com/radumarias/rencrypt-python/blob/main/resources/charts/decrypt-file.png?raw=true)\n\n**File size and duration in seconds**\n\n<table>\n    <thead>\n        <tr>\n            <th>MB</th>\n            <th>rencrypt<br>encrypt</th>\n            <th>PyFLocker<br>encrypt</th>\n            <th>rencrypt<br>decrypt</th>\n            <th>PyFLocker<br>decrypt</th>\n        </tr>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td>0.031251</td>\n            <td>0.00010</td>\n            <td>0.00280</td>\n            <td>0.00004</td>\n            <td>0.00479</td>\n        </tr>\n        <tr>\n            <td>0.062501</td>\n            <td>0.00009</td>\n            <td>0.00218</td>\n            <td>0.00005</td>\n            <td>0.00143</td>\n        </tr>\n        <tr>\n            <td>0.125</td>\n            <td>0.00020</td>\n            <td>0.00212</td>\n            <td>0.00014</td>\n            <td>0.00129</td>\n        </tr>\n        <tr>\n            <td>0.25</td>\n            <td>0.00034</td>\n            <td>0.00232</td>\n            <td>0.00020</td>\n            <td>0.00165</td>\n        </tr>\n        <tr>\n            <td>0.5</td>\n            <td>0.00050</td>\n            <td>0.00232</td>\n            <td>0.00035</td>\n            <td>0.00181</td>\n        </tr>\n        <tr>\n            <td>1</td>\n            <td>0.00087</td>\n            <td>0.00356</td>\n            <td>0.00065</td>\n            <td>0.00248</td>\n        </tr>\n        <tr>\n            <td>2</td>\n            <td>0.00215</td>\n            <td>0.00484</td>\n            <td>0.00154</td>\n            <td>0.00363</td>\n        </tr>\n        <tr>\n            <td>4</td>\n            <td>0.00361</td>\n            <td>0.00765</td>\n            <td>0.00301</td>\n            <td>0.00736</td>\n        </tr>\n        <tr>\n            <td>8</td>\n            <td>0.00688</td>\n            <td>0.01190</td>\n            <td>0.00621</td>\n            <td>0.00876</td>\n        </tr>\n        <tr>\n            <td>16</td>\n            <td>0.01503</td>\n            <td>0.02097</td>\n            <td>0.01202</td>\n            <td>0.01583</td>\n        </tr>\n        <tr>\n            <td>32</td>\n            <td>0.02924</td>\n            <td>0.03642</td>\n            <td>0.02563</td>\n            <td>0.02959</td>\n        </tr>\n        <tr>\n            <td>64</td>\n            <td>0.05737</td>\n            <td>0.06473</td>\n            <td>0.04431</td>\n            <td>0.05287</td>\n        </tr>\n        <tr>\n            <td>128</td>\n            <td>0.11098</td>\n            <td>0.12646</td>\n            <td>0.08944</td>\n            <td>0.09926</td>\n        </tr>\n        <tr>\n            <td>256</td>\n            <td>0.22964</td>\n            <td>0.24716</td>\n            <td>0.17402</td>\n            <td>0.19420</td>\n        </tr>\n        <tr>\n            <td>512</td>\n            <td>0.43506</td>\n            <td>0.46444</td>\n            <td>0.38143</td>\n            <td>0.38242</td>\n        </tr>\n        <tr>\n            <td>1024</td>\n            <td>0.97147</td>\n            <td>0.95803</td>\n            <td>0.78137</td>\n            <td>0.87363</td>\n        </tr>\n        <tr>\n            <td>2048</td>\n            <td>2.07143</td>\n            <td>2.10766</td>\n            <td>1.69471</td>\n            <td>2.99210</td>\n        </tr>\n        <tr>\n            <td>4096</td>\n            <td>4.85395</td>\n            <td>4.69722</td>\n            <td>5.40580</td>\n            <td>8.73779</td>\n        </tr>\n        <tr>\n            <td>8192</td>\n            <td>10.76984</td>\n            <td>11.76741</td>\n            <td>10.29253</td>\n            <td>21.00636</td>\n        </tr>\n        <tr>\n            <td>16384</td>\n            <td>21.84490</td>\n            <td>26.27385</td>\n            <td>39.56230</td>\n            <td>43.55530</td>\n        </tr>\n    </tbody>\n</table>\n\n# Usage\n\nThere are two ways in which you can use the lib, the first one is a bit faster, the second offers a bit more flexible way to use it sacrificing a bit of performance.\n\n1. **With a buffer in memory**: using `seal_in_place()`/`open_in_place()`, is useful when you keep a buffer (or have it from somewhere), set your plaintext/ciphertext in there, and then encrypt/decrypt in-place in that buffer. This is the most performant way to use it, because it does't copy any bytes nor allocate new memory.  \n**The buffer has to be a `numpy array`**, so that it's easier for you to collect data with slices that reference to underlying data. This is because the whole buffer needs to be the size of ciphertext (which is plaintext_len + tag_len + nonce_len) but you may pass a slice of the buffer to a BufferedReader to `read_into()` the plaintext.  \nIf you can directly collect the data to that buffer, like `BufferedReader.read_into()`, **this is the preffered way to go**.\n2. **From some bytes into the buffer**: using `seal_in_place_from()`/`open_in_place_from()`, when you have some arbitrary data that you want to work with. It will first copy those bytes to the buffer then do the operation in-place in the buffer. This is a bit slower, especially for large data, because it first needs to copy the bytes to the buffer.\n\n`block_index`, `aad` and `nonce` are optional.\n\nIf `nonce` is not provided, on each encrypt operation (`seal_in_place*()`) it will generate a cryptographically secure random nonce using `ChaCha20`. You can also provide your own nonce, there is an example below.\n\n# Security\n\n- **The total number of invocations of the encryption functions (`seal_in_place*()`) shall not exceed `2^32`, including all nonce lengths and all instances of `Cipher` with the given key. Following this guideline, only `4,294,967,296` messages with random nonces can be encrypted under a given key. While this bound is high, it's possible to encounter in practice, and systems which might reach it should consider alternatives to purely random nonces, like a counter or a combination of a random nonce + counter.**\n- **When encrypting more than one block you should provide `block_index` as it's more secure because it ensures the order of the blocks was not changed in ciphertext.**\n- **When you encrypt files it's more secure to generate a random number per file and include that in AAD, this will prevent ciphertext blocks from being swapped between files.**\n- **For security reasons it's a good practice to lock the memory with `mlock()` in which you keep sensitive data like passwords or encrryption keys, or any other plaintext sensitive content. Also it's important to zeroize the data when not used anymore.**  \n- **In the case of [Copy-on-write fork](https://en.wikipedia.org/wiki/Copy-on-write) you need to zeroize the memory before forking the child process.**  \n\nIn the examples below you will see how to do it.\n\n# Encryption providers and algorithms (ciphers)\n\nYou will notice in the examples we create the `Cipher` from something like this `cipher_meta = CipherMeta.Ring(RingAlgorithm.Aes256Gcm)`. The first part `CipherMeta.Ring` is the encryption provider. The last part is the algorithm for that provider, in this case `Aes256Gcm`. Each provier might expose specific algorithms.\n\n## Providers\n\n```rust\nenum CipherMeta {\n    Ring { alg: RingAlgorithm },\n    RustCrypto { alg: RustCryptoAlgorithm },\n    Sodiumoxide { alg: SodiumoxideAlgorithm },\n    Orion { alg: OrionAlgorithm },\n}\n```\n\n- `Ring`: Based on [ring](https://crates.io/crates/ring) crate. ring is focused on the implementation, testing, and optimization of a core set of cryptographic operations exposed via an easy-to-use (and hard-to-misuse) API. ring exposes a Rust API and is written in a hybrid of Rust, C, and assembly language.  \n  Particular attention is being paid to making it easy to build and integrate ring into applications and higher-level frameworks, and to ensuring that ring works optimally on small devices, and eventually microcontrollers, to support Internet of Things (IoT) applications.  \n  Most of the C and assembly language code in ring comes from BoringSSL, and BoringSSL is derived from OpenSSL. ring merges changes from BoringSSL regularly. Also, several changes that were developed for ring have been contributed to and integrated into BoringSSL.\n- `RustCrypto`: Based on [RustCrypto](https://github.com/RustCrypto/AEADs) collection of Authenticated Encryption with Associated Data (AEAD) algorithms written in pure Rust. AEADs are high-level symmetric encryption primitives which defend against a wide range of potential attacks (i.e. IND-CCA3).\n- `Sodiumoxide`: Based on [sodiumoxide](https://crates.io/crates/sodiumoxide) crate which aims to provide a type-safe and efficient Rust binding that's just as easy to use.  \n  [`NaCl`](https://nacl.cr.yp.to) (pronounced \"salt\") is a new easy-to-use high-speed software library for network communication, encryption, decryption, signatures, etc. NaCl's goal is to provide all of the core operations needed to build higher-level cryptographic tools. Of course, other libraries already exist for these core operations. NaCl advances the state of the art by improving security, by improving usability, and by improving speed.  \n  [Sodium](https://github.com/jedisct1/libsodium) is a portable, cross-compilable, installable, packageable fork of NaCl (based on the latest released upstream version nacl-20110221), with a compatible API.\n- `Orion`: Based on [orion](https://crates.io/crates/orion) crate. Written in pure Rust, it aims to provide easy and usable crypto while trying to minimize the use of unsafe code. You can read more about Orion in the [wiki](https://github.com/orion-rs/orion/wiki).\n\n## Algorithms\n\n```rust\nenum RingAlgorithm {\n    ChaCha20Poly1305,\n    Aes128Gcm,\n    Aes256Gcm,\n}\n```\n\n```rust\nenum RustCryptoAlgorithm {\n    ChaCha20Poly1305,\n    XChaCha20Poly1305,\n    Aes128Gcm,\n    Aes256Gcm,\n    Aes128GcmSiv,\n    Aes256GcmSiv,\n    Aes128Siv,\n    Aes256Siv,\n    Ascon128,\n    Ascon128a,\n    Ascon80pq,\n    DeoxysI128,\n    DeoxysI256,\n    DeoxysII128,\n    DeoxysII256,\n    Aes128Eax,\n    Aes256Eax,\n}\n```\n\n```rust\nenum SodiumoxideAlgorithm {\n    ChaCha20Poly1305,\n    ChaCha20Poly1305Ieft,\n    XChaCha20Poly1305Ieft,\n}\n```\n\n```rust\nenum OrionAlgorithm {\n    ChaCha20Poly1305,\n    XChaCha20Poly1305,\n}\n```\n\n## Audited\n\n**Only for `Aes128Gcm`, `Aes256Gcm` and `ChaCha20Poly1305` with `Ring` and `RustCrypto` providers underlying crates have been audited.**\n\n- [`Aes128Gcm`/`Aes256Gcm`](https://datatracker.ietf.org/doc/html/rfc5288): If you have hardware acceleration (e.g. `AES-NI`), then `AES-GCM` provides better performance. If you do not have a hardware acceleration, `AES-GCM` is either slower than `ChaCha20Poly1305`, or it leaks your encryption keys in cache timing. With `RustCrypto` provider the underlying `aes-gcm` has received one security audit by NCC Group, with no significant findings. With `Ring` provider the underlying `ring` crate was also audited.\n- [`ChaCha20Poly1305`](https://en.wikipedia.org/wiki/ChaCha20-Poly1305): Is notable for being simple and fast when implemented in pure software. The underlying `ChaCha20` stream cipher uses a simple combination of `add`, `rotate`, and `XOR` instructions (a.k.a. `\"ARX\"`), and the `Poly1305` hash function is likewise extremely simple. With `RustCrypto` provider the underlying `chacha20poly1305` has received one security audit by NCC Group, with no significant findings. With `Ring` provider the underlying `ring` crtate was also audited.\n  If you do not have a hardware acceleration, `ChaCha20Poly1305` is faster than `AES-GCM`.\n  While it hasn't received approval from certain standards bodies (i.e. NIST) the algorithm is widely used and deployed. Notably it's mandatory to implement in the Transport Layer Security (TLS) protocol. The underlying `ChaCha20` cipher is also widely used as a cryptographically secure random number generator, including internal use by the Rust standard library.\n- [`XChaCha20Poly1305`](https://en.wikipedia.org/wiki/ChaCha20-Poly1305#XChaCha20-Poly1305_%E2%80%93_extended_nonce_variant): A variant of `ChaCha20Poly1305` with an extended 192-bit (24-byte) nonce.\n\n## Not audited\n\n**USE AT YOUR OWN RISK!**\n\n- [`Aes128GcmSiv` / `Aes256GcmSiv`](https://en.wikipedia.org/wiki/AES-GCM-SIV): Provides nonce reuse misuse resistance. Suitable as a general purpose symmetric encryption cipher, `AES-GCM-SIV` also removes many of the \"sharp edges\" of `AES-GCM`, providing significantly better security bounds while simultaneously eliminating the most catastrophic risks of nonce reuse that exist in `AES-GCM`. Decryption performance is equivalent to `AES-GCM`. Encryption is marginally slower.\n- [`Aes128Siv` / `Aes256Siv`](https://github.com/miscreant/meta/wiki/AES-SIV): Cipher which also provides nonce reuse misuse resistance.\n- [`Ascon128` / `Ascon128a` / `Ascon80pq`](https://ascon.iaik.tugraz.at): Designed to be lightweight and easy to implement, even with added countermeasures against side-channel attacks. Ascon has been selected as new standard for lightweight cryptography in the NIST Lightweight Cryptography competition (2019\u20132023). Ascon has also been selected as the primary choice for lightweight authenticated encryption in the final portfolio of the CAESAR competition (2014\u20132019).\n- [`Deoxys`](https://sites.google.com/view/deoxyscipher): Based on a 128-bit lightweight ad-hoc tweakable block cipher. It may be used in two modes to handle nonce-respecting users (`Deoxys-I`) or nonce-reusing user (`Deoxys-II`). `Deoxys-II` has been selected as first choice for the \"in-depth security\" portfolio of the `CAESAR` competition.\n- [`Aes128Eax` / `Aes256Eax`](https://en.wikipedia.org/wiki/EAX_mode): Designed with a two-pass scheme, one pass for achieving privacy and one for authenticity for each block. `EAX` mode was submitted on October 3, 2003, to the attention of NIST in order to replace `CCM` as standard `AEAD` mode of operation, since `CCM` mode lacks some desirable attributes of `EAX` and is more complex.\n- For `Sodiumoxide` provider [`ChaCha20Poly1305`](https://libsodium.gitbook.io/doc/secret-key_cryptography/aead/chacha20-poly1305/original_chacha20-poly1305_construction): The original `ChaCha20-Poly1305` construction can safely encrypt a pratically unlimited number of messages with the same key, without any practical limit to the size of a message (up to ~ 2^64 bytes).\n- For `Sodiumoxide` provider [`ChaChaCha20Poly1305Ieft`](https://libsodium.gitbook.io/doc/secret-key_cryptography/aead/chacha20-poly1305/ietf_chacha20-poly1305_construction): The IETF variant of the `ChaCha20-Poly1305` construction can safely encrypt a practically unlimited number of messages, but individual messages cannot exceed 64*(2^32)-64 bytes (approximatively 256 GB).\n\n# Examples\n\nYou can see more in [examples](https://github.com/radumarias/rencrypt-python/tree/main/examples) directory and in [bench.py](https://github.com/radumarias/rencrypt-python/tree/main/bench.py) which has some benchmarks. Here are few simple examples:\n\n## Encrypt and decrypt with a buffer in memory\n\n`seal_in_place()`/`open_in_place()`\n\nThis is the most performant way to use it as it will not copy bytes to the buffer nor allocate new memory for plaintext and ciphertext.\n\n```python\nfrom rencrypt import Cipher, CipherMeta, RingAlgorithm\nimport os\nfrom zeroize import zeroize1, mlock, munlock\nimport numpy as np\n\n\nif __name__ == \"__main__\":\n    try:\n        # You can use also other algorithms like cipher_meta = CipherMeta.Ring(RingAlgorithm.ChaCha20Poly1305)`.\n        cipher_meta = CipherMeta.Ring(RingAlgorithm.Aes256Gcm)\n        key_len = cipher_meta.key_len()\n        key = bytearray(key_len)\n        # for security reasons we lock the memory of the key so it won't be swapped to disk\n        mlock(key)\n        cipher_meta.generate_key(key)\n        # The key is copied and the input key is zeroized for security reasons.\n        # The copied key will also be zeroized when the object is dropped.\n        cipher = Cipher(cipher_meta, key)\n        # it was zeroized we can unlock it\n        munlock(key)\n\n        # we create a buffer based on plaintext block len of 4096\n        # the actual buffer needs to be a bit larger as the ciphertext also includes the tag and nonce\n        plaintext_len = 4096\n        ciphertext_len = cipher_meta.ciphertext_len(plaintext_len)\n        buf = np.array([0] * ciphertext_len, dtype=np.uint8)\n        # for security reasons we lock the memory of the buffer so it won't be swapped to disk, because it contains plaintext after decryption\n        mlock(buf)\n\n        aad = b\"AAD\"\n\n        # put some plaintext in the buffer, it would be ideal if you can directly collect the data into the buffer without allocating new memory\n        # but for the sake of example we will allocate and copy the data\n        plaintext = bytearray(os.urandom(plaintext_len))\n        # for security reasons we lock the memory of the plaintext so it won't be swapped to disk\n        mlock(plaintext)\n        # cipher.copy_slice is slighlty faster than buf[:plaintext_len] = plaintext, especially for large plaintext, because it copies the data in parallel\n        # cipher.copy_slice takes bytes as input, cipher.copy_slice1 takes bytearray\n        cipher.copy_slice(plaintext, buf)\n        # encrypt it, this will encrypt in-place the data in the buffer\n        print(\"encryping...\")\n        ciphertext_len = cipher.seal_in_place(buf, plaintext_len, 42, aad)\n        cipertext = buf[:ciphertext_len]\n        # you can do something with the ciphertext\n\n        # decrypt it\n        # if you need to copy ciphertext to buffer, we don't need to do it now as it's already in the buffer\n        # cipher.copy_slice(ciphertext, buf[:len(ciphertext)])\n        print(\"decryping...\")\n        plaintext_len = cipher.open_in_place(buf, ciphertext_len, 42, aad)\n        plaintext2 = buf[:plaintext_len]\n        # for security reasons we lock the memory of the plaintext so it won't be swapped to disk\n        mlock(plaintext2)\n        assert plaintext == plaintext2\n\n    finally:\n        # best practice, you should always zeroize the plaintext and keys after you are done with it (key will be zeroized when the enc object is dropped)\n        zeroize1(plaintext)\n        zeroize1(buf)\n\n        munlock(buf)\n        munlock(plaintext)\n\n        print(\"bye!\")\n```\n\nYou can use other ciphers like `cipher_meta = CipherMeta.Ring(RingAlgorithm.ChaCha20Poly1305)`.\n\nYou can also provide your own nonce that you can generate based on your contraints.\n\n```python\nfrom rencrypt import Cipher, CipherMeta, RingAlgorithm\nimport os\nfrom zeroize import zeroize1, mlock, munlock\nimport numpy as np\n\n\nif __name__ == \"__main__\":\n    try:\n        # You can use also other algorithms like cipher_meta = CipherMeta.Ring(RingAlgorithm.ChaCha20Poly1305)`.\n        cipher_meta = CipherMeta.Ring(RingAlgorithm.Aes256Gcm)\n        key_len = cipher_meta.key_len()\n        key = bytearray(key_len)\n        # for security reasons we lock the memory of the key so it won't be swapped to disk\n        mlock(key)\n        cipher_meta.generate_key(key)\n        # The key is copied and the input key is zeroized for security reasons.\n        # The copied key will also be zeroized when the object is dropped.\n        cipher = Cipher(cipher_meta, key)\n        # it was zeroized we can unlock it\n        munlock(key)\n\n        # we create a buffer based on plaintext block len of 4096\n        # the actual buffer needs to be a bit larger as the ciphertext also includes the tag and nonce\n        plaintext_len = 4096\n        ciphertext_len = cipher_meta.ciphertext_len(plaintext_len)\n        buf = np.array([0] * ciphertext_len, dtype=np.uint8)\n        # for security reasons we lock the memory of the buffer so it won't be swapped to disk, because it contains plaintext after decryption\n        mlock(buf)\n\n        aad = b\"AAD\"\n        # create our own nonce\n        nonce = os.urandom(cipher_meta.nonce_len())\n\n        # put some plaintext in the buffer, it would be ideal if you can directly collect the data into the buffer without allocating new memory\n        # but for the sake of example we will allocate and copy the data\n        plaintext = bytearray(os.urandom(plaintext_len))\n        # for security reasons we lock the memory of the plaintext so it won't be swapped to disk\n        mlock(plaintext)\n        # cipher.copy_slice is slighlty faster than buf[:plaintext_len] = plaintext, especially for large plaintext, because it copies the data in parallel\n        # cipher.copy_slice takes bytes as input, cipher.copy_slice1 takes bytearray\n        cipher.copy_slice(plaintext, buf)\n        # encrypt it, this will encrypt in-place the data in the buffer\n        # provide our own nonce\n        print(\"encryping...\")\n        ciphertext_len = cipher.seal_in_place(buf, plaintext_len, 42, aad, nonce)\n        cipertext = buf[:ciphertext_len]\n        # you can do something with the ciphertext\n\n        # decrypt it\n        # if you need to copy ciphertext to buffer, we don't need to do it now as it's already in the buffer\n        # cipher.copy_slice(ciphertext, buf[:len(ciphertext)])\n        print(\"decryping...\")\n        plaintext_len = cipher.open_in_place(buf, ciphertext_len, 42, aad)\n        plaintext2 = buf[:plaintext_len]\n        # for security reasons we lock the memory of the plaintext so it won't be swapped to disk\n        mlock(plaintext2)\n        assert plaintext == plaintext2\n\n    finally:\n        # best practice, you should always zeroize the plaintext and keys after you are done with it (key will be zeroized when the enc object is dropped)\n        zeroize1(plaintext)\n        zeroize1(buf)\n\n        munlock(buf)\n        munlock(plaintext)\n\n        print(\"bye!\")\n```\n\n## Encrypt and decrypt a file\n\n```python\nimport errno\nimport io\nimport os\nfrom pathlib import Path\nimport shutil\nfrom rencrypt import Cipher, CipherMeta, RingAlgorithm\nimport hashlib\nfrom zeroize import zeroize1, mlock, munlock\nimport numpy as np\n\n\ndef read_file_in_chunks(file_path, buf):\n    with open(file_path, \"rb\") as file:\n        buffered_reader = io.BufferedReader(file, buffer_size=len(buf))\n        while True:\n            read = buffered_reader.readinto(buf)\n            if read == 0:\n                break\n            yield read\n\n\ndef hash_file(file_path):\n    hash_algo = hashlib.sha256()\n    with open(file_path, \"rb\") as f:\n        for chunk in iter(lambda: f.read(4096), b\"\"):\n            hash_algo.update(chunk)\n    return hash_algo.hexdigest()\n\n\ndef compare_files_by_hash(file1, file2):\n    return hash_file(file1) == hash_file(file2)\n\n\ndef silentremove(filename):\n    try:\n        os.remove(filename)\n    except OSError as e:  # this would be \"except OSError, e:\" before Python 2.6\n        if e.errno != errno.ENOENT:  # errno.ENOENT = no such file or directory\n            raise  # re-raise exception if a different error occurred\n\n\ndef create_directory_in_home(dir_name):\n    # Get the user's home directory\n    home_dir = Path.home()\n\n    # Create the full path for the new directory\n    new_dir_path = home_dir / dir_name\n\n    # Create the directory\n    try:\n        new_dir_path.mkdir(parents=True, exist_ok=True)\n    except Exception as e:\n        print(f\"Error creating directory: {e}\")\n\n    return new_dir_path.absolute().__str__()\n\n\ndef create_file_with_size(file_path_str, size_in_bytes):\n    with open(file_path_str, \"wb\") as f:\n        for _ in range((size_in_bytes // 4096) + 1):\n            f.write(os.urandom(min(4096, size_in_bytes)))\n        f.flush()\n\n\ndef delete_dir(path):\n    if os.path.exists(path):\n        shutil.rmtree(path)\n    else:\n        print(f\"Directory {path} does not exist.\")\n\n\nif __name__ == \"__main__\":\n    try:\n        tmp_dir = create_directory_in_home(\"rencrypt_tmp\")\n        fin = tmp_dir + \"/\" + \"fin\"\n        fout = tmp_dir + \"/\" + \"fout.enc\"\n        create_file_with_size(fin, 10 * 1024 * 1024)\n\n        chunk_len = 256 * 1024\n\n        # You can use also other algorithms like cipher_meta = CipherMeta.Ring(RingAlgorithm.ChaCha20Poly1305)`.\n        cipher_meta = CipherMeta.Ring(RingAlgorithm.Aes256Gcm)\n        key_len = cipher_meta.key_len()\n        key = bytearray(key_len)\n        # for security reasons we lock the memory of the key so it won't be swapped to disk\n        mlock(key)\n        cipher_meta.generate_key(key)\n        # The key is copied and the input key is zeroized for security reasons.\n        # The copied key will also be zeroized when the object is dropped.\n        cipher = Cipher(cipher_meta, key)\n        # it was zeroized we can unlock it\n        munlock(key)\n\n        plaintext_len = chunk_len\n        ciphertext_len = cipher_meta.ciphertext_len(plaintext_len)\n        buf = np.array([0] * ciphertext_len, dtype=np.uint8)\n        mlock(buf)\n\n        aad = b\"AAD\"\n\n        # encrypt\n        print(\"encryping...\")\n        with open(fout, \"wb\", buffering=plaintext_len) as file_out:\n            i = 0\n            for read in read_file_in_chunks(fin, buf[:plaintext_len]):\n                ciphertext_len = cipher.seal_in_place(buf, read, i, aad)\n                file_out.write(buf[:ciphertext_len])\n                i += 1\n            file_out.flush()\n\n        # decrypt\n        print(\"decryping...\")\n        tmp = fout + \".dec\"\n        with open(tmp, \"wb\", buffering=plaintext_len) as file_out:\n            i = 0\n            for read in read_file_in_chunks(fout, buf):\n                plaintext_len2 = cipher.open_in_place(buf, read, i, aad)\n                file_out.write(buf[:plaintext_len2])\n                i += 1\n            file_out.flush()\n\n        assert compare_files_by_hash(fin, tmp)\n\n        delete_dir(tmp_dir)\n\n    finally:\n        # best practice, you should always zeroize the plaintext and keys after you are done with it (key will be zeroized when the enc object is dropped)\n        # buf will containt the last block plaintext so we need to zeroize it\n        zeroize1(buf)\n\n        munlock(buf)\n\n    print(\"bye!\")\n```\n\n## Encrypt and decrypt from some bytes into the buffer\n\n`encrypt_from()`/`decrypt_from()`\n\nThis is a bit slower than handling data only via the buffer, especially for large plaintext, but there are situations when you can't directly collect the data to the buffer but have some data from somewhere else.\n\n```python\nfrom rencrypt import Cipher, CipherMeta, RingAlgorithm\nimport os\nfrom zeroize import zeroize1, mlock, munlock\nimport numpy as np\n\n\nif __name__ == \"__main__\":\n    try:\n        # You can use also other algorithms like cipher_meta = CipherMeta.Ring(RingAlgorithm.ChaCha20Poly1305)`.\n        cipher_meta = CipherMeta.Ring(RingAlgorithm.Aes256Gcm)\n        key_len = cipher_meta.key_len()\n        key = bytearray(key_len)\n        # for security reasons we lock the memory of the key so it won't be swapped to disk\n        mlock(key)\n        cipher_meta.generate_key(key)\n        # The key is copied and the input key is zeroized for security reasons.\n        # The copied key will also be zeroized when the object is dropped.\n        cipher = Cipher(cipher_meta, key)\n        # it was zeroized we can unlock it\n        munlock(key)\n\n        # we create a buffer based on plaintext block len of 4096\n        # the actual buffer needs to be a bit larger as the ciphertext also includes the tag and nonce\n        plaintext_len = 4096\n        ciphertext_len = cipher_meta.ciphertext_len(plaintext_len)\n        buf = np.array([0] * ciphertext_len, dtype=np.uint8)\n        # for security reasons we lock the memory of the buffer so it won't be swapped to disk, because it contains plaintext after decryption\n        mlock(buf)\n\n        aad = b\"AAD\"\n\n        plaintext = bytearray(os.urandom(plaintext_len))\n        # for security reasons we lock the memory of the plaintext so it won't be swapped to disk\n        mlock(plaintext)\n\n        # encrypt it, after this will have the ciphertext in the buffer\n        print(\"encryping...\")\n        ciphertext_len = cipher.seal_in_place_from(plaintext, buf, 42, aad)\n        cipertext = bytes(buf[:ciphertext_len])\n\n        # decrypt it\n        print(\"decryping...\")\n        plaintext_len = cipher.open_in_place_from(cipertext, buf, 42, aad)\n        plaintext2 = buf[:plaintext_len]\n        # for security reasons we lock the memory of the plaintext so it won't be swapped to disk\n        mlock(plaintext2)\n        assert plaintext == plaintext2\n\n    finally:\n        # best practice, you should always zeroize the plaintext and keys after you are done with it (key will be zeroized when the enc object is dropped)\n        zeroize1(plaintext)\n        zeroize1(buf)\n\n        munlock(buf)\n        munlock(plaintext)\n\n        print(\"bye!\")\n```\n\n## Zeroing memory before forking child process\n\nThis mitigates the problems that appears on [Copy-on-write fork](https://en.wikipedia.org/wiki/Copy-on-write). You need to zeroize the data before forking the child process.\n\n```python\nimport os\nfrom zeroize import zeroize1, mlock, munlock\n\n\nif __name__ == \"__main__\":\n    try:\n        # Maximum you can mlock is 4MB\n        sensitive_data = bytearray(b\"Sensitive Information\")\n        mlock(sensitive_data)\n\n        print(\"Before zeroization:\", sensitive_data)\n\n        zeroize1(sensitive_data)\n        print(\"After zeroization:\", sensitive_data)\n\n        # Forking after zeroization to ensure no sensitive data is copied\n        pid = os.fork()\n        if pid == 0:\n            # This is the child process\n            print(\"Child process memory after fork:\", sensitive_data)\n        else:\n            # This is the parent process\n            os.wait()  # Wait for the child process to exit\n        \n        print(\"all good, bye!\")\n\n    finally:\n        # Unlock the memory\n        print(\"unlocking memory\")\n        munlock(sensitive_data)\n```\n\n# Build from source\n\n## Browser\n\n[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/radumarias/rencrypt-python)\n\n[![Open in Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/?repo=radumarias%2Frencrypt-python&ref=main)\n\n## Geting sources from GitHub\n\nSkip this if you're starting it in browser.\n\n```bash\ngit clone https://github.com/radumarias/rencrypt-python && cd Cipher-python\n```\n\n## Compile and run\n\n```bash\ncurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\n```\n\nTo configure your current shell, you need to source\nthe corresponding env file under $HOME/.cargo.\nThis is usually done by running one of the following (note the leading DOT):\n\n```bash\n. \"$HOME/.cargo/env\"\n```\n\n```bash\npython -m venv .env\nsource .env/bin/activate\npip install -r requirements.txt\nmaturin develop --release\npytest\npython examples/encrypt.py\npython examples/encrypt_into.py\npython examples/encrypt_from.py\npython examples/encrypt_file.py\npython benches/bench.py\n```\n\n# More benchmarks\n\n## Different ways to use the lib\n\n**Encrypt**  \n![Encrypt buffer](https://github.com/radumarias/rencrypt-python/blob/main/resources/charts/encrypt-all.png?raw=true)\n\n**Decrypt**  \n ![Decrypt buffer](https://github.com/radumarias/rencrypt-python/blob/main/resources/charts/decrypt-all.png?raw=true)\n\n**Block size and duration in seconds**\n\n<table>\n    <thead>\n        <tr>\n            <td>MB</td>\n            <td>rencrypt<br>encrypt</td>\n            <td>PyFLocker<br>encrypt update_into</td>\n            <td>rencrypt<br>encrypt_from</td>\n            <td>PyFLocker<br>encrypt update</td>\n            <td>rencrypt<br>decrypt</td>\n            <td>PyFLocker<br>decrypt update_into</td>\n            <td>rencrypt<br>decrypt_from</td>\n            <td>\n                <div>\n                    <div>PyFLocker<br>decrypt update</div>\n                </div>\n            </td>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td>0.03125</td>\n            <td>0.00001</td>\n            <td>0.00091</td>\n            <td>0.00001</td>\n            <td>0.00009</td>\n            <td>0.00001</td>\n            <td>0.00004</td>\n            <td>0.00001</td>\n            <td>0.00005</td>\n        </tr>\n        <tr>\n            <td>0.0625</td>\n            <td>0.00001</td>\n            <td>0.00005</td>\n            <td>0.00002</td>\n            <td>0.00005</td>\n            <td>0.00001</td>\n            <td>0.00004</td>\n            <td>0.00002</td>\n            <td>0.00008</td>\n        </tr>\n        <tr>\n            <td>0.125</td>\n            <td>0.00002</td>\n            <td>0.00005</td>\n            <td>0.00003</td>\n            <td>0.00011</td>\n            <td>0.00003</td>\n            <td>0.00005</td>\n            <td>0.00003</td>\n            <td>0.00013</td>\n        </tr>\n        <tr>\n            <td>0.25</td>\n            <td>0.00004</td>\n            <td>0.00008</td>\n            <td>0.00007</td>\n            <td>0.00019</td>\n            <td>0.00005</td>\n            <td>0.00009</td>\n            <td>0.00007</td>\n            <td>0.00023</td>\n        </tr>\n        <tr>\n            <td>0.5</td>\n            <td>0.0001</td>\n            <td>0.00014</td>\n            <td>0.00015</td>\n            <td>0.00035</td>\n            <td>0.00011</td>\n            <td>0.00015</td>\n            <td>0.00014</td>\n            <td>0.00043</td>\n        </tr>\n        <tr>\n            <td>1</td>\n            <td>0.00021</td>\n            <td>0.00024</td>\n            <td>0.0008</td>\n            <td>0.00082</td>\n            <td>0.00021</td>\n            <td>0.00029</td>\n            <td>0.00044</td>\n            <td>0.00103</td>\n        </tr>\n        <tr>\n            <td>2</td>\n            <td>0.00043</td>\n            <td>0.00052</td>\n            <td>0.00082</td>\n            <td>0.00147</td>\n            <td>0.00044</td>\n            <td>0.00058</td>\n            <td>0.00089</td>\n            <td>0.00176</td>\n        </tr>\n        <tr>\n            <td>4</td>\n            <td>0.00089</td>\n            <td>0.00098</td>\n            <td>0.00174</td>\n            <td>0.00284</td>\n            <td>0.00089</td>\n            <td>0.00117</td>\n            <td>0.0013</td>\n            <td>0.0034</td>\n        </tr>\n        <tr>\n            <td>8</td>\n            <td>0.00184</td>\n            <td>0.0019</td>\n            <td>0.00263</td>\n            <td>0.00523</td>\n            <td>0.00192</td>\n            <td>0.00323</td>\n            <td>0.00283</td>\n            <td>0.00571</td>\n        </tr>\n        <tr>\n            <td>16</td>\n            <td>0.00353</td>\n            <td>0.00393</td>\n            <td>0.00476</td>\n            <td>0.0141</td>\n            <td>0.00367</td>\n            <td>0.00617</td>\n            <td>0.00509</td>\n            <td>0.01031</td>\n        </tr>\n        <tr>\n            <td>32</td>\n            <td>0.00678</td>\n            <td>0.00748</td>\n            <td>0.00904</td>\n            <td>0.0244</td>\n            <td>0.00749</td>\n            <td>0.01348</td>\n            <td>0.01014</td>\n            <td>0.02543</td>\n        </tr>\n        <tr>\n            <td>64</td>\n            <td>0.01361</td>\n            <td>0.01461</td>\n            <td>0.01595</td>\n            <td>0.05064</td>\n            <td>0.0146</td>\n            <td>0.02697</td>\n            <td>0.0192</td>\n            <td>0.05296</td>\n        </tr>\n        <tr>\n            <td>128</td>\n            <td>0.02923</td>\n            <td>0.03027</td>\n            <td>0.03343</td>\n            <td>0.10362</td>\n            <td>0.03134</td>\n            <td>0.0541</td>\n            <td>0.03558</td>\n            <td>0.1138</td>\n        </tr>\n        <tr>\n            <td>256</td>\n            <td>0.06348</td>\n            <td>0.06188</td>\n            <td>0.07303</td>\n            <td>0.20911</td>\n            <td>0.06136</td>\n            <td>0.10417</td>\n            <td>0.07572</td>\n            <td>0.20828</td>\n        </tr>\n        <tr>\n            <td>512</td>\n            <td>0.11782</td>\n            <td>0.13463</td>\n            <td>0.14283</td>\n            <td>0.41929</td>\n            <td>0.1209</td>\n            <td>0.21114</td>\n            <td>0.14434</td>\n            <td>0.41463</td>\n        </tr>\n        <tr>\n            <td>1024</td>\n            <td>0.25001</td>\n            <td>0.24953</td>\n            <td>0.28912</td>\n            <td>0.8237</td>\n            <td>0.25377</td>\n            <td>0.42581</td>\n            <td>0.29795</td>\n            <td>0.82588</td>\n        </tr>\n    </tbody>\n</table>\n\n## Speed throughput\n\n`256KB` seems to be the sweet spot for buffer size that offers the max `MB/s` speed for encryption, on benchmarks that seem to be the case.\nWe performed `10.000` encryption operations for each size varying from `1KB` to `16MB`.\n\n![Speed throughput](https://github.com/radumarias/rencrypt-python/blob/main/resources/charts/speed-throughput.png?raw=true)\n\n| MB    | MB/s |\n| ----- | ------- |\n| 0.0009765625 | 1083 |\n| 0.001953125 | 1580 |\n| 0.00390625 | 2158 |\n| 0.0078125 | 2873 |\n| 0.015625 | 3348 |\n| 0.03125 | 3731 |\n| 0.0625 | 4053 |\n| 0.125 | 4156 |\n| <span style=\"color: red; font-weight: bold;\">0.25</span> | <span style=\"color: red; font-weight: bold;\">4247</span> |\n| 0.5 | 4182 |\n| 1.0 | 3490 |\n| 2.0 | 3539 |\n| 4.0 | 3684 |\n| 8.0 | 3787 |\n| 16.0 | 3924 |\n\n# For the future\n\n- Generating key from password (`KDF`)\n- Maybe add support for `RSA` and `Elliptic-curve cryptography`\n- Saving and loading keys from file\n\n# Considerations\n\nThis lib hasn't been audited, but it wraps `ring` crate (well known and audited library) and `RustCrypto` (`AES-GCM` and `ChaCha20Poly1305` ciphers are audited), so in principle at least the primitives should offer a similar level of security.\n\n# Contribute\n\nFeel free to fork it, change and use it in any way that you want. If you build something interesting and feel like sharing pull requests are always appreciated.\n\nUnless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache License, shall be dual-licensed as above, without any additional terms or conditions.\n\n## How to contribute\n\n1. Fork the repo\n2. Make the changes in your fork\n3. Add tests for your changes, if applicable\n4. `cargo build --all --all-features` and fix any issues\n5. `cargo fmt --all`, you can cnofigure your IDE to do this on save [RustRover](https://www.jetbrains.com/help/rust/rustfmt.html) and [VSCode](https://code.visualstudio.com/docs/languages/rust#_formatting)\n6. `cargo check --all --all-features` and fix any errors and warnings\n7. `cargo clippy --all --all-features` and fix any errors\n8. `cargo test --all --all-features` and fix any issues\n9. `cargo bench --all --all-features` and fix any issues\n10. Create a PR\n11. Monitor the checks (GitHub actions runned)\n12. Respond to any comments\n13. In the end ideally it will be merged to `main`\n\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "A Python encryption library implemented in Rust. It supports AEAD with various ciphers. It uses multiple providers to handle encryption.",
    "version": "1.0.7",
    "project_urls": {
        "Homepage": "https://github.com/radumarias/rencrypt-python",
        "Issues": "https://github.com/radumarias/rencrypt-python/issues"
    },
    "split_keywords": [
        "cryptography",
        " encryption",
        " security",
        " rust",
        " speed",
        " aead",
        " cipher"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "fefc15139cf9e5738841a0d7e157fb79fa44a23cd427ee2ebfadb772c03480bd",
                "md5": "7a2dddae374e2b756589894cee567c26",
                "sha256": "43acba194a67fcf3b823fd5bd2356dddee3e5c6463d87e4dad3e9e19bb9171bd"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp310-cp310-macosx_10_12_x86_64.whl",
            "has_sig": false,
            "md5_digest": "7a2dddae374e2b756589894cee567c26",
            "packagetype": "bdist_wheel",
            "python_version": "cp310",
            "requires_python": ">=3.7",
            "size": 521733,
            "upload_time": "2024-06-22T03:15:16",
            "upload_time_iso_8601": "2024-06-22T03:15:16.929154Z",
            "url": "https://files.pythonhosted.org/packages/fe/fc/15139cf9e5738841a0d7e157fb79fa44a23cd427ee2ebfadb772c03480bd/rencrypt-1.0.7-cp310-cp310-macosx_10_12_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "327ea7d1652c5594f21a5c03f365b2a8f34669bba7c152e1fc4c54af365d3522",
                "md5": "d29c6235273948b74926258b3235b8a1",
                "sha256": "efaebd78c56c1137fccab7d286a7af815bf63de2094054a523484cab63079b70"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp310-cp310-macosx_11_0_arm64.whl",
            "has_sig": false,
            "md5_digest": "d29c6235273948b74926258b3235b8a1",
            "packagetype": "bdist_wheel",
            "python_version": "cp310",
            "requires_python": ">=3.7",
            "size": 381629,
            "upload_time": "2024-06-22T03:15:08",
            "upload_time_iso_8601": "2024-06-22T03:15:08.977669Z",
            "url": "https://files.pythonhosted.org/packages/32/7e/a7d1652c5594f21a5c03f365b2a8f34669bba7c152e1fc4c54af365d3522/rencrypt-1.0.7-cp310-cp310-macosx_11_0_arm64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "6f8f21e7dd2eb015b0e52b4c47a39e0c1b80bffb953f3ee2587e26c02da58c85",
                "md5": "ca0deca1e6748b0d15efd88c55646879",
                "sha256": "64eab69632a9fb49ffcb517453d3e7f527ff1ae560a3831c246b052a724e0bfc"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "has_sig": false,
            "md5_digest": "ca0deca1e6748b0d15efd88c55646879",
            "packagetype": "bdist_wheel",
            "python_version": "cp310",
            "requires_python": ">=3.7",
            "size": 549743,
            "upload_time": "2024-06-22T03:13:41",
            "upload_time_iso_8601": "2024-06-22T03:13:41.034750Z",
            "url": "https://files.pythonhosted.org/packages/6f/8f/21e7dd2eb015b0e52b4c47a39e0c1b80bffb953f3ee2587e26c02da58c85/rencrypt-1.0.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "95c6ff698498807f291d528da5732fdf43bb1b6cb7121c4c24221ef7dbc08a38",
                "md5": "61bb6f84f0f95afe8fb2b72053851451",
                "sha256": "2873c2eee0e365d1fb818db93b57d1dc71936611b272cc9e741349e19004ac75"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl",
            "has_sig": false,
            "md5_digest": "61bb6f84f0f95afe8fb2b72053851451",
            "packagetype": "bdist_wheel",
            "python_version": "cp310",
            "requires_python": ">=3.7",
            "size": 577566,
            "upload_time": "2024-06-22T03:14:30",
            "upload_time_iso_8601": "2024-06-22T03:14:30.456753Z",
            "url": "https://files.pythonhosted.org/packages/95/c6/ff698498807f291d528da5732fdf43bb1b6cb7121c4c24221ef7dbc08a38/rencrypt-1.0.7-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "616ec77b4d9a305e7dbef0348bd4fdfca9a22dc7c0a0290690d98a7ae34dc389",
                "md5": "3131971d73b1027f816e63bef1be199b",
                "sha256": "0844cc870becd43405cedbe1a65bea094226c628880a093a4ed49b15dddc477f"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "has_sig": false,
            "md5_digest": "3131971d73b1027f816e63bef1be199b",
            "packagetype": "bdist_wheel",
            "python_version": "cp310",
            "requires_python": ">=3.7",
            "size": 545499,
            "upload_time": "2024-06-22T03:13:58",
            "upload_time_iso_8601": "2024-06-22T03:13:58.355070Z",
            "url": "https://files.pythonhosted.org/packages/61/6e/c77b4d9a305e7dbef0348bd4fdfca9a22dc7c0a0290690d98a7ae34dc389/rencrypt-1.0.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "d2d5a7e0734802a3ef36c6b6e9f9fb7832bb82f981cbfb36c1bfc159ad909618",
                "md5": "a6ac392ecb53a45c8664e4f5db62d5a7",
                "sha256": "12339fd8ba8256bcbf009cd0863ff9d5c3c97f4769217375f75c40974493bf88"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "has_sig": false,
            "md5_digest": "a6ac392ecb53a45c8664e4f5db62d5a7",
            "packagetype": "bdist_wheel",
            "python_version": "cp310",
            "requires_python": ">=3.7",
            "size": 576044,
            "upload_time": "2024-06-22T03:14:13",
            "upload_time_iso_8601": "2024-06-22T03:14:13.131963Z",
            "url": "https://files.pythonhosted.org/packages/d2/d5/a7e0734802a3ef36c6b6e9f9fb7832bb82f981cbfb36c1bfc159ad909618/rencrypt-1.0.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "689e9233c6d5ae74149a966e5bace6bb7d1b6f4f582e6d8a9a239e1eef6356fa",
                "md5": "e4af32f1be0f9f8ba7eb08138e84b2d1",
                "sha256": "20f5a295699952b8a787719db3ba4e5e52a331cee3d91f3299c37e8739bcb3a4"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "has_sig": false,
            "md5_digest": "e4af32f1be0f9f8ba7eb08138e84b2d1",
            "packagetype": "bdist_wheel",
            "python_version": "cp310",
            "requires_python": ">=3.7",
            "size": 570623,
            "upload_time": "2024-06-22T03:14:49",
            "upload_time_iso_8601": "2024-06-22T03:14:49.703749Z",
            "url": "https://files.pythonhosted.org/packages/68/9e/9233c6d5ae74149a966e5bace6bb7d1b6f4f582e6d8a9a239e1eef6356fa/rencrypt-1.0.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "1572441f088e2678c4adf04c7583916036f06a419fe8b02072344b9af69e5cf9",
                "md5": "fe8aac0ec279ee89ecccbad36c906a2e",
                "sha256": "8c6a72090c2443059ba8d724eaf502c7fcc67e47b6767cb9afba35d690467486"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp310-none-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "fe8aac0ec279ee89ecccbad36c906a2e",
            "packagetype": "bdist_wheel",
            "python_version": "cp310",
            "requires_python": ">=3.7",
            "size": 563081,
            "upload_time": "2024-06-22T03:15:25",
            "upload_time_iso_8601": "2024-06-22T03:15:25.271949Z",
            "url": "https://files.pythonhosted.org/packages/15/72/441f088e2678c4adf04c7583916036f06a419fe8b02072344b9af69e5cf9/rencrypt-1.0.7-cp310-none-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "8c6613275c77f17a2ccaee0a124c620369281ccd7ee48c92d4a0de9e6b8bc963",
                "md5": "9f0986b93e1e9f56e5ce77a62e5e3184",
                "sha256": "975ed2a5c013ac6638df59512c2502c262fca469ef5ace5745ef5217a0223e55"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp311-cp311-macosx_10_12_x86_64.whl",
            "has_sig": false,
            "md5_digest": "9f0986b93e1e9f56e5ce77a62e5e3184",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.7",
            "size": 521408,
            "upload_time": "2024-06-22T03:15:18",
            "upload_time_iso_8601": "2024-06-22T03:15:18.683769Z",
            "url": "https://files.pythonhosted.org/packages/8c/66/13275c77f17a2ccaee0a124c620369281ccd7ee48c92d4a0de9e6b8bc963/rencrypt-1.0.7-cp311-cp311-macosx_10_12_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "12709f463302f67c6458b46c45a7406c31a238e045878e3d94d64d3522e78f9e",
                "md5": "833634c754f9227fb6aaef0ae29b5c8d",
                "sha256": "082fdb5229b1915b5463d7df278cd885dd492f6f759cd915d3799d703a5319bd"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp311-cp311-macosx_11_0_arm64.whl",
            "has_sig": false,
            "md5_digest": "833634c754f9227fb6aaef0ae29b5c8d",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.7",
            "size": 381444,
            "upload_time": "2024-06-22T03:15:11",
            "upload_time_iso_8601": "2024-06-22T03:15:11.256328Z",
            "url": "https://files.pythonhosted.org/packages/12/70/9f463302f67c6458b46c45a7406c31a238e045878e3d94d64d3522e78f9e/rencrypt-1.0.7-cp311-cp311-macosx_11_0_arm64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "889d9e914a386ed157cef053612603729ba393c4ea6d69c77fcaaa01416e7c65",
                "md5": "716898623f729ad01ca151be9879862f",
                "sha256": "d7fe3960ad34adb7fb48f5a5e0799de90bb8d9a7e357afad35a10582d0318f3a"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "has_sig": false,
            "md5_digest": "716898623f729ad01ca151be9879862f",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.7",
            "size": 549843,
            "upload_time": "2024-06-22T03:13:42",
            "upload_time_iso_8601": "2024-06-22T03:13:42.875457Z",
            "url": "https://files.pythonhosted.org/packages/88/9d/9e914a386ed157cef053612603729ba393c4ea6d69c77fcaaa01416e7c65/rencrypt-1.0.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "f114bc45caff6a173d88388fa239ac6c9634dee56460d380855222129ae66fbe",
                "md5": "734da373e2245342b775bb2e57c37462",
                "sha256": "ead603b0028ff02dd8c4b33930cbe20159c82b1939e03b6849780e7cfd727af1"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl",
            "has_sig": false,
            "md5_digest": "734da373e2245342b775bb2e57c37462",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.7",
            "size": 577503,
            "upload_time": "2024-06-22T03:14:32",
            "upload_time_iso_8601": "2024-06-22T03:14:32.049082Z",
            "url": "https://files.pythonhosted.org/packages/f1/14/bc45caff6a173d88388fa239ac6c9634dee56460d380855222129ae66fbe/rencrypt-1.0.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "7c52e34e40d4d2fb84110290e192dee237524178b089ead6fbe6019cf4e4fe76",
                "md5": "81b571a90431bbc2b22c8762913dc3f6",
                "sha256": "9cdad7b7c79eb9e41615c4451262a26d8a228db8ef4971d26276cea64979ef6d"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "has_sig": false,
            "md5_digest": "81b571a90431bbc2b22c8762913dc3f6",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.7",
            "size": 546462,
            "upload_time": "2024-06-22T03:13:59",
            "upload_time_iso_8601": "2024-06-22T03:13:59.704617Z",
            "url": "https://files.pythonhosted.org/packages/7c/52/e34e40d4d2fb84110290e192dee237524178b089ead6fbe6019cf4e4fe76/rencrypt-1.0.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "c6c1fb73b3e8bec154d12c9aab1bdd83ffa1098206ebca855d0ee0c0e8a1ea92",
                "md5": "faa5624fb05db161f25758f6e27f1f24",
                "sha256": "7ff1c756d6b727fd25cdf099b405d7b5e35de9f0e74e2a5528fb5459bf3b4650"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "has_sig": false,
            "md5_digest": "faa5624fb05db161f25758f6e27f1f24",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.7",
            "size": 576610,
            "upload_time": "2024-06-22T03:14:14",
            "upload_time_iso_8601": "2024-06-22T03:14:14.632046Z",
            "url": "https://files.pythonhosted.org/packages/c6/c1/fb73b3e8bec154d12c9aab1bdd83ffa1098206ebca855d0ee0c0e8a1ea92/rencrypt-1.0.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "5ae71e084417b921cfc7590b639af1d6200cdbcc2f952f3c3ac846bad64ad7cd",
                "md5": "7d3c8fffb47593adaf672aa92d7220c0",
                "sha256": "fe2fbc76e2e5cc4b26e4f1adffa55462704e30b5e50dc075ce46e298e4865c18"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "has_sig": false,
            "md5_digest": "7d3c8fffb47593adaf672aa92d7220c0",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.7",
            "size": 569574,
            "upload_time": "2024-06-22T03:14:51",
            "upload_time_iso_8601": "2024-06-22T03:14:51.803774Z",
            "url": "https://files.pythonhosted.org/packages/5a/e7/1e084417b921cfc7590b639af1d6200cdbcc2f952f3c3ac846bad64ad7cd/rencrypt-1.0.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "2eece0c4de94d0038cfa2bb308bc17480050f59a9c6496744bc1365f3923e28b",
                "md5": "4cf8fc20228d413b0bed7514609714b2",
                "sha256": "d918edebaa00aeefb174b26e68a7a9d46ca8ad357510c1f61b84aaa459eb95f9"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp311-none-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "4cf8fc20228d413b0bed7514609714b2",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.7",
            "size": 562701,
            "upload_time": "2024-06-22T03:15:27",
            "upload_time_iso_8601": "2024-06-22T03:15:27.198044Z",
            "url": "https://files.pythonhosted.org/packages/2e/ec/e0c4de94d0038cfa2bb308bc17480050f59a9c6496744bc1365f3923e28b/rencrypt-1.0.7-cp311-none-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "8ea99c4b090be734dd9503f54ed881d5bb9a4351b62901fc11e6cc7e648b4cc8",
                "md5": "bcf297b8ad5843e67db6a828c31af1d3",
                "sha256": "0d21c1bd42d47463a38685aae1073a76af677eb6da8f606df03aaced6eed3c58"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp312-cp312-macosx_10_12_x86_64.whl",
            "has_sig": false,
            "md5_digest": "bcf297b8ad5843e67db6a828c31af1d3",
            "packagetype": "bdist_wheel",
            "python_version": "cp312",
            "requires_python": ">=3.7",
            "size": 519835,
            "upload_time": "2024-06-22T03:15:20",
            "upload_time_iso_8601": "2024-06-22T03:15:20.377801Z",
            "url": "https://files.pythonhosted.org/packages/8e/a9/9c4b090be734dd9503f54ed881d5bb9a4351b62901fc11e6cc7e648b4cc8/rencrypt-1.0.7-cp312-cp312-macosx_10_12_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "b41a1f713a53d49fc3ab37b22291ebf9b912959aafdf9bde45a56c989bd70af4",
                "md5": "2d15e608d629a3c5a21531c2732d97ee",
                "sha256": "8a75c902cebb3384e10189248a8a14f1a76779141b258932868cc9b0c3ef61cb"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp312-cp312-macosx_11_0_arm64.whl",
            "has_sig": false,
            "md5_digest": "2d15e608d629a3c5a21531c2732d97ee",
            "packagetype": "bdist_wheel",
            "python_version": "cp312",
            "requires_python": ">=3.7",
            "size": 381063,
            "upload_time": "2024-06-22T03:15:13",
            "upload_time_iso_8601": "2024-06-22T03:15:13.129089Z",
            "url": "https://files.pythonhosted.org/packages/b4/1a/1f713a53d49fc3ab37b22291ebf9b912959aafdf9bde45a56c989bd70af4/rencrypt-1.0.7-cp312-cp312-macosx_11_0_arm64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "6b515d1e99bf13f1f222405a4eefc08ca12cf25c8ccd734d02dccb028c6d7e7a",
                "md5": "e489406f0ba9961955f5d3c29dbe10d4",
                "sha256": "5e7f602e81592c9a8ed1d021994f902b6ad518fa7db47fed8a8de8ede9eb777e"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "has_sig": false,
            "md5_digest": "e489406f0ba9961955f5d3c29dbe10d4",
            "packagetype": "bdist_wheel",
            "python_version": "cp312",
            "requires_python": ">=3.7",
            "size": 548136,
            "upload_time": "2024-06-22T03:13:44",
            "upload_time_iso_8601": "2024-06-22T03:13:44.305089Z",
            "url": "https://files.pythonhosted.org/packages/6b/51/5d1e99bf13f1f222405a4eefc08ca12cf25c8ccd734d02dccb028c6d7e7a/rencrypt-1.0.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "d170679ae273918903a6add9c594a46147c5475df37e81fe11418a88cedc9e2b",
                "md5": "2ebecdd06d2aefb9d73fea8f26159c83",
                "sha256": "1694d7cc57d98d4cbcb1a85cb709036b9b253614febf0a96be930d0ab423107e"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl",
            "has_sig": false,
            "md5_digest": "2ebecdd06d2aefb9d73fea8f26159c83",
            "packagetype": "bdist_wheel",
            "python_version": "cp312",
            "requires_python": ">=3.7",
            "size": 577981,
            "upload_time": "2024-06-22T03:14:33",
            "upload_time_iso_8601": "2024-06-22T03:14:33.993015Z",
            "url": "https://files.pythonhosted.org/packages/d1/70/679ae273918903a6add9c594a46147c5475df37e81fe11418a88cedc9e2b/rencrypt-1.0.7-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "7c2f8339aa64b7e1dce54daa92865c8a81a5099be30e33266443013ed6c1d7fc",
                "md5": "5a9a3f2dfb3e4163f18d44babf2f103b",
                "sha256": "c63b296fc3ed77faf682a51f72214eb51394d7526ce32f96e2f3a011d9c53c93"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "has_sig": false,
            "md5_digest": "5a9a3f2dfb3e4163f18d44babf2f103b",
            "packagetype": "bdist_wheel",
            "python_version": "cp312",
            "requires_python": ">=3.7",
            "size": 543927,
            "upload_time": "2024-06-22T03:14:01",
            "upload_time_iso_8601": "2024-06-22T03:14:01.086818Z",
            "url": "https://files.pythonhosted.org/packages/7c/2f/8339aa64b7e1dce54daa92865c8a81a5099be30e33266443013ed6c1d7fc/rencrypt-1.0.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "e5592348272cd00af4aec353fcffaedda2b2ca947ec1fc1c928368d24655e1cc",
                "md5": "39998f7c2232327b808446a793a33742",
                "sha256": "1ba49d2f8f85cfcad4376e12834f0d064fae666ac593cf3a931394e9890da9c9"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "has_sig": false,
            "md5_digest": "39998f7c2232327b808446a793a33742",
            "packagetype": "bdist_wheel",
            "python_version": "cp312",
            "requires_python": ">=3.7",
            "size": 569270,
            "upload_time": "2024-06-22T03:14:16",
            "upload_time_iso_8601": "2024-06-22T03:14:16.222472Z",
            "url": "https://files.pythonhosted.org/packages/e5/59/2348272cd00af4aec353fcffaedda2b2ca947ec1fc1c928368d24655e1cc/rencrypt-1.0.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "ee469a9b2592bf463d5d26fa73993e63194348183241d6e612251a20f6f9f329",
                "md5": "d3e98bd0e40b8dd87fd448ad0d9f11bc",
                "sha256": "570319ea5f17db8f0822d55c40ede8d2a8f4eae26e8f98dbce2f56def633f4a2"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "has_sig": false,
            "md5_digest": "d3e98bd0e40b8dd87fd448ad0d9f11bc",
            "packagetype": "bdist_wheel",
            "python_version": "cp312",
            "requires_python": ">=3.7",
            "size": 567554,
            "upload_time": "2024-06-22T03:14:53",
            "upload_time_iso_8601": "2024-06-22T03:14:53.436820Z",
            "url": "https://files.pythonhosted.org/packages/ee/46/9a9b2592bf463d5d26fa73993e63194348183241d6e612251a20f6f9f329/rencrypt-1.0.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "0df1bb6ffdaf7cc4f021841e61326085c301c6c222c4e301f8b2fc4c9d1b1d7f",
                "md5": "f7ba5d66718f860d493769f745feb5f1",
                "sha256": "25615ad86f1c1b1b710ae925070c848f52ae729a926eec4741adfbc00a42c1b6"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp312-none-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "f7ba5d66718f860d493769f745feb5f1",
            "packagetype": "bdist_wheel",
            "python_version": "cp312",
            "requires_python": ">=3.7",
            "size": 563785,
            "upload_time": "2024-06-22T03:15:28",
            "upload_time_iso_8601": "2024-06-22T03:15:28.929268Z",
            "url": "https://files.pythonhosted.org/packages/0d/f1/bb6ffdaf7cc4f021841e61326085c301c6c222c4e301f8b2fc4c9d1b1d7f/rencrypt-1.0.7-cp312-none-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "d2c317d10369ac18a448f4d054a52cbf0212a8f06858402af4c33430c3e6bc5d",
                "md5": "754b9ed07ff84f9f6e80310db502af0f",
                "sha256": "1a7cb63a51ccde32e6fa3b04a1da933ef4086a48baf3550679a2dfd6283ddd6b"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "has_sig": false,
            "md5_digest": "754b9ed07ff84f9f6e80310db502af0f",
            "packagetype": "bdist_wheel",
            "python_version": "cp37",
            "requires_python": ">=3.7",
            "size": 551296,
            "upload_time": "2024-06-22T03:13:45",
            "upload_time_iso_8601": "2024-06-22T03:13:45.592595Z",
            "url": "https://files.pythonhosted.org/packages/d2/c3/17d10369ac18a448f4d054a52cbf0212a8f06858402af4c33430c3e6bc5d/rencrypt-1.0.7-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "a216a925adbed7980162acd78754929b10fa25c60192474bea4fd9f2191292d3",
                "md5": "4b1ff6c1c9e1ba4619f43ea25c189f60",
                "sha256": "4625f3c691604d8d2b9dbb6483d005d23c783ba2d6c5ab913cf4177747260170"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl",
            "has_sig": false,
            "md5_digest": "4b1ff6c1c9e1ba4619f43ea25c189f60",
            "packagetype": "bdist_wheel",
            "python_version": "cp37",
            "requires_python": ">=3.7",
            "size": 578851,
            "upload_time": "2024-06-22T03:14:36",
            "upload_time_iso_8601": "2024-06-22T03:14:36.075748Z",
            "url": "https://files.pythonhosted.org/packages/a2/16/a925adbed7980162acd78754929b10fa25c60192474bea4fd9f2191292d3/rencrypt-1.0.7-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "10f7cc38f4b05b5c5f5fc94f4984dcf7382df10df5f4c4ba2065d469326e5573",
                "md5": "677d839abf5467ceca91e5e7a4aaf82e",
                "sha256": "e35f34f8117b617fa77a8eb32ce2e98dada7374f63d10a3f836ba76d8912cdc6"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "has_sig": false,
            "md5_digest": "677d839abf5467ceca91e5e7a4aaf82e",
            "packagetype": "bdist_wheel",
            "python_version": "cp37",
            "requires_python": ">=3.7",
            "size": 545712,
            "upload_time": "2024-06-22T03:14:02",
            "upload_time_iso_8601": "2024-06-22T03:14:02.528727Z",
            "url": "https://files.pythonhosted.org/packages/10/f7/cc38f4b05b5c5f5fc94f4984dcf7382df10df5f4c4ba2065d469326e5573/rencrypt-1.0.7-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "66ccd9e83484cb2a83751375bac6d8118a5bb9094aed07490bff6610691db1d2",
                "md5": "a53e72cd442861d1c14f9d39462a8953",
                "sha256": "4aa948ea90e834635d6e69fca6bc85766b891b26a9720f38e60bf4884e01edfd"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "has_sig": false,
            "md5_digest": "a53e72cd442861d1c14f9d39462a8953",
            "packagetype": "bdist_wheel",
            "python_version": "cp37",
            "requires_python": ">=3.7",
            "size": 576480,
            "upload_time": "2024-06-22T03:14:18",
            "upload_time_iso_8601": "2024-06-22T03:14:18.395435Z",
            "url": "https://files.pythonhosted.org/packages/66/cc/d9e83484cb2a83751375bac6d8118a5bb9094aed07490bff6610691db1d2/rencrypt-1.0.7-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "61aba21a131d04f8ba53ba1aa076e442de56165994fa02f3a6f723c8840698e9",
                "md5": "5a20aa1d3d73287fb000c8d1e0704b16",
                "sha256": "b026be6b183019aef062411226c302332850f9e3be0c6b41ec3e5a73cd4742df"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "has_sig": false,
            "md5_digest": "5a20aa1d3d73287fb000c8d1e0704b16",
            "packagetype": "bdist_wheel",
            "python_version": "cp37",
            "requires_python": ">=3.7",
            "size": 569769,
            "upload_time": "2024-06-22T03:14:55",
            "upload_time_iso_8601": "2024-06-22T03:14:55.089271Z",
            "url": "https://files.pythonhosted.org/packages/61/ab/a21a131d04f8ba53ba1aa076e442de56165994fa02f3a6f723c8840698e9/rencrypt-1.0.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "20d4de149710f5c116c250f20b98ea8ec47ac53ab54266a7de054f62c8335262",
                "md5": "32936cc703fb2a2845ff0f5b982043d0",
                "sha256": "06209fdb9f5898317a2619306005b27bf23ae91f93132dc046b7beb0cf1ab1ce"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp37-none-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "32936cc703fb2a2845ff0f5b982043d0",
            "packagetype": "bdist_wheel",
            "python_version": "cp37",
            "requires_python": ">=3.7",
            "size": 562891,
            "upload_time": "2024-06-22T03:15:30",
            "upload_time_iso_8601": "2024-06-22T03:15:30.461572Z",
            "url": "https://files.pythonhosted.org/packages/20/d4/de149710f5c116c250f20b98ea8ec47ac53ab54266a7de054f62c8335262/rencrypt-1.0.7-cp37-none-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "5ff531997ad89170ececcc951ea0eb173e4d567b1b7a98fb7b1bfb36358b50a2",
                "md5": "23df08654821ee098d41290d74e130fa",
                "sha256": "b78676ec304467d203a6f55de41285438ce3fa09bb638c241bcb702e433d0087"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "has_sig": false,
            "md5_digest": "23df08654821ee098d41290d74e130fa",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.7",
            "size": 550004,
            "upload_time": "2024-06-22T03:13:47",
            "upload_time_iso_8601": "2024-06-22T03:13:47.495075Z",
            "url": "https://files.pythonhosted.org/packages/5f/f5/31997ad89170ececcc951ea0eb173e4d567b1b7a98fb7b1bfb36358b50a2/rencrypt-1.0.7-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "fc54d7c267c83055fe0f84a14cbe8715cd1aa7322fb9bfaec9b5bdccccce482f",
                "md5": "d5c4fd9ed1dd703f54fd765c1ad02f64",
                "sha256": "2052aaacfb04d80405766e163bb1c0c2855281b9b521fe84dc16d459b1831962"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl",
            "has_sig": false,
            "md5_digest": "d5c4fd9ed1dd703f54fd765c1ad02f64",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.7",
            "size": 578278,
            "upload_time": "2024-06-22T03:14:37",
            "upload_time_iso_8601": "2024-06-22T03:14:37.619116Z",
            "url": "https://files.pythonhosted.org/packages/fc/54/d7c267c83055fe0f84a14cbe8715cd1aa7322fb9bfaec9b5bdccccce482f/rencrypt-1.0.7-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "0e013e257f03c949e25a662360b7c0e2fe173f69790088a95170a276d80e0333",
                "md5": "d9b5e02431eebe75e28a96380d67eb3a",
                "sha256": "762df8b1f18b04cc6f3d7947bf809b0bf9e8c6c8da36d561a9f5d28d092f0dba"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "has_sig": false,
            "md5_digest": "d9b5e02431eebe75e28a96380d67eb3a",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.7",
            "size": 545588,
            "upload_time": "2024-06-22T03:14:03",
            "upload_time_iso_8601": "2024-06-22T03:14:03.976145Z",
            "url": "https://files.pythonhosted.org/packages/0e/01/3e257f03c949e25a662360b7c0e2fe173f69790088a95170a276d80e0333/rencrypt-1.0.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "87942a04b9a21d92b5051fa0a0f3bd1514f2a80bfc6cde1ad284cabf5a7eb140",
                "md5": "13ca244dc4454837d17ccf6ea9f84133",
                "sha256": "5e8bb5e71270f11ebc3b87cc578fbb2401b8ff943fb9143edbb93e02bf6cb63b"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "has_sig": false,
            "md5_digest": "13ca244dc4454837d17ccf6ea9f84133",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.7",
            "size": 577426,
            "upload_time": "2024-06-22T03:14:20",
            "upload_time_iso_8601": "2024-06-22T03:14:20.324015Z",
            "url": "https://files.pythonhosted.org/packages/87/94/2a04b9a21d92b5051fa0a0f3bd1514f2a80bfc6cde1ad284cabf5a7eb140/rencrypt-1.0.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "15ac968716953dc62dded774b0bb90b4e41d5b516c4b3b206a5c920ffd05c5eb",
                "md5": "75065c6df3f8f7c72f4166a0f10f29fe",
                "sha256": "5df9406d920ac18962dafa44a74b2b44f8dc927191396ea282f58c1bdc604aa8"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "has_sig": false,
            "md5_digest": "75065c6df3f8f7c72f4166a0f10f29fe",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.7",
            "size": 568957,
            "upload_time": "2024-06-22T03:14:57",
            "upload_time_iso_8601": "2024-06-22T03:14:57.149083Z",
            "url": "https://files.pythonhosted.org/packages/15/ac/968716953dc62dded774b0bb90b4e41d5b516c4b3b206a5c920ffd05c5eb/rencrypt-1.0.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "2369f7549ebaa560f7d3e1485cefc4b4b992d9812ac2a837c21fa469de412f21",
                "md5": "480cf0e3baea809398f9634250a65468",
                "sha256": "6fa3add56bed5f25d62181bd224d33ea605da0a18de9bd4cc5d2dc353ba5b0a6"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp38-none-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "480cf0e3baea809398f9634250a65468",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.7",
            "size": 563442,
            "upload_time": "2024-06-22T03:15:32",
            "upload_time_iso_8601": "2024-06-22T03:15:32.296482Z",
            "url": "https://files.pythonhosted.org/packages/23/69/f7549ebaa560f7d3e1485cefc4b4b992d9812ac2a837c21fa469de412f21/rencrypt-1.0.7-cp38-none-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "ac9f72117932f6fa41cbe17c694fe910a6883edfade5633b13f574362d5c4d43",
                "md5": "31508f979ccd1706b0ee0ebf8470fc64",
                "sha256": "b5911aa93f98bb0d036e1316a43ad78f9fd2d43b8ac51d7f8331982fada8b54e"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp39-cp39-macosx_10_12_x86_64.whl",
            "has_sig": false,
            "md5_digest": "31508f979ccd1706b0ee0ebf8470fc64",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": ">=3.7",
            "size": 520750,
            "upload_time": "2024-06-22T03:15:22",
            "upload_time_iso_8601": "2024-06-22T03:15:22.029692Z",
            "url": "https://files.pythonhosted.org/packages/ac/9f/72117932f6fa41cbe17c694fe910a6883edfade5633b13f574362d5c4d43/rencrypt-1.0.7-cp39-cp39-macosx_10_12_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "b53abd736c9d8c4af17cba645ed4cb7df4f81edcfcf4c27a345eac515adaa534",
                "md5": "931ab2d20dee5955ce31273c15c6d15c",
                "sha256": "a0f0ffd0b14cf4af0da07a5c9878bfea54f7a58463eccd1c6c3df5c918d719cf"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp39-cp39-macosx_11_0_arm64.whl",
            "has_sig": false,
            "md5_digest": "931ab2d20dee5955ce31273c15c6d15c",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": ">=3.7",
            "size": 382285,
            "upload_time": "2024-06-22T03:15:15",
            "upload_time_iso_8601": "2024-06-22T03:15:15.341854Z",
            "url": "https://files.pythonhosted.org/packages/b5/3a/bd736c9d8c4af17cba645ed4cb7df4f81edcfcf4c27a345eac515adaa534/rencrypt-1.0.7-cp39-cp39-macosx_11_0_arm64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "37a31795cee5da17735655843fb9aab7f8ea338436364d1f903ac2627a4477cd",
                "md5": "6c414dc2576986ed4e79ef5d5cfb5baf",
                "sha256": "7b2c5dd3b82cd093aaef0886ce7e6dbfa09506abc24b0d912a5e65faa35ceb63"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "has_sig": false,
            "md5_digest": "6c414dc2576986ed4e79ef5d5cfb5baf",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": ">=3.7",
            "size": 550148,
            "upload_time": "2024-06-22T03:13:49",
            "upload_time_iso_8601": "2024-06-22T03:13:49.151529Z",
            "url": "https://files.pythonhosted.org/packages/37/a3/1795cee5da17735655843fb9aab7f8ea338436364d1f903ac2627a4477cd/rencrypt-1.0.7-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "9bd2c947597910376319a158ef6f476de36b0bf00a05444d29fcd601ade6c2b7",
                "md5": "1a94be4334147ef3907aad39bf208257",
                "sha256": "c17ccb33cf74ac2c440a5fd3ed137b69aba5fb78df3babf8314055aa2f85b46e"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl",
            "has_sig": false,
            "md5_digest": "1a94be4334147ef3907aad39bf208257",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": ">=3.7",
            "size": 578756,
            "upload_time": "2024-06-22T03:14:39",
            "upload_time_iso_8601": "2024-06-22T03:14:39.251099Z",
            "url": "https://files.pythonhosted.org/packages/9b/d2/c947597910376319a158ef6f476de36b0bf00a05444d29fcd601ade6c2b7/rencrypt-1.0.7-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "f3fd47411cfaec201e8e8b9b8427aa6417971fcf6ea9bcd04488e3da5131552b",
                "md5": "86a0c08c88b03f3b40426b85bc1aa7aa",
                "sha256": "c267b8f5e8102a3c82182010d18474d9a83e48d5838d5cd93e7490f2ed1269db"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "has_sig": false,
            "md5_digest": "86a0c08c88b03f3b40426b85bc1aa7aa",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": ">=3.7",
            "size": 545331,
            "upload_time": "2024-06-22T03:14:05",
            "upload_time_iso_8601": "2024-06-22T03:14:05.847371Z",
            "url": "https://files.pythonhosted.org/packages/f3/fd/47411cfaec201e8e8b9b8427aa6417971fcf6ea9bcd04488e3da5131552b/rencrypt-1.0.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "cb04ebc70d2039588899367d4d5e090a99345733b45a459c720dadf33a104d28",
                "md5": "bbcc0d6215514d8e0c52dd34d169ffe5",
                "sha256": "189c685ebce3228d0c9017a34a6d075b07bfc7335467f640a657d848e2f4a261"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "has_sig": false,
            "md5_digest": "bbcc0d6215514d8e0c52dd34d169ffe5",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": ">=3.7",
            "size": 576544,
            "upload_time": "2024-06-22T03:14:21",
            "upload_time_iso_8601": "2024-06-22T03:14:21.838446Z",
            "url": "https://files.pythonhosted.org/packages/cb/04/ebc70d2039588899367d4d5e090a99345733b45a459c720dadf33a104d28/rencrypt-1.0.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "e3168a20d80ee5d53c8125859404cb13f4cb999adb6ba7cd04b5e2d281eb8935",
                "md5": "0e7b652ace5f339d9b81c854d0573465",
                "sha256": "abc03b75f0b5f464f46bcce3c502509ec6b617ff894dedc92e5f8c4014f1e38a"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "has_sig": false,
            "md5_digest": "0e7b652ace5f339d9b81c854d0573465",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": ">=3.7",
            "size": 569332,
            "upload_time": "2024-06-22T03:14:59",
            "upload_time_iso_8601": "2024-06-22T03:14:59.301081Z",
            "url": "https://files.pythonhosted.org/packages/e3/16/8a20d80ee5d53c8125859404cb13f4cb999adb6ba7cd04b5e2d281eb8935/rencrypt-1.0.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "8fd1556f4451d4a3d4cc99668f05e4a1abb4ac85d836b3a2150c89ff0c8e1c2a",
                "md5": "121d636a9e6504601784fd80d211494a",
                "sha256": "530237ff47d87ac2b94d16bd34c0aeafa397e922d9a9bd961cd7d3f1f5424b94"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-cp39-none-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "121d636a9e6504601784fd80d211494a",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": ">=3.7",
            "size": 563763,
            "upload_time": "2024-06-22T03:15:33",
            "upload_time_iso_8601": "2024-06-22T03:15:33.894657Z",
            "url": "https://files.pythonhosted.org/packages/8f/d1/556f4451d4a3d4cc99668f05e4a1abb4ac85d836b3a2150c89ff0c8e1c2a/rencrypt-1.0.7-cp39-none-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "1428c88ca9b1a14963209cac8a87af3636439254fc2f40fe35678235b86018dd",
                "md5": "f83b40e9fbb70b610728a46be414001f",
                "sha256": "a721a74fbd74ebe23e39097ffbb18cbf7b543cdf7a56a8edf873764236e4d6a0"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "has_sig": false,
            "md5_digest": "f83b40e9fbb70b610728a46be414001f",
            "packagetype": "bdist_wheel",
            "python_version": "pp310",
            "requires_python": ">=3.7",
            "size": 551476,
            "upload_time": "2024-06-22T03:13:50",
            "upload_time_iso_8601": "2024-06-22T03:13:50.990144Z",
            "url": "https://files.pythonhosted.org/packages/14/28/c88ca9b1a14963209cac8a87af3636439254fc2f40fe35678235b86018dd/rencrypt-1.0.7-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "5105222c5e2421df93ce7149ba39a60fd8e8b4e0a56218b0bff3b0f15d7f39e1",
                "md5": "fe6a99dc50f1d28be0973e6608256579",
                "sha256": "d565c147af64ee7e7dc777276c0f1627d28c6c046df7de041617ce2c2b25a079"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl",
            "has_sig": false,
            "md5_digest": "fe6a99dc50f1d28be0973e6608256579",
            "packagetype": "bdist_wheel",
            "python_version": "pp310",
            "requires_python": ">=3.7",
            "size": 577265,
            "upload_time": "2024-06-22T03:14:41",
            "upload_time_iso_8601": "2024-06-22T03:14:41.693089Z",
            "url": "https://files.pythonhosted.org/packages/51/05/222c5e2421df93ce7149ba39a60fd8e8b4e0a56218b0bff3b0f15d7f39e1/rencrypt-1.0.7-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "c1c7e1eb208fb2b8857ec936db201fc80ab7a9c57ffe85c1ca59591889831eef",
                "md5": "5249f181d4af2e4996c0ee380de60fd2",
                "sha256": "1efc933a4128cd2ff13b8e6a6e0e5a7da7516d2c4111bd1600f284dcb6bc0060"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "has_sig": false,
            "md5_digest": "5249f181d4af2e4996c0ee380de60fd2",
            "packagetype": "bdist_wheel",
            "python_version": "pp310",
            "requires_python": ">=3.7",
            "size": 545365,
            "upload_time": "2024-06-22T03:14:07",
            "upload_time_iso_8601": "2024-06-22T03:14:07.253824Z",
            "url": "https://files.pythonhosted.org/packages/c1/c7/e1eb208fb2b8857ec936db201fc80ab7a9c57ffe85c1ca59591889831eef/rencrypt-1.0.7-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "42adf9a30bc7f7e93957567bdd0ff61742c433b02a9a66ebba6637fe4c81e3c7",
                "md5": "adee95be2967665a651dc432d1824d1a",
                "sha256": "63c7b913cbec0c2ec71ebf1e5b5e4f19d5df2b95597fa8e889d2e162e91d2167"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "has_sig": false,
            "md5_digest": "adee95be2967665a651dc432d1824d1a",
            "packagetype": "bdist_wheel",
            "python_version": "pp310",
            "requires_python": ">=3.7",
            "size": 574795,
            "upload_time": "2024-06-22T03:14:23",
            "upload_time_iso_8601": "2024-06-22T03:14:23.845754Z",
            "url": "https://files.pythonhosted.org/packages/42/ad/f9a30bc7f7e93957567bdd0ff61742c433b02a9a66ebba6637fe4c81e3c7/rencrypt-1.0.7-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "1ba1ce1a982768e6f2e8a49be793c36589e861f2d6b5cea0c4d5fadd0708bba9",
                "md5": "f2e7511e2371db512546393ce1729b83",
                "sha256": "5388aa8fc928d1a796eff4330c16a5d53f9eeb1826ed60007b99920736d92fc3"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "has_sig": false,
            "md5_digest": "f2e7511e2371db512546393ce1729b83",
            "packagetype": "bdist_wheel",
            "python_version": "pp310",
            "requires_python": ">=3.7",
            "size": 568508,
            "upload_time": "2024-06-22T03:15:01",
            "upload_time_iso_8601": "2024-06-22T03:15:01.047439Z",
            "url": "https://files.pythonhosted.org/packages/1b/a1/ce1a982768e6f2e8a49be793c36589e861f2d6b5cea0c4d5fadd0708bba9/rencrypt-1.0.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "b2dbd6d199ba21191e1f171a26730fbc91e14584bc07caf798c620abfec42d91",
                "md5": "5aa0b0a82fd33c5e00df91e04730010d",
                "sha256": "dc3223509bddaa25c1798b51409f5e29f803eca6f967f7aa1905e7beae99e8cb"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp37-pypy37_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "has_sig": false,
            "md5_digest": "5aa0b0a82fd33c5e00df91e04730010d",
            "packagetype": "bdist_wheel",
            "python_version": "pp37",
            "requires_python": ">=3.7",
            "size": 552733,
            "upload_time": "2024-06-22T03:13:52",
            "upload_time_iso_8601": "2024-06-22T03:13:52.629880Z",
            "url": "https://files.pythonhosted.org/packages/b2/db/d6d199ba21191e1f171a26730fbc91e14584bc07caf798c620abfec42d91/rencrypt-1.0.7-pp37-pypy37_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "0cea50922a9d776d2685cb6fc4747e1e834a92dcbae06b064f50cfc3224341b7",
                "md5": "141e2a067ed8e62ca1948b5374f3dfad",
                "sha256": "360bd6829cbf974dc8a9cd8dee75c1bd0acaf06bdeaa0609e6cbd55586ca8b4d"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl",
            "has_sig": false,
            "md5_digest": "141e2a067ed8e62ca1948b5374f3dfad",
            "packagetype": "bdist_wheel",
            "python_version": "pp37",
            "requires_python": ">=3.7",
            "size": 579001,
            "upload_time": "2024-06-22T03:14:44",
            "upload_time_iso_8601": "2024-06-22T03:14:44.924815Z",
            "url": "https://files.pythonhosted.org/packages/0c/ea/50922a9d776d2685cb6fc4747e1e834a92dcbae06b064f50cfc3224341b7/rencrypt-1.0.7-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "6bd00ec1b7a4ae4fa7f8bec7ceae3bf5f8dda4562ef3dcd0407c9914a19bea51",
                "md5": "460a94b283402f05394650697e713970",
                "sha256": "d9a4031f10119e48ea71dc24e8e6fb65b007461280e1b8196ebdc31ee451be25"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp37-pypy37_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "has_sig": false,
            "md5_digest": "460a94b283402f05394650697e713970",
            "packagetype": "bdist_wheel",
            "python_version": "pp37",
            "requires_python": ">=3.7",
            "size": 548569,
            "upload_time": "2024-06-22T03:14:08",
            "upload_time_iso_8601": "2024-06-22T03:14:08.679689Z",
            "url": "https://files.pythonhosted.org/packages/6b/d0/0ec1b7a4ae4fa7f8bec7ceae3bf5f8dda4562ef3dcd0407c9914a19bea51/rencrypt-1.0.7-pp37-pypy37_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "e9f7b3a0c06431be0a32e0cdf460c3a6e044863f132bf73053fccefcb356b8e2",
                "md5": "f3488809edb4c36f3edf385144ee491f",
                "sha256": "e32400eb81646e9207f78be71e9fbde943e52dfdc5dc1a1b5876040eafcb095c"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp37-pypy37_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "has_sig": false,
            "md5_digest": "f3488809edb4c36f3edf385144ee491f",
            "packagetype": "bdist_wheel",
            "python_version": "pp37",
            "requires_python": ">=3.7",
            "size": 579114,
            "upload_time": "2024-06-22T03:14:25",
            "upload_time_iso_8601": "2024-06-22T03:14:25.446103Z",
            "url": "https://files.pythonhosted.org/packages/e9/f7/b3a0c06431be0a32e0cdf460c3a6e044863f132bf73053fccefcb356b8e2/rencrypt-1.0.7-pp37-pypy37_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "89f2778f4c21b7a6b9fdf3b60b91000b0bb516966ba565b300087a9b4f52309b",
                "md5": "ef15ba57ad41a260bada538683a8cd50",
                "sha256": "9d022b5481f54340899239da87b26c1d79531e1842376610757cf6e076574fbb"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "has_sig": false,
            "md5_digest": "ef15ba57ad41a260bada538683a8cd50",
            "packagetype": "bdist_wheel",
            "python_version": "pp37",
            "requires_python": ">=3.7",
            "size": 571630,
            "upload_time": "2024-06-22T03:15:03",
            "upload_time_iso_8601": "2024-06-22T03:15:03.258368Z",
            "url": "https://files.pythonhosted.org/packages/89/f2/778f4c21b7a6b9fdf3b60b91000b0bb516966ba565b300087a9b4f52309b/rencrypt-1.0.7-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "6fa1c0291808c66b73f80b31953e805e7c4534a358a253c39b0953e1078703de",
                "md5": "93c9353a81193782b66c307d3bc67d34",
                "sha256": "d688ec2c79ebce0e811f2455ef897ec0a82ab20e5b4a362c25326265bb480a3d"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "has_sig": false,
            "md5_digest": "93c9353a81193782b66c307d3bc67d34",
            "packagetype": "bdist_wheel",
            "python_version": "pp38",
            "requires_python": ">=3.7",
            "size": 550885,
            "upload_time": "2024-06-22T03:13:54",
            "upload_time_iso_8601": "2024-06-22T03:13:54.052243Z",
            "url": "https://files.pythonhosted.org/packages/6f/a1/c0291808c66b73f80b31953e805e7c4534a358a253c39b0953e1078703de/rencrypt-1.0.7-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "9f079263b2cdb0e149ac358411c3bc9624f94a0c186cd5d50856edf026efeb1f",
                "md5": "daa567414b662ec691adf4ec10853088",
                "sha256": "c643d0c579875f57d19f947742062fb4b47513fb12c56b0d891e1bc8fd766d98"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl",
            "has_sig": false,
            "md5_digest": "daa567414b662ec691adf4ec10853088",
            "packagetype": "bdist_wheel",
            "python_version": "pp38",
            "requires_python": ">=3.7",
            "size": 577070,
            "upload_time": "2024-06-22T03:14:46",
            "upload_time_iso_8601": "2024-06-22T03:14:46.557009Z",
            "url": "https://files.pythonhosted.org/packages/9f/07/9263b2cdb0e149ac358411c3bc9624f94a0c186cd5d50856edf026efeb1f/rencrypt-1.0.7-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "c32e5931797a889830d8dc00183ebd3fdcc9501c08266d7ff3a74b7a9d72d94c",
                "md5": "4eb34240587970fda61c767ed63d7040",
                "sha256": "30aa8cb0476c0d351d5afac789fe2f8b710ffdd250896442f37271aab4c9d5c9"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "has_sig": false,
            "md5_digest": "4eb34240587970fda61c767ed63d7040",
            "packagetype": "bdist_wheel",
            "python_version": "pp38",
            "requires_python": ">=3.7",
            "size": 545754,
            "upload_time": "2024-06-22T03:14:10",
            "upload_time_iso_8601": "2024-06-22T03:14:10.265277Z",
            "url": "https://files.pythonhosted.org/packages/c3/2e/5931797a889830d8dc00183ebd3fdcc9501c08266d7ff3a74b7a9d72d94c/rencrypt-1.0.7-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "0a315524338fe5f13c3fdc6df2eda325e84ccb3b3061e16388b9f13422aa2e2f",
                "md5": "178b61a8cec5b0c382ddbf1d92e7d2e7",
                "sha256": "34341eddf9bc955029376b2c0d1925866cb2e6631b4cda491065931d3779271c"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "has_sig": false,
            "md5_digest": "178b61a8cec5b0c382ddbf1d92e7d2e7",
            "packagetype": "bdist_wheel",
            "python_version": "pp38",
            "requires_python": ">=3.7",
            "size": 577351,
            "upload_time": "2024-06-22T03:14:26",
            "upload_time_iso_8601": "2024-06-22T03:14:26.857698Z",
            "url": "https://files.pythonhosted.org/packages/0a/31/5524338fe5f13c3fdc6df2eda325e84ccb3b3061e16388b9f13422aa2e2f/rencrypt-1.0.7-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "b0b23eb1eb2514e81816af345f9a1cf7faefbb624d2d1395eaca01731b850b43",
                "md5": "f76be4d0da80eb524c8906601baed221",
                "sha256": "75bee139ce9d528cc4baa4c3e01ec5decc0cbacd775af34516aa94208da8a4a5"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "has_sig": false,
            "md5_digest": "f76be4d0da80eb524c8906601baed221",
            "packagetype": "bdist_wheel",
            "python_version": "pp38",
            "requires_python": ">=3.7",
            "size": 569476,
            "upload_time": "2024-06-22T03:15:05",
            "upload_time_iso_8601": "2024-06-22T03:15:05.389943Z",
            "url": "https://files.pythonhosted.org/packages/b0/b2/3eb1eb2514e81816af345f9a1cf7faefbb624d2d1395eaca01731b850b43/rencrypt-1.0.7-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "2e568cc9096aa58d39c935ad71a6e21b2218b599c887ac0991b5ee64cbd4aab8",
                "md5": "8d04d6903485520f646aa3b2d63e4eec",
                "sha256": "d92556a594b777bcd8d5bba94df78a118d7343053bf2062938987c3eecae62f1"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "has_sig": false,
            "md5_digest": "8d04d6903485520f646aa3b2d63e4eec",
            "packagetype": "bdist_wheel",
            "python_version": "pp39",
            "requires_python": ">=3.7",
            "size": 551277,
            "upload_time": "2024-06-22T03:13:56",
            "upload_time_iso_8601": "2024-06-22T03:13:56.283859Z",
            "url": "https://files.pythonhosted.org/packages/2e/56/8cc9096aa58d39c935ad71a6e21b2218b599c887ac0991b5ee64cbd4aab8/rencrypt-1.0.7-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "4fbf6ca3fa752fb9cf51f8d969e1407a80941e45bb556f842a181b9e1f0ee5d3",
                "md5": "0e9255e41c3951621a44e22d19c8f4af",
                "sha256": "3c5ee36d2a736dd2699a5d625ff24d31186aa099a4b93597bd0948c8f05f870b"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl",
            "has_sig": false,
            "md5_digest": "0e9255e41c3951621a44e22d19c8f4af",
            "packagetype": "bdist_wheel",
            "python_version": "pp39",
            "requires_python": ">=3.7",
            "size": 576949,
            "upload_time": "2024-06-22T03:14:48",
            "upload_time_iso_8601": "2024-06-22T03:14:48.171832Z",
            "url": "https://files.pythonhosted.org/packages/4f/bf/6ca3fa752fb9cf51f8d969e1407a80941e45bb556f842a181b9e1f0ee5d3/rencrypt-1.0.7-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "89f53e19267c5671801bdaf210acad1c674ed0ea13d84f6c5db138dd7cc8433b",
                "md5": "41b11dbcf8d9edfb18349dad0d906d12",
                "sha256": "e3687dc3344f9ec8cd3e5c5dee0ece9893a0a7bba86e4b94fb25464ef1d643f8"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "has_sig": false,
            "md5_digest": "41b11dbcf8d9edfb18349dad0d906d12",
            "packagetype": "bdist_wheel",
            "python_version": "pp39",
            "requires_python": ">=3.7",
            "size": 545603,
            "upload_time": "2024-06-22T03:14:11",
            "upload_time_iso_8601": "2024-06-22T03:14:11.775199Z",
            "url": "https://files.pythonhosted.org/packages/89/f5/3e19267c5671801bdaf210acad1c674ed0ea13d84f6c5db138dd7cc8433b/rencrypt-1.0.7-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "5bd92daac3a75ef96ef93fe8d5f1a70402108e94fd46c3ad93bef1cc6d3c7371",
                "md5": "65a37c1f359410996ab1f905f2438d27",
                "sha256": "e20c3b24da8b2ec5736efbcf1f72c38240df33ef348885f0a37b733be84abf7b"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "has_sig": false,
            "md5_digest": "65a37c1f359410996ab1f905f2438d27",
            "packagetype": "bdist_wheel",
            "python_version": "pp39",
            "requires_python": ">=3.7",
            "size": 577490,
            "upload_time": "2024-06-22T03:14:28",
            "upload_time_iso_8601": "2024-06-22T03:14:28.263050Z",
            "url": "https://files.pythonhosted.org/packages/5b/d9/2daac3a75ef96ef93fe8d5f1a70402108e94fd46c3ad93bef1cc6d3c7371/rencrypt-1.0.7-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "df46cf0b2b10e1f8a533847e7a1500d37672e4d9fcf56316348e9035f4dfd68f",
                "md5": "870bc3ca7abff157c439e0d8c7c20a9c",
                "sha256": "29aebc0a3e93301a79c6fbe2a333cc762438d227fe2f8d58d077d8be65e67322"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "has_sig": false,
            "md5_digest": "870bc3ca7abff157c439e0d8c7c20a9c",
            "packagetype": "bdist_wheel",
            "python_version": "pp39",
            "requires_python": ">=3.7",
            "size": 569504,
            "upload_time": "2024-06-22T03:15:07",
            "upload_time_iso_8601": "2024-06-22T03:15:07.101461Z",
            "url": "https://files.pythonhosted.org/packages/df/46/cf0b2b10e1f8a533847e7a1500d37672e4d9fcf56316348e9035f4dfd68f/rencrypt-1.0.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "ecd1be2039a3d6c351dfc0a8966a7625fb64973168004ccb667aceecdaf33318",
                "md5": "4a8df89aa8c12cb7e540f6d88091c105",
                "sha256": "047844a385971ab99e56794b5c97fedb0a960431bbd97070bef96ca0911bfbea"
            },
            "downloads": -1,
            "filename": "rencrypt-1.0.7.tar.gz",
            "has_sig": false,
            "md5_digest": "4a8df89aa8c12cb7e540f6d88091c105",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 287059,
            "upload_time": "2024-06-22T03:15:23",
            "upload_time_iso_8601": "2024-06-22T03:15:23.731500Z",
            "url": "https://files.pythonhosted.org/packages/ec/d1/be2039a3d6c351dfc0a8966a7625fb64973168004ccb667aceecdaf33318/rencrypt-1.0.7.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-06-22 03:15:23",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "radumarias",
    "github_project": "rencrypt-python",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [],
    "lcname": "rencrypt"
}
        
Elapsed time: 0.39317s