Skip to content
This repository has been archived by the owner on Oct 29, 2019. It is now read-only.

Commit

Permalink
Initial commit and public release
Browse files Browse the repository at this point in the history
  • Loading branch information
austinmoore- committed Jan 26, 2017
0 parents commit 216ab12
Show file tree
Hide file tree
Showing 33 changed files with 2,782 additions and 0 deletions.
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.DS_Store
/venv
*.py[cdo]
*.swp
.idea/
MANIFEST
build/
dist/
docs/_build
.cache
.tox/
.eggs/
*.egg-info/
10 changes: 10 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.. :changelog:
Release History
---------------

1.0.0 (2017-01-25)
++++++++++++++++++

- Initial public release

13 changes: 13 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright 2017 AOL Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include README.md HISTORY.rst requirements.txt
178 changes: 178 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
mrcrypt: Multi-Region Encryption
================================

mrcrypt is a command-line tool that allows you to encrypt secrets in
multiple AWS regions using KMS keys using a technique called `Envelope
Encryption <http://docs.aws.amazon.com/kms/latest/developerguide/workflow.html>`__.
It is intended to be used with the `AWS Encryption SDK for
Java <https://github.com/awslabs/aws-encryption-sdk-java>`__, but could
be used on its own.

Compatability with the AWS Encryption SDK
'''''''''''''''''''''''''''''''''''''''''

**All files encrypted with mrcrypt can be decrypted with the AWS
Encryption SDK.** But not all files encrypted with the AWS Encryption
SDK can be decrypted by mrcrypt.

Currently, mrcrypt only supports the AWS Encryption SDK's default (and
most secure) cryptographic algorithm:

- Content Type: Framed
- Frame size: 4096
- Algorithm: ALG\_AES\_256\_GCM\_IV12\_TAG16\_HKDF\_SHA384\_ECDSA\_P384

Support for the remaining algorithms are planned, but files encrypted
with the AWS Encryption SDK using one of the other algorithms are
currently not supported in mrcrypt.

Also, the AWS Encryption SDK creates files using elliptic curve point
compression. Files created with mrcrypt do not use point compression
because they are not currently supported in
`Cryptography <https://github.com/pyca/cryptography>`__, a Python
package mrcrypt uses. The uncompressed points are just as secure as the
compressed points, but files are a few bytes larger. The AWS Encryption
SDK can decrypt files that use uncompressed points, meaning all files
created with mrcrypt are compatible with the AWS Encryption SDK.

Installation
------------

To install mrcrypt simply clone the repo, and run ``pip install .``
inside of the directory:

::

git clone ssh://[email protected]:2022/identity_services/mrcrypt.git
cd mrcrypt
pip install .

**Note:** mrcrypt uses the Python package
`Cryptography <https://github.com/pyca/cryptography>`__ which depends on
``libffi``. You may need to install it on your system if
``pip install .`` fails. For more specific instructions for your OS:
https://cryptography.io/en/latest/installation/

Usage
-----

::

usage: mrcrypt [-h] [-p PROFILE] [-e ENCRYPTION_CONTEXT] [-d] [-o OUTFILE]
{encrypt,decrypt} ...

Multi Region Encryption. A tool for managing secrets across multiple AWS
regions.

positional arguments:
{encrypt,decrypt}

optional arguments:
-h, --help show this help message and exit
-p PROFILE, --profile PROFILE
The profile to use
-e ENCRYPTION_CONTEXT, --encryption_context ENCRYPTION_CONTEXT
An encryption context to use. (Cannot have whitespace)
-d, --debug Enable more output for debugging
-o OUTFILE, --outfile OUTFILE
The file to write the results to

Both the encrypt, and decrypt commands can encrypt and decrypt files in
directories recursively.

Named Profiles
''''''''''''''

If you have multiple named profiles in your ``~/.aws/credentials`` file,
you can specify one using the ``-p`` argument.

::

mrcrypt -p my_profile encrypt alias/master-key secrets.txt

Encryption Context
''''''''''''''''''

You can specify an `encryption
context <http://docs.aws.amazon.com/kms/latest/developerguide/encryption-context.html>`__
using the ``-e`` argument. This flag takes a JSON object with no spaces:

::

# encrypt
mrcrypt -e '{"key":"value","key2":"value2"}' encrypt alias/master-key secrets.txt

# decrypt
mrcrypt -e '{"key":"value","key2":"value2"}' decrypt secrets.txt.encrypted

Output file name
''''''''''''''''

If you want to specify the output filename, you can use the ``-o``
argument.

``# Encrypt 'file.txt' writing the output into 'encrypted-file.txt' mrcrypt -o encrypted-file.txt encrypt alias/master-key file.txt``

By default, when encrypting, mrcrypt will create a file with the same
file name as the input file with ``.encrypted`` appended to the end.
When decrypting, if the file ends with ``.encrypted`` it will write the
plaintext output to a file of the same name but without the
``.encrypted``.

Encryption
----------

::

usage: mrcrypt encrypt [-h] [-r REGIONS [REGIONS ...]] [-e ENCRYPTION_CONTEXT]
key_id filename

Encrypts a file or directory recursively

positional arguments:
key_id An identifier for a customer master key.
filename The file or directory to encrypt. Use a - to read from
stdin

optional arguments:
-h, --help show this help message and exit
-r REGIONS [REGIONS ...], --regions REGIONS [REGIONS ...]
A list of regions to encrypt with KMS. End the list
with --
-e ENCRYPTION_CONTEXT, --encryption_context ENCRYPTION_CONTEXT
An encryption context to use

**Example:** Encrypt ``secrets.txt`` with the key alias
``alias/master-key`` in the regions ``us-east-1`` and ``us-west-2``:

``mrcrypt encrypt -r us-east-1 us-west-2 -- alias/master-key secrets.txt``

Decryption
----------

::

usage: mrcrypt decrypt [-h] filename

Decrypts a file

positional arguments:
filename The file or directory to decrypt. Use a - to read from stdin

optional arguments:
-h, --help show this help message and exit

**Example:** To decrypt ``secrets.txt.encrypted``:

::

mrcrypt decrypt secrets.txt.encrypted

**Note:** Be careful when decrypting a directory. If the directory
contains files that are not encrypted, it will fail.

Testing
'''''''

Running tests for mrcrypt is easy if you have ``tox`` installed. Simply
run ``tox`` at the project's root.
Empty file added mrcrypt/__init__.py
Empty file.
152 changes: 152 additions & 0 deletions mrcrypt/algorithms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
"""
mrcrypt.algorithms
~~~~~~~~~~~~~~~~~~
Contains named tuples that describe different algorithms supported by this tool.
"""
from collections import namedtuple

#: Max unsigned 16 bit number
GCM_MAX_CONTENT_LENGTH_BITS = (1 << 16) - 1

#: All lengths are in bytes, unless stated otherwise.
AlgorithmProfile = namedtuple('AlgorithmProfile',
'block_size_bits, iv_length, tag_length, max_content_length_bits, '
'key_algorithm, key_length, id, data_key_algorithm, '
'data_key_length, trailing_signature_algorithm, '
'trailing_signature_length_bits')

alg_aes_128_gcm_iv12_tag16_no_kdf = AlgorithmProfile(
block_size_bits=128,
iv_length=12,
tag_length=16,
max_content_length_bits=GCM_MAX_CONTENT_LENGTH_BITS,
key_algorithm='AES',
key_length=16,
id=0x0014,
data_key_algorithm='AES',
data_key_length=16,
trailing_signature_algorithm=None,
trailing_signature_length_bits=None)

alg_aes_192_gcm_iv12_tag16_no_kdf = AlgorithmProfile(
block_size_bits=128,
iv_length=12,
tag_length=16,
max_content_length_bits=GCM_MAX_CONTENT_LENGTH_BITS,
key_algorithm='AES',
key_length=24,
id=0x0046,
data_key_algorithm='AES',
data_key_length=24,
trailing_signature_algorithm=None,
trailing_signature_length_bits=None)

alg_aes_256_gcm_iv12_tag16_no_kdf = AlgorithmProfile(
block_size_bits=128,
iv_length=12,
tag_length=16,
max_content_length_bits=GCM_MAX_CONTENT_LENGTH_BITS,
key_algorithm='AES',
key_length=32,
id=0x0078,
data_key_algorithm='AES',
data_key_length=32,
trailing_signature_algorithm=None,
trailing_signature_length_bits=None)

alg_aes_128_gcm_iv12_tag16_hkdf_sha256 = AlgorithmProfile(
block_size_bits=128,
iv_length=12,
tag_length=16,
max_content_length_bits=GCM_MAX_CONTENT_LENGTH_BITS,
key_algorithm='AES',
key_length=16,
id=0x0114,
data_key_algorithm='HkdfSHA256',
data_key_length=16,
trailing_signature_algorithm=None,
trailing_signature_length_bits=None)

alg_aes_192_gcm_iv12_tag16_hkdf_sha256 = AlgorithmProfile(
block_size_bits=128,
iv_length=12,
tag_length=16,
max_content_length_bits=GCM_MAX_CONTENT_LENGTH_BITS,
key_algorithm='AES',
key_length=24,
id=0x0146,
data_key_algorithm='HkdfSHA256',
data_key_length=24,
trailing_signature_algorithm=None,
trailing_signature_length_bits=None)

alg_aes_256_gcm_iv12_tag16_hkdf_sha256 = AlgorithmProfile(
block_size_bits=128,
iv_length=12,
tag_length=16,
max_content_length_bits=GCM_MAX_CONTENT_LENGTH_BITS,
key_algorithm='AES',
key_length=32,
id=0x0178,
data_key_algorithm='HkdfSHA256',
data_key_length=32,
trailing_signature_algorithm=None,
trailing_signature_length_bits=None)

alg_aes_128_gcm_iv12_tag16_hkdf_sha256_ecdsa_p256 = AlgorithmProfile(
block_size_bits=128,
iv_length=12,
tag_length=16,
max_content_length_bits=GCM_MAX_CONTENT_LENGTH_BITS,
key_algorithm='AES',
key_length=16,
id=0x0214,
data_key_algorithm='HkdfSHA256',
data_key_length=16,
trailing_signature_algorithm='SHA256withECDSA',
trailing_signature_length_bits=72)

alg_aes_192_gcm_iv12_tag16_hkdf_sha384_ecdsa_p384 = AlgorithmProfile(
block_size_bits=128,
iv_length=12,
tag_length=16,
max_content_length_bits=GCM_MAX_CONTENT_LENGTH_BITS,
key_algorithm='AES',
key_length=24,
id=0x0346,
data_key_algorithm='HkdfSHA384',
data_key_length=24,
trailing_signature_algorithm='SHA384withECDSA',
trailing_signature_length_bits=104)

alg_aes_256_gcm_iv12_tag16_hkdf_sha384_ecdsa_p384 = AlgorithmProfile(
block_size_bits=128,
iv_length=12,
tag_length=16,
max_content_length_bits=GCM_MAX_CONTENT_LENGTH_BITS,
key_algorithm='AES',
key_length=32,
id=0x0378,
data_key_algorithm='HkdfSHA384',
data_key_length=32,
trailing_signature_algorithm='SHA384withECDSA',
trailing_signature_length_bits=104)


def algorithm_from_id(algorithm_id):
"""Retrieves an :class:`AlgorithmProfile` from ``algorithm_id``."""
mapping = _get_mapping()
try:
return mapping[algorithm_id]
except KeyError:
raise ValueError('The number {} does not map to an algorithm'.format(algorithm_id))


def _get_mapping():
"""Builds a dictionary, mapping IDs to their corresponding :class:`AlgorithmProfile`."""
return dict((v.id, v) for v in globals().values() if type(v) is AlgorithmProfile)


def default_algorithm():
return alg_aes_256_gcm_iv12_tag16_hkdf_sha384_ecdsa_p384
Empty file added mrcrypt/cli/__init__.py
Empty file.
Loading

0 comments on commit 216ab12

Please sign in to comment.