C# で TOTP のシークレット・キーを生成する方法

TOTP のシークレットキーとは?

TOTP は Time-Based One-Time Password の略です。 RFC6238 で定義されており、主に二段階認証などで用いられるワンタイムパスワードを安全に使うための仕組みです。

TOTP は HOTP を基にして実装されています。HOTP では、サーバー側とクライアント側で共有する「シークレットキー」と「メッセージデータ」(カウンター値) を必要とします。

シークレットキーは認証を行うクライアント毎に固有のものです。

ここでは TOTP の実装として、 Google 認証システム (Google Authenticator) を利用する状況を念頭におき、 Google 認証システムで使えるシークレットキーを生成する方法を紹介します。

Google 認証システムで使うシークレットキーの長さとエンコード

シークレットキーは基本的には単に、任意の長さのランダムなバイト列です。しかし、セキュリティを考慮して RFC4226 では最低でも 16 バイト、20バイト推奨と記載されています。

また Google 認証システムでは Base32 でエンコードすることになっています。

Base32 というのは、エンコードの考え方は Base64 と一緒ですが、エンコードに使う文字はわずか 32 文字だけになります。さまざまなデバイスからの入力が簡単なように、 紛らわしい文字が出現しないように配慮されているのが特徴です。ただし、エンコード結果のサイズはやや長くなります。

Base32 はいずれフレームワークでサポートされるでしょうが、現時点ではサポートされていません。ここでは Base32 については、GitHub で公開されている Base32.cs を利用させていただきます。

Google 認証システムのシークレットキーでは Base32 エンコードで、パディングの = は省略します。

TOTP のシークレットキーを生成する方法

上で説明したように、シークレットは単に「ランダムなバイト列」です。バイト列の長さは「20 バイト」が推奨。

このバイト列を Google 認証システムでの利用を考慮し、Base 32 でエンコードを行います。

これらの要件から、下記の GenerateSecret() 関数のように実装できます。

using System;
using System.Security.Cryptography;

namespace GenerateSecret
{
  class Program
  {
    static void Main(string[] args)
    {
      Console.WriteLine(GenerateSecret());
    }

    public static string GenerateSecret(int length = 20)
    {
      var rng = new RNGCryptoServiceProvider();
      var buf = new byte[length];
      rng.GetBytes(buf);
      return Base32.ToBase32String(buf);
    }
  }
}

このプログラムの実行を行うたびに、全くランダムな文字列が生成されることがわかると思います。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 C# 入門