ネットワーク WG
Request for Comments: 3174
分類: 情報提供

D. Eastlake, 3rd
Motorola
P. Jones
Cisco Systems
2001年 9月

English

SHA-1
(US Secure Hash Algorithm 1 (SHA1))

このメモの位置付け

このメモは、インターネット コミュニティに情報を提供するものです。いかなるインターネット標準をも規定するものではありません。このメモの配布に制限はありません。

著作権表記

Copyright (C) The Internet Society (2001). All Rights Reserved.

要旨

本書の目的は、SHA-1 (Secure Hash Algorithm 1) を、インターネットコミュニティが容易に利用できるようにすることにあります。米国は、ここで記述する SHA-1 ハッシュアルゴリズムを FIPS (Federal Information Processing Standard) として採用しています。本書のほとんどの文章は、FIPS 180-1 から転記したものです。C 言語による実装のみが「オリジナル」です。

謝辞

本書の文章の大部分は、[FIPS 180-1] からのものです。C 言語による実装のみが「オリジナル」です。実装方法は、既に発行されている MD4 と MD5 の RFC [RFC 1320, 1321] と同様の形式で記述してい ます。

SHA-1 は、MIT の Ronald L. Rivest 教授が MD4 メッセージダイジェストアルゴリズム [MD4] を設計したときに使用した原理と同様の原理に基づいており、また、そのアルゴリズムをモデルとしています [RFC 1320]。

下記の方々から本書に含まれている有用なコメントを頂きました。感謝しています。

Tony Hansen, Garrett Wollman.

目次

1. 概要

2. bit 文字列と整数の定義

3. 各ワードに対する演算

4. メッセージへのパディング

5. 使用関数と使用定数

6. メッセージダイジェストの計算

6.1 方法 1
6.2 方法 2

7. C言語コード

7.1 .h ファイル
7.2 .c ファイル
7.3 テストドライバ

8. セキュリティに関する考慮事項

参考文献

著者のアドレス

著作権表記全文

 

1. 概要  English

注:下記の文章は、そのほとんどを[FIPS 180-1] から転記したものであり、SHA-1 のセキュリティ検証は、米国政府、[FIPS 180-1]の著者とその他の方々によって行れている。

本書においては、メッセージもしくはデータファイルの圧縮表記を計算するための Secure Hash Algorithm である SHA-1 を規定する。2^64bit 以下の長さを持つメッセージの入力に対して SHA-1 は 、メッセージダイジェストと呼ばれる 160 bit の出力値を生成する。メッセージダイジェストは、例えば、メッセージの署名作成または検証を行うための署名アルゴリズムへの入力となる。メッセージ自体ではなくメッセージダイジェストに署名を行うことで、通常は署名処理の効率が向上する。これは通常メッセージダイジェストはメッセージよりもサイズが小さいからである。デジタル署名を作成するのに使用したアルゴリズムと同じアルゴリズムを使用してデジタル署名の検証を行わなければならない。メッセージの転送中にメッセージへの変更が発生すると、非常に高い確率で異なるメッセージダイジェストを計算することになるため、署名検証に失敗することになる。

SHA-1 は、セキュアであるとされている。それは与えられたメッセージダイジェストからメッセージを発見したり、同じメッセージダイジェストを持つ異なる 2つのメッセージを発見したりすることが計算上不可能だからである。メッセージの転送中にメッセージへの変更が発生すると、非常に高い確率で異なるメッセージダイジェストを計算することになるため、署名検証に失敗することになる。

2章以下では、用語や、ブロック化を行い SHA-1 処理を行う機能を定義する。

 

2. bit 文字列と整数の定義  English

bit 文字列と整数に関する次の用語を使う。

a. 16進数とは、{0, 1, ... , 9, A, ... , F} で構成されている集合の中の 1つの要素である。16 進数は 4 bit 文字列を表記したものである。 例: 7 = 0111, A = 1010

b. ワードとは32bit の文字列のことで、8個の16進数の列で表記される。 1つのワードを 8 個の 16 進数に変換するには、4bit 文字列ごとに、(a)で定義される16進数に変換する。 例: 1010 0001 0000 0011 1111 1110 0010 0011 = A103FE23

c. 0から2^32 - 1までの間の整数は、1つのワードで表記することが出来る。整数における最下位 4bit は、ワードの 16進数表記における最も右側の16進数となる。 例: 整数 291 = 2^8+2^5+2^1+2^0 = 256+32+2+1 は、16進数で 00000123 と表記される。

z を 0 <= z < 2^64 の整数とすると、z = (2^32)x + y 、ただし 0 <= x < 2^32 であり 0 <= y < 2^32 である。x と y はそれぞれワード X と Y として表記できるため、z はワードの組(X,Y)として表記できる。

d. ブロックとは、512 bit の文字列である。ひとつのブロック(例:B)は、 16ワード列として表記できる。

 

3. 各ワードに対する演算  English

以下の論理演算が、ワードに対して適用される。

a. bit ごとの論理ワード演算

X AND Y = X と Y の、bit ごとの論理積

X OR Y = X と Y の、bit ごとの論理和

X XOR Y = X と Y の、bit ごとの排他的論理和

NOT X = X のbit ごとの論理否定

例:

               01101100101110011101001001111011

         XOR   01100101110000010110100110110111

               --------------------------------

           =   00001001011110001011101111001100

b. 演算 X + Y は以下のように定義される。ワード X と Y は、整数 x と y を表す。ここで 0 <= x < 2^32 であり、また 0 <= y < 2^32 である。正の整数 n と m に対し、n mod m を、m で n を割ったときの剰余とする。以下を計算する。

z = (x + y) mod 2^32

このとき、0 <= z < 2^32 となる。そして z を1ワード Z に変換したものを、 Z = X + Y と定義する。

c. X は1ワード、n は 0 <= n < 32 となる整数であるとき、循環左シフト演算 S^n(X) は以下のように定義される。

S^n(X) = (X << n) OR (X >> 32-n)

上式における、X << n は以下のようにして得られる。X の左 n bit を捨て、n bit のゼロを右に付加する(結果はやはり32bit である)。上式における X >> n は、X の右 n bit を捨て、n bit のゼロを左に付加することで得られる。したがって S^n(X) は、X を n 個分左に循環シフトしたものと等価となる。

 

4. メッセージへのパディング  English

SHA-1は、入力として提供されるメッセージまたはデータファイルのメッセージ ダイジェストを計算するために使用される。メッセージまたはデータファイルは、 bit 文字列と見なされる。メッセージ長は、メッセージのbit 数(空メッ セージは長さ0)である。メッセージの bit 数が 8 の倍数であれば、簡便さのため メッセージを 16進数で表す。メッセージに対してはパディングを行うが、その目的は、パディングを行った後のメッセージ長が512の倍数になるようにすることである。SHA-1では、メッセージダイジェストを計算する際に、512bit のブロック ごとに処理を行う。以下では、このパディングがどのように行われるかについて記述する。簡単に述べると、1つの"1"を付加し、その後にm個の"0"を付加して、 最後に64bit の整数を付加することで、メッセージ長を 512 * n とする。この 64 bit 整数というのは、オリジナルメッセージの長さである。パディングの 行われたメッセージは、その後n個の 512bit ブロックとして解釈され、SHA-1 により処理される。

あるメッセージの長さ l が、l < 2^64 であるとする。これを SHA-1 に入力する前に、 メッセージはその右側に対して以下のようなパディングを行う。

a. 1個の"1"を付加する。 例:オリジナルメッセージが"01010000"であるとき、パディングされたメッセージは"010100001"である。

b. "0"を付加する。付加する"0"の個数はオリジナルメッセージの長さに依存する。最後の 512bit ブロックにおける最後の64bit は、オリジナルメッセージの長さ l を格納するために予約されている。例:オリジナルメッセージが以下のようなbit 文字列であったとき、

01100001 01100010 01100011 01100100 01100101

ステップ(a)の処理を行うと、以下のようになる。

01100001 01100010 01100011 01100100 01100101 1

l = 40 であるため、上記の bit 数は 41 bit であり、407個の"0"が付加されて 448 bit とされる。したがって、16進数で 次のようになる。

61626364 65800000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000

c. オリジナルメッセージのbit 数 l を2ワードで表記する。l < 2^32 であれば、最初のワードはすべて0になる。これらの2 ワードをメッセージに付加する。例:オリジナルメッセージが(b)と同じである場合、l = 40 となる( l はパディングを行う前に計算することに注意)。40を 2ワード表記すると16進数で 00000000 00000028となる。それゆえパディング処理により最終的に得られるメッセージは、16進数で 次のようになる。

61626364 65800000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000028

パディングされたメッセージには、16 * n 個(ただし任意の n > 0 )のワードが含まれている。パディングされたメッセージは、最初の文字(もしくはbit )から順に、n 個のブロック M(1), M(2), となる。

 

5. 使用関数と使用定数  English

SHA-1では、論理関数のシーケンス f(0), f(1),..., f(79)を使用する。それぞれの f(t), 0 <= t <= 79 では、3つの 32bit ワード B, C, D を処理し 1つの 32bit ワードを出力する。ワード B, C, D に対し、f(t;B,C,D)を以下のように定義する。

f(t;B,C,D) = (B AND C) OR ((NOT B) AND D) ( 0 <= t <= 19)

f(t;B,C,D) = B XOR C XOR D (20 <= t <= 39)

f(t;B,C,D) = (B AND C) OR (B AND D) OR (C AND D) (40 <= t <= 59)

f(t;B,C,D) = B XOR C XOR D (60 <= t <= 79)

SHA-1では、定数ワードのシーケンス K(0), K(1), ... , K(79) を使用する。それぞれは、16 進表記で以下のように定義される。

K(t) = 5A827999 ( 0 <= t <= 19)

K(t) = 6ED9EBA1 (20 <= t <= 39)

K(t) = 8F1BBCDC (40 <= t <= 59)

K(t) = CA62C1D6 (60 <= t <= 79)

 

6. メッセージダイジェストの計算  English

以下の 6.16.2 で示されている 2つの方法は、どちらも同じダイジェスト値を出力する。方法 2 は方法 1 に比べ、32bit ワード 64個分の記憶域を使用しなくて済むが、ステップcにおけるそれぞれの W[t] のアドレス計算が複雑であるため実行時間が長くなるようである。同じ結果を出力する他の計算方法も存在する。

6.1 方法 1  English

メッセージダイジェストは、4章で示されているメッセージパディングを使用して計算する。計算に際して 2 つのバッファを使用する。それぞれのバッファは 32bit ワード5つ分で構成されている。さらに 32 bit ワード 80 個分のワードシーケンスを 1つ使用する。1つの 5ワードバッファにおけるそれぞれのワードを A,B,C,D,E とする。もうひとつの 5 ワードバッファにおけるそれぞれのワードを H0, H1, H2, H3, H4 とする。 80 ワードシーケンスにおけるそれぞれのワードは W(0), W(1),..., W(79) とする。そして 1ワードのバッファ TEMP を使用する。

メッセージダイジェストの計算では、4章で定義された 16ワードブロックM(1), M(2),...,M(n)を、この順序で処理する。それぞれのM(i) の処理に対して 80ステップの処理が行われる。

ワードブロックを処理する前に、それぞれのHを以下のように初期化する(16進で表記している)。

H0 = 67452301

H1 = EFCDAB89

H2 = 98BADCFE

H3 = 10325476

H4 = C3D2E1F0.

そして M(1), M(2), ... , M(n) の計算を行う。 M(i)の処理を以下のように行う。

a. M(i)を、16個のワード W(0), W(1), ... , W(15) に分割する。ここで W(0) は 最上位ワードである。

b. 16から79までのtに対して、以下の計算を行う。

W(t) = S^1(W(t-3) XOR W(t-8) XOR W(t-14) XOR W(t-16))

c. A, B, C, D, E をそれぞれ、A = H0, B = H1, C = H2, D = H3, E = H4 とする。

d. 0から79までのtに対して、以下の計算を行う。

TEMP = S^5(A) + f(t;B,C,D) + E + W(t) + K(t);

E = D; D = C; C = S^30(B); B = A; A = TEMP;

e. HO, H1, H2, H3, H4 をそれぞれ、H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E とする。

M(n)の処理を行うと、メッセージダイジェストは、以下の5ワードで表される 160bit の 文字列として得られる。

H0 H1 H2 H3 H4

6.2 方法 2  English

上記の方法では、シーケンスW(0), ... , W(79)は 32bit ワード 80個をもつ配列として実装されることを仮定している。これは実行時間を最小化するという点から見ると効果的であるといえる。それはステップbにおけるW(t-3), ... ,W(t-16)のアドレスが簡単に求まるからである。しかしメモリ使用量を極力抑えたい場合には、他の計算方法として、W(t) の列を循環キューと見なす方法がある。この場合、16個の 32bit ワードW[0], ... W[15] の配列を使用するような実装を行うことができる。

ここではMASKを、16進表記で MASK = 0000000F と定義する。M(i)の計算は以下のようになる。

a. M(i)を、16個のワード W[0], ... , W[15] に分割する。ここで W[0] は 最上位ワードである。

b. A, B, C, D, E をそれぞれ、A = H0, B = H1, C = H2, D = H3, E = H4 とする。

c. 0から79までのtに対して、以下の計算を行う。

s = t AND MASK;

if (t >= 16) W[s] = S^1(W[(s + 13) AND MASK] XOR W[(s + 8) AND MASK] XOR W[(s + 2) AND MASK] XOR W[s]);

TEMP = S^5(A) + f(t;B,C,D) + E + W[s] + K(t);

E = D; D = C; C = S^30(B); B = A; A = TEMP;

d. HO, H1, H2, H3, H4 をそれぞれ、H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E とする。

 

7. C言語コード  English

以下は、C言語による SHA-1 実装例である。7.1 は、ヘッダファイルであり、7.2 は 、C言語コードであり、そして 7.3 は、テストドライバである。

7.1 .h ファイル

/*

 *  sha1.h

 *

 *  Description:

 *      This is the header file for code which implements the Secure

 *      Hashing Algorithm 1 as defined in FIPS PUB 180-1 published

 *      April 17, 1995.

 *

 *      Many of the variable names in this code, especially the

 *      single character names, were used because those were the names

 *      used in the publication.

 *

 *      Please read the file sha1.c for more information.

 *

 */



#ifndef _SHA1_H_

#define _SHA1_H_



#include 

/*

 * If you do not have the ISO standard stdint.h header file, then you

 * must typdef the following:

 *    name              meaning

 *  uint32_t         unsigned 32 bit integer

 *  uint8_t          unsigned 8 bit integer (i.e., unsigned char)

 *  int_least16_t    integer of >= 16 bits

 *

 */



#ifndef _SHA_enum_

#define _SHA_enum_

enum

{

    shaSuccess = 0,

    shaNull,            /* Null pointer parameter */

    shaInputTooLong,    /* input data too long */

    shaStateError       /* called Input after Result */

};

#endif

#define SHA1HashSize 20



/*

 *  This structure will hold context information for the SHA-1

 *  hashing operation

 */

typedef struct SHA1Context

{

    uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest  */



    uint32_t Length_Low;            /* Message length in bits      */

    uint32_t Length_High;           /* Message length in bits      */



                               /* Index into message block array   */

    int_least16_t Message_Block_Index;

    uint8_t Message_Block[64];      /* 512-bit message blocks      */



    int Computed;               /* Is the digest computed?         */

    int Corrupted;             /* Is the message digest corrupted? */

} SHA1Context;



/*

 *  Function Prototypes

 */



int SHA1Reset(  SHA1Context *);

int SHA1Input(  SHA1Context *,

                const uint8_t *,

                unsigned int);

int SHA1Result( SHA1Context *,

                uint8_t Message_Digest[SHA1HashSize]);



#endif

 

7.2 .c ファイル

/*

 *  sha1.c

 *

 *  Description:

 *      This file implements the Secure Hashing Algorithm 1 as

 *      defined in FIPS PUB 180-1 published April 17, 1995.

 *

 *      The SHA-1, produces a 160-bit message digest for a given

 *      data stream.  It should take about 2**n steps to find a

 *      message with the same digest as a given message and

 *      2**(n/2) to find any two messages with the same digest,

 *      when n is the digest size in bits.  Therefore, this

 *      algorithm can serve as a means of providing a

 *      "fingerprint" for a message.

 *

 *  Portability Issues:

 *      SHA-1 is defined in terms of 32-bit "words".  This code

 *      uses  (included via "sha1.h" to define 32 and 8

 *      bit unsigned integer types.  If your C compiler does not

 *      support 32 bit unsigned integers, this code is not

 *      appropriate.

 *

 *  Caveats:

 *      SHA-1 is designed to work with messages less than 2^64 bits

 *      long.  Although SHA-1 allows a message digest to be generated

 *      for messages of any number of bits less than 2^64, this

 *      implementation only works with messages with a length that is

 *      a multiple of the size of an 8-bit character.

 *

 */





#include "sha1.h"



/*

 *  Define the SHA1 circular left shift macro

 */

#define SHA1CircularShift(bits,word) \

                (((word) << (bits)) | ((word) >> (32-(bits))))



/* Local Function Prototyptes */

void SHA1PadMessage(SHA1Context *);

void SHA1ProcessMessageBlock(SHA1Context *);



/*

 *  SHA1Reset

 *

 *  Description:

 *      This function will initialize the SHA1Context in preparation

 *      for computing a new SHA1 message digest.

 *

 *  Parameters:

 *      context: [in/out]

 *          The context to reset.

 *

 *  Returns:

 *      sha Error Code.

 *

 */

int SHA1Reset(SHA1Context *context)

{

    if (!context)

    {

        return shaNull;

    }



    context->Length_Low             = 0;

    context->Length_High            = 0;

    context->Message_Block_Index    = 0;



    context->Intermediate_Hash[0]   = 0x67452301;

    context->Intermediate_Hash[1]   = 0xEFCDAB89;

    context->Intermediate_Hash[2]   = 0x98BADCFE;

    context->Intermediate_Hash[3]   = 0x10325476;

    context->Intermediate_Hash[4]   = 0xC3D2E1F0;



    context->Computed   = 0;

    context->Corrupted  = 0;



    return shaSuccess;

}



/*

 *  SHA1Result

 *

 *  Description:

 *      This function will return the 160-bit message digest into the

 *      Message_Digest array  provided by the caller.

 *      NOTE: The first octet of hash is stored in the 0th element,

 *            the last octet of hash in the 19th element.

 *

 *  Parameters:

 *      context: [in/out]

 *          The context to use to calculate the SHA-1 hash.

 *      Message_Digest: [out]

 *          Where the digest is returned.

 *

 *  Returns:

 *      sha Error Code.

 *

 */

int SHA1Result( SHA1Context *context,

                uint8_t Message_Digest[SHA1HashSize])

{

    int i;



    if (!context || !Message_Digest)

    {

        return shaNull;

    }



    if (context->Corrupted)

    {

        return context->Corrupted;

    }



    if (!context->Computed)

    {

        SHA1PadMessage(context);

        for(i=0; i<64; ++i)

        {

            /* message may be sensitive, clear it out */

            context->Message_Block[i] = 0;

        }

        context->Length_Low = 0;    /* and clear length */

        context->Length_High = 0;

        context->Computed = 1;

    }



    for(i = 0; i < SHA1HashSize; ++i)

    {

        Message_Digest[i] = context->Intermediate_Hash[i>>2]

                            >> 8 * ( 3 - ( i & 0x03 ) );

    }



    return shaSuccess;

}



/*

 *  SHA1Input

 *

 *  Description:

 *      This function accepts an array of octets as the next portion

 *      of the message.

 *

 *  Parameters:

 *      context: [in/out]

 *          The SHA context to update

 *      message_array: [in]

 *          An array of characters representing the next portion of

 *          the message.

 *      length: [in]

 *          The length of the message in message_array

 *

 *  Returns:

 *      sha Error Code.

 *

 */

int SHA1Input(    SHA1Context    *context,

                  const uint8_t  *message_array,

                  unsigned       length)

{

    if (!length)

    {

        return shaSuccess;

    }



    if (!context || !message_array)

    {

        return shaNull;

    }



    if (context->Computed)

    {

        context->Corrupted = shaStateError;

        return shaStateError;

    }



    if (context->Corrupted)

    {

         return context->Corrupted;

    }

    while(length-- && !context->Corrupted)

    {

    context->Message_Block[context->Message_Block_Index++] =

                    (*message_array & 0xFF);



    context->Length_Low += 8;

    if (context->Length_Low == 0)

    {

        context->Length_High++;

        if (context->Length_High == 0)

        {

            /* Message is too long */

            context->Corrupted = 1;

        }

    }



    if (context->Message_Block_Index == 64)

    {

        SHA1ProcessMessageBlock(context);

    }



    message_array++;

    }



    return shaSuccess;

}



/*

 *  SHA1ProcessMessageBlock

 *

 *  Description:

 *      This function will process the next 512 bits of the message

 *      stored in the Message_Block array.

 *

 *  Parameters:

 *      None.

 *

 *  Returns:

 *      Nothing.

 *

 *  Comments:

 *      Many of the variable names in this code, especially the

 *      single character names, were used because those were the

 *      names used in the publication.

 *

 *

 */

void SHA1ProcessMessageBlock(SHA1Context *context)

{

    const uint32_t K[] =    {       /* Constants defined in SHA-1   */

                            0x5A827999,

                            0x6ED9EBA1,

                            0x8F1BBCDC,

                            0xCA62C1D6

                            };

    int           t;                 /* Loop counter                */

    uint32_t      temp;              /* Temporary word value        */

    uint32_t      W[80];             /* Word sequence               */

    uint32_t      A, B, C, D, E;     /* Word buffers                */



    /*

     *  Initialize the first 16 words in the array W

     */

    for(t = 0; t < 16; t++)

    {

        W[t] = context->Message_Block[t * 4] << 24;

        W[t] |= context->Message_Block[t * 4 + 1] << 16;

        W[t] |= context->Message_Block[t * 4 + 2] << 8;

        W[t] |= context->Message_Block[t * 4 + 3];

    }



    for(t = 16; t < 80; t++)

    {

       W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);

    }



    A = context->Intermediate_Hash[0];

    B = context->Intermediate_Hash[1];

    C = context->Intermediate_Hash[2];

    D = context->Intermediate_Hash[3];

    E = context->Intermediate_Hash[4];



    for(t = 0; t < 20; t++)

    {

        temp =  SHA1CircularShift(5,A) +

                ((B & C) | ((~B) & D)) + E + W[t] + K[0];

        E = D;

        D = C;

        C = SHA1CircularShift(30,B);

        B = A;

        A = temp;

    }



    for(t = 20; t < 40; t++)

    {

        temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];

        E = D;

        D = C;

        C = SHA1CircularShift(30,B);

        B = A;

        A = temp;

    }



    for(t = 40; t < 60; t++)

    {

        temp = SHA1CircularShift(5,A) +

               ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];

        E = D;

        D = C;

        C = SHA1CircularShift(30,B);

        B = A;

        A = temp;

    }



    for(t = 60; t < 80; t++)

    {

        temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];

        E = D;

        D = C;

        C = SHA1CircularShift(30,B);

        B = A;

        A = temp;

    }



    context->Intermediate_Hash[0] += A;

    context->Intermediate_Hash[1] += B;

    context->Intermediate_Hash[2] += C;

    context->Intermediate_Hash[3] += D;

    context->Intermediate_Hash[4] += E;



    context->Message_Block_Index = 0;

}





/*

 *  SHA1PadMessage

 *

 *  Description:

 *      According to the standard, the message must be padded to an even

 *      512 bits.  The first padding bit must be a '1'.  The last 64

 *      bits represent the length of the original message.  All bits in

 *      between should be 0.  This function will pad the message

 *      according to those rules by filling the Message_Block array

 *      accordingly.  It will also call the ProcessMessageBlock function

 *      provided appropriately.  When it returns, it can be assumed that

 *      the message digest has been computed.

 *

 *  Parameters:

 *      context: [in/out]

 *          The context to pad

 *      ProcessMessageBlock: [in]

 *          The appropriate SHA*ProcessMessageBlock function

 *  Returns:

 *      Nothing.

 *

 */



void SHA1PadMessage(SHA1Context *context)

{

    /*

     *  Check to see if the current message block is too small to hold

     *  the initial padding bits and length.  If so, we will pad the

     *  block, process it, and then continue padding into a second

     *  block.

     */

    if (context->Message_Block_Index > 55)

    {

        context->Message_Block[context->Message_Block_Index++] = 0x80;

        while(context->Message_Block_Index < 64)

        {

            context->Message_Block[context->Message_Block_Index++] = 0;

        }



        SHA1ProcessMessageBlock(context);



        while(context->Message_Block_Index < 56)

        {

            context->Message_Block[context->Message_Block_Index++] = 0;

        }

    }

    else

    {

        context->Message_Block[context->Message_Block_Index++] = 0x80;

        while(context->Message_Block_Index < 56)

        {

            context->Message_Block[context->Message_Block_Index++] = 0;

        }

    }



    /*

     *  Store the message length as the last 8 octets

     */

    context->Message_Block[56] = context->Length_High >> 24;

    context->Message_Block[57] = context->Length_High >> 16;

    context->Message_Block[58] = context->Length_High >> 8;

    context->Message_Block[59] = context->Length_High;

    context->Message_Block[60] = context->Length_Low >> 24;

    context->Message_Block[61] = context->Length_Low >> 16;

    context->Message_Block[62] = context->Length_Low >> 8;

    context->Message_Block[63] = context->Length_Low;



    SHA1ProcessMessageBlock(context);

}



7.3 テストドライバ

以下のコードは、sha1.c のコードを実行するためのテストドライバである。

/*

 *  sha1test.c

 *

 *  Description:

 *      This file will exercise the SHA-1 code performing the three

 *      tests documented in FIPS PUB 180-1 plus one which calls

 *      SHA1Input with an exact multiple of 512 bits, plus a few

 *      error test checks.

 *

 *  Portability Issues:

 *      None.

 *

 */



#include 

#include 

#include 

#include "sha1.h"



/*

 *  Define patterns for testing

 */

#define TEST1   "abc"

#define TEST2a  "abcdbcdecdefdefgefghfghighijhi"

#define TEST2b  "jkijkljklmklmnlmnomnopnopq"

#define TEST2   TEST2a TEST2b

#define TEST3   "a"

#define TEST4a  "01234567012345670123456701234567"

#define TEST4b  "01234567012345670123456701234567"

    /* an exact multiple of 512 bits */

#define TEST4   TEST4a TEST4b

char *testarray[4] =

{

    TEST1,

    TEST2,

    TEST3,

    TEST4

};

long int repeatcount[4] = { 1, 1, 1000000, 10 };

char *resultarray[4] =

{

    "A9 99 3E 36 47 06 81 6A BA 3E 25 71 78 50 C2 6C 9C D0 D8 9D",

    "84 98 3E 44 1C 3B D2 6E BA AE 4A A1 F9 51 29 E5 E5 46 70 F1",

    "34 AA 97 3C D4 C4 DA A4 F6 1E EB 2B DB AD 27 31 65 34 01 6F",

    "DE A3 56 A2 CD DD 90 C7 A7 EC ED C5 EB B5 63 93 4F 46 04 52"

};



int main()

{

    SHA1Context sha;

    int i, j, err;

    uint8_t Message_Digest[20];



    /*

     *  Perform SHA-1 tests

     */

    for(j = 0; j < 4; ++j)

    {

        printf( "\nTest %d: %d, '%s'\n",

                j+1,

                repeatcount[j],

                testarray[j]);



        err = SHA1Reset(&sha);

        if (err)

        {

            fprintf(stderr, "SHA1Reset Error %d.\n", err );

            break;    /* out of for j loop */

        }



        for(i = 0; i < repeatcount[j]; ++i)

        {

            err = SHA1Input(&sha,

                  (const unsigned char *) testarray[j],

                  strlen(testarray[j]));

            if (err)

            {

                fprintf(stderr, "SHA1Input Error %d.\n", err );

                break;    /* out of for i loop */

            }

        }



        err = SHA1Result(&sha, Message_Digest);

        if (err)

        {

            fprintf(stderr,

            "SHA1Result Error %d, could not compute message digest.\n",

            err );

        }

        else

        {

            printf("\t");

            for(i = 0; i < 20 ; ++i)

            {

                printf("%02X ", Message_Digest[i]);

            }

            printf("\n");

        }

        printf("Should match:\n");

        printf("\t%s\n", resultarray[j]);

    }



    /* Test some error returns */

    err = SHA1Input(&sha,(const unsigned char *) testarray[1], 1);

    printf ("\nError %d. Should be %d.\n", err, shaStateError );

    err = SHA1Reset(0);

    printf ("\nError %d. Should be %d.\n", err, shaNull );

    return 0;

}

 

8. セキュリティに関する考慮事項 English

本書は、インターネットコミュニティに対して、米国 FIPS (Federal Information Processing Standard) Secure Hash Function SHA-1 [FIPS 180-1] のオープンソースを提供することを目的としている。本ハッシュ関数のセキュリティについて、著者らによる独自の主張を行うことを目的としていない。

 

参考文献

[FIPS 180-1] "Secure Hash Standard", United States of American, National Institute of Science and Technology, Federal Information Processing Standard (FIPS) 180-1, 1993年 4月.
 
[MD4] "The MD4 Message Digest Algorithm," Advances in Cryptology - CRYPTO '90 Proceedings, Springer-Verlag, 1991年, pp. 303-311.
 
[RFC 1320] Rivest, R., "The MD4 Message-Digest Algorithm",
RFC 1320, 1992年 4月.
 
[RFC 1321] Rivest, R., 
「MD5 メッセージダイジェストアルゴリズム(The MD5 Message-Digest Algorithm)」,
RFC 1321, 1992年 4月.
 
[RFC 1750] 「セキュリティのための乱雑さについての推奨事項(Eastlake, D., Crocker, S. and J. Schiller, "Randomness Requirements for Security)」,
RFC 1750, 1994年12月.

 

著者のアドレス

Donald E. Eastlake, 3rd
Motorola
155 Beaver Street Milford, MA 01757 USA

電話: +1 508-634-2066 (h) +1 508-261-5434 (w)
Fax: +1 508-261-4777
EMail: Donald.Eastlake@motorola.com

Paul E. Jones
Cisco Systems, Inc.
7025 Kit Creek Road Research Triangle Park, NC 27709 USA

電話: +1 919 392 6948
EMail: paulej@packetizer.com

翻訳者のアドレス

西原 啓輔, Ph.D
(株)日立製作所

EMail: k-west@mba.ocn.ne.jp

宮川 寧夫
情報処理推進機構

Email: miyakawa@ipa.go.jp

 

著作権表記全文

Copyright (C) The Internet Society (2001). All Rights Reserved.

This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Internet Society or other Internet organizations, except as needed for the purpose of developing Internet standards in which case the procedures for copyrights defined in the Internet Standards process must be followed, or as required to translate it into languages other than English.

The limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns.

This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

謝辞

RFCの運営基金は現在、Internet Society によって提供されている。