Skip to content

Commit 7cb26d2

Browse files
committed
First release 0.0.1
0 parents commit 7cb26d2

File tree

7 files changed

+112
-0
lines changed

7 files changed

+112
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
*.pyc
2+
build/*
3+
dist/*
4+
*.egg-info/
5+
.eggs/*

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 digitalepidemiologylab
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Rails ActiveRecord encryption for python
2+
3+
Rails 7 introduced a new option in ActiveRecord to encrypt data.
4+
5+
This library aims at decrypting the data with a simple interface.
6+
7+
## Usage
8+
9+
1. Find your credentials `primary_key` and `key_derivation_salt` (those generated by Rails `bin/rails db:encryption:init` - see RoR docs linked below)
10+
1. Add the package `pip install git+ssh://git@github.com/digitalepidemiologylab/rails_ar_encryption.git`
11+
1. Use it
12+
13+
```
14+
from rails_ar_encryption import derive_key, decrypt
15+
16+
# step 1 - derive the encryption key
17+
key = derive_key(primary_key, key_derivation_salt)
18+
19+
# step 2 - decrypt message (message is the full payload generated by Rails)
20+
clear_text = decrypt(message, key)
21+
```
22+
23+
Have a look at a working [example](example.py).
24+
25+
## Notes
26+
27+
* [Rails active record encryption](https://edgeguides.rubyonrails.org/active_record_encryption.html)

example.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from rails_ar_encryption.base import derive_key, decrypt
2+
3+
# RUN TEST
4+
password = "ptJvigCRrrlKX29kU4bx80FUmxmjUej0"
5+
salt = "dMoxVXAxoRrnOutfiPyeYqtfMiFICTva"
6+
message = {"p":"SY0Ky7wFH3i6s73Bi7LL2cI=","h":{"iv":"mr7kZJHH2DOYZDM6","at":"qlrSLDRNH0qpB9/ATlHbQg=="}}
7+
8+
key = derive_key(password, salt)
9+
clear_text = decrypt(message, key)
10+
11+
print("Decrypted data is => {}".format(clear_text))

rails_ar_encryption/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .base import derive_key, decrypt

rails_ar_encryption/base.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from base64 import b64decode
2+
from Crypto.Cipher import AES
3+
from Crypto.Hash import SHA1
4+
from Crypto.Protocol.KDF import PBKDF2
5+
6+
def decrypt(message, key):
7+
"""
8+
Decrypt message just like it's done on Rails side, see:
9+
https://github.com/rails/rails/blob/main/activerecord/lib/active_record/encryption/cipher/aes256_gcm.rb
10+
"""
11+
headers = message["h"]
12+
13+
ciphertext = b64decode(message["p"])
14+
nonce = b64decode(headers["iv"])
15+
tag = b64decode(headers["at"])
16+
17+
cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
18+
19+
return cipher.decrypt_and_verify(ciphertext, tag).decode()
20+
21+
22+
def derive_key(password, salt):
23+
""""
24+
Derive the key just like it's done on Rails side, see:
25+
https://github.com/rails/rails/blob/main/activesupport/lib/active_support/key_generator.rb#L39
26+
"""
27+
return PBKDF2(password, salt, 32, count=2**16, hmac_hash_module=SHA1)

setup.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from setuptools import setup, find_packages
2+
3+
with open("README.md", "r", encoding = "utf-8") as fh:
4+
long_description = fh.read()
5+
6+
setup(
7+
name="rails-ar-encryption",
8+
version="0.0.1",
9+
author="ghn",
10+
description="Decrypts Rails payload.",
11+
long_description = long_description,
12+
long_description_content_type = "text/markdown",
13+
packages=find_packages(),
14+
include_package_data=True,
15+
install_requires=["pycryptodome"],
16+
classifiers=[
17+
"Programming Language :: Python :: 3",
18+
],
19+
python_requires='>=3.6'
20+
)

0 commit comments

Comments
 (0)