# Crypto-Factory

Main purpose of Crypto-Factory library is to provide a **common interface** 
to application for cryptographic tasks.

Based on Factory method design pattern, it provides an abstraction layer to
define cryptographic recipes as service providers, a **'factory' manager** to
register and create individual instances, and a standardized client interface
to interact with them.
With this approach, implementing existing or new cryptographic methods is
simplified, more reusable and easier to maintain.

Crypto-Factory do not provides any Cryptographic algorithms on its own but
relies on existing Python packages such as
[pyca/cryptography](https://github.com/pyca/cryptography) which is used to
define some **built-in Crypto providers**. These providers can be used as a 
quick starter or samples for dedicated implementations.  
For this purpose, **Templates** class are also available to design your own
recipes using your preferred cryptography packages.


## Quick Start

```pydocstring
# Import  & initialize
>>> from crypto_factory import CryptoFactory
>>> cf = CryptoFactory()

# Define your Crypto providers configuration
>>> conf_AES = { 
...     # existing service
...     'key' : b'WkqHg8m9RwmE1iPQJAbuJRKmh72vLvUNFepIWrOldKg=',
...     'iv'  : b'vdU1T6NvAZJIlnznSe8gbQ==',
... }


>>> new_key = cf.utils.generate_key()
>>> conf_Fernet = { 
...     # new service
...     'id' : 'new',
...     'builder' : 'FernetServiceBuilder',
...     'tag' : 'FERNET_TAG',
...     'key' : new_key,
... }

# Register both providers
>>> cf.services.register(
...     conf_AES,
...     sid='aes',
...     builder='AESServiceBuilder',
...     tag="AES_TAG",
... )
'aes'

>>> new_mode = cf.services.register(conf_Fernet)
>>> print(new_mode)
'new'

# Encrypt data
>>> old_secret = cf.encrypt('My_Secret', mode='aes', tag=False)
>>> new_secret = cf.encrypt('My_Secret', new_mode)

# Decrypt data
>>> cf.decrypt(old_secret, mode='aes')
'My_Secret'

>>> cf.decrypt(new_secret)  # (mode is not required with tagging)
'My_Secret'

# Decrypt wrong hash
>>> cf.decrypt(old_secret, mode='new')
Traceback (most recent call last):
...
CryptoFactoryError: Unable to decrypt with Crypto service: new

# Rotate cipher from one or more modes to a target one (migration)
>>> secret = cf.rotate(old_secret, from_modes=['aes', ], to_mode='new')
>>> cf.decrypt(secret, mode='new')
'My_Secret'
```


## Features

Current implemented features are:

**Client interface**:  
    Symmetric encryption: encrypt, decrypt, rotate.

**Factory** (Services manager):  
    To register and call Crypto service providers.

**Built-in Crypto providers**:  
    Services for AES & Fernet encryption.
    (can be used as quick starter or samples to define your own recipes)

**Tagging mechanism**:  
    Tag encrypted data to identify provider ; can be enforced or disabled.

**Utilities & helpers**:  
    Manage tags & providers, generate random keys, string encoding, ...

**Exceptions**:  
    Single `CryptoFactoryError` class to catch errors.
    (basic implementation to simplify errors management on client side)

**Templates**:  
    Base classes to implement a Crypto services and its related builder(s).


## Install

Crypto-Factory is best installed via [pip](http://pip-installer.org):

    $ pip install Crypto-Factory


Or cloning the Git repository and running within it:

    $ pip install -e .


## Dependencies

In order for Crypto-Factory's installation to succeed, you will need the following:

* [Python](https://www.python.org/downloads/) programming language, versions 3.4+
* [Attr-Dict](https://pypi.org/project/Attr-Dict/) and
  [cryptography](https://pypi.org/project/cryptography/) libraries

