2016年5月10日火曜日

Python ftps ダウンロードと圧縮と暗号化のメモ

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 ==========================================================

0 件のコメント:

コメントを投稿