ネットワーク 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. 1. 概要
  2. 2. bit文字列と整数の定義
  3. 3. 各ワードに対する演算
  4. 4. メッセージへのパディング
  5. 5. 使用関数と使用定数
  6. 6. メッセージダイジェストの計算
    1. 6.1 方法1
    2. 6.2 方法2
  7. 7. C言語コード
    1. 7.1 .hファイル
    2. 7.2 .cファイル
    3. 7.3 テストドライバ
  8. 8. セキュリティに関する考慮事項
  9. 参考文献
  10. 著者のアドレス
  11. 著作権表記全文

1. 概要 English

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

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

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

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

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

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

a. 16進数とは、{0, 1, ... , 9, A, ... , F}で構成されている集合の中の1つの要素である。 16進数は4bit文字列を表記したものである。 例: 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. ブロックとは、512bitの文字列である。 ひとつのブロック(例: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とする。 この64bit整数というのは、オリジナルメッセージの長さである。 パディングの行われたメッセージは、 その後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数は41bitであり、 407個の"0"が付加されて448bitとされる。 したがって、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つ分で構成されている。 さらに32bitワード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)の処理を以下のように行う。

  1. M(i)を、16個のワードW(0), W(1), ... , W(15)に分割する。 ここでW(0)は最上位ワードである。
  2. 16から79までのtに対して、以下の計算を行う。
     W(t) = S^1(W(t-3) XOR W(t-8) XOR W(t-14) XOR W(t-16))
  3. A, B, C, D, E をそれぞれ、A = H0, B = H1, C = H2, D = H3, E = H4とする。
  4. 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;
  5. 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)の計算は以下のようになる。

  1. M(i)を、16個のワードW[0], ... , W[15]に分割する。 ここでW[0]は最上位ワードである。
  2. A, B, C, D, Eをそれぞれ、 A = H0, B = H1, C = H2, D = H3, E = H4とする。
  3. 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;
  4. 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 <stdint.h>
/*
 * 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 <stdint.h> (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 <stdint.h>
#include <stdio.h>
#include <string.h>
#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 によって提供されている。