オープンソースなSHA256ハッシュを求める為のクラス(とプログラム)です.
結構前に某ソフトで使う為に書きました.
C++ディレクトリを探索してたら見つけたので公開します.

ライセンス

どんなソフトのどんな部分にでも,自由に使ったり参考にしていただいて構いません.

更新履歴

  • 2008/03/21
    高速化.
  • 2008/03/18
    無駄なコピーの削減,ループの展開等
  • 2008/03/16
    バグ修正.暗号工房さんありがとうございます.
  • 2005/11/20
    作った

ソースコード

VC.NET 2003とgcc4でコンパイルできる事を確認しています.
失敗しても,(long longが使えない環境とかだと)sha256.hのコメントを読めば*1直る事があるかもです.
C++的なプログラムの書き方の勉強にはなりませんので,注意.

  • ソース
    sha256.cpp filesha256.cpp
    sha256.h filesha256.h

    g++ sha256.cppな感じで普通にコンパイル通ると思います.

それと,私が最初に実装したSHA-256ライブラリも見つかったので置いておきます.
コードはこっちの方が読みやすいので,仕様をコードに落とせなくて困っている方はどうぞ.
filesha256_simple.cpp

使い方

コマンドラインで使う事になります.
ファイルを読み込ませて求める

sha256 file

か,直接文字列を入力する.

sha256 -s string

になります.引数無しで実行すると,標準入力から読み込みます(テストして無いけれど...)

性能

  • 入力のサイズ
    適当なバイナリ4GBのハッシュはちゃんと求めれました.それ以上は試してないですが
    2^64ビットまでは大丈夫な気がします(未確認です). 追記:未確認だった2^32ビット以上のメッセージですが,正常に動作しないようです.
    最新版は大丈夫な気がします(未確認ですが...).
  • 実行時間
    BSDに標準で入ってるsha256コマンドより1.5倍くらいの時間がかかります・・・
    チューニングとかしてないです^^;
  • バイナリサイズ
    > ll a.out
    -rwxr-xr-x  1 safii  safii  7120 Feb 28 19:29 a.out
    > ll /sbin/sha256
    -r-xr-xr-x  4 root  wheel  9412 Sep 14 18:50 /sbin/sha256
    実行ファイルのサイズはBSDの物より小さいです(ぉ.

参考

  • FIP180-2
    仕様書です.自分で実装する場合はここを見ながらする事になるかと思います.

コメント

使用報告やバグ報告,どこそこを修正すると早くなるかも等がありましたら是非教えてください.

  • sha256.hの #define U64_HIGH(a) *2 ではないでしょうか? -- 暗号工房 2008-03-15 16:22:55 (土)
  • SHA256::Final の W[m_WIndex++/4]|=0x00<<(24-(m_WIndex%4)*8);は W[m_WIndex++/4]|=0x0;と同じになってしまうように思いますが? -- 暗号工房 2008-03-15 16:30:47 (土)
  • SHA256::Final の W[m_WIndex++/4]|=0x00<<(24-(m_WIndex%4)*8);は W[m_WIndex++/4]|=0x0;と同じになってしまうように思いますが? -- 暗号工房 2008-03-15 16:31:27 (土)
  • その通りですね.ご指摘ありがとうございます.大きいサイズのメッセージを求めようとすると正常に動きませんね.謎のシフトはなんでこんなことになっているんでしょうね? 覚えていませんが直しておきます. あと,コメントが書きにくくて申し訳ありませんでした. -- Naoki 2008-03-16 00:31:09 (日)
  • 上記の者ですが、間違えて実名を入れてしまってので、訂正をお願いします。また、void SHA256::CalcIntermediateHash() を次の様に書き換えると、高速になります。エンターが使えないので見難いですが
    void SHA256::CalcIntermediateHash(){
        i_^=1;
        i_1^=1;
        u_32 x[8];
    
        memcpy(x, H[i_1], 32);
        int T1, T2;
        int t;
    #define ROUND(n,a,b,c,d,e,f,g,h) \
        T1=x[h]+S256_1(x[e])+Ch(x[e],x[f],x[g])+K[t+n]+W[t+n]; \
        T2=S256_0(x[a])+Maj(x[a],x[b],x[c]); \
        x[d]=x[d]+T1; \
        x[h]=T1+T2
        
        for(t=0; t<64; t+=8){
            ROUND(0,0,1,2,3,4,5,6,7);
            ROUND(1,7,0,1,2,3,4,5,6);
            ROUND(2,6,7,0,1,2,3,4,5);
            ROUND(3,5,6,7,0,1,2,3,4);
            ROUND(4,4,5,6,7,0,1,2,3);
            ROUND(5,3,4,5,6,7,0,1,2);
            ROUND(6,2,3,4,5,6,7,0,1);
            ROUND(7,1,2,3,4,5,6,7,0);
        }
        H[i_][0]=x[0]+H[i_1][0];
        H[i_][1]=x[1]+H[i_1][1];
        H[i_][2]=x[2]+H[i_1][2];
        H[i_][3]=x[3]+H[i_1][3];
        H[i_][4]=x[4]+H[i_1][4];
        H[i_][5]=x[5]+H[i_1][5];
        H[i_][6]=x[6]+H[i_1][6];
        H[i_][7]=x[7]+H[i_1][7];
    }
    
    • 暗号工房 2008-03-16 09:46:58 (日)
  • 名前は修正しておきました.それと,高速化のアイデアありがとうございます.昨日のループも0でor取ってるので意味がないんですよね・・・ 色々と修正できる部分がありそうですね. -- Naoki 2008-03-16 14:47:01 (日)
  • 修正版をアップロードしておきました.他の箇所のループの展開的なことはやっていませんが,他にも少しいじってあります.それと,コメントを見やすいように編集しておきました -- Naoki 2008-03-18 23:34:37 (火)
  • sha256.cppのコードを公開して頂き、大変勉強になりました。お蔭さまで、ハッシュのコードがわかるようになりました。ありがとうございました。ところで、コードに、もう2箇所ばかり気になるところがあります。一つ目は i_,i_1,H[2][8]についてです。これはi_,i_1を使わずにH[8]とした方が良いと思われます。ただし -- 暗号工房 2008-03-20 14:14:03 (木)
  • 間違って送信してしまったため、上記の続きです。  SHA256::CalcIntermediateHash()のH[i_][0]=x[0]+H[i_1][0];などはH[0]+=x[0];などに変わりますが、gccで試したところ、この方が高速になりました。二つ目はSHA256::Finalのfor(t=m_WIndex/4+1;t<16; t++)W[t]=0;の+1の部分です。W[t]に既に0が代入されているため、この行全体がなくても動作しますので、バグではありませんが、このコードを参考にする人のために+1は削除した方が良いと思います。 -- 暗号工房 2008-03-20 14:20:29 (木)
  • Hの内容はxにコピーしてあるのでいらないですね.ありがとうございます.196行目のmemsetもきちんと書けば削れそうですね.こんなに色々とレビューしていただけるなら,これからも喜んで公開しますよ^^ -- Naoki 2008-03-21 16:30:36 (金)
  • こちらのソースを参考にさせていただきました。ありがとうございます。ここがなかったら実装はあきらめていたかも知れません。 1つ質問させて下さい。sha256.cpp内 SHA256::Pushの167行〜182行までの記述ですが、これは簡単に記述しようとすれば、 W[t_4/4]|=pMes[MesIndex++]<<(24-(t_4%4)*8); の部分を、 (t_4<64) && (MesIndex<Len) まで繰り返す形で書けると思っています(やってみましたが同じ結果が出ました)。この記述方法になっているのは、高速化のためという理解でいいでしょうか? -- はるあき 2008-06-05 18:11:09 (木)
  • 参考になりましたか.嬉しいです.二つのループでまわしている部分ですが,高速化のためであっています.コメント書いておかないと分かりにくいですね^^; -- Naoki 2008-06-08 18:04:52 (日)
  • Push()に1byteの長さのデータを10回渡してFinish()するのと、同じ10byteのデータを一回渡してFinish()するのとで答えが変わります。Push()を複数回呼び出す時は、データサイズが1024の倍数でないとならないとかじゃないでしょうか。できれば不定長データの複数呼び出しに対応して頂ければ助かります -- K 2013-02-17 17:45:20 (日)
  • http://create.stephan-brumme.com/hash-library ここにあるプログラムだと正しい計算ができるのですが、ここに公開されているプログラムだと同じハッシュ値になりませんでした。 -- G 2016-07-25 22:38:31 (月)
  • 訂正します、外国のサイトのコードは正しい値が計算できるのですが、岩崎さんのコードだと正しい値が出ませんでした。 -- G 2016-07-25 22:40:53 (月)
  • Gさん、前提不明な結果を書かれるより、具体的な環境、与えるファイルサイズ等を書かれた方が、訂正しやすいと思うのですが…(^^;) -- 機械言語 2016-08-08 02:31:33 (月)
  • お礼が後になってしまいました。公開ありがとうございます m(_ _)m ハッシュ値の正当性は、GNUのツールや、WindowsならPowerShellで確認出来ます。 6,481,507,740 バイトのバイナリで、ハッシュ値の一致を確認出来ました。 -- 機械言語 2016-08-08 03:17:17 (月)
  • 重箱の隅ですみません…。ケアレスミス一つ発見しました。sha256.hの24行目 m_MesLen は a ですよね。あと、Pushの先頭部分のバッファのコピーは、ポインタをキャストして単にmemcpyを使ってはどうでしょう。それと、これはこのコードを利用する方へ注意なのですが、Pushに渡すバッファがコーディング程度の大きさで無いと、ハッシュ計算バッファを超えて実行時エラーか暴走になります。ご注意を。 -- 機械言語 2016-08-09 02:11:54 (火)
  • …すみません、memcpyの件は誤りでした m(_ _)m アルゴリズムも良く見ずにすみません…。色々勉強になりました。 -- 機械言語 2016-08-09 02:21:37 (火)
  • 今更ながらすみません、このソースは再配布等条件があるのでしょうか?あくまで参考用でしょうか?オープンソースライセンスに違反する可能性があるか気になっています。 -- D 2017-02-02 19:28:14 (木)
  • 自由に使っていただいて構いません。もし役に立ちましたら直接あったときにはぜひビールでもおごってください。 -- Naoki 2017-02-03 00:25:47 (金)
  • ご回答ありがとうございます。m(_ _)m。今の時期なら熱燗ですかね?^^ -- D 2017-02-03 09:29:23 (金)

お名前:

*1 仮64ビット整数クラスがあります
*2 u_32)m_MesLen>>32) は #define U64_HIGH(a) ((u_32)(a>>32
添付ファイル: filesha256.h 5061件 [詳細] filesha256_simple.cpp 4976件 [詳細] filesha256.cpp 8989件 [詳細]