python ftps ダウンロードと圧縮と暗号化のメモ
netからexampleを参考に書いてみました。
ftps TLS接続しダウンロード ー> zip -> 暗号化します。
復号化は最後のコードを参考に作成してみてください。
※エラー処理は適当なので付け加えてください。
##### source code ##########################################
# coding: utf-8
from ftplib import FTP_TLS
import os
import sys
import getpass # パスワード入力用
import termios # Yes or No 入力用
import tty # Yes or No 入力用
import codecs # エンコード用
import unicodedata
import zipfile
from hashlib import md5
from Crypto.Cipher import AES
from Crypto import Random
# ===== 暗号化 =====
def derive_key_and_iv(password, salt, key_length, iv_length):
d = d_i = ''
while len(d) < key_length + iv_length:
d_i = md5(d_i + password + salt).digest()
d += d_i
return d[:key_length], d[key_length:key_length+iv_length]
def encrypt(in_file, out_file, password, key_length=32):
bs = AES.block_size
salt = Random.new().read(bs - len('Salted__'))
key, iv = derive_key_and_iv(password, salt, key_length, bs)
cipher = AES.new(key, AES.MODE_CBC, iv)
out_file.write('Salted__' + salt)
finished = False
while not finished:
chunk = in_file.read(1024 * bs)
if len(chunk) == 0 or len(chunk) % bs != 0:
padding_length = (bs - len(chunk) % bs) or bs
chunk += padding_length * chr(padding_length)
finished = True
out_file.write(cipher.encrypt(chunk))
# ===== 復号化 =====
def decrypt(in_file, out_file, password, key_length=32):
bs = AES.block_size
salt = in_file.read(bs)[len('Salted__'):]
key, iv = derive_key_and_iv(password, salt, key_length, bs)
cipher = AES.new(key, AES.MODE_CBC, iv)
next_chunk = ''
finished = False
while not finished:
chunk, next_chunk = next_chunk, cipher.decrypt(in_file.read(1024 * bs))
if len(next_chunk) == 0:
padding_length = ord(chunk[-1])
chunk = chunk[:-padding_length]
finished = True
out_file.write(chunk)
# ===== zip ======
def zip_write_dir(base_dir, src_dir, zip_name):
"""ディレクトリをzip圧縮する
base_dir: src_dirが属するディレクトリを表す
src_dir: 圧縮対象のディレクトリを表す
zip_name: 出力先のzipファイルのフルパスを表す
"""
zf = zipfile.ZipFile(zip_name, 'w', zipfile.ZIP_DEFLATED)
current_dir = os.getcwd();
os.chdir(base_dir)
for root,dirs,files in os.walk(src_dir):
for _file in files:
filename = os.path.join(root,_file)
arcname = filename
zf.write(filename, arcname)
zf.close()
os.chdir(current_dir)
# ===== Yes or No =====
def yesno(message):
result = ''
sys.stdout.write(message)
sys.stdout.flush()
attribute = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin)
try:
while True:
char = sys.stdin.read(1)
if char == 'y' or char == 'Y':
result = 'y'
break
elif char == 'n' or char == 'N':
result = 'n'
break
except KeyboardInterrupt:
result = '^C'
termios.tcsetattr(sys.stdin, termios.TCSAFLUSH, attribute)
print(result)
return result
# ===== other input ==============================================
_usr = getpass.getpass('>>>>> ユーザー名: ')
if _usr == '':
sys.exit()
_pass = getpass.getpass('>>>>> パスワード: ')
if _pass == '':
sys.exit()
_makedir = raw_input('>>>>> 書き込むディレクトリ: ')
try:
if _makedir != '' and not os.path.exists(_makedir):
if _makedir.find('/') == -1:
os.mkdir(_makedir)
print('ディレクトリ ' + _makedir + ' を作成しました。')
else:
os.makedirs(_makedir)
print('ディレクトリ ' + _makedir + ' を作成しました。')
except:
print('>>>>> Error mkdirに失敗しました。')
sys.exit()
res = yesno('>>>>> ' + _makedir + ' にダウンロードします。\n ※ 処理を続行しますか? (Yes or No) ')
if res != 'y':
print('>>>>> ※ 処理をキャンセルしました。')
sys.exit()
# ===== ftps connect ====================================================
try:
try:
## 'なんとか.com'は書き換えてください。
ftps = FTP_TLS('なんとか.com', timeout = 850)
# login anonymously before securing control channel
ftps.set_pasv(True) # パッシブモードON
ftps.set_debuglevel(1) # ログ出力
ftps.login(_usr, _pass)
ftps.prot_p() # switch to secure data connection
## 'ssl/cgi-bin'は書き換えてください。
ftps.cwd('ssl/cgi-bin')
except Exception as e:
print('>>>>> Error ftp接続に失敗しました。')
print('>>>>> 内容: ' + str(type(e)) + '\n' + str(e))
# ===== download =====================================================
filelist = ftps.nlst()
print(str(filelist))
ftps.set_debuglevel(0) # ログ出力
_cnt = 0
for _file in filelist:
if _file != '.' and _file != '..':
ftps.retrbinary('RETR ' + _file, open(_makedir + '/' + _file, 'wb').write)
_cnt +=1
print('>>>>> ( ' + str(_cnt) + ' ) ' + _file + ' をダウンロードしました。')
print('>>>>> ' + str(_cnt) + ' download Complete!!')
except Exception as e:
print('>>>>> Error ' + _file + ' をダウンロードが出来ませんでした。')
print('>>>>> 内容: ' + str(type(e)) + '\n' + str(e))
ftps.close()
sys.exit()
finally:
ftps.close()
_zip_name = raw_input('>>>>> 圧縮ファイル名 (.zipなし): ')
if _zip_name == '':
sys.exit()
zip_write_dir('.', _makedir, _zip_name + '.zip')
print('>>>>> ' + _zip_name + '.zip' + ' 圧縮 Complete!!')
password = getpass.getpass('>>>>> 暗号化パスワード: ')
if _pass == '':
sys.exit()
# ===== 暗号化 =====
with open(_zip_name + '.zip', 'rb') as in_file, open(_zip_name + '.panz', 'wb') as out_file:
encrypt(in_file, out_file, password)
print('>>>>> ' + _zip_name + '.panz' + ' 暗号化 Complete!!')
quit()
# ===== 復号化 =====
# with open(in_filename, 'rb') as in_file, open(out_filename, 'wb') as out_file:
# decrypt(in_file, out_file, password)
# print('>>>>> ' + _zip_name + '.panz' + ' 復号化 Complete!!')
# ===== 2016/05/10_1 ==========================================================