python3
sha256
SHA2

ライブラリに頼らず一から Python 3 で SHA2 を実装する

概要

pysha2 という pure Python な SHA-2 ライブラリがあるのだが、これが Python 2 用だったので、Python 3 で動くようにして、Github 上で公開した。

pysha2 の Python 3 版

SHA256 のコアな処理

分かりづらい命名だが、SHA256 は SHA2 の一部の規格である。

SHA-2 - Wikipedia

上記のコードのうち、SHA256 の核心的な部分を記す。

    def _rotr(self, x, y):
        return ((x >> y) | (x << (32-y))) & 0xFFFFFFFF

    def _sha256_process(self, c):
        w = [0]*64
        w[0:16] = struct.unpack('!16L', c)

        for i in range(16, 64):
            s0 = self._rotr(w[i-15], 7) ^ self._rotr(w[i-15], 18) ^ (w[i-15] >> 3)
            s1 = self._rotr(w[i-2], 17) ^ self._rotr(w[i-2], 19) ^ (w[i-2] >> 10)
            w[i] = (w[i-16] + s0 + w[i-7] + s1) & 0xFFFFFFFF

        a,b,c,d,e,f,g,h = self._h

        for i in range(64):
            s0 = self._rotr(a, 2) ^ self._rotr(a, 13) ^ self._rotr(a, 22)
            maj = (a & b) ^ (a & c) ^ (b & c)
            t2 = s0 + maj
            s1 = self._rotr(e, 6) ^ self._rotr(e, 11) ^ self._rotr(e, 25)
            ch = (e & f) ^ ((~e) & g)
            t1 = h + s1 + ch + self._k[i] + w[i]

            h = g
            g = f
            f = e
            e = (d + t1) & 0xFFFFFFFF
            d = c
            c = b
            b = a
            a = (t1 + t2) & 0xFFFFFFFF

        self._h = [(x+y) & 0xFFFFFFFF for x,y in zip(self._h, [a,b,c,d,e,f,g,h])]

self._k は64個の4バイトの数字の定数表。
self._h は8個の4バイトの数字が格納されるワーキングエリアで、ある定数の初期値が設定されている。

要するに、ローテート・シフト・AND・XOR・NOT等の典型的な論理演算を、最初から設定されている定数とダイジェストしたいメッセージに対して行って、self._h という32バイトのワーキングエリアを更新していき、最後に self._h をハッシュ値として出力している。SHA256 の名前のとおり、このハッシュ値は 32バイト * 8 = 256ビットになる。

想像より単純な実装という印象である。これが現代の情報セキュリティの基礎になっているのかと思うと感慨深い。

参考

Federal Information Processing Standards Publication 180-2