Pythonとハッシュ関数

ハッシュ関数とは?

ハッシュ関数は普段聴き慣れない言葉だとは思いますが、私たちの生活にけっして欠かすことのできない技術の一つです。では、どこで使われているのでしょうか?

それはWEBアプリケーションやEC(ネットショッピング)サイトの中のユーザー登録の中で使われています。例えばユーザー登録の際に設定したパスワードがそのままの形でサーバーに格納されていたらセキュリティ的に不安ですよね。また、サービス提供者が勝手にパスワードを覗き見るなんてこともできてしまいます。これでは安心してWEBサービスを利用できませんね。

ここで使われるのがハッシュ関数です。ハッシュ関数とはある単語を別の形に変換してくれます。パスワードのような絶対他者には伝えたくない文字列などはハッシュ関数を利用することで解読できないようにすることができます。

ハッシュ関数の3つの特徴

ここでハッシュ関数の重要性がわかったと思いますが、次はハッシュ関数の特徴をご紹介します。基本的にハッシュ関数の特徴とは不可逆性・固定長出力・機密性の3つです。これらをそれぞれ解説していきます。

不可逆性

ハッシュ関数は一方向関数と呼ばれており、暗号化はできるが復号化はかなり難しいとされています。つまり一度ハッシュ関数を通して暗号化された文字列は、逆にもとに戻すことが難しいです。

固定長出力

固定長出力とは、いかなる入力値に対してすべて同じ長さの出力を行なってくれます。例えば「hello」と「hello world」をハッシュ関数を通して暗号化した場合、どちらの暗号文も同じ長さになってくれます。データのビット数を揃えたり、データを圧縮するために使われたりします。

機密性

ハッシュ関数は文字列を暗号化する際に決まった規則性があるわけではありません。つまり、似たような二つの文字列を暗号化すると全く別のデータとして返ってきます。例えば「book」と「bool」の二つの単語はとてもよく似ていますね。このように一文字しか違わない単語でもハッシュ関数を通すと完全に異なる単語になって返ってくるわけです。

Pythonでハッシュ関数使ってみる

では実際にPythonを使ってハッシュ関数で遊んでみたいと思います。Python以外の言語でもハッシュ関数を使うことができますが、Pythonの場合はhashlibという標準ライブラリが用意されているのでオススメです。

https://docs.python.org/3/library/hashlib.html#module-hashlib

今回はこちらで記載されている「sha256」というモジュールを使っていきましょう。sha256とは「Secure Hash Algorism 256 bit]の略で暗号化したい文字列を256ビットで返してくれるハッシュ関数です。
世の中にはいろいろなハッシュ関数が存在しますがその中でもshaシリーズはNIST(アメリカ国立標準技術研究所)で定義されています。かなり安全性に富んでいます。
また、sha256はブロックチェーン技術の中でもよく使われています。

また256 bitsは16進数で64文字です。つまりどんな文字列を入力しても64文字で返ってきます。まずは手始めに「hello」を暗号化していきたいと思います。

import hashlib

ciphertext=hashlib.sha256(b"hello").hexdigest()

print("暗号文:\n" + ciphertext)

1行目は標準ライブラリであるhashlibをインポートしました。

2行目は出力するデータを英語で暗号文という意味を持つ「ciphertext」と定義しています。右辺はhashlibというライブラリからsha256というモジュールを使うことを宣言しています。
次に「b”hello”」はhelloのデータをバイト型に変換しています。ハッシュ関数では入力値はバイト型である必要があります。
次にhexdigest()は出力する文字列を16進数と設定しています。

このプログラムを実行するとこのようになりました

暗号文:
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

helloのような短い文章なのにhash256を使うことによってこんなに長い文字列に変換されましたね。これを復号するのはほぼ不可能だとわかったと思います。これがハッシュ関数の徳直の一つである不可逆性です。

次に「book」と「bool」を暗号化してみましょう。お互い似ている単語ですがハッシュ関数を通すとどのように変換されるのでしょうか。

import hashlib

cipher_book=hashlib.sha256(b"book").hexdigest()
cipher_bool=hashlib.sha256(b"bool").hexdigest()

print("bookの暗号文:\n" + cipher_book + "\n\n" +
      "boolの暗号文:\n" + cipher_bool)

これを実行すると下のような結果が得られました。

bookの暗号文:
92719fe0cf8cd51592af31ee8a5736d79f7273777fa3f7b70bfe993a4cd32180

boolの暗号文:
b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903

全く別の文字列に変換されましたね。このことから機密性については納得していただけたかなと思います。
また二つの暗号文は同じ長さ、つまり固定長出力であることがわかると思います。