Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to encrypt media files before uploading #821

Closed
wants to merge 2 commits into from
Closed

Add option to encrypt media files before uploading #821

wants to merge 2 commits into from

Conversation

va1entin
Copy link

@va1entin va1entin commented Mar 11, 2018

I added an encryption module, which allows users to automatically encrypt their videos and photos before uploading them to an external file storage such as Google Drive.

It requires PyNaCl version 1.2.0 or greater and works as follows:

Execute meyeGenerateKeys --directory /etc/motioneye to generate a key pair. The private key is encrypted with a password and used to decrypt the files, the public key is used to encrypt the files.
meyeGenerateKeys uses over 500mb of RAM to encrypt the key by default. With the option --memlimit a smaller value can be specified for computers such as the Raspberry Pi 1, which has only 512 mb of RAM in total.

Once the keys have been created and the public key has been placed in the motionEye config directory, three options below file storage can be used. They're all set to False by default.

The private key can be removed from the device completely and stored in a safe location because it is not needed for encryption. This way a device can be stolen and nobody will be able to decrypt the media files on it, if the user has set both "Encrypt files before cloud upload" and "Remove unencrypted files after encryption" to True.

To decrypt files meyeDecrypt can be used. It works as follows:
meyeDecrypt -k /path/to/private.key --file /path/to/file.mp4.crypt
or to decrypt all files ending with .crypt in a directory:
meyeDecrypt -k /path/to/private.key --directory /path/to/dir

screenshot_20180311_155402

If there are any questions feel free to ask!

@va1entin va1entin changed the base branch from dev to master March 20, 2018 18:46
@va1entin va1entin changed the base branch from master to dev March 20, 2018 18:46
import files from master

implement encryption options

move GenerateKeys out of encrypt.py, add key_path to settings

add memlimit option to generateKeys, use motioneye conf_path for key retrieval

generateKeys.py: backup existing key files

make generateKeys.py non-interactive, introduce option to upload unencrypted files to cloud in case encryption fails

more logging

add --directory option to generateKeys

remove whitespace

add decryption tool

add option to remove unencrypted source file

fix removeSourceFile function

store memlimit in keyfile

simplify write operations, add shebang to decrypt.py

add shebang to generateKeys.py

simplify file operations

move encryption options to file storage options, add --file parameter to decrypt.py

remove -d parameter from decrypt.py, add --directory and --file instead

don't throw traceback if decryption of a file fails

move decryption script to motioneye folder

modify code to fit rest of motionEye, add entry point for key generation tool to setup.py

pass mem to write_private_key

use current version of main.js from dev branch

add pynacl to Dockerfile

add python-dev to Dockerfile.armv7-armhf

add gcc6 and libffi-dev to Dockerfile.armv7-armhf

use gcc-arm-linux-gnueabihf instead of gcc6

use build-essential instead of gcc-arm-linux-gnueabihf in Dockerfile.armv7-armhf

add new .travis.yml from dev

add new main.js from dev

dont remove obsolete whitespace in main.js
@va1entin
Copy link
Author

Do you already have some feedback on this PR, @ccrisan ?

@ccrisan
Copy link
Collaborator

ccrisan commented May 16, 2018

The reasons why I don't like this PR are:

  • The majority of motionEye(OS) users use Raspberry PI or similar boards, which are limited in terms of performance; encryption would only add more work to the CPU.
  • In my opinion, very few users are actually concerned about the privacy of their videos uploaded to the cloud, meaning that they would probably be ready to give up encryption to gain 1-2% CPU performance.
  • People actually worrying about exposing their videos to cloud providers can use external uploading methods that could pass files through encryption first. I really don't think this is a task for motionEye.
  • The newly introduced options in the settings menu are very large and break the layout on smaller screens (e.g. mobile phones).
  • Having to decrypt the file on the (a) motionEye machine that has the encryption key kind of makes things difficult, given that there's no easy way to download the encrypted files back to the machine.
  • There's no way to completely disable encryption (i.e. remove the functionality from a motionEye setup), meaning that every motionEye setup will have, from now on, to pull new dependencies, such as pynacl.
  • I think the meyeEncrypt/meyeGenerateKeys scripts should live under meyectl rather than being standalone entry points (commands). Also we rarely have capitals in commands.

Long story short, there's a lot of new code that brings relatively little functionality for a limited number of users, potentially affecting performance.

Otherwise, the code is well written and follows the various conventions used in motionEye. It appears to be doing the job correctly, as expected.

I am not closing this PR right away. Let's wait for more feedback from the community on this matter and, if a significant number of users express their needs for this feature, we'll reconsider merging it, after a few small changes.

@va1entin
Copy link
Author

I understand your concerns and appreciate the feedback.
I'll answer to the separate topics:

Performance:

  • I haven't measured the impact of the encryption on the performance exactly, but couldn't find a noticeable overhead during tests with a Raspberry PI 1 B+ while observing the logs. Actually I was surprised that the Pi handled it so well that I didn't notice a difference with/without the encryption enabled.

UI:

  • Initially, I added a new sub-menu called "Encryption", but eventually moved them to "File Storage" to make it's scope clearer. I'll try and think of ways to shorten the option's titles.

Additional dependency:

  • Users wouldn't necessarily be forced to install pynacl on their devices, because motioneye itself keeps working without it. In case the user activates encryption but doesn't have pynacl installed, it wouldn't really impair the functionality either because the encryption module simply returns the original file, if it can't encrypt the file for some reason (i.e. module missing). So if a user doesn't install pynacl, and configures upload and encryption, the unencrypted files would be uploaded (unless the "don't upload unencrypted files" option is activated). The encryption module would log errors then.
    I understand your hesitation to add that much new code in general. 👍

Use case/general:

  • I understand that the encryption is probably not a concern to a lot of users. I'd like to quickly describe my use case for motioneye to make the reason behind this clearer: I've set up a security camera to have some sort of evidence in case of a home invasion, after I suffered one in the past. This use case also implies that I don't have full control of the device at all times. Since the camera captures footage of my home, I don't want anyone with physical access to be able to view the data, so I wouldn't leave the private key on the device and do the decryption on another PC (even though it wouldn't necessarily be a problem, because there's also a password needed to decrypt the key itself, but anyway). Also I don't want the footage to be lost, if the device is stolen, which is why I need an external storage, preferably outside of my house.

Since I see your points regarding your reluctance to include this feature, I'd propose to proceed as follows.

Firstly, I'd like to wait for feedback from the community as well. Who knows what it might bring.
If the community decides that this is entirely out of scope for motioneye, this PR can be closed and I will move the code towards a more independent and general application in it's own repo.

Then, I'd write a little article for the Wiki on using that together with motioneye in case any users want to implement this in the future. Of course, it's still up to you whether to include the article then. ;-)

@ccrisan
Copy link
Collaborator

ccrisan commented May 17, 2018

Sounds like a plan! The idea of having a separate piece of code that works well with motionEye and that is documented in a Wiki article sounds even greater.

@mmaypo
Copy link

mmaypo commented May 19, 2018

A separate piece of code that integrates well with Motioneye would be my preference.

I'm curious for your stated use case : do courts care about authentication and time? So, if you were to integrate trusted time stamping, a court would know with certainty exactly when video was filmed. Seems pretty useful, but does it matter to the court? Also, it's clear that keeping a private key on the pi would be bad if it gets ripped off, but using a public key to encrypt takes authentication off the table. Again, would a court care? I imagine it's not an issue, given that footage of your house is pretty compelling evidence that you are in fact filming your house, but I know very little about the law, which can be surprising and strange at times :-\

Anyway, I appreciate you working on something to help the ecosystem and will definitely be following!

@francisuk1989
Copy link

personally, I think this should be a optional thing but my advise would be to alert/warn the user before doing so...Something on the lines of:

by setting encryption on your video uploads this may break

Anyway good work @va1entin

@va1entin
Copy link
Author

va1entin commented Sep 8, 2018

Thanks for the feedback everyone!

As suggested I took the code and made a python module called "plasm" from it. I've been using it for about two weeks now with motionEye on Raspbian. To install plasm, create a key pair and patch motionEye to use it, you can use the following commands:

Download and installation

$ wget https://github.com/va1entin/plasm/archive/refs/heads/master.zip -O plasm-master.zip
$ unzip plasm-master.zip
$ cd plasm-master
$ pip install .

Key pair creation
This generates a public and a private key. The public key is required for encryption, the private key is required for decryption. The private key is additionally encrypted with a password. You need both the private key file and the password to be able to decrypt files. The private key can be stored on another device because it's not required for encryption.
To encrypt the private key, plasm uses about 1 GB of RAM by default. If your device (e.g. a Raspberry Pi with ~500 MB of RAM) can't handle that, I suggest you create the key pair on a device that can and transfer the public key file to the Pi afterwards.

$ python
>>> from plasm import gen_keys
>>> gen_keys.generate_key_pair('/path/to/private.key', '/path/to/public.key', 'password')

Customizing the patch
Last but not least uploadservices.py needs to be patched to encrypt files before uploading them. I wrote a little patch file for that. It currently looks as follows and is available on GitHub as well.

26a27
> from plasm import encrypt
875a877
>         filename = encrypt.encrypt_file(filename, '/etc/plasm/public.key')

You can customize the patch to use a public key file from another path or remove unencrypted input files after successful encryption. By default input files are kept. The patch would look likes this then:

26a27
> from plasm import encrypt
875a877
>         filename = encrypt.encrypt_file(filename, '/different/path/to/public.key', remove_input_file=True)

Applying the patch
Finally, apply the patch, remove the .pyc file and restart motionEye. Paths may differ depending on your distribution.

systemctl stop motioneye.service
patch /usr/local/lib/python2.7/dist-packages/motioneye/uploadservices.py motioneye-uploadservices.patch 
rm /usr/local/lib/python2.7/dist-packages/motioneye/uploadservices.pyc
systemctl start motioneye.service

@va1entin va1entin closed this Sep 8, 2018
@va1entin va1entin deleted the dev-encryption branch September 8, 2018 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

4 participants