- add pgpy to poetry
- add test PGP keys to local_data
- add encrypt_file_with_pgpy()
- use randomly pgpy
This commit is contained in:
Son NK 2020-10-28 11:50:14 +01:00
parent 71be3b27f7
commit 9210459a72
8 changed files with 183 additions and 104 deletions

View File

@ -1278,7 +1278,7 @@ class EmailLog(db.Model, ModelMixin):
# for ex if alias is disabled, this forwarding is blocked # for ex if alias is disabled, this forwarding is blocked
blocked = db.Column(db.Boolean, nullable=False, default=False) blocked = db.Column(db.Boolean, nullable=False, default=False)
# can happen when user email service refuses the forwarded email # can happen when user mailbox refuses the forwarded email
# usually because the forwarded email is too spammy # usually because the forwarded email is too spammy
bounced = db.Column(db.Boolean, nullable=False, default=False, server_default="0") bounced = db.Column(db.Boolean, nullable=False, default=False, server_default="0")

View File

@ -3,11 +3,13 @@ from io import BytesIO
import gnupg import gnupg
from memory_profiler import memory_usage from memory_profiler import memory_usage
from pgpy import PGPMessage
from app.config import GNUPGHOME from app.config import GNUPGHOME
from app.log import LOG from app.log import LOG
from app.models import Mailbox, Contact from app.models import Mailbox, Contact
from app.utils import random_string from app.utils import random_string
import pgpy
gpg = gnupg.GPG(gnupghome=GNUPGHOME) gpg = gnupg.GPG(gnupghome=GNUPGHOME)
gpg.encoding = "utf-8" gpg.encoding = "utf-8"
@ -92,3 +94,12 @@ def encrypt_file(data: BytesIO, fingerprint: str) -> str:
raise PGPException(f"Cannot encrypt, status: {r.status}") raise PGPException(f"Cannot encrypt, status: {r.status}")
return str(r) return str(r)
def encrypt_file_with_pgpy(data: bytes, public_key: str) -> PGPMessage:
key = pgpy.PGPKey()
key.parse(public_key)
msg = pgpy.PGPMessage.new(data, encoding="utf-8")
r = key.encrypt(msg)
return r

View File

@ -34,6 +34,7 @@ import argparse
import asyncio import asyncio
import email import email
import os import os
import random
import time import time
import uuid import uuid
from email import encoders from email import encoders
@ -392,7 +393,7 @@ _MIME_HEADERS = [
_MIME_HEADERS = [h.lower() for h in _MIME_HEADERS] _MIME_HEADERS = [h.lower() for h in _MIME_HEADERS]
def prepare_pgp_message(orig_msg: Message, pgp_fingerprint: str): def prepare_pgp_message(orig_msg: Message, pgp_fingerprint: str, public_key: str):
msg = MIMEMultipart("encrypted", protocol="application/pgp-encrypted") msg = MIMEMultipart("encrypted", protocol="application/pgp-encrypted")
# copy all headers from original message except all standard MIME headers # copy all headers from original message except all standard MIME headers
@ -417,11 +418,23 @@ def prepare_pgp_message(orig_msg: Message, pgp_fingerprint: str):
"octet-stream", _encoder=encoders.encode_7or8bit, name="encrypted.asc" "octet-stream", _encoder=encoders.encode_7or8bit, name="encrypted.asc"
) )
second.add_header("Content-Disposition", 'inline; filename="encrypted.asc"') second.add_header("Content-Disposition", 'inline; filename="encrypted.asc"')
# encrypt original message # encrypt original message
encrypted_data = pgp_utils.encrypt_file( # ABTest between pgpy and python-gnupg
BytesIO(orig_msg.as_bytes()), pgp_fingerprint x = random.randint(0, 9)
) if x >= 5:
second.set_payload(encrypted_data) LOG.d("encrypt using python-gnupg")
encrypted_data = pgp_utils.encrypt_file(
BytesIO(orig_msg.as_bytes()), pgp_fingerprint
)
second.set_payload(encrypted_data)
else:
LOG.d("encrypt using pgpy")
encrypted_data = pgp_utils.encrypt_file_with_pgpy(
orig_msg.as_bytes(), public_key
)
second.set_payload(str(encrypted_data))
msg.attach(second) msg.attach(second)
return msg return msg
@ -632,7 +645,9 @@ def forward_email_to_mailbox(
if mailbox.pgp_finger_print and user.is_premium() and not alias.disable_pgp: if mailbox.pgp_finger_print and user.is_premium() and not alias.disable_pgp:
LOG.d("Encrypt message using mailbox %s", mailbox) LOG.d("Encrypt message using mailbox %s", mailbox)
try: try:
msg = prepare_pgp_message(msg, mailbox.pgp_finger_print) msg = prepare_pgp_message(
msg, mailbox.pgp_finger_print, mailbox.pgp_public_key
)
except PGPException: except PGPException:
LOG.exception( LOG.exception(
"Cannot encrypt message %s -> %s. %s %s", contact, alias, mailbox, user "Cannot encrypt message %s -> %s. %s %s", contact, alias, mailbox, user
@ -901,7 +916,9 @@ def handle_reply(envelope, msg: Message, rcpt_to: str) -> (bool, str):
if contact.pgp_finger_print and user.is_premium(): if contact.pgp_finger_print and user.is_premium():
LOG.d("Encrypt message for contact %s", contact) LOG.d("Encrypt message for contact %s", contact)
try: try:
msg = prepare_pgp_message(msg, contact.pgp_finger_print) msg = prepare_pgp_message(
msg, contact.pgp_finger_print, contact.pgp_public_key
)
except PGPException: except PGPException:
LOG.exception( LOG.exception(
"Cannot encrypt message %s -> %s. %s %s", alias, contact, mailbox, user "Cannot encrypt message %s -> %s. %s %s", alias, contact, mailbox, user

View File

@ -0,0 +1,57 @@
-----BEGIN PGP PRIVATE KEY BLOCK-----
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
0GzRi859Yrp2jhdAzkXArMVq6CS8G+8H5w==
=1B0F
-----END PGP PRIVATE KEY BLOCK-----

30
local_data/public-pgp.asc Normal file
View File

@ -0,0 +1,30 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBF+YdvUBCAC6ztR1r2A5Sl8MuHrNavIHPI2/GKYe61GnR8h8HVocJ8Q7j6dd
XeeaMkfiZWwvP1ya3b4F+irQXNXtsWqV3F3QLBF7NYtqW96JJsKZIuvehI8UXPIL
4ibA/ptGd8Cd6713PhByZGUPAQsdFKjsVRgdIm6aJpvFZpGktn2T3Yx6sJZ0CXQS
WEbRv+ld9sE9Pe0CRwJ/R29ktFSZ8A7hHABXXoLtawgtsa6EIvbn+XbsQxs5WpyK
Zr7XNrPCflkSOHihjOnbFsmEsGIyMFZvwrsc5akqF9dPIJNWp/j+SXuRuMFj+7jd
LQHitppBuloPMtCja41xEAyan4mbF795FK4VABEBAAG0F1Rlc3QgPHRlc3RAZXhh
bXBsZS5vcmc+iQFOBBMBCAA4FiEE3tfq+zchw8t7RxNrI+oMxASbosIFAl+YdvUC
GwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQI+oMxASbosKdcwgAjwnmkHPG
nS1tuTJrlZjqtH7Apvwv0HBUe4HEVJv1TivmTvDwQ0fsSc/57tdUqgd2Vcq00qSP
Gq1Un/7e7WMIlZP7vtj2FWkowxcAFI1Nf5CgKiADlay0p4KSmTpZoPTLgfraRPlj
O7xjjiXjEmYrk1GugUN8LbeTP2evYx3RbsEibDT0kWY5kaqcG2OY4sKWEPHdKXEe
DzDU5f6DBequ/rhpmBQj5Y5qbRR8TCCgAlLhPo5favos09HyPKGBGz4PLxBP9UbV
Qs2yjxJH9M2KC4omkNJQjVbocGjUVnsYk70JYjymB0DHvqUPW2c0WpEQDBIFadaa
tkdDQBiCZ7KcrLkBDQRfmHb1AQgAtInXbwTh0QwZC3yXv55dN5We1tCgLQXDaJlV
r7k4eJ54lYBn0+8xYvWJD6JZ3TPVsmf/vFVQLjMI1X5CLGS1BiWNtfQxGZ42gyXK
MGg7WoTJ4iHlbmIsAPL60/lt3j8aS6x+sBJlXVV0pklBMasMUXn+AvPDz4EbhMc4
oLp9L4lqRb5759aMUoAYOp06HxfxbhM5EqE60DzPAKEP+WZ7fJea/o9fJCHeBuA7
2AuJHOBcFPQPeqhFY1Bht3WMd5L5OhGbmR1mCsR7up9yVvdqaPTzE6aCDXEvbeZ9
y/QSwpCAGFECUNIZbmiJrKL6HVVto6VozomkYISNVwSJ0SoI2QARAQABiQE2BBgB
CAAgFiEE3tfq+zchw8t7RxNrI+oMxASbosIFAl+YdvUCGwwACgkQI+oMxASbosJh
FQgAs/g+srMLJO4PZYx2vCrZXvi5M2YeIr4LZyyo8wu1vLRIyZixhQgEaDAz8Af/
jnhhJaXb/xIvokspRHbV8+WckL+RDChibngqo5NMzsnjGThLWnmQ/Ys8q0ZF5kPD
QjR+CvR5seTF5a232YzgX2AoRONqle7SzxbkyzM0iTaT4cabzSvBd5CK7jRurAmK
C6+WlunG2mkfJ6t01Rx/aKoWJpSc2Frw7SCTBYhRq0qDdiRsDGHGlb5UdqEfR1b1
DlR05txblUYSFun369BjpuPA5MWAEaAH7SI9ThCbfQ1vjUH1iIBxT4kX0GzRi859
Yrp2jhdAzkXArMVq6CS8G+8H5w==
=/FAe
-----END PGP PUBLIC KEY BLOCK-----

19
poetry.lock generated
View File

@ -983,6 +983,19 @@ version = "4.8.0"
[package.dependencies] [package.dependencies]
ptyprocess = ">=0.5" ptyprocess = ">=0.5"
[[package]]
category = "main"
description = "Pretty Good Privacy for Python"
name = "pgpy"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
version = "0.5.3"
[package.dependencies]
cryptography = ">=2.6"
pyasn1 = "*"
six = ">=1.9.0"
[[package]] [[package]]
category = "main" category = "main"
description = "a port of the serialize and unserialize functions of php to python." description = "a port of the serialize and unserialize functions of php to python."
@ -1688,7 +1701,7 @@ test = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
[metadata] [metadata]
content-hash = "0e3ade53af79b805e718ebf5e7a047ff0d067ec4ed32154d77255579b1940e83" content-hash = "16dc20a48cada11374ca312b3cbcccfe3b4b93380c6d8b3964eb6a64d37c1fe5"
lock-version = "1.0" lock-version = "1.0"
python-versions = "^3.7" python-versions = "^3.7"
@ -2161,6 +2174,10 @@ pexpect = [
{file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"},
{file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"},
] ]
pgpy = [
{file = "PGPy-0.5.3-py2.py3-none-any.whl", hash = "sha256:cba6fbbb44a896a8a4f5807b3d8d4943a8f7a6607be11587f4a27734c711c1dd"},
{file = "PGPy-0.5.3.tar.gz", hash = "sha256:a49c269cedcaf82ac6999bcae5fd3f543ecb1c759f9d48a15ad8d8fa4ac03987"},
]
phpserialize = [ phpserialize = [
{file = "phpserialize-1.3.tar.gz", hash = "sha256:bf672d312d203d09a84c26366fab8f438a3ffb355c407e69974b7ef2d39a0fa7"}, {file = "phpserialize-1.3.tar.gz", hash = "sha256:bf672d312d203d09a84c26366fab8f438a3ffb355c407e69974b7ef2d39a0fa7"},
] ]

View File

@ -73,6 +73,7 @@ memory_profiler = "^0.57.0"
gevent = "^20.9.0" gevent = "^20.9.0"
aiospamc = "^0.6.1" aiospamc = "^0.6.1"
email_validator = "^1.1.1" email_validator = "^1.1.1"
PGPy = "^0.5.3"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
pytest = "^6.1.0" pytest = "^6.1.0"

View File

@ -1,107 +1,53 @@
import os
from io import BytesIO from io import BytesIO
from app.pgp_utils import load_public_key, gpg, encrypt_file import pgpy
from pgpy import PGPMessage
pubkey = """-----BEGIN PGP PUBLIC KEY BLOCK----- from app.config import ROOT_DIR
Version: Keybase OpenPGP v1.0.0 from app.pgp_utils import (
Comment: https://keybase.io/crypto load_public_key,
gpg,
xo0EXlqP9wEEALoJsLHZA5W4yGQf+TIlIuYjj72SGEXbZyvMJxDk89YE8SWHAP+L encrypt_file,
+GkyNBfiPidJ1putLBOTDuxjDroDa6zMmjxCORUYdtq35RIDo/raamAaYg32X/TI encrypt_file_with_pgpy,
3WyL3lgVf7K+VhXntG2V3OfM1r5nt3C1sy8Rsvzbih3p+eHpE3xCImg7ABEBAAHN )
FFRlc3QgPHRlc3RAc2wubG9jYWw+wq0EEwEKABcFAl5aj/cCGy8DCwkHAxUKCAIe
AQIXgAAKCRCtrxG3FC3nSGhDA/wMT4PM8pWCsbsGA32SMN0j0MRsmc6KT4BGX8qd
CwTv7s5DvZlkFL9uJQxcKFe+yYpjnrPvW0p81ispj7pVJqUTyx4brZHiWFi/vODz
YyzTXNJvWJOp27G4YzWPeEeSKuGjF1CQScmZJA5luay7mkI5gttw4q3iqJlcDDFq
1sz2486NBF5aj/cBBADA7KbOa8klxOC8Oact0zzc30SCGxtCLuFQCBI/dIrnv2KC
lIbUd+CDlmD+cKCIu7MlrYPhCLF24MYnUXVFDbT3fP8YVy2HZTfk4Q64tj0S17ve
E9H1G1W6FqdDUhMCU1EmJgd8sKOrNOFtz4+b3IHJhtJIoUILDkiMjfUCHmQaqQAR
AQABwsCDBBgBCgAPBQJeWo/3BQkPCZwAAhsuAKgJEK2vEbcULedInSAEGQEKAAYF
Al5aj/cACgkQDjygQt7BuGFtPQQAmzUJqXB4UWo9HPZfutqSU6GElSMwZq1Dlf8S
Stjq7cYK+HSfcyw4wSBMRxMtG2zmbyhWlYTqx3fAAjgE32dBI/Rq8ku60u6SGEiE
egKCcm0lyR1TVUTYEsfjiYD5AmGWng8tTavz1ANdEoE66wGApkETfmTM7hOuQrKm
BjXpmembUQP5AXln8rWuDkeXVXhBa5RR3NgoD/fos2QJ5NxkZdfPmM57EwQkEXKv
S3c5rlvvhIupElSyJkxOzfykNlJewVrLxCicj+JPSt7ly6YlkMQglyevntI46y1l
2Msf0oeQZ3uedURGQiGQalC7nzPFnOARbNffFEJI3cJhcLkr2UFdL0rOjQReWo/3
AQQA+MJeovqVVVrE1Vsc3M/BuG5ao7xyP1y7YhgmJg3gi8HR7b4/ySJtKnCYAmLg
wwjfCUWed/GZ+3bGw48x8Fmn+6QTPG04j8RUOMUgVt9jc+TxC8VWSvqH1Taho3MK
6ZQpCwXPO0FmWc5ybp0AJzqy2YS4eZwue1WH3zFzjXrOBd0AEQEAAcLAgwQYAQoA
DwUCXlqP9wUJDwmcAAIbLgCoCRCtrxG3FC3nSJ0gBBkBCgAGBQJeWo/3AAoJEFJq
ki+hZCNMgH4EAPiamTuezRtMIEWpjEjYGjpRF+2uj5VmU6N2E6+5Nh73HUKNCVRj
AWeRarplye/CqZyhzPgotDNzAPzE4smo0N0vvc4zi6toqMiO4ODjR313d0y0v4iP
+n576QwpfGw/ddlTEL7Iv28dzdKJArjNc2/jRxefHrAYSzjEunl/GUq+ToQD/izQ
mPo6SWhlODsIy4eR/u3NpKtQQcs40XWLVci6M66ntyl5XmBGgFFu0WHIYeDOnTRc
qL1W5yEYaaJhaEbmNGk3tf26Ns9cTl91S2eylO9nWGOnqFg58jP63TZVR7q3jIq1
e5DKgszG2Vvye+bbK6qMKmaIXEMhnjw9eZuW6MGf
=yDVI
-----END PGP PUBLIC KEY BLOCK-----
"""
private_key = """-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: Keybase OpenPGP v1.0.0
Comment: https://keybase.io/crypto
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
U9jtqNTsHrr0XFzA2zno+zcopiZZOoPXcwxLf+pCetjN5EOkpMgqZTtV2nCppQRB
d3ZpsguOO4OVexEW6gWGOuas5+/qa846it9VMo+nlqtLyIAFbj2P02Zk/QrUnPF3
PEjKDJssrOEnZWlpAdEDfFhC1OrBVlG0lkD1qHDCNO9MTeT2dRMghbFGxlno9z2K
wnnB+Ep4UULuvbh08GsVflQPaA0a59IFDbOzYc7puS5kpJ5fQWwdXZvjNc/jOeQX
BHaLfQKmWYW3pCxs0BqKRhAnZ9E+kkIL6xU6MlJPs/NGO7aAykrFv8BdmBJQ8s00
9LGlgSUhdEdIsn5h3Kdn0f/7FXXWwsCDBBgBCgAPBQJeWo/3BQkPCZwAAhsuAKgJ
EK2vEbcULedInSAEGQEKAAYFAl5aj/cACgkQUmqSL6FkI0yAfgQA+JqZO57NG0wg
RamMSNgaOlEX7a6PlWZTo3YTr7k2HvcdQo0JVGMBZ5FqumXJ78KpnKHM+Ci0M3MA
/MTiyajQ3S+9zjOLq2ioyI7g4ONHfXd3TLS/iI/6fnvpDCl8bD912VMQvsi/bx3N
0okCuM1zb+NHF58esBhLOMS6eX8ZSr5OhAP+LNCY+jpJaGU4OwjLh5H+7c2kq1BB
yzjRdYtVyLozrqe3KXleYEaAUW7RYchh4M6dNFyovVbnIRhpomFoRuY0aTe1/bo2
z1xOX3VLZ7KU72dYY6eoWDnyM/rdNlVHureMirV7kMqCzMbZW/J75tsrqowqZohc
QyGePD15m5bowZ8=
=4OSo
-----END PGP PRIVATE KEY BLOCK-----"""
def test_load_public_key(): def test_load_public_key():
load_public_key(pubkey) public_key_path = os.path.join(ROOT_DIR, "local_data/public-pgp.asc")
public_key = open(public_key_path).read()
load_public_key(public_key)
assert len(gpg.list_keys()) == 1 assert len(gpg.list_keys()) == 1
def test_encrypt(): def test_encrypt():
fingerprint = load_public_key(pubkey) public_key_path = os.path.join(ROOT_DIR, "local_data/public-pgp.asc")
public_key = open(public_key_path).read()
fingerprint = load_public_key(public_key)
secret = encrypt_file(BytesIO(b"abcd"), fingerprint) secret = encrypt_file(BytesIO(b"abcd"), fingerprint)
assert secret != "" assert secret != ""
def test_encrypt_file_with_pgpy():
encrypt_decrypt_text("heyhey")
encrypt_decrypt_text("👍💪")
encrypt_decrypt_text("éèù")
encrypt_decrypt_text("片仮名")
def encrypt_decrypt_text(text: str):
public_key_path = os.path.join(ROOT_DIR, "local_data/public-pgp.asc")
public_key = open(public_key_path).read()
encrypted: PGPMessage = encrypt_file_with_pgpy(text.encode(), public_key)
# decrypt
private_key_path = os.path.join(ROOT_DIR, "local_data/private-pgp.asc")
private_key = open(private_key_path).read()
priv = pgpy.PGPKey()
priv.parse(private_key)
decrypted = priv.decrypt(encrypted).message
if type(decrypted) == str:
assert decrypted == text
elif type(decrypted) == bytearray:
assert decrypted.decode() == text