MD5 ハッシュ処理における符号化の不整合と API 署名の実装ガイド

MD5 アルゴリズムの基礎

MD5(Message-Digest Algorithm 5)は、データの完全性を保証するために用いられるハッシュアルゴリズムの一つです。これは元のメッセージを固定長の値に変換する機能を持ち、情報の改ざん検知や暗号化に応用されます。類似する前身バージョンとして MD2、MD3、MD4 が存在しており、現在も主要なプログラミング言語には標準的なライブラリが備わっています。

API 署名パラメータの構築方法

サービス連携時において、安全な通信のためパラメータの署名を行う必要があります。署名計算前の準備段階では、以下のルールに従ってパラメータを整列させることが一般的です。

  • キーベースのソート: すべての請求パラメータをキー名(パラメータ名)の辞書順で並べ替えます。ただし、署名自体を示す「sign」または同様のフィールドはこの計算対象から除外します。
  • 同等キーの扱い: キー名の先頭文字が一致する場合は、続く文字列に対して継続的にソートを行います。
  • 値の処理: ソート順が決まったら、各キーとその値を直接結合します。値部分は特に URL エンコードなどの加工を施さない場合がほとんどです。
  • 未設定のパラメータ: オプションパラメータでも値が空の場合、そのキー名のみを文字列に含めて対象とします。
  • 配列データ: 複数の値を持つパラメータがある場合、例えば `cartypelist=[1,2]` のようなケースでは、そのまま連結して `cartypelist1,2` の形式で処理します。

このようにして組み立てられた文字列を、最終的なシークレットキー(SecretKey)の後に付加し、全体としてハッシュ計算を行います。基本的な構文は以下の通りです:

md5(キー 1+値 1 + キー 2+値 2 +... + シークレット)

実装上の課題:文字符号化の相違

実際の開発現場では、同じ入力データであっても生成される MD5 ハッシュ値が不一致になる事象が発生することがあります。これは主に、内部で使用されている文字符号化方式の違いによるものです。例えば、UTF-8 とデフォルト符号化(システム依存の ANSI など)を混在させると、非 ASCII コード(漢字など)を含む場合にバイト列の結果が変わり、ハッシュ値が食い違ってしまいます。

C# での実装例比較

以下に、異なる符号化設定を採用した 2 つの C# メソッドを示します。これらは同等の機能を持っていますが、内部処理ロジックと変数名を変更しています。

// 推奨アプローチ:UTF-8 符号化を使用
public static string GenerateSecureDigest(string messageInput)
{
    var provider = System.Security.Cryptography.MD5.Create();
    var encoder = new System.Text.UTF8Encoding();
    
    // 入力をバイト列に変換
    byte[] rawBytes = encoder.GetBytes(messageInput);
    
    // ハッシュ計算実行
    byte[] digest = provider.ComputeHash(rawBytes);
    
    // バイト列を 16 進数文字列に変換(小文字→大文字に変更)
    return BitConverter.ToString(digest)
                  .Replace("-", "")
                  .ToLower()
                  .ToUpper();
}
// 非推奨アプローチ:デフォルト符号化を使用
/// <summary>
/// デフォルトエンコーディングによる 32 桁 MD5 計算
/// </summary>
public static string GetLegacyHash(string inputData)
{
    System.Security.Cryptography.MD5 hasher = System.Security.Cryptography.MD5.Create();
    
    // デフォルトエンコーディングでバイト取得(環境依存あり)
    byte[] encodedBytes = System.Text.Encoding.Default.GetBytes(inputData);
    
    byte[] result = hasher.ComputeHash(encodedBytes);
    var outputBuilder = new System.Text.StringBuilder();
    
    foreach (byte b in result)
    {
        outputBuilder.Append(b.ToString("X2"));
    }
    
    return outputBuilder.ToString();
}

解決策

上記のように、UTF-8 以外を採用すると日本語テキストが含まれる場合にバグの原因となります。相互運用性を確保するためには、すべてのシステム間で文字符号化方式を統一する必要があります。具体的には、すべてのテキストデータを事前に Unicode または UTF-8 形式に変換するか、サーバー側で受け取る際に指定されたエンコーディングに一貫性を持たせる対応が求められます。

タグ: MD5 C-Sharp api-authentication Unicode Cryptography

8月1日 08:36 投稿