├── .gitignore ├── README.md ├── decrypt.sh ├── encrypt.sh └── gen-keypair.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.pem 2 | *.enc 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Encrypting files in B2 2 | 3 | Backblaze’s backup product has been encrypting customer data by default from the day it shipped in 2008. The files are encrypted on the user’s computer, transferred to Backblaze via an encrypted SSL connection and stored in the encrypted format. In fact, there is no way to turn it off. Flash forward to 2016, we’ve now encrypted billions of files and decrypted millions of files. The way encryption works in the online backup product is described on the [Backblaze blog](https://www.backblaze.com/blog/how-to-make-strong-encryption-easy-to-use/). 4 | 5 | While B2 does support [server side encryption](https://www.backblaze.com/b2/docs/server_side_encryption.html), some customers perfer to manage their own encryption keys and upload encrypted files to B2. This article describes one way to encrypt files and push them to B2, using the a similar technique to how the Backblaze online backup product works today. 6 | 7 | **Prerequisities** 8 | - OpenSSL command line tool. 9 | This tool is installed on Mac and generally on Linux hosts by default. It needs be be downloaded and installed for Windows. 10 | 11 | - B2 CLI tool 12 | This can be found on [Github](https://github.com/Backblaze/B2_Command_Line_Tool) or can be installed via PIP “pip install b2”. After installation, you need to run the authorize_account step to provide your B2 credentials 13 | 14 | 15 | $ b2 authorize_account [accountId] [applicationKey] 16 | 17 | # Steps 18 | 19 | ## Create a private/public keypair. 20 | 21 | You only need to do this step once. (Alternatively - if you already have a public/private key pair, you can omit this.) 22 | 23 | PRIVATE_KEY="priv-key.pem" 24 | PUBLIC_KEY="pub-key.pem" 25 | 26 | # Generates a private key. The passphrase for the private 27 | # key is required to be typed in during key creation. 28 | 29 | openssl genrsa -aes256 -out $PRIVATE_KEY 2048 30 | 31 | # From the private key, generates a public key. This key will be used 32 | # to encrypt the one time password generated for each file's 33 | # encryption. This command will require the private key passphrase. 34 | 35 | openssl rsa -in $PRIVATE_KEY -pubout -out $PUBLIC_KEY 36 | 37 | The private key (priv-key.pem) and the passphrase you set should be saved in a secure location. If you lose either of these, any files encrypted using the technique below will be lost forever. 38 | 39 | As you'll see below, the private key is only needed for decrypting files. For added security, do not keep this file on the computer you use for encrypting data. 40 | 41 | ## Encrypt and transmit file to B2. 42 | 43 | You need to run this step for each file you wish to encrypt. This step generates a 180 character one-time per file password and uses this to encrypt the file. Then, this one-time password is itself encrypted, using the public key and stored to disk. 44 | 45 | Finally, both the encrypted file and the encrypted one-time password is transmitted to B2. 46 | 47 | PUBLIC_KEY="pub-key.pem" 48 | FILE_TO_ENCRYPT="myfile.zip" 49 | B2_BUCKET_NAME="encryptiondemo" 50 | 51 | # Generate a one-time per file password that's 180 characters long. 52 | # Save it into RAM only for use by subsequent commands. 53 | 54 | ONE_TIME_PASSWORD=`openssl rand -base64 180` 55 | 56 | # Now, encrypt the file. The file is encrypted using symmetrical 57 | # encryption along with the 180 character one-time password above. 58 | 59 | echo $ONE_TIME_PASSWORD | \ 60 | openssl aes-256-cbc -a -salt -pass stdin \ 61 | -in $FILE_TO_ENCRYPT -out $FILE_TO_ENCRYPT.enc 62 | 63 | # Now, encrypt the 180 character one-time password using the public 64 | # key. This password was computed in RAM and only written to disk 65 | # encrypted for security. Password is encrypted into a binary format. 66 | 67 | echo $ONE_TIME_PASSWORD | \ 68 | openssl rsautl -encrypt -pubin -inkey $PUBLIC_KEY \ 69 | -out $FILE_TO_ENCRYPT.key.enc 70 | 71 | # Upload the encrypted file and the encrypted one time password to B2. 72 | 73 | b2 upload_file $B2_BUCKET_NAME $FILE_TO_ENCRYPT.enc \ 74 | $FILE_TO_ENCRYPT.enc 75 | b2 upload_file $B2_BUCKET_NAME $FILE_TO_ENCRYPT.key.enc \ 76 | $FILE_TO_ENCRYPT.key.enc 77 | 78 | ## Download and decrypt from B2. 79 | 80 | You need to run this step for every file you want to retreive from B2 and decrypt. This step fetches the encrypted file and one-time passsword from B2. The one-time password is decrypted using your private key. Then, this password is used to decrypt the file. 81 | 82 | PRIVATE_KEY="priv-key.pem" 83 | FILE_TO_DECRYPT="myfile.zip" 84 | BUCKET_NAME="encryptiondemo" 85 | 86 | # Download the encrypted file and encrypted one time password from B2. 87 | 88 | b2 download_file_by_name $BUCKET_NAME $FILE_TO_DECRYPT.enc \ 89 | $FILE_TO_DECRYPT.enc 90 | b2 download_file_by_name $BUCKET_NAME $FILE_TO_DECRYPT.key.enc \ 91 | $FILE_TO_DECRYPT.key.enc 92 | 93 | # Then, decrypt the file. The command is excuted as one command to 94 | # ensure that the one time password remains in memory and isn't ever 95 | # written to disk in plaintext. 96 | 97 | # openssl rsautl -decrypt -inkey $PRIVATE_KEY 98 | # This command decrypts the one time password using the private key. 99 | # This command requires the private key passphrase to be typed into 100 | # the console. Once decrypted, the plaintext one time password is 101 | # passed via stdin to: 102 | 103 | # openssl enc -aes-256-cbc -d -a -pass stdin -in \ 104 | # $FILE_TO_DECRYPT.enc -out $FILE_TO_DECRYPT 105 | # This command decrypts the file using the one-time password and 106 | # saves to the filesystem. 107 | 108 | openssl rsautl -decrypt -inkey $PRIVATE_KEY -in \ 109 | $FILE_TO_DECRYPT.key.enc | \ 110 | openssl enc -aes-256-cbc -d -a -pass stdin -in \ 111 | $FILE_TO_DECRYPT.enc -out $FILE_TO_DECRYPT 112 | 113 | # Notes and Limitations 114 | 115 | Some additional notes and limitations to this encryption approach: 116 | 117 | - The filenames are not encrypted. The filename of the file on disk, is the filename that's stored in B2. 118 | - The encrypted file and the encrypted one-time password are stored as separately files in B2 and are being uploaded separately. Therefore, you need to ensure that both files are uploaded to B2 successfully. If only the encrypted content is uploaded, but not the encrypted one-time password, the file can't later be decrypted. 119 | - The private key and that private key's passphrase that's being used to decrypt the one-time passwords need to be secured well and backed up. Without this private key - the files cannot be decrypted. 120 | - This implementation does not upload the public or private key to B2. 121 | - Finally, there are many different methods to encrypt files and transmit them to B2. Backblaze doesn't guarantee that using this method will interoperate with encryption/decryption features that may be built into B2 in the future. 122 | 123 | # **FAQ** 124 | 125 | ## What happens if my private key is compromised? Do I need to re-encrypt my files? 126 | 127 | No. Because your files are encrypted with the one-time password. 128 | 129 | If your private key has been compromised, you need to follow these steps, (1) Generate a new public/private key pair, (2) download all the encrypted one-time password files from B2. (3) decrypt these one-time password files using the compromised private key, (4) re-encrypt the one-time password files with new public key, and (5) re-upload the newly encrypted one-time password files to B2. 130 | 131 | A one-time password file is only 345 bytes, so this operation can be done rapidly. 132 | 133 | ## If I change the passphrase on my private key, do I need to re-encrypt all my files? 134 | 135 | No. You can change the private key passphrase without changing anything on the B2 side. The private key passphrase is required when you use the private key to generate a public key or decrypt files. 136 | 137 | -------------------------------------------------------------------------------- /decrypt.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | PRIVATE_KEY="priv-key.pem" 4 | FILE_TO_DECRYPT="$@" 5 | BUCKET_NAME="b2demo" 6 | 7 | if [ -z "$FILE_TO_DECRYPT" ]; then 8 | echo "Usage: decrypt.sh " 9 | exit 1 10 | fi 11 | 12 | # Download the encrypted file and encrypted one time password from B2. 13 | 14 | b2 download_file_by_name $BUCKET_NAME $FILE_TO_DECRYPT.enc \ 15 | $FILE_TO_DECRYPT.enc 16 | b2 download_file_by_name $BUCKET_NAME $FILE_TO_DECRYPT.key.enc \ 17 | $FILE_TO_DECRYPT.key.enc 18 | 19 | # Then, decrypt the file. The command is excuted as one command to ensure that 20 | # the one time password remains in memory and isn't ever written to disk 21 | # in plaintext. 22 | 23 | # openssl rsautl -decrypt -inkey $PRIVATE_KEY 24 | # This command decrypts the one time password using the private key. This 25 | # command requires the private key passphrase to be typed into the console. 26 | # Once decrypted, the plaintext one time password is passed via stdin to: 27 | 28 | # openssl enc -aes-256-cbc -d -a -pass stdin -in $FILE_TO_DECRYPT.enc -out 29 | # $FILE_TO_DECRYPT 30 | # This command decrypts the file using the one-time password and saves to 31 | # the filesystem. 32 | 33 | openssl rsautl -decrypt -inkey $PRIVATE_KEY -in $FILE_TO_DECRYPT.key.enc | \ 34 | openssl enc -aes-256-cbc -d -a -pass stdin -in \ 35 | $FILE_TO_DECRYPT.enc -out $FILE_TO_DECRYPT 36 | 37 | 38 | -------------------------------------------------------------------------------- /encrypt.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | PUBLIC_KEY="pub-key.pem" 4 | FILE_TO_ENCRYPT="$@" 5 | B2_BUCKET_NAME="b2demo" 6 | 7 | # Ensure there is a file name specified. 8 | 9 | if [ -z "$FILE_TO_ENCRYPT" ]; then 10 | echo "Usage: encrypt.sh " 11 | exit 1 12 | fi 13 | 14 | # Generate a one-time per file password that's 180 characters long. Save it 15 | # into RAM only for use by subsequent commands. 16 | 17 | ONE_TIME_PASSWORD=`openssl rand -base64 180` 18 | 19 | # Now, encrypt the file. The file is encrypted using symmetrical 20 | # encryption along with the 180 character one-time password above. 21 | 22 | echo $ONE_TIME_PASSWORD | \ 23 | openssl aes-256-cbc -a -salt -pass stdin \ 24 | -in $FILE_TO_ENCRYPT -out $FILE_TO_ENCRYPT.enc 25 | 26 | # Now, encrypt the 180 character one-time password using your public key. This 27 | # password was computed in RAM and only written to disk encrypted for security. 28 | # Password is encrypted into a binary format. 29 | 30 | echo $ONE_TIME_PASSWORD | \ 31 | openssl rsautl -encrypt -pubin -inkey $PUBLIC_KEY \ 32 | -out $FILE_TO_ENCRYPT.key.enc 33 | 34 | # Upload the encrypted file and the encrypted one time password to B2. 35 | 36 | b2 upload_file $B2_BUCKET_NAME $FILE_TO_ENCRYPT.enc $FILE_TO_ENCRYPT.enc 37 | b2 upload_file $B2_BUCKET_NAME $FILE_TO_ENCRYPT.key.enc \ 38 | $FILE_TO_ENCRYPT.key.enc 39 | -------------------------------------------------------------------------------- /gen-keypair.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | PRIVATE_KEY="priv-key.pem" 4 | PUBLIC_KEY="pub-key.pem" 5 | 6 | # Generates a private key. The passphrase for the private key is 7 | # required to be typed in during key creation. 8 | 9 | openssl genrsa -aes256 -out $PRIVATE_KEY 2048 10 | 11 | # From the private key, generates a public key. This key will be used to 12 | # encrypt the one time password generated for each file's encryption. 13 | # This command will require the private key passphrase. 14 | 15 | openssl rsa -in $PRIVATE_KEY -pubout -out $PUBLIC_KEY --------------------------------------------------------------------------------