使用python将照片加密上传到阿里云OSS

将照片存储在本地经常因为格式化硬盘忘记备份而丢失,所以想把照片存放在云端以保证照片不丢失!某云免费的2T空间下载速度实在是太慢了,所以决定将照片放在阿里云OSS上,如果不是经常大流量的存取的话,一个月也就几毛到几块钱,试用后感觉速度也很不错!出于对数据安全的考虑,还是决定加密后上传!

本文固定地址:https://blog.jiangjiaolong.com/file-encrypt-oss.html
python官方库里没有找到加密后可以反向解密的库,网上搜索了一下python文件加密的解决方案,参考了一下Python3中加密与解密详解这篇文章,配合阿里云的python SDK写了一个自动加密上传,下载解密的脚本!下面附上python代码!

安装必要的库

安装阿里云oss SDK:

1
pip install oss2

注意:oss SDK暂时不支持python3.6
安装用来加密,解密的库:

1
pip install pycryptodome

开始写程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# -*- coding:utf-8 -*-
#导入必要的包
import os
from Crypto.PublicKey import RSA
from Crypto.Random import get_random_bytes
from Crypto.Cipher import AES, PKCS1_OAEP
from oss2 import Auth,Bucket
import urllib

#定义一个处理加密上传,下载解密的类
class photoencrypt():
#构造函数,请根据需求修改你的Endpoint
def __init__(self,AK,AS,BUCKET):
auth = Auth(AK,AS)
self.bucket = Bucket(auth,'oss-cn-beijing.aliyuncs.com',BUCKET)
#设置公钥和私钥的方法,一开始在每次上传或下载的传入公钥或私钥参数,但是每次调用都需要传入,感觉太累赘!
def setkey(self,publickey,privatekey):
self.publickey = publickey
self.privatekey = privatekey
#生成公钥和私钥的方法,给出私钥的路径和要设置的密码即可,密码为可选参数
#生成的公钥名为私钥+.pub后缀
def keygen(self,genprivatekey,password=None):
key = RSA.generate(2048)
encrypted_key = key.exportKey(passphrase=password,protection="scryptAndAES128-CBC")
with open(genprivatekey,'wb') as f:
f.write(encrypted_key)
with open(genprivatekey+'.pub','wb') as f:
f.write(key.publickey().exportKey())
print("证书生成成功!")

#定义加密上传方法,传入文件路径即可
def put(self,file_path):
recipient_key = RSA.import_key(open(self.publickey).read())
session_key = get_random_bytes(16)
cipher_rsa = PKCS1_OAEP.new(recipient_key)
result = self.bucket.append_object(file_path+'.bin',0,cipher_rsa.encrypt(session_key))
cipher_aes = AES.new(session_key,AES.MODE_EAX)

with open(file_path,'rb') as in_file:
data = in_file.read()
ciphertext, tag = cipher_aes.encrypt_and_digest(data)
result = self.bucket.append_object(file_path+'.bin',result.next_position,cipher_aes.nonce)
result = self.bucket.append_object(file_path+'.bin',result.next_position,tag)
#如果不设置分段上传的话,上传大文件时会报错,我设置的分段大小为10M,请根据需求修改
[self.bucket.append_object(file_path+'.bin',result.next_position+i,ciphertext[i:i+1024*10240]) for i in range(0,len(ciphertext),1024*10240)]
print("上传了%s"%file_path)

#定义下载解密的方法
#传入oss文件路径及私钥的密码
def get(self,file_path,password=None):
url = self.bucket.sign_url('GET',file_path,60).replace('http://','https://')
print(url)
enfilename = file_path.split('.bin')[0]
private_key = RSA.import_key(open(self.privatekey).read(),passphrase=password)

with urllib.request.urlopen(url) as remote_stream:
enc_session_key, nonce, tag = [ remote_stream.read(x) for x in (private_key.size_in_bytes(),16, 16) ]
ciphertext = bytes()
while True:
temp = remote_stream.read(1024*10240)
if temp:
ciphertext += temp
else:
break
cipher_rsa = PKCS1_OAEP.new(private_key)
session_key = cipher_rsa.decrypt(enc_session_key)
cipher_aes = AES.new(session_key, AES.MODE_EAX, nonce)
data = cipher_aes.decrypt_and_verify(ciphertext, tag)
with open(enfilename,'wb') as in_file:
in_file.write(data)

调用示例

1
2
3
4
p = photoencrypt('yourak','yoursk','bucketname')
p.setkey('yourpublickey','yourprivatekey')
p.put('yourfile')
p.get('yourfile','yourpassword')

文件夹批量处理

定义一个批量处理函数:

1
2
3
4
5
6
7
8
9
def upphoto(dirpath,upfunc):
file_list = os.listdir(dirpath)
for i in file_list:
fullpath = dirpath +'/' + i
if os.path.isdir(fullpath):
upphoto(fullpath,upfunc)
else:
upfunc(fullpath)
#将要上传的文件夹及处理方法p.put传入即可使用

本文参考

本文历史

  • 2018年4月16日 首次发表