sha 256 と sha 512 について回答させてください。要するに、アルゴリズム自体はエンディアンに依存しません。エンディアンに依存する部分は、データがバイト バッファーからアルゴリズムの作業変数にインポートされるときと、ダイジェスト結果 (バイト バッファーも) にエクスポートされるときです。インポート/エクスポートにキャストが含まれる場合、エンディアンが重要になります。
キャストが発生する可能性がある場所: sha 512 には、128 バイトの作業バッファーがあります。私のコードでは、次のように定義されています。
union
{
U64 w [80]; (see U64 example below)
byte buffer [128];
};
入力データはこのバイト バッファにコピーされ、W で処理が行われます。これは、データが 64 ビット タイプにキャストされたことを意味します。このデータは交換する必要があります。私の場合、リトルエンディアンのマシンに交換されています。
より良い方法は、各バイトを受け取り、それを u64 型の正しい場所に配置する get マクロを準備することです。
アルゴリズムが完了すると、ダイジェストの結果が作業変数からバイト バッファーに出力されます。これが memcpy によって行われる場合は、スワップも必要になります。
sha 512 (64 ビット マシン用に設計されている) を 32 ビット マシンに実装すると、別のキャストが発生する可能性があります。私の場合、定義されている 64 ビット型があります。
typedef struct {
uint high;
uint low;
} U64;
次のように、リトルエンディアンに対しても定義するとします。
typedef struct {
uint low;
uint high;
} U64;
そして、k アルゴリズムの初期化は次のように行われます。
static const SHA_U64 k[80] =
{
{0xD728AE22, 0x428A2F98}, {0x23EF65CD, 0x71374491}, ...
...
...
}
しかし、どのマシンでも k[0].high の論理値が同じである必要があります。したがって、この例では、高い値と低い値が入れ替わった別の k 配列が必要になります。
データが作業パラメーターに格納された後は、ビッグ エンディアンとリトル エンディアンの両方のマシンでビット単位の操作を行っても同じ結果になります。
適切な方法は、キャストを避けることです。マクロを使用して、入力バッファーから作業パラメーターにバイトをインポートします。メモリ マッピングを考えずに論理値を操作します。出力をマクロでダイジェスト結果にエクスポートします。
バイト バッファから int32 に 32 ビットを取得するためのマクロ (BE = ビッグ エンディアン):
#define GET_BE_BYTES_FROM32(a)
((((NQ_UINT32) (a)[0]) << 24) |
(((NQ_UINT32) (a)[1]) << 16) |
(((NQ_UINT32) (a)[2]) << 8) |
((NQ_UINT32) (a)[3]))
#define GET_LE_BYTES_FROM32(a)
((((NQ_UINT32) (a)[3]) << 24) |
(((NQ_UINT32) (a)[2]) << 16) |
(((NQ_UINT32) (a)[1]) << 8) |
((NQ_UINT32) (a)[0]))