見出し画像

Pythonでhash値を求める

 最近Linuxのアプリケーションのハッキングのニュースを見た。Webフレームワークのダウンロードモジュールが悪意のある書き換えをされて置き換えられたらしい。
 このモジュールは最近更新されていないもので、GitHubにあるソースコードに変更がないのに、モジュールが更新されており気づいたようだ。今回はダウンロードサイトに記述されているhash値と比較していたら入れ替えに気づいたとのこと。できる限りソフトウェアーのダウンロードの際にはhash値の確認をするようにと言う記事だった。正直言うと僕もhash値でダウンロードしたソフトウェアーを確認するという習慣はない。これからはそれではいけないと言うことで、ハッシュで比較していくことを心がけたい。

しかし、
 どうやるの???
ってことだし、hashを求めるソフトが改残されていたら・・・。と妙に心配性になってしまった。

 ならばPythonで作ってみようということで、hash値を求めたり比較したりするコマンドを作ってみた。GUIは(今のところ)。これからダウンロードしたファイルはこれでチェックしていきたい。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Python hash check
#
# cre. 2022.06.02 dai.

import sys
import argparse
import hashlib


def m_argparse(modes: list):
    # 引数定義とパース
    # input: list of hash mode
    parser = argparse.ArgumentParser(description="check hash value")
    parser.add_argument('-f', '--file', default='<gui>',
                        help='file to made hash')
    parser.add_argument('--hash', help='hash value')
    parser.add_argument('-a', '--all', action='store_true',
                        help='make all possiblity value')
    parser.add_argument('-m', '--mode', default='sha256', choices=modes,
                        help='hash mode')
    parser.add_argument('-l', '--list', help='list hash mode',
                        action='store_true')
    args = parser.parse_args()
    return(args.file, args.mode, args.hash, args.list, args.all)


def mc_hash(fmodes: dict, filename: str, mode: str, vhash: str,
            f_all: bool) -> int:
    ret = -1
    try:
        # ファイル を バイナリーモード で開く
        with open(filename, 'rb') as f:
            # ファイルを読み取る
            fileData = f.read()
            # ファイルのハッシュ値の計算
            if vhash is not None:
                # 引数に渡したhash値と比較
                if fmodes[mode](fileData).hexdigest() == vhash:
                    print(f'same hash values {vhash}')
                    ret = 0

                else:
                    print(f'unmatch hash value {vhash}')
                    ret = -1
            else:
                if f_all:
                    # すべてのhash値を出力
                    for key, func in fmodes.items():
                        print(f'{key} : {fmodes[key](fileData).hexdigest()}')
                    ret = 1

                else:
                    # 引数に指定されたhash値を出力
                    print(f'{mode} : {fmodes[mode](fileData).hexdigest()}')
                    ret = 1
        return(ret)

    except Exception as err:
        print(type(err))
        print(err)
        return(-1)


def main() -> int:
    # Hash名とhashlibのハッシュ関数を辞書に登録
    fmodes = {'md5': hashlib.md5,
              'sha1': hashlib.sha1,
              'sha224': hashlib.sha224,
              'sha256': hashlib.sha256,
              'sha384': hashlib.sha384,
              'sha512': hashlib.sha512,
              'sha3_224': hashlib.sha3_224,
              'sha3_256': hashlib.sha3_256,
              'sha3_384': hashlib.sha3_384,
              'sha3_512': hashlib.sha3_512,
              'blake2b': hashlib.blake2b,
              'blake2s': hashlib.blake2s}
    modes = list(fmodes.keys())

    # 引数定義とパース
    (filename, mode, vhash, f_list, f_all) = m_argparse(modes)

    # 扱えるhashの一覧を表示
    if f_list:
        print(f'mode\n{modes}')
        return(1)

    # hash計算メイン
    if filename != '<gui>':
        return(mc_hash(fmodes, filename, mode, vhash, f_all))
    else:
        print('I am sorry that gui version is not implemented yet.')
        return(-1)


if __name__ == "__main__":
    ret = main()
    if ret < 0:
        print(f'error : {ret}')
    sys.exit(ret)

補足
引数処理はあとで構造化する
GUI版は気が向いたら作る

ーーーーーーーーーーーーーーーーーー
自己責任でソースコードの2次利用は可能。
本プログラムで問題を起こしても責任は負いません。












いいなと思ったら応援しよう!