NTLM 認証プロトコルとセキュリティサポートプロバイダ

概要

このドキュメントは、NTLM認証プロトコルと関連するセキュリティサポートプロバイダの機能について、実装を行なう際のリファレンスとなるように、上級者向けの詳細を記載したものである。 このドキュメントが NTLM に関する網羅的な記載となっていくことを期待しているが、現在のところ筆者の知識不足と記載不足による抜け洩れがあり、いくつかの誤りも含んだものとなっている。 とはいえ、このドキュメントはさらなる調査を進める上での確実な第一歩を提供していると信じている。 ここに記載している情報は、http://jcifs.samba.org で提供しているオープンソースの jCIFS ライブラリにおける NTLM 認証の実装に用いられている。 このドキュメントは筆者による調査と、Samba における実装の解析に基づいて執筆されている。

目次


NTLMとは

NTLM は、さまざまなマイクロソフト社のネットワークプロトコルの実装に用いられており、NTLM セキュリティサポートプロバイダ (NTLMSSP) においてサポートされている、認証とセッションセキュリティのプロトコル群である。 NTLM は、本来セキュアな DCE/RPC の認証とネゴシエーションのためのものだったが、統合されたシングルサインオン機構として、マイクロソフト社システムの至るところで用いられている。NTLM は、HTTP 認証における「統合Windows認証」の一部として認識されていることが多いと思うが、その他にも、マイクロソフト社の SMTP、POP3、IMAP(これらは 3 つは Exchange Server に実装されている)、CIFS/SMB、Telnet、SIP、その他多くの実装でも用いられている。

NTLM セキュリティサービスプロバイダは認証、整合性、機密性を提供するサービスであり、Windows セキュリティサポートプロバイダインタフェース(SSPI)のフレームワーク中に存在している。 SSPI はプロバイダによって実装されるセキュリティ機能の基本要件を定義したものであり、NTLMSSP もこうしたプロバイダの一つとなっている。SSPI は、以下のような基本要件を定義しており、これらは NTLMSSP も実装している。

  1. 認証 -- NTLM はチャレンジアンドレスポンス認証機構を提供する。これにより、クライアントはサーバにパスワードを送出することなく、自身の身元を証明することができる。
  2. 署名 -- NTLMSSP はメッセージにデジタル署名を行なう方法を提供する。これにより、署名されたメッセージが(明示的にも暗黙のうちにも)改変されていないことを保証するとともに、署名者が共有シークレットの情報を持っていることを保証する。 NTLM は対称型の署名スキーム(Message Authentication Code/MAC)を実装しており、適切な署名は共通の共有鍵を持っている者によってのみ生成可能であり、かつ検証可能である。
  3. 暗号化 -- NTLMSSP は対称鍵暗号機構を実装しており、これによってメッセージが暗号化される。NTLM の場合、暗号化を行なう際には署名も行なわれる(署名のみで暗号化を行なわないことは可能であるが、暗号化されたメッセージは署名も行なわれている)。

ドメイン環境における認証プロトコルとしての NTLM は、多くの場合 Kerberos に取って代わられているが、Kerberos は信頼できる第三者(trusted-third-party)の存在を前提としているため、これが存在しないメンバサーバ(ドメインに参加していないサーバ)やローカルアカウント、信頼されていないドメイン上のリソースの認証に用いることができない。こうした環境においては、NTLM が主要な認証機構としての座を保ち続けている(その地位はもうしばらく続きそうである)。

NTLM の用語

詳細についての記載を行なう前に、さまざまなプロトコルで用いられているいくつかの用語について定義しておく必要がある。

NTLM 認証は、チャンンジレスポンス機構であり、通常 Type 1(ネゴシエーション)、Type 2 (チャレンジ)、Type 3(認証)と呼ばれる 3 つのメッセージからなっている。これらは基本的に以下のように動作する。

  1. クライアントは Type 1 メッセージをサーバに送信する。これには主としてクライアントによってサポートされており、サーバにサポートを要求する機能の一覧が含まれている。
  2. サーバは Type 2 メッセージで応答する。これにはサーバがサポートしており使用を合意した機能の一覧が含まれている。 重要な点として、このメッセージにはサーバ側で生成したチャレンジが含まれている。
  3. クライアントは Type 3 メッセージにより、チャレンジに対する応答を行なう。これには、クライアントユーザのドメインやユーザ名といった、クライアントに関する幾つかの情報が含まれている他、Type 2 チャレンジに対する 1 つ以上のレスポンスも含まれている。

Type 3 メッセージにおけるレスポンスは、サーバに対してクライアントのユーザは自身のアカウントのパスワードを把握しているという情報を提示するという点で非常に重要である。

認証のプロセスは両者の間で共有コンテキストを確立することから始まる。これには引続き行なわれる署名と暗号化処理に用いられる共有セッション鍵が含まれる。

(可能な限り)混乱を避けるため、このドキュメントでは、以下のような使いわけを行なう。

これにより、明確な使いわけが実現するが、「NTLM2 セッションレスポンス」認証(NTLMv1 認証のバリエーション)のような厄介なケースも例外的に存在することはある。ここでの定義が、こうした際の理解の助けになることを期待する。

本ドキュメントでは、「short値」をリトルエンディアンで16ビットの符合なし整数を意味するものとして扱う。 例えば、10進数の「1234」をshortとすると、16進数表記では「0xd204」として格納されている。

long値」とは、リトルエンディアンで32ビットの符合なし整数を意味する。10進数の「1234」をlong値だとすると、16進数表記では「0xd2040000」となる。

Unicode 文字列とは、各文字が16ビットのリトルエンディアンの値(16-bit UCS-2 Transformation Format, little-endian byte order, with no Byte Order Mark and no null-terminator)として格納された文字列を意味する。「hello」という文字列をUnicode表記したものを16進数で表すと、「0x680065006c006c006f00」となる。

OEM 文字列とは、各文字が8ビットのローカルマシンの各国の文字セット(DOS コードページ)として格納された文字列を意味する。NULL終端は存在しない。NTLMメッセージにおいて、OEM 文字列は通常大文字で表記される。「HELLO」という文字列をOEM表記したものを16進数で表すと、「0x48454c4c4f」となる。

「セキュリティバッファ」とはバイナリデータへのバッファを示すために用いられる構造体を意味する。これには、以下のメンバが含まれる。

  1. short値、バイト単位のバッファ長が格納される。
  2. short値、バイト単位でこのバッファに割り当てられている領域長が格納される(通常はバッファ長と同じである)。
  3. long値、バイト単位で、バッファの(NTLMメッセージ開始地点からの)オフセットが格納される。

例えば、「0xd204d204e1100000」というセキュリティバッファは、以下のように解析できる。

バッファ長: 0xd204 (1234 バイト)
割り当てられている領域: 0xd204 (1234 バイト)
オフセット: 0xe1100000 (4321 バイト目)

メッセージの最初のバイトからみると、4321バイトスキップした地点が、データバッファの先頭位置になる。ここから 1234 バイト(バッファ長)のデータを読みとれる。バッファに割り当てられた領域も 1234 バイトであるため、そこがバッファの終端になる。

NTLM メッセージヘッダのレイアウト

ようやく NTLM 認証メッセージの実形式について記載するところまでたどり着いた。

すべてのメッセージは、NULL 終端なしの「NTLMSSP」というASCII文字列(16進数では「0x4e544c4d53535000」)からなる NTLMSSP 署名(signature)が先頭にくる。

ついで、メッセージの Type (1、2、3)を示すlong値が続く。Type 1 メッセージの場合、これは16進数で「0x01000000」となる。

さらににメッセージ固有の情報が続く。これは通常セキュリティバッファとメッセージフラグから構成されている。

NTLM フラグ

メッセージフラグは、ヘッダ内のビットフィールドに格納されている。これは各ビットが特定のフラグを表すlong値である。これらのほとんどは後ほど説明するが、ここでは話を進めやすくするために、概要を説明する。以下の表で「未確認」もしくは「不明」と記載されたフラグは筆者が理解していないものである(もちろん筆者の理解は決して絶対的なものではない)。

フラグ名称詳細
0x00000001Negotiate Unicode セキュリティバッファのデータで、Unicode 文字列がサポートされていることを示す。
0x00000002Negotiate OEM セキュリティバッファのデータで、OEM 文字列がサポートされていることを示す。
0x00000004Request Target サーバの authentication realm が Type 2 メッセージに含まれることを要求する。
0x00000008不明 このフラグの用途は確認されていない。
0x00000010Negotiate Sign クライアントとサーバ間の認証に際して、デジタル署名(メッセージの整合性確保)の実施を指定する。
0x00000020Negotiate Seal クライアントとサーバ間の認証に際して、暗号化(メッセージの機密性確保)の実施を指定する。
0x00000040Negotiate Datagram Style datagram authentication の使用を指定する。
0x00000080Negotiate Lan Manager Key 認証に際して、Lan Manager Session Key の使用を指定する。
0x00000100Negotiate Netware このフラグの用途は確認されていない。
0x00000200Negotiate NTLM NTLM 認証の使用を指定する。
0x00000400不明 このフラグの用途は確認されていない。
0x00000800Negotiate Anonymous クライアントが送出する Type 3 メッセージで指定され、匿名コンテキストによる認証が確立されたことを示す。これはレスポンスフィールドの内容にも影響する(詳細は「匿名レスポンス(Anonymous Response)」セクションで記載している)。
0x00001000Negotiate Domain Supplied クライアントが送出する Type 1 メッセージで指定され、クライアントのワークステーションが所属するドメイン名の情報がメッセージに含まれていることを示す。 これは、サーバがクライアントをローカル認証すべきかどうかを決定する際に用いられる。
0x00002000Negotiate Workstation Supplied クライアントが送出する Type 1 メッセージで指定され、クライアントのワークステーション名がメッセージに含まれていることを示す。 これは、サーバがクライアントをローカル認証すべきかどうかを決定する際に用いられる。
0x00004000Negotiate Local Call サーバによって送出され、クライアントとサーバが同一マシンであることを示す。 これにより、クライアントはチャレンジに対するレスポンスを計算する代わりに、確立済のローカルな資格情報を使用することが可能となる。
0x00008000Negotiate Always Sign クライアントとサーバ間の認証に際して、「dummy」署名による署名を示す。
0x00010000Target Type Domain サーバが送出する Type 2 メッセージで指定され、対象の authentication realm がドメインであることを示す。
0x00020000Target Type Server サーバが送出する Type 2 メッセージで指定され、対象の authentication realm がサーバ(server)であることを示す。
0x00040000Target Type Share サーバが送出する Type 2 メッセージで指定され、対象の authentication realm が共有(share)であることを示す。おそらく、これは共有レベルのセキュリティを意味していると思われるが、用途は明確になっていない。
0x00080000Negotiate NTLM2 Key NTLM2 署名と暗号化のスキームを認証の際の保護に用いることを示す。 これは、セッションセキュリティのスキームに対するものであり、NTLMv2 認証の使用とは関係しない点に注意。 ただし、このフラグは、レスポンスの計算に影響を与える(詳細は「NTLM2 セッションレスポンス(NTLM2 Session Response)」セクションで記載している)。
0x00100000Request Init Response このフラグの用途は確認されていない。
0x00200000Request Accept Response このフラグの用途は確認されていない。
0x00400000Request Non-NT Session Key このフラグの用途は確認されていない。
0x00800000Negotiate Target Info サーバが送出する Type 2 メッセージで指定され、メッセージに Target Information ブロックが含まれることを示す。Target Information ブロックは NTLMv2 レスポンスの計算に用いられる。
0x01000000不明 このフラグの用途は確認されていない。
0x02000000不明 このフラグの用途は確認されていない。
0x04000000不明 このフラグの用途は確認されていない。
0x08000000不明 このフラグの用途は確認されていない。
0x10000000不明 このフラグの用途は確認されていない。
0x20000000Negotiate 128 128 ビットの暗号化がサポートされていることを示す。
0x40000000Negotiate Key Exchange クライアントが Type 3 メッセージの「Session Key」フィールドで暗号化されたマスター鍵を提供することを示す。
0x80000000Negotiate 56 56 ビットの暗号化がサポートされていることを示す。

一例として、以下を指定したメッセージの場合、

Negotiate Unicode (0x00000001)
Request Target (0x00000004)
Negotiate NTLM (0x00000200)
Negotiate Always Sign (0x00008000)

上記を合計した値は「0x00008205」となる。これは実際には「0x05820000」という形態で格納される(リトルエンディアンのバイト順で表現されるため)。

Type 1 メッセージ

以下、Type 1 メッセージについて見ていこう。

Description Content
0NTLMSSP 署名 NULL 終端された ASCII 文字列「NTLMSSP」 (0x4e544c4d53535000)
8NTLM メッセージのタイプ long (0x01000000)
12フラグlong
(16)Supplied Domain (オプション)セキュリティバッファ
(24)Supplied Workstation (オプション) セキュリティバッファ
(32)データブロックの先頭 (必要な場合)

Type 1 メッセージは、NTLM 認証を開始するにあたってクライアントからサーバに送信される。主要な目的は、フラグによって提示されるサポート可能なオプションを示すことにより、認証を行なう際の「ローカルルール」を確立することにある。 オプションとして、クライアントのワークステーション名と所属するドメイン名をサーバに提示することもできる。この情報は、クライアントのローカル認証が可能かどうかをサーバが確認する際に用いられる。

通常、Type 1 メッセージには、以下のフラグが設定されている。

Negotiate Unicode (0x00000001) Unicode 文字列のサポートを示すため、このフラグを設定する。
Negotiate OEM (0x00000002) OEM 文字列のサポートを示すため、このフラグを設定する。
Request Target (0x00000004) サーバに対して、Type 2 の応答の際に authentication target の送信を要求する。
Negotiate NTLM (0x00000200) NTLM 認証がサポートされていることを示す。
Negotiate Domain Supplied (0x00001000) 設定されている場合、クライアントはワークステーションが所属するドメイン名をメッセージの一部として送信する。
Negotiate Workstation Supplied (0x00002000) クライアントが自身のワークステーション名をメッセージの一部として送信することを示す。
Negotiate Always Sign (0x00008000) 認証後のクライアントとサーバ間の通信が「dummy」署名で行なわれることを示す。
Negotiate NTLM2 Key (0x00080000) クライアントが NTLM2 の認証と暗号化スキームをサポートすることが示される。 ネゴシエーションに成功した場合は、レスポンスの計算にも影響する。
Negotiate 128 (0x20000000) クライアントが強力な(128ビット)暗号をサポートしていることを示す。
Negotiate 56 (0x80000000) クライアントが中程度の(128ビット)暗号をサポートしていることを示す。

supplied domain はクライアントが所属するドメイン名を格納するセキュリティバッファである。これは、クライアントが Unicode をサポートしていても、常に OEM 形式で格納される。

supplied workstation はクライアントのワークステーション名を格納するセキュリティバッファである。これも、常に OEM 形式で格納される。

supplied domain と workstation はオプションのフィールドであることに注意。これらは空である(長さ 0 のセキュリティバッファである)ことや、全く送信されない(セキュリティバッファ自体が存在していない)ことがある。supplied domain や workstation が存在しない場合、Type 1 メッセージにはデータブロックが存在しない(メッセージはフラグフィールドで終了し、16バイト固定長となる)。 「最短の」Type 1 メッセージは以下のようになる。

    4e544c4d535350000100000002020000

このメッセージには、NTLMSSP 署名 、NTLM メッセージのタイプと最低限のフラグ(Negotiate NTLM と Negotiate OEM)だけが含まれている。

Type 1 メッセージのサンプル

16進数で表記した、以下の Type 1 メッセージを解析してみよう。

    4e544c4d535350000100000007320000060006002b0000000b000b0020000000
    574f524b53544154494f4e444f4d41494e

このメッセージは、以下のように解読できる。

0 0x4e544c4d53535000NTLMSSP 署名
8 0x01000000Type 1 を示す識別子
12 0x07320000 Flags:

Negotiate Unicode (0x00000001)
Negotiate OEM (0x00000002)
Request Target (0x00000004)
Negotiate NTLM (0x00000200)
Negotiate Domain Supplied (0x00001000)
Negotiate Workstation Supplied (0x00002000)

16 0x060006002b000000 Supplied Domain セキュリティバッファ:

長さ: 6 bytes (0x0600)
割当済領域: 6 bytes (0x0600)
オフセット: 43 bytes (0x2b000000)

24 0x0b000b0020000000 Supplied Workstation セキュリティバッファ:

長さ: 11 bytes (0x0b00)
割当済領域: 11 bytes (0x0b00)
オフセット: 32 bytes (0x20000000)

32 0x574f524b53544154494f4e Supplied Workstation のデータ ("WORKSTATION")
43 0x444f4d41494e Supplied Domain のデータ ("DOMAIN")

このメッセージから以下の情報を読みとることができる。

supplied workstation および supplied domain は OEM 形式で格納されていることに注意。また、前述した例では、supplied workstation のデータが supplied domain の前に格納されているが、セキュリティバッファのデータの格納順序は重要ではない。

クライアントが Type 1 を作成して、それをサーバに送信すると、サーバは我々が行なったのと同様にメッセージを解析して、応答を作成する。この応答が次のトピックである Type 2 メッセージである。

Type 2 メッセージ

Description Content
0NTLMSSP 署名 NULL 終端された ASCII 文字列「NTLMSSP」 (0x4e544c4d53535000)
8NTLM メッセージのタイプ long (0x02000000)
12Target Nameセキュリティバッファ
20Flagslong
24Challenge8 バイト
(32)Context (オプション) 8 bytes (2つのlong値)
(40)Target Information (オプション) セキュリティバッファ
32 (48) データブロックの先頭

Type 2 メッセージはクライアントの Type 1 メッセージに対する応答の形でサーバから送出される。 このメッセージでは、クライアントとのネゴシエーションのオプションが 提示される他、クライアントに対するチャレンジも提供される。 このメッセージには、 authentication target に関する情報が含まれることもある。

Type 2 メッセージでは、通常以下のフラグが設定される。

Negotiate Unicode (0x00000001) Unicode 文字列の使用を示すため、このフラグを設定する。 クライアントが (Type 1 メッセージで) Unicode のサポートを示した場合のみ、このフラグの設定を行なうこと このフラグか Negotiate OEM フラグのいずれかを設定する必要があるが、両方を設定してはならない。
Negotiate OEM (0x00000002) OEM 文字列の使用を示すため、このフラグを設定する。 クライアントが (Type 1 メッセージで) OEM 文字列のサポートを示した場合のみ、このフラグの設定を行なうこと このフラグか Negotiate Unicode フラグのいずれかを設定する必要があるが、両方を設定してはならない。
Request Target (0x00000004) このフラグは Type 2 メッセージで設定されることも多い。Type 1 メッセージでのフラグの目的は明示されているが、Type 2 メッセージでの目的は不明なままである。
Negotiate NTLM (0x00000200) NTLM 認証がサポートされていることを示す。
Negotiate Local Call (0x00004000) サーバとクライアントが同一マシン上に存在していることをクライアントに提示する。 サーバは、メッセージの一部としてローカルセキュリティコンテキストハンドルを提供する。
Negotiate Always Sign (0x00008000) 認証後のクライアントとサーバ間の通信が「dummy」署名で行なわれることを示す。
Target Type Domain (0x00010000) このフラグにより、メッセージ内で送信される authentication target がドメインを表すことを示す。
Target Type Server (0x00020000) このフラグにより、メッセージ内で送信される authentication target がサーバを表すことを示す。
Target Type Share (0x00040000) このフラグにより、メッセージ内で送信される authentication target がネットワーク共有を示すことが明示される。このフラグの用途は確認されていない。
Negotiate NTLM2 Key (0x00080000) サーバが NTLM2 の認証と暗号化スキームをサポートすることが示される。 ネゴシエーションに成功した場合は、クライアントからのレスポンスの計算にも影響する。
Negotiate Target Info (0x00800000) このフラグにより、Target Information ブロックがメッセージ内で送信されることを示す。
Negotiate 128 (0x20000000) クライアントが強力な(128ビット)暗号をサポートしていることを示す。
Negotiate 56 (0x80000000) クライアントが中程度の(128ビット)暗号をサポートしていることを示す。

target name は authentication target の名称が格納されたセキュリティバッファである。これは (Type 1 メッセージ中の Request Target フラグにより) target を要求したクライアントに対する応答として送信されることが多い。 これには、ドメイン名、サーバ名、もしくは(おそらく)ネットワーク共有名が含まれる。 target type は、Target Type Domain 、Target Type Server 、 Target Type Share フラグで示される。 target name は Type 2 メッセージ中のフラグの設定次第で、Unicode と OEM 文字列のいずれも可能である。

challenge は 8 バイトのランダムなデータである。クライアントはこの情報を用いてレスポンスを生成する。

context フィールドは、通常 Negotiate Local Call が設定された場合に存在する。 これには SSPI コンテキストハンドルが格納される。これにより、クライアントはチャレンジに対する応答を行なう代わりに「short-circuit」な認証を行なうことが可能となる。 context は 2 つの long値からなる。詳細は「ローカル認証」セクションで後述する。

target の情報は、Target Information ブロック中のセキュリティバッファに含まれる。これはNTLMv2 レスポンス (後述する)の計算に用いられる。このブロックは、サブブロックの配列から構成されている。各サブブロックは、以下の内容で構成されている。

フィールドContentDescription
Typeshort このサブブロックのデータのタイプを指定する。
1 (0x0100):サーバ名
2 (0x0200):ドメイン名
3 (0x0300): 完全修飾された DNS ホスト名 (server.domain.com形式)
4 (0x0400): DNS ドメイン名 (i.e., domain.com形式)
長さshort このサブブロックの content フィールドの長さ(バイト単位)
ContentUnicode 文字列 type フィールドで指定された情報。メッセージフラグで OEM が指定されていても、常に Unicode 文字列として送信される。

配列は、終端(terminator)サブブロックで終了する。このサブブロックは type が「0」で、長さ 0 である。type が「5」のサブブロックも存在する。これにはサーバが所属するドメインの「親」DNS ドメイン名が含まれているようである。その他にも未知のサブブロック type が存在するかも知れない。

context および target information は省略される場合がある。その場合、データブロックはオフセット 32 (チャレンジの直後)から開始される。最小の Type 2 メッセージは以下のようなバイト列となる。

    4e544c4d53535000020000000000000000000000020200000123456789abcdef

このメッセージには、NTLMSSP 署名 、NTLM メッセージタイプ、空の target namae 、最低限のフラグ(Negotiate NTLM と Negotiate OEM)、チャレンジが含まれている。

Type 2 メッセージのサンプル

16進数で表記した、以下の Type 2 メッセージを解析してみよう。

    4e544c4d53535000020000000c000c003000000001028100
    0123456789abcdef0000000000000000620062003c000000
    44004f004d00410049004e0002000c0044004f004d004100
    49004e0001000c0053004500520056004500520004001400
    64006f006d00610069006e002e0063006f006d0003002200
    7300650072007600650072002e0064006f006d0061006900
    6e002e0063006f006d0000000000

このメッセージは以下のフィールドに分割される。

0 0x4e544c4d53535000NTLMSSP 署名
8 0x02000000Type 2 を示す識別子
12 0x0c000c0030000000 Target Name セキュリティバッファ:

長さ: 12 バイト (0x0c00)
割当済領域: 12 バイト (0x0c00)
オフセット: 48 バイト (0x30000000)

20 0x01028100 フラグ:

Negotiate Unicode (0x00000001)
Negotiate NTLM (0x00000200)
Target Type Domain (0x00010000)
Negotiate Target Info (0x00800000)

24 0x0123456789abcdefchallenge
32 0x0000000000000000context
40 0x620062003c000000 Target Information セキュリティバッファ:

長さ: 98 バイト (0x6200)
割当済領域: 98 バイト (0x6200)
オフセット: 60 バイト (0x3c000000)

48
0x44004f004d004100
  49004e00
Target Name のデータ (「DOMAIN」)
60
0x02000c0044004f00
  4d00410049004e00
  01000c0053004500
  5200560045005200
  0400140064006f00
  6d00610069006e00
  2e0063006f006d00
  0300220073006500
  7200760065007200
  2e0064006f006d00
  610069006e002e00
  63006f006d000000
  0000
Target Information のデータ:

0x02000c0044004f00
  4d00410049004e00
ドメイン名サブブロック:

Type: 2 (ドメイン名, 0x0200)
長さ: 12 bytes (0x0c00)
データ: 「DOMAIN

0x01000c0053004500
  5200560045005200
サーバ名サブブロック:

Type: 1 (サーバ名, 0x0100)
長さ: 12 バイト (0x0c00)
データ: 「SERVER

0x0400140064006f00
  6d00610069006e00
  2e0063006f006d00
DNS ドメイン名サブブロック:

Type: 4 (DNS ドメイン名, 0x0400)
長さ: 20 バイト (0x1400)
データ: 「domain.com

0x0300220073006500
  7200760065007200
  2e0064006f006d00
  610069006e002e00
  63006f006d00
DNS ホスト名サブブロック:

Type: 3 (DNS server name, 0x0300)
長さ: 34 バイト (0x2200)
データ: 「server.domain.com

0x00000000 終端サブブロック:

Type: 0 (終端, 0x0000)
長さ: 0 bytes (0x0000)

このメッセージから以下の情報を読みとることができる。

target name は(Negotiate Unicode フラグで指定されたように)、Unicode 形式である点に注意。

サーバが Type 2 メッセージを作成して、クライアントに送信する。サーバのチャレンジに対するレスポンスは、クライアントが送出する Type 3 メッセージで提示される。

Type 3 メッセージ

Description Content
0NTLMSSP 署名 NULL 終端された ASCII 文字列「NTLMSSP」 (0x4e544c4d53535000)
8NTLM メッセージのタイプ long (0x03000000)
12LM/LMv2 レスポンス セキュリティバッファ
20NTLM/NTLMv2 レスポンス セキュリティバッファ
28ドメイン名 セキュリティバッファ
36ユーザ名 セキュリティバッファ
44ワークステーション名 セキュリティバッファ
(52)セッション鍵(オプション) セキュリティバッファ
(60)フラグ (オプション) long
52 (64) データブロックの先頭

Type 3 メッセージは認証の最終段階である。このメッセージには、Type 2 チャレンジに対するクライアントのレスポンスが含まれている。これにより、クライアントはパスワードを直接送付することなしに、パスワード情報を把握していることを提示できる。 Type 3 メッセージは認証するアカウントのクライアントのワークステーション名と併せて、ドメイン名とユーザ名の情報も提示する。

Type 3 メッセージにおいて、フラグはオプションであることに注意。以前のクライアントでは、メッセージ中にセッション鍵もフラグも含まれない。この場合、データブロックはワークステーション名セキュリティバッファ直後のオフセット 52 から開始される。Type 3 メッセージにフラグが存在していた場合でも、コネクションの認証に関しての情報は格納しないこと、認証にもセッションセキュリティの確立にも何ら影響を及ぼさないことが試験的に(experimentally)決定されている。クライアントがフラグを送信する場合は、通常 Type 2 メッセージで確立された設定のコピーである。このフラグを、サーバがネゴシエーションされた設定をキャッシュしてしまわないように、確立されたオプションの「リマインダ」として用いることが可能である。Type 3 のフラグについては、データグラム形式の認証 と関連している。

LM/LMv2 および NTLM/NTLMv2 レスポンスは Type 2 メッセージのチャレンジに対する応答としてユーザのパスワードから生成されたレスポンスを含むセキュリティバッファである。これらのレスポンスを生成する処理については、次のセクションで概説する。

ドメイン名は、認証されるアカウントが所属する authentication realm を含むセキュリティバッファである。これはネゴシエートされたエンコーディングにより、Unicode もしくは OEM 文字列として格納される。

ユーザ名は、認証されるアカウント名を含むセキュリティバッファである。これもネゴシエートされたエンコーディングにより、Unicode もしくは OEM 文字列として格納される。

ワークステーション名はクライアントのワークステーション名を含むセキュリティバッファである。これもネゴシエートされたエンコーディングにより、Unicode もしくは OEM 文字列として格納される。

セッション鍵の値は、鍵交換の際にセッションセキュリティ機構によって用いられる。詳細については、Session Security セクションにて記載している。

Type 2 メッセージで「Negotiate Local Call」が確立されていた場合、Type 3 メッセージのセキュリティバッファは通常すべて空(0 バイト長)である。クライアントは、レスポンスを計算する代わりに Type 2 メッセージで送付された SSPI context を「採用」する。

チャレンジに対するレスポンス

クライアントは Type 2 メッセージのチャレンジに対して、以下のいずれか 1 つ以上のレスポンスを生成して、Type 3 メッセージで送信する。レスポンスには以下の 6 種類がある。

これらに関する詳細情報を把握した場合は、Christopher Hertel の Implementing CIFS、特に the section on authentication を一読することを強く推奨する。

LM レスポンス

LM レスポンスはほとんどのクライアントから送出される。これは NTLM レスポンスより古いものであり、セキュリティ的にも劣る。新しいクライアントはセキュリティ的により強固な NTLM レスポンスをサポートしているが、通常は古いサーバとの相互接続性維持のため、両方のレスポンスを送出する。そのため、LM レスポンスにはセキュリティ上の欠陥が指摘されているにも関わらず、NTLM レスポンスをサポートするクライアントの多くがいまだに LM レスポンスも送出している。

LM レスポンスの計算方法を以下に記載する (Java における実装については 付録 D を参照のこと)。

  1. ユーザのパスワード(OEM 文字列)を大文字に変換する。
  2. このパスワードが 14 バイトになるように NULL パディングするか切り詰める。
  3. この「確定」パスワードを 2 つの 7 バイトのバイト列に分割する。
  4. このバイト列は DES 鍵として用いられる (7 バイト長のバイト列各々について)。
  5. 各々の鍵を用いて、「KGS!@#$%」という固定の ASCII 文字列を DES 暗号化する。(これにより 2 つの暗号文が生成される。)
  6. 生成された 2 つの暗号文を繋げて、16 バイトのバイト列を生成する。これが LM ハッシュである。
  7. 16 バイトの LM ハッシュを NULL パディングして 21 バイトにする。
  8. この値を 3 つの 7 バイトのバイト列に分割する。
  9. このバイト列は 3 つの DES 鍵として用いられる (7 バイトのバイト列各々について)。
  10. 3 つの鍵の各々が、Type 2 メッセージのチャレンジを DES 暗号化するために用いられる (これにより 3 つの 8 バイトの暗号文が生成される)。
  11. これら 3 つの暗号文を結合して 24 バイトの文字列を生成する。これが LM レスポンスとなる。

この処理を詳細に記載したのが以下の例である。ユーザが「SecREt01」というパスワードを用いており、Type 2 チャレンジ「0x0123456789abcdef」に応答しようとしていると仮定する。

  1. パスワード(OEM 文字列である)が大文字に変換され、「SECRET01」となる (16進数では「0x5345435245543031」となる)。
  2. パスワードは 14 バイト長となるように NULL パディングされ、「0x5345435245543031000000000000」となる。
  3. この値が、2 つの 7 バイトのバイト列、「0x53454352455430」と「0x31000000000000」に分割される。
  4. これら 2 つのバイト列から 2 つの DES 鍵が生成される。DES 鍵は 8 バイト長であり、各バイトのうち 7 ビット文が鍵そのものであり、1 ビットが奇数パリティビットである (パリティビットが実際に使用されるかどうかは、DES の実装に依存する)。今回のサンプルの先頭 7 バイトである「0x53454352455430」は、ビット列で以下のように表現される。

    01010011 01000101 01000011 01010010 01000101 01010100 00110000

    これを DES 鍵として使えるようにパリティビットの値を考慮せず、単にビットを挿入すると、以下になる。

    01010010 10100010 01010000 01101010 00100100 00101010 01010000 01100000

    (パリティビットは赤文字で表示している. これを 16 進数表記すると「0x52a2506a242a5060」となる。このバイト列に対して奇数パリティの条件を満たすように各オクテット毎にビットを設定したものが以下となる。

    01010010 10100010 01010001 01101011 00100101 00101010 01010001 01100001

    これが 1 つめの DES 鍵となる (16 進数で「0x52a2516b252a5161」)。引続き、同様の処理を 2 つ目のバイト列である「0x31000000000000」に対して行なう。このバイト列をビット列で表すと以下となる。

    00110001 00000000 00000000 00000000 00000000 00000000 00000000

    これを DES 鍵として使えるようにパリティビットの値を考慮せず、単にビットを挿入すると、以下となる

    00110000 10000000 00000000 00000000 00000000 00000000 00000000 00000000

    (16進数では「0x3080000000000000」) 。奇数パリティの設定を行なったものは以下となる。

    00110001 10000000 00000001 00000001 00000001 00000001 00000001 00000001

    これが 2 つ目の DES 鍵であり、16 進数では「0x3180010101010101」となる。DES の実装によっては(実際のところ多くの実装では)パリティを使用しないため、この処理は省略できる。この場合 DES 鍵として使えるように単にビットを挿入したバイト列が DES 鍵として用いられる。多くの場合、パリティビットは暗号化処理に影響を及ぼさない。

  5. 各々の鍵は、固定の ASCII 文字列「KGS!@#$%」(16進数で「0x4b47532140232425」)を暗号化するために用いられる。 これにより、「0xff3750bcc2b22412」(1 つ目の鍵を使用)と「0xc2265b23734e0dac」(2 つ目を使用)という暗号文が生成される。
  6. これらの暗号文を結合したものが、16 バイトのLM ハッシュ - 「0xff3750bcc2b22412c2265b23734e0dac」となる。
  7. これを 21 バイトになるように NULL パディングしたものが「0xff3750bcc2b22412c2265b23734e0dac0000000000」となる。
  8. この値を 3 つの 7 バイトのバイト列、「0xff3750bcc2b224」、「0x12c2265b23734e」、「0x0dac0000000000」に分割する。
  9. これらの 3 つのバイト列を用いて 3 つの DES 鍵を生成する。先に概要を示した作業が行なわれ、最初のバイト列

    11111111 00110111 01010000 10111100 11000010 10110010 00100100

    からは、パリティ処理を行なった DES 鍵として以下が生成される

    11111110 10011011 11010101 00010110 11001101 00010101 11001000 01001001

    (16 進数では「0xfe9bd516cd15c849」)。2 つ目のバイト列である

    00010010 11000010 00100110 01011011 00100011 01110011 01001110

    からは、以下のバイト列が生成される

    00010011 01100001 10001001 11001011 10110011 00011010 11001101 10011101

    (16 進数では「0x136189cbb31acd9d」)。最後に、3 つ目のバイト列である

    00001101 10101100 00000000 00000000 00000000 00000000 00000000

    からは、以下のバイト列が生成される。

    00001101 11010110 00000001 00000001 00000001 00000001 00000001 00000001

    これが 3 つ目の DES 鍵(「0x0dd6010101010101」)となる。

  10. 各々の鍵が、Type 2 メッセージに含まれるチャレンジの値(今回の例では「0x0123456789abcdef」) の DES 暗号化に用いられる。これにより、以下のような暗号文、 「0xc337cd5cbd44fc97」 (1 つ目の鍵を使用)、「0x82a667af6d427c6d」 (2 つ目を使用) 、「0xe67c20c2d3e77c56」(3 つ目を使用) が生成される。
  11. これら 3 つの暗号文を結合して 24 バイトのバイト列としたものが LM レスポンスとなる。

    0xc337cd5cbd44fc9782a667af6d427c6de67c20c2d3e77c56

このアルゴリズムには平文を推測可能である脆弱性がいくつか存在する。脆弱性についての詳細は、Hertel のドキュメントで記載されているが、最も顕著な問題は、以下のようなものである。

NTLM レスポンス

NTLM レスポンスは最近のクライアントが送出する。 これは、LM レスポンスの欠陥に対応したものであるが、以前として強力なものであるとはいい難い。 加えて、ほとんどの場合 NTLM レスポンスは LM レスポンスとともに送出される。 LM レスポンスのアルゴリズムの脆弱性により、大文字小文字が不明な状態でのパスワードが取得されてしまい、ここからはトライアンドエラーで、 NTLM レスポンスが用いる大文字小文字を区別した形式のパスワードを確認することができてしまう。

NTLM レスポンスは以下のようにして計算される (Java における実装例については 付録 D を参照のこと)。

  1. MD4 メッセージダイジェストアルゴリズム (RFC 1320 にて記載されている) が Unicode ベースの大文字小文字が混在したパスワードに対して適用される。 この結果、16 バイトのバイト列が生成される。これが NTLM ハッシュである。
  2. 16 バイトの NTLM ハッシュが 21 バイトになるように NULL パディングされる。
  3. この値が 3 つの 7 バイトのバイト列に分割される。
  4. これら 7 バイトの値の各々が DES 鍵として用いられる。
  5. これらの鍵の各々を用いて、Type 2 メッセージのチャレンジが DES 暗号化される (この結果、3 つの 8 バイトの暗号文が生成される)。
  6. これら 3 つの暗号文を結合して 24 バイトの値を生成する。これが NTLM レスポンスである。

LM レスポンスと異なるのはハッシュ値の生成部分だけであり、レスポンスの計算部分は同一である。 詳細に記載するために、先ほど用いたサンプル(ユーザのパスワードが「SecREt01」で、Type 2 チャレンジ「0x0123456789abcdef」に応答しようとしている)にこの処理を適用してみよう。

  1. Unicode ベースの大文字小文字が混在したパスワードは 16 進数で「0x53006500630052004500740030003100」となる。この値の MD4 ハッシュを計算することで、「0xcd06ca7c7e10c99b1d33b7485a2ed808」という値が生成される。これが NTLM ハッシュである。
  2. これを 21 バイトになるように NULL パディングして、「0xcd06ca7c7e10c99b1d33b7485a2ed8080000000000」という値が生成される。
  3. この値を 3 つの 7 バイトの値に分割し、「0xcd06ca7c7e10c9」、「0x9b1d33b7485a2e」、「0xd8080000000000」という値が生成される。
  4. この 3 つの値は 3 つの DES 鍵を生成するのに用いられる。最初の値

    11001101 00000110 11001010 01111100 01111110 00010000 11001001

    からは、パリティ処理を行なった DES 鍵として

    11001101 10000011 10110011 01001111 11000111 11110001 01000011 10010010

    (16 進数で「0xcd83b34fc7f14392」)が生成される。2 つ目の値

    10011011 00011101 00110011 10110111 01001000 01011010 00101110

    からは、

    10011011 10001111 01001100 01110110 01110101 01000011 01101000 01011101

    (16進数で「0x9b8f4c767543685d」)が生成され、3 つ目の値

    11011000 00001000 00000000 00000000 00000000 00000000 00000000

    からは、

    11011001 00000100 00000001 00000001 00000001 00000001 00000001 00000001

    (16 進数で「0xd904010101010101」)が生成される。

  5. これら 3 つの鍵が、Type 2 メッセージのチャレンジ(「0x0123456789abcdef」)の DES 暗号化に用いられる。これにより、以下の値、 「0x25a98c1c31e81847」 (1 つ目の鍵を使用)、 「0x466b29b2df4680f3」 (2 つ目を使用)、 「0x9958fb8c213a9cc6」 (3 つ目の鍵を使用) が生成される。
  6. これら 3 つの暗号文を結合して、24 バイトのバイト列としたものが、以下の NTLM レスポンスである。

    0x25a98c1c31e81847466b29b2df4680f39958fb8c213a9cc6

NTLMv2 レスポンス

NTLM version 2 (「NTLMv2」) は NTLM に存在したセキュリティの問題を解決するために作られた。その実効性については疑問の余地はあるものの、これが LM レスポンスに対する最もセキュアな代替策である。NTLMv2 が有効な場合、NTLM レスポンスが NTLMv2 レスポンスに置き換えられ、LM レスポンスは (次で説明する) LMv2 レスポンスに置き換えられる。

NTLMv2 レスポンスは以下のようにして計算される (Java による実装例については 付録 D を参照のこと)。

  1. NTLM パスワードハッシュが生成される (前述したように、これは Unicode ベースの大文字小文字の混在したパスワードの MD4 ダイジェストである)。
  2. 大文字化したユーザ名の Unicode 文字列が大文字化した authentication target (ドメイン名もしくはサーバ名)の Unicode 文字列と結合される。HMAC-MD5 メッセージ認証コードアルゴリズム (RFC 2104 で記載) が 16 バイトの NTLM ハッシュを鍵として、このバイト列に適用される。この結果、16 バイトの値が生成される。これが NTLMv2 ハッシュである。
  3. 「blob」という名称で呼ばれているデータブロックが構築される。Hertel のドキュメントでは、この構造体のフォーマットが詳細に記載されているが、ここでは簡単に説明する。
    Description Content
    0Blob 署名 0x01010000
    4予約 long (0x00000000)
    8Timestamp 1601 年 1 月 1 日から 10 マイクロ秒単位の時刻を格納した 64 ビットの符合付き、リトルエンディアンの数値
    16Client Nonce8 bytes
    24不明4 bytes
    28Target Information Target Information ブロック (Type 2 メッセージより)
    (可変)不明 4 bytes
  4. Type 2 メッセージのチャレンジにこの blob が結合される。これに HMAC-MD5 メッセージ認証コードアルゴリズムが (ステップ 2 で計算された) 16 バイトの NTLMv2 ハッシュを鍵として適用される。これにより 16 バイトのバイト列が生成される。
  5. このバイト列を先ほどの blob と結合したものが NTLMv2 レスポンスである。

以下に例を示す。NTLMv2 レスポンスを計算するためにはいくつか必要な情報があるが、今回はここまでの例にならい、以下の値を用いる。

ドメイン名: DOMAIN
ユーザ名: user
パスワードd: SecREt01
チャレンジ: 0x0123456789abcdef
Target Information:
0x02000c0044004f00
  4d00410049004e00
  01000c0053004500
  5200560045005200
  0400140064006f00
  6d00610069006e00
  2e0063006f006d00
  0300220073006500
  7200760065007200
  2e0064006f006d00
  610069006e002e00
  63006f006d000000
  0000

  1. Unicode ベースの大文字小文字が混在したパスワードは、16 進数で「0x53006500630052004500740030003100」となる。このバイト列の MD4 ハッシュを計算すると、「0xcd06ca7c7e10c99b1d33b7485a2ed808」となる。これが NTLM ハッシュである。
  2. 大文字化したユーザの Unicode 文字列が大文字化した authentication target の Unicode 文字列と結合され、「USERDOMAIN (16進数では「0x550053004500520044004f004d00410049004e00」)というUnicode 文字列が生成される。 この文字列に対して、先に生成した 16 バイトの NTLM ハッシュを鍵として HMAC-MD5 が適用される。これにより「0x04b8e0ba74289cc540826bab1dee63ae」という値が生成される。これが NTLMv2 ハッシュである。
  3. 引続き、blob を生成する。タイムスタンプは長いだけでなんの変哲もない。デスクの時計をみると、東部夏時間(EDT)で 2003 年 6 月 17 日の 6:00 ちょうどだったとする。UNIX 時間において、これは始点から 1055844000 秒経過した時刻となる。さらに 11644473600 を加えることで、1601 年 1 月 1 日からの秒単位の経過時刻 (12700317600) を取得できる。これを 10 の 7 乗 (10000000) したものがマイクロ秒単位の経過時刻 (127003176000000000) となる。これをリトルエンディアンの 64 ビットの値として表すと (16 進数で)「0x0090d336b734c301」となる。

    次に、ランダムな 8 バイトの「client nonce」を生成する必要がある。ここでは乱雑性に低いが「0xffffff0011223344」という値を用いることとする。blob の残りの部分は簡単に生成できる。これらを結合しよう。

    0x01010000(Blob 署名)
    0x00000000(予約値)
    0x0090d336b734c301(タイムスタンプ)
    0xffffff0011223344(ランダムなクライアントの値)
    0x00000000(不明だが、0 にしておけば動作する)
    0x02000c0044004f00
      4d00410049004e00
      01000c0053004500
      5200560045005200
      0400140064006f00
      6d00610069006e00
      2e0063006f006d00
      0300220073006500
      7200760065007200
      2e0064006f006d00
      610069006e002e00
      63006f006d000000
      0000
    (target information ブロック)
    0x00000000(不明だが、0 にしておけば動作する)

  4. ここで Type 2 チャレンジと blob を結合して、以下のバイト列を生成する。
    0x0123456789abcdef0101000000000000
      0090d336b734c301ffffff0011223344
      0000000002000c0044004f004d004100
      49004e0001000c005300450052005600
      450052000400140064006f006d006100
      69006e002e0063006f006d0003002200
      7300650072007600650072002e006400
      6f006d00610069006e002e0063006f00
      6d000000000000000000
    

    これに ステップ 2 で生成した NTLMv2 ハッシュを鍵として用いて、HMAC-MD5 を適用することで、16 ビットの値「0xcbabbca713eb795d04c97abc01ee4983」が生成される。

  5. この値を blob と結合したものが NTLMv2 レスポンスである。
    0xcbabbca713eb795d04c97abc01ee4983
      01010000000000000090d336b734c301
      ffffff00112233440000000002000c00
      44004f004d00410049004e0001000c00
      53004500520056004500520004001400
      64006f006d00610069006e002e006300
      6f006d00030022007300650072007600
      650072002e0064006f006d0061006900
      6e002e0063006f006d00000000000000
      0000
    

LMv2 レスポンス

LMv2 レスポンスは、古いサーバとのパススルー認証の互換性を維持するために用いられる。クライアントの通信先のサーバが実際の認証を行なわず、ドメインコントローラにレスポンスを提示する形態はごく一般的なことである。古いサーバでは、LM レスポンスのみを提示していた。これは 24 バイトのバイト列であった。LMv2 レスポンスはこれらのサーバを適切に動作させるために設計された。実際のところ、LMv2 レスポンスは「最低限の」NTLMv2 レスポンスである。以下に計算例を示す (Java による実装例については 付録 D を参照のこと)。

  1. NTLM パスワードハッシュが計算される (Unicode ベースの大文字小文字が混在したパスワードの MD4 ダイジェストである)。
  2. 大文字化したユーザ名の Unicode 文字列と、大文字化した authentication target (ドメイン名もしくはサーバ名) の Unicode 文字列が結合される。HMAC-MD5 メッセージ認証コードアルゴリズムが、16 バイトの NTLM ハッシュを鍵として、このバイト列に適用される。この結果生成される 16 バイトの値が NTLMv2 ハッシュである。
  3. ランダムな 8 バイトの client nonce が生成される (これは NTLMv2 の blog で用いられているものと同じである)。
  4. Type 2 メッセージからのチャレンジが client nonce と結合される。HMAC-MD5 メッセージ認証アルゴリズムが (ステップ 2 で計算された) 16 バイトの NTLMv2 ハッシュを鍵として、このバイト列に適用される。これにより 16 バイトのバイト列が出力される。
  5. この値を 8 バイトの client nonce と結合したものが、 24 バイトの LM2 レスポンスである。

この処理を、前述した値を用いた例で簡単に説明しよう。

ドメイン名: DOMAIN
ユーザ名: user
パスワード: SecREt01
チャレンジ: 0x0123456789abcdef

  1. Unicode ベースの大文字小文字の混在したパスワードは、16 進数で「0x53006500630052004500740030003100」である。このバイト列の MD4 ハッシュを計算すると、「0xcd06ca7c7e10c99b1d33b7485a2ed808」となる。これが NTLM ハッシュである。
  2. 大文字化したユーザ名の Unicode 文字列を大文字化した authentication target の Unicode 文字列と結合して、「USERDOMAIN (16進数で「0x550053004500520044004f004d00410049004e00」)」という文字列を得る。 以前に生成した 16 バイトの NTLM ハッシュを鍵として、この文字列に HMAC-MD5 を適用する。この結果、「0x04b8e0ba74289cc540826bab1dee63ae」というバイト列が生成される。これが NTLMv2 ハッシュである。
  3. ランダムな 8 バイトの client nonce が生成される。NTLMv2 のサンプルと同様に、ここでは「0xffffff0011223344」というバイト列を用いることとする。
  4. ここで Type 2 チャレンジに client nonce を結合する。

    0x0123456789abcdefffffff0011223344

    ステップ 2 で生成した NTLMv2 ハッシュを鍵として、上記のバイト列に HMAC-MD5 を適用する。これにより「0xd6e6152ea25d03b7c6ba6629c2d6aaf0」という 16 バイトのバイト列が生成される。

  5. この値を client nonce と結合した以下の 24 バイトのバイト列が LMv2 レスポンスである。

    0xd6e6152ea25d03b7c6ba6629c2d6aaf0ffffff0011223344

NTLM2 セッションレスポンス(NTLM2 Session Response)

NTLM2 セッションレスポンスは(「Negotiate NTLM2 Key」フラグを有効にすることで使用できる) NTLM2 セッションセキュリティと共に用いることができる。 これにより、NTLMv2 認証がサポートされない環境において、計算済の辞書攻撃(特に Rainbow Table ベースの攻撃)に対する耐性が強化される。

NTLM2 セッションレスポンスは、以下で記載するように、LM レスポンスと NTLM レスポンスの両方を置き換える (Java による実装については 付録 D を参照のこと)。

  1. ランダムな 8 バイトの client nonce が生成される。
  2. client nonce が 24 バイト長になるように NULL パディングされる。この値は、Type 3 メッセージの LM レスポンス欄に格納される。
  3. session nonce を生成するために Type 2 メッセージに含まれるチャレンジが 8 バイトの client nonce と結合される。
  4. MD5 メッセージダイジェストアルゴリズム (RFC 1321 で記載) が session nonce に適用され、16 バイトのバイト列が生成される。
  5. NTLM2 セッションハッシュを生成するため、このバイト列が 8 バイトに切り詰められる。
  6. NTLM パスワードハッシュが生成される (前述したように、Unicode ベースの大文字小文字が混在したパスワードの MD4 ダイジェストである)。
  7. 16 バイトの NTLM ハッシュが 21 バイトになるように NULL パディングされる。
  8. このバイト列を 3 つの 7 バイトの値に分割する。
  9. これらの値を用いて、3 つの DES 鍵が生成される。
  10. 鍵の各々が NTLM2 セッションハッシュを DES 暗号化するために用いられる(その結果、 3 つの 8 バイト長の暗号文が生成される)。
  11. この 3 つの暗号文を結合して 24 バイトのバイト列とする。これが NTLM2 セッションレスポンスであり、Type 3 メッセージの NTLM レスポンスフィールドに格納されるものである。

先ほど用いたサンプル(ユーザのパスワードが「SecREt01」で、Type 2 チャレンジ「0x0123456789abcdef」に応答しようとしている)にこの処理を適用してみよう。

  1. A ランダムな 8 バイトの client nonce が生成される。ここでは先ほどの例と同様に「0xffffff0011223344」という値を用いることとする。
  2. チャレンジが 24 バイトとなるように NULL パディングされる。

    0xffffff001122334400000000000000000000000000000000

    この値は Type 3 メッセージの LM レスポンスフィールドに格納される。

  3. Type 2 メッセージのチャレンジが client nonce に結合される。このバイト列(「0x0123456789abcdefffffff0011223344」)が session nonce となる。
  4. この nonce に MD5 ダイジェストが適用され、16 バイトのバイト列「0xbeac9a1bc5a9867c15192b3105d5beb1」が生成される。
  5. NTLM2 セッションハッシュを取得するために、このバイト列が 8 バイトに切り詰められる( 「0xbeac9a1bc5a9867c」)。
  6. 大文字小文字の混在する Unicode 文字列のパスワード「0x53006500630052004500740030003100」に対して MD4 ダイジェストが適用され、NTLM ハッシュ(「0xcd06ca7c7e10c99b1d33b7485a2ed808」)が生成される。
  7. この値が 21 バイトとなるように NULL パディングされ、「0xcd06ca7c7e10c99b1d33b7485a2ed8080000000000」というバイト列が生成される。
  8. この値が 3 つの 7 バイト長のバイト列、「0xcd06ca7c7e10c9」、「0x9b1d33b7485a2e」、「0xd8080000000000」に分割される。
  9. このバイト列から 3 つの DES 鍵が生成される (先の NTLM レスポンスの例で計算したのと同様にして、「0xcd83b34fc7f14392」、「0x9b8f4c767543685d」、「0xd904010101010101」という 3 つの鍵が生成される)。
  10. 3 つの鍵の各々が NTLM2 セッションハッシュ(「0xbeac9a1bc5a9867c」)を暗号化するために用いられる。これにより、「0x10d550832d12b2cc」(1 つ目の鍵から)、「0xb79d5ad1f4eed3df」(2つ目から)、「0x82aca4c3681dd455」 (3 つ目の鍵から)というバイト列が生成される。
  11. これら 3 つの暗号文を結合したものが 24 バイトの NTLM2 セッションレスポンス

    0x10d550832d12b2ccb79d5ad1f4eed3df82aca4c3681dd455

    であり、Type 3 メッセージの NTLM レスポンスフィールドに格納される。

匿名レスポンス(Anonymous Response)

匿名レスポンスは、クライアントが実在するユーザのコンテキストでなく、匿名コンテキストでの通信を確立したことを意味する。これは認証ユーザを必要としない処理のための「placeholder」が必要な場合に返却される。匿名コネクションは Windows の「Guest」ユーザと同一ではない(後者は実在するユーザアカウントであるが、匿名コネクションには如何なるアカウントも割り当てられない)。

匿名の Type 3 メッセージは、クライアントにより「Negotiate Anonymous」フラグが設定され、NTLM レスポンスフィールドが空(0 バイト長)、LM レスポンスフィールドには 1 バイトの NULL 文字(「0x00」)が格納される。

Type 3 Message の例

Type 3 レスポンスについての知識を深めるため、以下の Type 3 メッセージを解析してみよう。

    4e544c4d5353500003000000180018006a00000018001800
    820000000c000c0040000000080008004c00000016001600
    54000000000000009a0000000102000044004f004d004100
    49004e00750073006500720057004f0052004b0053005400
    4100540049004f004e00c337cd5cbd44fc9782a667af6d42
    7c6de67c20c2d3e77c5625a98c1c31e81847466b29b2df46
    80f39958fb8c213a9cc6

This message is decomposed as:

0 0x4e544c4d53535000NTLMSSP 署名
8 0x03000000Type 3 識別子
12 0x180018006a000000 LM Response セキュリティバッファ:

長さ: 24 バイト (0x1800)
割当済領域: 24 バイト (0x1800)
オフセット: 106 バイト (0x6a000000)

20 0x1800180082000000 NTLM Response セキュリティバッファ:

長さ: 24 bytes (0x1800)
割当済領域: 24 バイト (0x1800)
オフセット: 130 バイト (0x82000000)

28 0x0c000c0040000000 ドメイン名セキュリティバッファ:

長さ: 12 バイト (0x0c00)
割当済領域: 12 バイト (0x0c00)
オフセット: 64 バイト (0x40000000)

36 0x080008004c000000 ユーザ名セキュリティバッファ:

長さ: 8 バイト (0x0800)
割当済領域: 8 バイト (0x0800)
オフセット: 76 バイト (0x4c000000)

44 0x1600160054000000 ワークステーション名セキュリティバッファ:

長さ: 22 バイト (0x1600)
割当済領域: 22 バイト (0x1600)
オフセット: 84 バイト (0x54000000)

52 0x000000009a000000 セッション鍵セキュリティバッファ:

長さ: 0 バイト (0x0000)
割当済領域: 0 バイト (0x0000)
オフセット: 154 バイト (0x9a000000)

60 0x01020000 フラグ:

Negotiate Unicode (0x00000001)
Negotiate NTLM (0x00000200)

64
0x44004f004d004100
  49004e00
ドメイン名データ (「DOMAIN」)
76 0x7500730065007200 ユーザ名データ (「user」)
84
0x57004f0052004b00
  5300540041005400
  49004f004e00
ワークステーション名データ (「WORKSTATION」)
106
0xc337cd5cbd44fc97
  82a667af6d427c6d
  e67c20c2d3e77c56
LM Response データ
130
0x25a98c1c31e81847
  466b29b2df4680f3
  9958fb8c213a9cc6
NTLM Response データ

この解析結果から、以下のことが確認できる。

Type 3 メッセージを受信したサーバは LM レスポンスと NTLM レスポンスを計算し、これらをクライアントから提供された値と比較する。これらが合致した場合、ユーザの認証は成功する。

NTLM Version 2

NTLM version 2 は 3 つの新しいレスポンスアルゴリズム(前述した NTLMv2、LMv2、NTLM2 session レスポンス)と 1 つの新しい署名および暗号化のスキーム(NTLM2 セッションセキュリティ)からなっている。 NTLM2 セッションセキュリティは「Negotiate NTLM2 Key」フラグが設定されていた場合にネゴシエートされる。ただし、NTLMv2 認証を有効にするには、レジストリの修正が必要である。更に、認証を成功させるためには、クライアントとドメインコントローラの両方で互換性のあるレジストリ設定を行なう必要がある(NTLMv2 認証を、この認証をサポートしていない古いサーバから NTLMv2 をサポートしたドメインコントローラにパススルーさせることは可能)。 NTLMv2 を用いるには、設定と計画が必須となることが、ほとんどの場合デフォルトの設定(NTLMv1)が用いられ、NTLMv2 認証が普及していない原因となっている。

NTLM Version 2 を有効にする方法の詳細については、 マイクロソフト社の技術情報 239869を参照のこと。一言でいうと、以下のレジストリ registry value:

    HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\LSA\LMCompatibilityLevel

(Windows 9x ベースのシステムでは LMCompatibility) の修正が必要となる。 これは REG_DWORD のエントリであり、以下の値のいずれかを設定できる。

レベルクライアントとして送信するレスポンスサーバとして受信するレスポンス
0 LM
NTLM
LM
NTLM
LMv2
NTLMv2
1 LM
NTLM
LM
NTLM
LMv2
NTLMv2
2 NTLM LM
NTLM
LMv2
NTLMv2
3 LMv2
NTLMv2
LM
NTLM
LMv2
NTLMv2
4 LMv2
NTLMv2
NTLM
LMv2
NTLMv2
5 LMv2
NTLMv2
LMv2
NTLMv2

NTLM2 セッションセキュリティは、すべてのレベルでサポートされており、利用可能な場合はネゴシエートされる(ほとんどのドキュメントでは、NTLM2 セッションセキュリティはレベル 1 以上でのみ有効であるという記載があるが、確認した限りレベル 0 でも同様に有効であった。 Windows 95 および Windows 98 プラットフォームがデフォルトでサポートするのは LM レスポンスのみであるが、ディレクトリサービスクライアントをインストールすることで、NTLMv2 もサポートされるようになる (加えて LMCompatibility の設定が有効となるが、設定可能な値は 0 と 3 のみとなる)。

レベル 2 の場合、クライアントは NTLM レスポンスを 2 重に (LM レスポンスと NTLM レスポンスフィールドの両方で) 送信する。レベル 3 以上では、LM と NTLM レスポンスが LMv2 と NTLMv2 レスポンスに置き換えられる。

NTLM2 セッションセキュリティがネゴシエートされた場合 (「Negotiate NTLM Key」フラグで確認可能)、レベル 0、1、2 では、脆弱な LM および NTLM レスポンスが NTLM2 セッションレスポンスに置き換えられる。 これにより、サーバ上での辞書攻撃に対する NTLMv1 の耐性が向上する。与えられたチャレンジに対するクライアントのレスポンスは、ランダムな client nonce を計算に加えることで、乱雑性の高いものとなる。

NTLM2 セッションレスポンスは、これをサポートしない古いドメインコントローラが存在していた場合でも、クライアントとサーバが新しいスキームをサポートしていればネゴシエートすることが可能となる点に注目したい。 典型的な例として、認証に関連するサーバはユーザのパスワードハッシュを持っておらず、ドメインコントローラのみが保持している場合を想定しよう。マシンが NT ドメインに参加した場合、暗号化された相互認証されたドメインコントローラとの間のチャネル(通常「NetLogon pipe」と呼んでいる) が確立される。クライアントが「本来の」NTLMv1 ハンドシェイクを用いてサーバに対して認証を行なう場合、背後では以下の処理が実行される。

  1. クライアントは Type 1 メッセージを送出する。これには前述したフラグその他の情報が含まれる。
  2. サーバはクライアントに対するチャレンジを生成し、negotiated フラグを設定した Type 2 メッセージで送信する。
  3. クライアントは LM/NTLM レスポンスによりチャレンジに対するレスポンスを行なう。
  4. サーバはチャレンジとクライアントのレスポンスを NetLogon pipe 経由でドメインコントローラに送信する。
  5. ドメインコントローラは認証の際の計算を軽減するため、格納されているハッシュとサーバから提供されたチャレンジを用いる。これらがレスポンスと合致すれば、認証は成功する。

NTLM2 セッションレスポンスが用いられる場合、クライアントとサーバの両方が新しいプロトコルを用いることが可能な状態である必要があるが、ドメインコントローラは古いままでよい。 上記を可能とするため、前述したハンドシェイクが以下のように若干修正される。

  1. クライアントは Type 1 メッセージを送出する。これには「Negotiate NTLM Key」フラグが設定されている。
  2. サーバはクライアントに対するチャレンジを生成し、negotiated フラグを設定した Type 2 メッセージで送信する。(「Negotiate NTLM2 Key」フラグも設定されている)
  3. クライアントはチャレンジに対するレスポンスを行なう。この際 client nonce が LM フィールドで、NTLM2 セッションレスポンスが NTLM フィールドで提供される。 NTLM2 セッションレスポンスでは、NTLM レスポンスと同じ計算が行なわれるが、サーバのチャレンジを暗号化する代わりに、クライアントはサーバのチャレンジと client nonce を結合したバイト列の MD5 ハッシュを暗号化する点が異なる。
  4. チャレンジを NetLogon pipe を経由して直接サーバからドメインコントローラに送出する代わりに、サーバはサーバのチャレンジと client nonce を結合したものの MD5 ハッシュを(LM レスポンスフィールドに格納して)送出する。 加えて、(通常通り)クライアントからのレスポンスも送出する。
  5. ドメインコントローラはサーバから送出されたチャレンジフィールドの内容を格納されているハッシュを鍵として暗号化し、それが NTLM レスポンスフィールドと合致していることを確認する。このため、クライアントの認証は成功する。
  6. ドメインコントローラは通常の NTLM ユーザセッション鍵を生成の上、サーバに送信する。サーバはそれを用いてNTLM2 セッションレスポンスのユーザセッション鍵(subsequent sectionで説明する)を生成するために、再度計算を行なう。

重要なのは、ドメインコントローラが古いままで NTLMv2 をサポートしていない(もしくはネットワーク管理者が LMCompatibilityLevel レジストリを設定して NTLMv2 を用いるようにしていない) ネットワークにおいても、クライアントとサーバが NTLM2 セッションレスポンスを用いることが可能な点である。

LMCompatibilityLevel の設定に関連する設定として、NtlmMinClientSecNtlmMinServerSec という設定がある。これらは NTLMSSP が確立する NTLM コンテキストで最低限必要とされる設定を指定するものである。 いずれも REG_WORD のエントリとなっており、以下の NTLM フラグを組み合わせて指定可能なビットフィールドとなっている。

これらのフラグを設定するよりは、NTLM2 の署名と暗号化を行なった方がより適切であろう。ただし、「Negotiate NTLM2 Key」だけは NTLM2 セッションセキュリティのネゴシエートが行なえないホストとの通信の確立を抑止するという意味で、認証において重要な役割を持つ。このフラグを設定すると、LM および NTLM レスポンスが送信されない(認証に際しては、最低でも NTLM2 セッションセキュリティを常に用いることを要求する)。

NTLMSSP と SSPI

ここで NTLM の認証機構全体の中での位置付けについて解説する。

Windows は SSPI - Security Support Provider interface という名称のセキュリティフレームワークを提供している。これは GSS-API (Generic Security Service Application Program Interface、RFC 2743) のマイクロソフト版であり、非常に高レベルで下位の認証機構に依存しない認証、整合性、秘匿性確保のフレームワークを提供する。 SSPI は幾つかの下位プロバイダをサポートしている。その一つが NTLMSSP (NTLM Security Support Provider) であり、ここまで解説してきた NTLM 認証機構を提供するものである。 SSPI は柔軟な opaque やプロバイダ固有の認証トークンを扱うための柔軟な API を提供する。NTLM Type 1、Type 2、Type 3 メッセージもこうしたトークンの一つであり、NTLMSSP によって定義され、処理されている。 SSPI によって提供される API の概要については、NTLM の詳細とはほとんど関係がない。 アプリケーションの開発者はNTLM が用いられているかことを意識する必要はなく、アプリケーションレベルでは無修正もしくは微小な修正で、(Kerberos など)別の認証機構に変更することが可能である。

ここでは SSPI のフレームワークについて深くは言及しないが、SSPI 認証のハンドシェイクが、どのように NTLM に対して適用されているかを俯瞰したい。

  1. クライアントは SSPI の AcquireCredentialsHandle 関数により、ユーザの資格情報に対応づけられた情報を取得する。
  2. クライアントは SSPI の InitializeSecurityContext 関数を呼び出して、認証リクエストトークン(ここでは Type 1 メッセージ)を取得する。 クライアントはこのトークンをサーバに送出する。関数からの返却値は認証が二段ステップであることを示す。
  3. サーバはクライアントからのトークンを受けとり、それを AcceptSecurityContext という SSPI 関数への入力値として用いる。これにより、サーバ上でクライアントに提示するローカルセキュリティコンテキストが生成され、クライアントに応答するための認証レスポンストークン(Type 2 メッセージ)が作成される。 関数からの返却値は、クライアントから更に情報が必要かどうかを示す。
  4. クライアントはサーバからのレスポンストークンを受けとり、再度 InitializeSecurityContext 関数を呼び出す。この時サーバのトークンを入力値としてそのまま渡す。これにより、先ほどとは異なる認証リクエストトークン (Type 3 メッセージ)が生成される。 この関数の返却値はセキュリティコンテキストが適切に初期化されたことを示す。このトークンがサーバに送出される。
  5. サーバはクライアントからのトークンを受けとり、再度 AcceptSecurityContext 関数を呼び出す。この際入力値として Type 3 メッセージを用いる。 返却値はコンテキストが正常に受け入れられたことを示す。さらなるトークンは生成されず、認証は完了する。

ローカル認証(Local Authentication)

ここまでの解説では、ローカル認証の手順について、さまざまな視点から言及してきた。SSPI の基本を理解することで、この詳細に確認できる。

ローカル認証は NTLM メッセージ中の情報に基づいて、クライアントとサーバ間で一連の決定が適切に行なわれた場合にネゴシエートされる。これは以下のように動作する。

  1. クライアントは AcquireCredentialsHandle 関数を 「pAuthData」パラメータに NULL を指定することでデフォルトの資格情報を指定した形で呼び出す。これにより、ログオンしているユーザの資格情報をシングルサインオン用途で扱うためのハンドルを取得する。
  2. クライナトは SSPI の InitializeSecurityContext 関数を発行して、Type 1 メッセージを生成する。デフォルトの資格情報のハンドルが提示された場合、Type 1 メッセージにはクライアントのワークステーションとドメイン名が格納される。これは、「Negotiate Doman Supplied」 および「Negotiate Workstation Supplied」フラグが設定され、メッセージにも supplied domain および supplied workstation セキュリティバッファが存在することで識別される。
  3. サーバはクライアントからの Type 1 メッセージを受けとり、AcceptSecurityContext を呼び出す。これにより、サーバ上にはクライアントに対応づけられたローカルセキュリティコンテキストが生成される。 サーバはクライアントから送付されたドメイン名とワークステーション名の情報を確認し、クライアントとサーバが同一マシンかどうかを確定する。 該当する場合、サーバは返却する Type 2 メッセージに「Negotiate Local Call」フラグを設定することで、ローカル認証を開始する。 Type 2 メッセージのコンテキストフィールドの最初の long は新規に取得された SSPI コンテキストハンドルの「上位」(SSPI の CtxtHandle 構造体の「dwUpper」フィールド)が格納される。 コンテキストフィールドの次の long は常に空となる (論理的には、コンテキストハンドルの「下位」が格納されると考えることもできるが)。
  4. クライアントはサーバから Type 2 メッセージを受けとり、それを InitializeSecurityContext に引き渡す。前述した「Negotiate Local Call」フラグのところで記載したように、クライアントはサーバのコンテキストハンドルを確認して、正当なローカルセキュリティコンテキストからのものであるかを判断する。 そのコンテキストが正当なものであることを確認できなかった場合、通常の認証が継続される。すなわち適切なレスポンスが計算され、ドメイン、ワークステーション、ユーザ名が Type 3 メッセージに格納される。 Type 2 メッセージのセキュリティコンテキストハンドルが正当なものであると確認できた場合は、こうしたレスポンスは生成されない。代わりにデフォルトの資格情報が、サーバのコンテキストに内部的に割り当てられる。その結果、Type 3 メッセージは実質的に空となり、ユーザ名、ドメイン名、ワークステーション名を示すセキュリティバッファは 0 バイト長となる。
  5. サーバは Type 3 メッセージを受けとり、それを AcceptSecurityContext 関数の入力値として用いる。サーバはセキュリティコンテキストがユーザに割り当てられたことを確認する。割り当てが行なわれた場合、認証は成功する。割り当てが行なわれなかった場合、認証は失敗する。

データグラム認証

データグラム形式の認証は、NTLM をコネクションレスの伝送路でネゴシエートする際に用いられる。メッセージの大半の部分は同一であるが、顕著な差異も幾つか存在する。

「通常の(コネクション型の)」認証の場合、すべてのオプションはクライアントとサーバ間で行なわれる初回のやりとり、Type 1 メッセージと Type 2 メッセージのやりとりの中でネゴシエートされる。 ネゴシエートされた設定はサーバ側で「記憶」されると共に、クライアントの Type 3 メッセージで適用される。 ほとんどのクライアントがネゴシエート済のフラグを Type 3 メッセージで送出するが、これらはコネクション型の認証では用いられない。

一方、データグラム認証においては、このやりかたに少し変更がある。サーバ側でネゴシエートされたオプションを記録する(コネクションレスの状態でこれを行なうのは困難である)必要性を低減するため、Type 1 メッセージは完全に削除される。サーバは Type 2 メッセージに(もちろんチャレンジと一緒に)サポート可能なすべてのフラグを格納して送出する。 クライアントはどのオプションをサポートするかを決定して、Type 3 メッセージにチャレンジに対するレスポンスと選択したフラグの情報を格納して応答する。データグラムにおける SSPI のハンドシェイク手順は以下のようになる。

  1. クライアントは AcquireCredentialsHandle を呼び出して、ユーザの資格情報セットの情報を取得する。
  2. クライアントは InitializeSecurityContext を呼び出し、fContextReq パラメータに必須フラグである ISC_REQ_DATAGRAM を渡す。 これにより、クライアントのセキュリティコンテキストが生成されるが、リクエストトークン(Type 1 メッセージ)は生成されない
  3. サーバは、必須フラグである ASC_REQ_DATAGRAM フラグを設定して、入力トークンを NULL として AcceptSecurityContext 関数を呼び出す。これにより、ローカルセキュリティコンテキストが生成され、認証レスポンスのトークン(Type 2 メッセージ)が生成される。この Type 2 メッセージにはサーバがサポートするさまざまなフラグと共に「Negotiate Datagram Style」フラグが設定される。これが通常通りクライアントに送出される。
  4. クライアントは受信した Type 2 メッセージを InitializeSecurityContext に渡す。 クライアントはサーバから提示された(設定が必須の「Negotiate Datagram Style」を含む)オプションからから適切なものを選択し、チャレンジに対するレスポンスを生成し、それらを Type 3 メッセージに格納する。このメッセージがサーバに返却される。
  5. サーバは Type 3 メッセージを AcceptSecurityContext 関数に渡す。メッセージはクライアントが選択したフラグに応じて処理され、コンテキストが適切に選択される。

SSPI の範疇では、データグラム形式の Type 1 メッセージを生成する方法は提供されていない。しかし、データグラムの Type 1 トークンを生成するために、低レベルな操作でNTLMSSP トークンを巧みに変更することにより、データグラム形式のメッセージを「作成」することが可能な点については記録しておきたい。

これは、コネクション型の SSPI ハンドシェイクにおける最初の InitializeSecurityContext 呼び出しにより生成された Type 1 メッセージに対して、トークンがサーバに渡される前に「Negotiate Datagram Style」フラグを設定することで実現される。 この修正された Type 1 メッセージを AcceptSecurityContext 関数に渡すと、サーバは (ASC_REQ_DATAGRAM が設定されていなくても)、データグラム型の認証を適用する。 これにより、「Negotiate Datagram Style」フラグが設定された Type 2 メッセージが生成されるが、それ以外の点は通常に生成されたコネクション型のメッセージと同一である。 これは、クライアントから送出された Type 1 メッセージ中のフラグが Type 2 メッセージを生成する際に考慮され、単純にサポートするすべてのオプションが送出されるわけではないということである。

クライアントは Type 2 のトークンを用いて InitializeSecurityContext を呼び出すことが可能である。この時点では、クライアントはコネクション型モードのままであることに注意。生成された Type 3 メッセージは Type 2 メッセージで適用されている「Negotiate Datagram Style」フラグを無視したままである。一方、サーバ側は強制的にデータグラム認証が適用されているため、Type 3 メッセージにこのフラグが明示的に設定されている必要がある。「Type 3 メッセージがサーバに送出される前に、手動で「Negotiate Datagram Style」フラグを追加することで、サーバはこの修正されたトークンを用いて、 AcceptSecurityContext の呼び出しを成功させることができる。

これにより認証が成功となる。「人工の」 Type 1 メッセージがサーバ側をデータグラム形式の認証モードに変更させたことが、Type 3 メッセージのフラグから確認できる。現実的な用途があるわけではないが、NTLM メッセージを意図的に操作することで、興味深い想定外の挙動が確認できる。

セッションセキュリティ - 署名と暗号化のコンセプト

SSPI では認証サービスに加えて、メッセージの整合性と機密性の機能が提供されている。これらも NTLM Security Support Provider に組み込まれている。「署名」は SSPI の MakeSignature 関数により実行され、これにより Message Authentication Code (MAC) がメッセージに付加される。 これにより受信者がメッセージの正当性を検証することが可能となり、メッセージが伝送路上で改竄されていないことが確実に保証される。署名は、送信者と受信者の両方が把握している秘密鍵を用いて生成される。MAC は鍵を所有していない限り検証ができない(これにより、署名が送信者によって行なわれたものであることが保証できる)。 「暗号化(Sealing)」は SSPI の EncryptMessage 関数によって行なわれる。これにより、伝送路上で第三者から閲覧されないようにメッセージが暗号化される。NTLMSSP は幾つかの対象鍵の暗号機構(暗号化と復号化に同じ鍵が用いられる)を用いている。

署名と暗号化に用いられる鍵は NTLM の認証プロセス中にプロダクト固有の方法で確立される。クライアントの身元の確認に加え、認証のハンドシェイク中には、送受信者間でのメッセージの署名と暗号化に必要な鍵の情報を含むクライアント、サーバ間のコンテキストの確立も行なわれる。 ここでは、こうした鍵の生成方法と、NTLMSSP による署名や暗号化における使用形態について記載する。

署名と暗号化には、さまざまな鍵のスキームが適用できる。ここでは鍵の形式とセッションセキュリティの中核について概説することから始めたい。

ユーザセッション鍵

これはセッションセキュリティを実現する上で、基本となる鍵である。これには以下のようにさまざまな形式が存在する。

使用されるメソッドは、Type 3 メッセージで送出されたレスポンスに依存する。これらのメソッドと計算方法については、以下に概説する。

LM User Session Key

LM レスポンスのみが提供される場合(Windows 9x クライアント)に使用される。LM User Session Key は以下のようにして生成される。

  1. 16バイト LM ハッシュ (計算済のもの) を 8 バイトに切り詰める
  2. これを 16 バイトになるように NULL パディングする。このバイト列が LM User Session Key である。

NTLM User Session Key

この形式は、クライアントが NTLM レスポンスを送出する際に用いられる。鍵の計算方式は、非常に単純である。

  1. NTLM ハッシュが取得される(大文字小文字を区別する Unicode ベースのパスワードの MD4 ダイジェスト、計算済のもの)
  2. MD4 メッセージダイジェストのアルゴリズムが NTLM ハッシュに適用される。この結果、16 バイトのバイト列が生成される。これが NTLM User Session Key である。

LMv2 User Session Key

LMv2 レスポンスが送出される(しかし、NTLMv2 レスポンスは送出されない) 場合に用いられる。この鍵の生成方法は若干複雑であるが、複雑過ぎるというレベルではない。

  1. NTLMv2 ハッシュが取得される(計算済のもの)。
  2. LMv2 client nonce が取得される (LMv2 レスポンスで用いられたもの)。
  3. Type 2 メッセージのチャレンジが client nonce と結合される。HMAC-MD5 メッセージ認証コードのアルゴリズムが NTLMv2 ハッシュを鍵として、このバイト列に適用される。これにより 16 バイトのバイト列が出力される。
  4. HMAC-MD5 アルゴリズムが NTLMv2 ハッシュを鍵として、このバイト列に再度適用される。この結果生成された 16 バイトのバイト列が LMv2 User Session Key となる。

NTLMv2 User Session Key

NTLMv2 レスポンスが送出される際に用いられる。この鍵の計算方法は、LMv2 User Session Key と非常に類似している。

  1. NTLMv2 ハッシュが取得される (計算済のもの)。
  2. NTLMv2 の「blob」が取得される(NTLMv2 レスポンスで用いられたもの)。
  3. Type 2 メッセージのチャレンジがこの blob と結合される。HMAC-MD5 メッセージ認証コードのアルゴリズムが NTLMv2 ハッシュを鍵として、このバイト列に対して適用される。この結果、16 バイトのバイト列が生成される。
  4. HMAC-MD5 アルゴリズムが NTLMv2 ハッシュを鍵として、このバイト列に再度適用される。この結果生成された 16 バイトのバイト列が NTLMv2 User Session Key となる。

NTLM2 Session Response User Session Key

NTLM2 セッションレキュリティを用いて NTLMv2 認証が行なわれる際に用いられる。この鍵は、NTLM2 セッションレスポンスの情報から以下のようにして生成される。

  1. NTLM User Session Key が前述したようにして取得される。
  2. session nonce が取得される (これは、前述したように Type 2 チャレンジと NTLM2 セッションレスポンスの nonce を結合したものである)。
  3. HMAC-MD5 アルゴリズムが NTLM User session Key を鍵として、この session nonce に適用される。この結果、生成される 16 バイトの値が NTLM2 Session Response User Session Key となる。

Null User Session Key

Null User Session Key は匿名認証が実施される際に用いられる。これは単純に 16 バイトの NULL バイト (「0x00000000000000000000000000000000」) となる。

Lan Manager Session Key

Lan Manager Session Key は、NTLM フラグの「Negotiate Lan Manager Key」が設定された際に、User Session Key の代わりとして NTLM1 署名と暗号化の際の鍵に用いられる。 Lan Manager Session Key の計算方法は以下のとおりである。

  1. 16 バイトの LM ハッシュ (計算済のもの) が 8 バイトに切り詰められる。
  2. これが 14 バイトになるように「0xbdbdbdbdbdbd」の値でパディングされる。
  3. この値が 2 つの 7 バイトのバイト列に分割される。
  4. これら 2 つのバイト列から 2 つの DES 鍵が生成される。
  5. これらの鍵の各々が LM レスポンスの最初の 8 バイトを DES 暗号化する際に用いられる (これにより 8 バイトの暗号文が 2 つ生成される)。
  6. これら 2 つの暗号文の値を結合して 16 バイトのバイト列としたものが、 Lan Manager Session Key となる。

Lan Manager Session Key は LM レスポンスを元にしたものである(LM ハッシュそのものではない)ことに注意。これは、サーバのチャレンジによって値が変化することを意味する。 これはパスワードハッシュのみに依存する LM User Session Key に対する優位点となる。 LM/NTLM User Session Keys は、ユーザがパスワードを変更しない限り、変わることがないが、Lan Manager Session Key は認証を実施する毎に変化する。 このため、Lan Manager Session Key は LM User Session Key より強力である。 とはいえ、これは NTLM User Session Key (認証毎に変化はしないものの 128 ビットの鍵空間を持つ。LM User Session Key と Lan Manager Session Key は両方とも有効な鍵空間が 64 ビットである) よりは脆弱であると考えて良いだろう。

鍵交換

「Negotiate Key Exchange」フラグがネゴシエートされた 場合、クライアントとサーバは、「第二の」鍵について合意したことになる。これは session key の代わりに認証と署名に用いられる。この処理は以下のようにして行なわれる。

  1. クライアントはランダムな 16 バイトの鍵を選択する(第二の鍵)。
  2. セッション鍵(User Session Key か Lan Manager Session Key のいずれか。「Negotiate Lan Manager Key」の設定に依存する) を用いて、第二の鍵が RC4 暗号化される。この結果、16 バイトの暗号文が生成される。
  3. この値が Type 3 メッセージの「Session Key」フィールドに格納されてサーバに送出される。
  4. サーバは Type 3 メッセージを受信すると、クライアントから送信された値(User Session Key もしくは Lan Manager Session Key が RC4 暗号化されたもの)を復号化する。
  5. これにより、第二の鍵が復元される。これが署名や暗号化の際に、セッション鍵に代わって用いられる。

なお、この鍵交換の処理により、NTLM2 セッションセキュリティにおける署名のプロトコルが巧みに変更されている(詳細は以下で記載する)。

鍵の弱体化

署名と暗号化に用いられる鍵は暗号の輸出制限により、「弱体化」されている。鍵長は、「Negotiate 128」および「Negotiate 56」フラグで決定される。最終的な鍵の強度は、クライアントとサーバの双方でサポートされる最大強度のものとなる。いずれのフラグも設定されない場合、デフォルトの 40 ビットの鍵長が用いられる。NTLM1 の署名と暗号化は 40 ビットと 56 ビットの鍵をサポートしている。 NTLM2 セッションセキュリティは 40ビット、56ビット、弱体化されていない 128 ビットの鍵をサポートしている。

NTLM1 Session Security

NTLM1 は「オリジナル」の NTLMSSP の署名および暗号化スキームであり、「Negotiate NTLM2 Key」フラグがネゴシエートされなかった場合に用いられる。このスキームにおける鍵の生成は、以下の NTLM フラグにより制御される。

Negotiate Lan Manager Key これが設定されている場合、(User Session Key ではなく) Lan Manager Session Key が署名や認証の際に用いられる。 このフラグが確立されなかった場合は、User Session Key が用いられる。
Negotiate 56 56 ビットの鍵のサポートを示す。これがネゴシエートされなかった場合、40 ビットの鍵が用いられる。これは「Negotiate Lan Manager Key」と組み合わせる場合のみ、設定可能である。 NTLM1 における User Session Key は弱体化させることはできない(すでに弱体化しているため)。
Negotiate Key Exchange 鍵交換を行ない、署名および暗号化に第二の鍵を用いることを示す。

NTLM1 Key Derivation

NTLM1 の鍵は、大きく以下の 3 段階に分けて生成される。

  1. Master key negotiation
  2. Key exchange
  3. 鍵の弱体化

Master Key Negotiation

ネゴシエーションの第一段階は、最終的な署名と暗号化のための鍵を生成するための 128 ビット「マスタ鍵」のネゴシエートである。これは NTLM フラグの「Negotiate Lan Manager Key」により制御される。このフラグが設定されていた場合、Lan Manager Session Key がマスタ鍵として用いられる。それ以外の場合は、User Session Key が用いられる。

ここまでの例と同様に、ユーザのパスワードが「SecREt01」だとしよう。また「Negotiate Lan Manager Key」が設定されておらず、NTLM レスポンスが Type 3 メッセージにおいて提供されていたとすると、マスタ鍵として NTLM User Session Key が用いられることになる。 これは NTLM ハッシュ(これ自体が Unicode パスワードの MD4 ハッシュである)の MD4 ダイジェストをとったものであり、以下のバイト列となる。

0x3f373ea8e4af954f14faa506f8eebdc4

Key Exchange

「Negotiate Key Exchange」フラグが設定されていた場合、クライアントは Type 3 メッセージの「Session Key」フィールドに先ほどのマスタ鍵で RC4 暗号化した新しいマスタ鍵を格納する。 サーバはこの値を復号化して、新しいマスタ鍵を取得する。

一例として、クライアントがランダムなマスタ鍵として、「0xf0f0aabb00112233445566778899aabb」を選択したとする。クライアントはこのバイト列をネゴシエート済のマスタ鍵(「0x3f373ea8e4af954f14faa506f8eebdc4」)を用いて RC4 暗号化し、以下の値を生成する。

0x1d3355eb71c82850a9a2d65c2952e6f3

これを Type 3 メッセージの「Session Key」フィールドに格納して、サーバに送付する。 サーバはこの値を古いマスタ鍵を用いて RC4 復号化し、クライアントが生成した新しいマスタ鍵(「0xf0f0aabb00112233445566778899aabb」)を復元する。

鍵の弱体化

最終的に、鍵は輸出規制を満たすため弱体化される。 NTLM1 は 40 ビットと 56 ビットの鍵をサポートする。NTLM フラグの「Negotiate 56」が設定されていた場合、128 ビットのマスタ鍵は、56 ビットに弱体化される。それ以外の場合、これは 40 ビットに弱体化される。 鍵の弱体化処理は、NTLM1 において Lan Manager Session Key を用いている場合(「Negotiate Lan Manager Key」が設定されている場合)にのみ実施される。LM および NTLM User Session Key はレスポンスではなく、パスワードハッシュを元にしており、NTLM1 の場合、あるパスワードからは常に同一の User Session Key が生成される。User Session Key はユーザのパスワードハッシュから用意に復元できてしまうため、明示的な弱体化は必要とされないと考えられる。

NTLM1 における鍵の弱体化処理は、以下のようにして行なわれる。

0x0102030405060708090a0b0c0d0e0f00」というマスタ鍵を例にとると、署名と暗号化に用いる 40 ビットの鍵は、「0x0102030405e538b0」となる。56 ビットの鍵がネゴシエートされた場合、最終的な鍵は「0x01020304050607a0」となる。

署名

ネゴシエートされた鍵は、メッセージの整合性を提供するデジタル署名に使うことが可能となる。 署名をサポートするためには、NTLM フラグの「Negotiate Sign」が設定されていることが必要である。

NTLM1 署名(SSPI の MakeSignature 関数によって実行される) は以下のようにして行なわれる。

  1. ネゴシエート済の鍵を用いて、RC4 暗号鍵が初期化される。これは一度だけ(最初に署名の処理が行なわれる際に)行なわれ、鍵は再設定されない。
  2. メッセージの CRC32 チェックサムが計算される。これは long 値(32ビットのリトルエンディアンの値)となる。
  3. シーケンス番号が取得される。この番号は 0 から始まり、メッセージが署名されるたびに増加していく。この番号は long 値をとる。
  4. CRC32 の値とシーケンス番号の値に 4 バイトの値 0 のバイト列が結合され、12 バイトの値が生成される(「0x00000000」 + CRC32(message) + sequenceNumber)。
  5. この値が先ほど初期化された RC4 暗号によって暗号化される。
  6. 暗号文の最初の 4 バイトが仮想乱数生成器の生成した値によって上書きされる(実際の値は重要でない)。
  7. このバイト列にバージョン番号 (「0x01000000」)が結合されて、署名が生成される。

一例として、メッセージ「jCIFS(16 進数で「0x6a43494653」)」に先ほど生成した 40 ビットの鍵を用いて署名してみよう。

  1. CRC32 チェックサムが計算される(リトルエンディアンの 16 進数で「0xa0310bb7」となる)。
  2. シーケンス番号が取得される。ここでは署名する最初のメッセージだと仮定しよう。シーケンス番号は 0 (「0x00000000」)となる。
  3. 4 バイトの値 0 のバイトが CRC32 の値とシーケンス番号と結合されて、12 バイトの値(「0x00000000a0310bb700000000」)となる。
  4. この値が、RC4 の鍵(「0x0102030405e538b0」)を用いて RC4 暗号化される。これにより、「0xecbf1ced397420fe0e5a0f89」という暗号文が生成される。
  5. 最初の 4 バイトがランダムな値で上書きされる。仮に「0x78010900」とした場合、生成される値は「0x78010900397420fe0e5a0f89」となる。
  6. バージョン値が結合され、最終的な署名が形成される。

    0x0100000078010900397420fe0e5a0f89

次のメッセージは、シーケンス番号 1 として署名される。再度注記するが、最初の署名時に初期化された RC4 鍵については、再度初期化されることはない。

暗号化

メッセージの整合性に加えて、暗号化により、メッセージの機密性も提供される。NTLM フラグの「Negotiate Seal」により、暗号化のサポートが示される。 SSPI 上の NTLM プロバイダにおいて、暗号化は必ず署名と共に行なわれる(メッセージを暗号化すると同時に署名も生成される)。署名と暗号化には、同一の RC4 鍵が用いられる。

NTLM1 暗号化 (SSPI の EncryptMessage 関数によって実行される) は以下のようにして行なわれる。

  1. RC4 暗号が、ネゴシエート済の鍵を用いて初期化される。これは一度だけ(最初に暗号化処理が行なわれる際に)行なわれる。鍵が再設定されることはない。
  2. メッセージが RC4 暗号鍵を用いて暗号化される。これにより暗号文が生成される。
  3. メッセージに対する署名が前述したようにして生成され、security trailer buffer に格納される。

一例として、「jCIFS(16 進数で「0x6a43494653」)」というメッセージを「0x0102030405e538b0」という 40 ビットの鍵を用いて暗号化してみよう。

  1. RC4 暗号が鍵(「0x0102030405e538b0」)を用いて初期化される。
  2. メッセージに RC4 暗号が行なわれ、以下の暗号文「0x86fc55abca」が生成される。これが暗号化されたメッセージとなる。
  3. メッセージの CRC32 チェックサムが計算される(16 進数のリトルエンディアン値「0xa0310bb7」となる)。
  4. シーケンス番号が取得される。ここでは最初の暗号化処理だと仮定しよう。シーケンス番号は 0 (「tt>0x00000000」)となる。
  5. CRC32 の値とシーケンス番号に 4 バイトの値 0 のバイト列が結合され、12 バイトの値(「0x00000000a0310bb700000000」)が生成される。
  6. この値が暗号から生成された鍵を用いて RC4 暗号化される。これにより、暗号文「0x452b490efa3e828bcc8affc3」が生成される。
  7. 最初の 4 バイトがランダムな値で上書きされる。仮に「0x78010900」とした場合、生成される値は「0x78010900fa3e828bcc8affc3」となる。
  8. バージョン値が結合され、最終的な署名が形成される。これがsecurity trailer buffer に格納される値である。

    0x0100000078010900fa3e828bcc8affc3

    暗号化された構造体全体を 16 進数でダンプすると以下のようになる。

    0x86fc55abca0100000078010900fa3e828bcc8affc3

NTLM2 Session Security

NTLM2 は新しい署名と暗号化のスキームであり、「Negotiate NTLM2 Key」がネゴシエートされた場合に用いられる。このスキームによる鍵の種類は、以下の NTLM フラグにより制御される。

Negotiate NTLM2 Key NTLM2 session security のサポートを示す。
Negotiate 56 56 ビット鍵のサポートを示す。このフラグと「Negotiate 128」フラグのいずれも指定されない場合、40 ビットの鍵が用いられる。
Negotiate 128 128 ビット鍵のサポートを示す。このフラグと「Negotiate 56」フラグのいずれも指定されない場合、40 ビットの鍵が用いられる。
Negotiate Key Exchange 鍵交換を行ない、署名および暗号化に第二の鍵を用いることを示す。

NTLM2 鍵の生成

NTLM2 における鍵の生成は、以下の 4 段階で行なわれる。

  1. マスタ鍵のネゴシエート
  2. 鍵交換
  3. 鍵の弱体化
  4. Subkey の生成

マスタ鍵のネゴシエーション

NTLM2 の署名および暗号化を行なう上での基本となるマスタ鍵としては、常に User Session Key が用いられる。NTLMv2 認証が行なわれる場合、LMv2 もしくは NTLMv2 User Session Key のいずれかがマスタ鍵として用いられる。NTLMv1 認証がNTLM2 セッションセキュリティを使用して行なわれた場合、NTLM2 Session Response User Session Key がマスタ鍵として用いられる。NTLM2 で用いられる User Session Key は NTLM1 における対応する鍵や、Lan Manager Session Key と比較すると非常に強力であり、サーバのチャレンジと client nonce の両方が組み込まれている。

鍵交換

鍵交換は、前述した NTLM1 と同様にして行なわれる。 クライアントは第二のマスタ鍵を生成し、基本となるマスタ鍵を用いてRC4 暗号化を行なって、生成された暗号文を Type 3 メッセージの「Session Key」フィールドに格納して、サーバに送出する。これは、「Negotiate Key Exchange」フラグが設定されていた場合に行なわれる。

鍵の弱体化

NTLM2 における鍵の弱体化は単純にマスタ鍵(鍵交換が行なわれる場合は第二のマスタ鍵)を適切な長さに切り詰めることで実行される。一例を示すと、マスタ鍵が「0xf0f0aabb00112233445566778899aabb」の場合、これを 40 ビットに弱体化したものは「0xf0f0aabb00」となり、56ビットにしたものは、「0xf0f0aabb001122」となる。 NTLM2 では 128 ビットの鍵がサポートされており、subkey の生成に際しては、このマスタ鍵が(弱体化なしに)そのまま用いられることに注意。

NTLM2 においてマスタ鍵が弱体化されるのは、暗号化の subkey を生成する場合に限られる。署名用の鍵としては、128 ビットのマスタ鍵が常に用いられる。

Subkey の生成

NTLM2 において、4 つの subkey が生成される。マスタ鍵自体がメッセージの署名や暗号化に直接用いられることは決してない。subkey は以下のようにして生成される。

  1. 128 ビットの(弱体化されていない) マスタ鍵が NULL 終端された以下の ASCII 文字定数

    session key to client-to-server signing key magic constant

    と結合される。16 進数でこの定数を表現したものが以下である。

    0x73657373696f6e206b657920746f2063
      6c69656e742d746f2d73657276657220
      7369676e696e67206b6579206d616769
      6320636f6e7374616e7400

    改行しているのは、表示上の便宜を図ったものである。これに対して、MD5 メッセージダイジェストのアルゴリズムが適用され、16 バイトのバイト列が生成される。これがクライアントがメッセージに対する署名を生成する際に用いられる、Client Signing Key となる。

  2. 弱体化されないマスタ鍵が NULL 終端された以下の ASCII 文字定数

    session key to server-to-client signing key magic constant

    と結合される。16 進数でこの定数を表現したものが以下である。

    0x73657373696f6e206b657920746f2073
      65727665722d746f2d636c69656e7420
      7369676e696e67206b6579206d616769
      6320636f6e7374616e7400

    この値に対して MD5 ダイジェストが取得され、16 バイトの Server Signing Key が生成される。 これがサーバがメッセージに対する署名を生成する際に用いられる鍵となる。

  3. 弱体化された (ネゴシエートの結果に応じて、40 ビット、56 ビット、128 ビットのいずれかとなる)マスタ鍵に NULL 終端された以下の ASCII 文字定数

    session key to client-to-server sealing key magic constant

    が結合される。16 進数でこの定数を表現すると、以下となる。

    0x73657373696f6e206b657920746f2063
      6c69656e742d746f2d73657276657220
      7365616c696e67206b6579206d616769
      6320636f6e7374616e7400

    16 バイトの Client Sealing Key を生成するために、MD5 ダイジェストが適用される。この鍵は、クライアントがメッセージを暗号化する際に用いられる。

  4. 弱体化されたマスタ鍵に NULL 終端された以下の ASCII 文字定数

    session key to server-to-client sealing key magic constant

    が結合される。16 進数でこの定数を表現すると、以下となる。

    0x73657373696f6e206b657920746f2073
      65727665722d746f2d636c69656e7420
      7365616c696e67206b6579206d616769
      6320636f6e7374616e7400

    このバイト列に MD5 ダイジェストアルゴリズムが適用され、16 バイトのServer Sealing Key が生成される。 この鍵は、サーバがメッセージの暗号化を行なう際に用いられる。

署名

署名のサポートは、NTLM フラグの「Negotiate Sign」によって行なわれる。クライアントによる署名は、Client Singing Key によって行なわれ、サーバの署名は、Server Signing Key によって行なわれる。署名用の鍵は、弱体化されていないマスタ鍵によって(前述したようにして)生成されている。

NTLM2 署名は (SSPI の MakeSignature 関数によって実行される) 以下のようにして行なわれる。

  1. シーケンス番号が取得される。これは 0 から始まり、メッセージが署名されるたびに増加していく。この番号は long 値(32ビットのリトルエンディアン値)で表現されている。
  2. シーケンス番号がメッセージと結合される。このバイト列に適切な署名用の鍵を用いて HMAC-MD5 メッセージ認証コードのアルゴリズムが適用される。この結果、16 バイトのバイト列が生成される。
  3. 鍵交換がネゴシエートされていた場合、RC4 暗号が適切な暗号化鍵を用いて初期化される。 これは一度だけ(最初の暗号化処理の際に)行なわれ、keystream が再度初期化されることはない。 HMAC を適用したバイト列の先頭 8 バイトが RC4 暗号を用いて暗号化される。鍵交換がネゴシエートされていない場合、この処理は省略される。
  4. バージョン番号(「0x01000000」) が生成されたバイト列とシーケンス番号に結合され、署名が形成される。

一例として、「jCIFS(16 進数で「0x6a43494653」)」というメッセージをクライアント上で、「0x0102030405060708090a0b0c0d0e0f00」というマスタ鍵を用いて署名してみよう。 このマスタ鍵を定数と結合して、MD5 を適用することで、Client Signing Key (「0xf7f97a82ec390f9c903dac4f6aceb132」)および Client Sealing Key (「0x2785f595293f3e2813439d73a223810d」)が生成される。これらは以下でメッセージを署名する際に用いられる。

  1. シーケンス番号が取得される。ここでは署名する最初のメッセージだとしよう。シーケンス番号は 0 (「0x00000000」)となる。
  2. シーケンス番号をメッセージと結合すると以下のバイト列となる。

    0x000000006a43494653

    HMAC-MD5 が Client Signing Key (「0xf7f97a82ec390f9c903dac4f6aceb132」)を用いて適用される。この結果 16 バイトのバイト列「0x0a003602317a759a720dc9c7a2a95257」が生成される。

  3. RC4 暗号が前述した暗号鍵(「0x2785f595293f3e2813439d73a223810d」)を用いて初期化される。 最初の 8 バイトが暗号処理にかけられ、「0xe37f97f2544f4d7e」という暗号文が生成される。
  4. バージョン番号とシーケンス番号が前述したバイト列に結合され、最終的な署名が形成される。

    0x01000000e37f97f2544f4d7e00000000

暗号化

NTLM フラグの「Negotiate Seal」により、NTLM2 におけるメッセージ機密性のサポートが行なわれる。NTLM2 の機密性 (SSPI の EncryptMessage 関数で実行される) は、以下のようにして行なわれる。

  1. RC4 暗号が適切な暗号鍵(クライアントとサーバのいずれが暗号化を行なうかによって異なる)を用いて初期化される。これは一度だけ(最初に暗号化処理が行なわれる際に)行なわれる。この keystream が再初期化されることはない。
  2. メッセージが RC4 暗号を用いて暗号化される。これにより暗号化された暗号文が生成される。
  3. 前述したようにしてメッセージの署名が生成され、security trailer buffer に格納される。署名で用いられる RC4 暗号はすでに初期化されている(前述した処理で)ことに注意。署名処理において、再初期化されることはない。

一例として、「jCIFS(16進数で「0x6a43494653」)」)というメッセージを「0x0102030405060708090a0b0c0d0e0f00」というマスタ鍵を用いてクライアント側で暗号化することにしよう。 まずは、先の例で示したように、弱体化されていないマスタ鍵を用いて Client Signing Key (「0xf7f97a82ec390f9c903dac4f6aceb132」)を生成する。さらに Client Sealing Key を生成する必要がある。ここでは 40 ビットの脆弱な鍵がネゴシエートされたものとしよう。この弱体化されたマスタ鍵(「0x0102030405」)を定数と結合し、MD5 を適用することで、Client Sealing Key (「0x6f0d99535033951cbe499cd1914fe9ee」)が生成される。 以下の手順で、メッセージが暗号化される。

  1. RC4 暗号が Client Sealing Key (「0x6f0d99535033951cbe499cd1914fe9ee」)で初期化される。
  2. メッセージが RC4 暗号に処理され、「0xcf0eb0a939」という暗号文が生成される。これが暗号化されたメッセージとなる。
  3. シーケンス番号が取得される。ここでは暗号化処理が始めて行なわれるものとしよう。シーケンス番号は 0 (「0x00000000」)となる。
  4. シーケンス番号がメッセージと結合され、以下のバイト列となる。

    0x000000006a43494653

    Client Signing Key (「0xf7f97a82ec390f9c903dac4f6aceb132」)を用いて HMAC-MD5 が適用される。この結果以下の 16 バイトのバイト列「0x0a003602317a759a720dc9c7a2a95257」が生成される。

  5. このバイト列の最初の 8 バイトが暗号化用の暗号に渡され、「0x884b14809e53bfe7」という暗号文が生成される。
  6. バージョン番号が上記の暗号文とシーケンス番号に結合され、最終的な署名が形成される。これが security trailer buffer に格納されるバイト列となる。

    0x01000000884b14809e53bfe700000000

    暗号化された構造体の全体を 16進数でダンプすると、以下のバイト列となる。

    0xcf0eb0a93901000000884b14809e53bfe700000000

Miscellaneous Session Security Topics

その他のセッションセキュリティの事項として以下のようなトピックが存在する。

データグラムの署名と暗号化

これは、データグラムコンテキストが確立された場合(データグラム認証のハンドシェイクが行なわれ、「Negotiate Datagram Style」フラグが設定されることによって)に用いられる。 データグラムセッションのセキュリティは若干複雑である。署名については、クライアントが SSPI の InitializeSecurityContext 関数を最初に呼び出した直後 (サーバに対する通信を行なう前から) から開始することが可能となる。 これは、予め設定した署名と暗号化のスキーム(署名については、サーバとオプションのネゴシエートをする前に生成可能であるため)が前提となる。データグラムのセッションセキュリティは、40 ビットの Lan Manager Session Key と鍵交換のある NTLM1 がベースとなっている(レジストリを操作することで、より強力なスキームを定義することも可能である)。

データグラムモードでは、シーケンス番号の増加は行なわれず、常に 0 固定である。各々の署名には、この値が反映される。 同様に、RC4 keystream も署名および暗号化処理毎に初期化される。これは、既知の平文による攻撃に対する潜在的な脆弱性が存在することを意味するという点で重要である。

「Dummy」署名

これは、SSPI コンテキストがメッセージ整合性がサポートされないまま初期化された際に用いられる。 NTLM フラグの「Negotiate Always Sign」が確立されると、MakeSignature の呼び出しが成功し、固定された「署名」である以下のバイト列が返却される。

0x01000000000000000000000000000000

EncryptMessage の呼び出しは通常通り成功する(「実際の」署名が security trailer buffer に格納される)。 「Negotiate Always Sign」がネゴシエートされなかった場合、署名と暗号化は失敗する。


付録 A: リンクと参考資料

Web の世界は非常に動的かつ刻々と移り変わる性質のものであるため、以下のサイトは存在していないかも知れない。

The jCIFS Project Home Page
http://jcifs.samba.org/
jCIFS はオープンソースな CIFS/SMB の Java による実装である。このドキュメントで提示した実装例は、jCIFS の NTLM 認証の実装を元にしている。 jCIFS は、NTLM HTTP 認証スキームをクライアント、サーバともにサポートしている他、プロトコルに依存しない NTLM クラスも提供している。
The Samba Home Page
http://www.samba.org/
Samba はオープンソースな CIFS/SMB サーバおよびクライアントである。NTLM 認証とセッションセキュリティを実装している他、この本の多くの箇所で参照している。
Implementing CIFS: The Common Internet FileSystem
http://ubiqx.org/cifs/
Chirstopher R. Hertel による非常に情報量豊富なオンライン書籍である。特にこのドキュメントに関係する箇所は、the section on authentication である。
The Open Group ActiveX Core Technology Reference (Chapter 11, "NTLM")
http://www.opengroup.org/comsource/techref2/NCH1222X.HTM
Closest thing to an "official" reference on NTLM. Unfortunately, also rather old and not terribly accurate.
The Security Support Provider Interface
http://www.microsoft.com/windows2000/techinfo/howitworks/security/sspi2000.asp
A whitepaper discussing application development using the SSPI.
NTLM Authentication Scheme for HTTP
http://www.innovation.ch/java/ntlm.html
Informative discussion on the NTLM HTTP authentication mechanism.
Squid NTLM Authentication Project
http://squid.sourceforge.net/ntlm/
Project to provide NTLM HTTP authentication to the Squid proxy server.
Jakarta Commons HttpClient
http://jakarta.apache.org/commons/httpclient/
An open-source Java HTTP client which provides support for the NTLM HTTP authentication scheme.
The GNU Crypto Project
http://www.gnu.org/software/gnu-crypto/
An open-source Java Cryptography Extension provider supplying an implementation of the MD4 message-digest algorithm.
RFC 1320 - The MD4 Message-Digest Algorithm
http://www.ietf.org/rfc/rfc1320.txt
Specification and reference implementation for the MD4 digest (used to calculate the NTLM password hash).
RFC 1321 - The MD5 Message-Digest Algorithm
http://www.ietf.org/rfc/rfc1321.txt
Specification and reference implementation for the MD5 digest (used to calculate the NTLM2 session response).
RFC 2104 - HMAC: Keyed-Hashing for Message Authentication
http://www.ietf.org/rfc/rfc2104.txt
Specification and reference implementation for the HMAC-MD5 algorithm (used in the calculation of the NTLMv2/LMv2 responses).
How to Enable NTLM 2 Authentication
http://support.microsoft.com/default.aspx?scid=KB;en-us;239869
Describes how to enable negotiation of NTLMv2 authentication and enforce NTLM security flags.
Microsoft SSPI Function Documentation
http://windowssdk.msdn.microsoft.com/en-us/library/ms717571.aspx#sspi_functions
Provides an overview of the Security Support Provider Interface (SSPI) and related functions.

Appendix B: Application Protocol Usage of NTLM

This section examines the use of NTLM authentication within some of Microsoft's network protocol implementations.

NTLM HTTP Authentication

Microsoft has established the proprietary "NTLM" authentication scheme for HTTP to provide integrated authentication to IIS web servers. This authentication mechanism allows clients to access resources using their Windows credentials, and is typically used within corporate environments to provide single sign-on functionality to intranet sites. Historically, NTLM authentication was only supported by Internet Explorer; recently, however, support has been added to various other user agents.

The NTLM HTTP authentication mechanism works as follows:

  1. The client requests a protected resource from the server:
        GET /index.html HTTP/1.1
    
  2. The server responds with a 401 status, indicating that the client must authenticate. "NTLM" is presented as a supported authentication mechanism via the "WWW-Authenticate" header. Typically, the server closes the connection at this time:
        HTTP/1.1 401 Unauthorized
        WWW-Authenticate: NTLM
        Connection: close
    

    Note that Internet Explorer will only select NTLM if it is the first mechanism offered; this is at odds with RFC 2616, which states that the client must select the strongest supported authentication scheme.

  3. The client resubmits the request with an "Authorization" header containing a Type 1 message parameter. The Type 1 message is Base-64 encoded for transmission. From this point forward, the connection is kept open; closing the connection requires reauthentication of subsequent requests. This implies that the server and client must support persistent connections, via either the HTTP 1.0-style "Keep-Alive" header or HTTP 1.1 (in which persistent connections are employed by default). The relevant request headers appear as follows (the line break in the "Authorization" header below is for display purposes only, and is not present in the actual message):
        GET /index.html HTTP/1.1
        Authorization: NTLM TlRMTVNTUAABAAAABzIAAAYABgArAAAACwALACAAAABXT1
        JLU1RBVElPTkRPTUFJTg==
    
  4. The server replies with a 401 status containing a Type 2 message in the "WWW-Authenticate" header (again, Base-64 encoded). This is shown below (the line breaks in the "WWW-Authenticate" header are for editorial clarity only, and are not present in the actual header).
        HTTP/1.1 401 Unauthorized
        WWW-Authenticate: NTLM TlRMTVNTUAACAAAADAAMADAAAAABAoEAASNFZ4mrze8
        AAAAAAAAAAGIAYgA8AAAARABPAE0AQQBJAE4AAgAMAEQATwBNAEEASQBOAAEADABTA
        EUAUgBWAEUAUgAEABQAZABvAG0AYQBpAG4ALgBjAG8AbQADACIAcwBlAHIAdgBlAHI
        ALgBkAG8AbQBhAGkAbgAuAGMAbwBtAAAAAAA=
    
  5. The client responds to the Type 2 message by resubmitting the request with an "Authorization" header containing a Base-64 encoded Type 3 message (again, the line breaks in the "Authorization" header below are for display purposes only):
        GET /index.html HTTP/1.1
        Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGoAAAAYABgAggAAAAwADABAAA
        AACAAIAEwAAAAWABYAVAAAAAAAAACaAAAAAQIAAEQATwBNAEEASQBOAHUAcwBlAHIA
        VwBPAFIASwBTAFQAQQBUAEkATwBOAMM3zVy9RPyXgqZnr21CfG3mfCDC0+d8ViWpjB
        wx6BhHRmspst9GgPOZWPuMITqcxg==
    
  6. Finally, the server validates the responses in the client's Type 3 message and allows access to the resource.
        HTTP/1.1 200 OK
    

This scheme differs from most "normal" HTTP authentication mechanisms, in that subsequent requests over the authenticated connection are not themselves authenticated; NTLM is connection-oriented, rather than request-oriented. So a second request for "/index.html" would not carry any authentication information, and the server would request none. If the server detects that the connection to the client has been dropped, a request for "/index.html" would result in the server reinitiating the NTLM handshake.

A notable exception to the above is the client's behavior when submitting a POST request (typically employed when the client is sending form data to the server). If the client determines that the server is not the local host, the client will initiate reauthentication for POST requests over the active connection. The client will first submit an empty POST request with a Type 1 message in the "Authorization" header; the server responds with the Type 2 message (in the "WWW-Authenticate" header as shown above). The client then resubmits the POST with the Type 3 message, sending the form data with the request.

The NTLM HTTP mechanism can also be used for HTTP proxy authentication. The process is similar, except:

With Windows 2000, Microsoft introduced the "Negotiate" HTTP authentication mechanism. While primarily aimed at providing a means of authenticating the user against Active Directory via Kerberos, it is backward-compatible with the NTLM scheme. When the Negotiate mechanism is used in "legacy" mode, the headers passed between the client and server are identical, except "Negotiate" (rather than "NTLM") is indicated as the mechanism name.

NTLM POP3 Authentication

Microsoft's Exchange server provides an NTLM authentication mechanism for the POP3 protocol. This is a proprietary extension used with the POP3 AUTH command as documented in RFC 1734. On the client side, this mechanism is supported by Outlook and Outlook Express, and is called "Secure Password Authentication".

The POP3 NTLM authentication handshake occurs during the POP3 "authorization" state, and works as follows:

  1. The client may request a list of supported authentication mechanisms by sending the AUTH command with no arguments:
        AUTH
    
  2. The server responds with a success message, followed by the list of supported mechanisms; this list should include "NTLM", and is terminated by a line containing a single period (".").
        +OK The operation completed successfully.
        NTLM
        .
    
  3. The client initiates NTLM authentication by sending an AUTH command specifying NTLM as the authentication mechanism:
        AUTH NTLM
    
  4. The server responds with a success message as shown below. Note that there is a space between the "+" and the "OK"; RFC 1734 states that the server should reply with a challenge, but NTLM requires the Type 1 message from the client. So the server sends a "non-challenge", which is basically the message "OK".
        + OK
    
  5. The client then sends the Type 1 message, Base-64 encoded for transmission:
        TlRMTVNTUAABAAAABzIAAAYABgArAAAACwALACAAAABXT1JLU1RBVElPTkRPTUFJTg==
    
  6. The server replies with the Type 2 challenge message (again, Base-64 encoded). This is send in the challenge format specified by RFC 1734 ("+", followed by a space, followed by the challenge message). This is shown below; the line breaks are for editorial clarity and are not present in the server's reply:
        + TlRMTVNTUAACAAAADAAMADAAAAABAoEAASNFZ4mrze8AAAAAAAAAAGIAYgA8AAAA
        RABPAE0AQQBJAE4AAgAMAEQATwBNAEEASQBOAAEADABTAEUAUgBWAEUAUgAEABQAZA
        BvAG0AYQBpAG4ALgBjAG8AbQADACIAcwBlAHIAdgBlAHIALgBkAG8AbQBhAGkAbgAu
        AGMAbwBtAAAAAAA=
    
  7. The client calculates and sends the Base-64 encoded Type 3 response (the line breaks below are for display purposes only):
        TlRMTVNTUAADAAAAGAAYAGoAAAAYABgAggAAAAwADABAAAAACAAIAEwAAAAWABYAVA
        AAAAAAAACaAAAAAQIAAEQATwBNAEEASQBOAHUAcwBlAHIAVwBPAFIASwBTAFQAQQBU
        AEkATwBOAMM3zVy9RPyXgqZnr21CfG3mfCDC0+d8ViWpjBwx6BhHRmspst9GgPOZWP
        uMITqcxg==
    
  8. The server validates the response and indicates the result of authentication:
        +OK User successfully logged on
    

After successful authentication has occurred, the POP3 session enters the "transaction" state, allowing messages to be retrieved by the client.

NTLM IMAP Authentication

Exchange provides an IMAP authentication mechanism similar in form to the POP3 mechanism previously discussed. IMAP authentication is documented in RFC 1730; the NTLM mechanism is a proprietary extension provided by Exchange and supported by the Outlook client family.

The handshake sequence is similar to the POP3 mechanism:

  1. The server may indicate support for the NTLM authentication mechanism in the capability response. Upon connecting to the IMAP server, the client would request the list of server capabilities:
        0000 CAPABILITY
    
  2. The server responds with the list of supported capabilities; the NTLM authentication extension is indicated by the presence of the string "AUTH=NTLM" in the server's reply:
        * CAPABILITY IMAP4 IMAP4rev1 IDLE LITERAL+ AUTH=NTLM
        0000 OK CAPABILITY completed.
    
  3. The client initiates NTLM authentication by sending an AUTHENTICATE command specifying NTLM as the authentication mechanism:
        0001 AUTHENTICATE NTLM
    
  4. The server responds with an empty challenge, consisting simply of a "+":
        +
    
  5. The client then sends the Type 1 message, Base-64 encoded for transmission:
        TlRMTVNTUAABAAAABzIAAAYABgArAAAACwALACAAAABXT1JLU1RBVElPTkRPTUFJTg==
    
  6. The server replies with the Type 2 challenge message (again, Base-64 encoded). This is send in the challenge format specified by RFC 1730 ("+", followed by a space, followed by the challenge message). This is shown below; the line breaks are for editorial clarity and are not present in the server's reply:
        + TlRMTVNTUAACAAAADAAMADAAAAABAoEAASNFZ4mrze8AAAAAAAAAAGIAYgA8AAAA
        RABPAE0AQQBJAE4AAgAMAEQATwBNAEEASQBOAAEADABTAEUAUgBWAEUAUgAEABQAZA
        BvAG0AYQBpAG4ALgBjAG8AbQADACIAcwBlAHIAdgBlAHIALgBkAG8AbQBhAGkAbgAu
        AGMAbwBtAAAAAAA=
    
  7. The client calculates and sends the Base-64 encoded Type 3 response (the line breaks below are for display purposes only):
        TlRMTVNTUAADAAAAGAAYAGoAAAAYABgAggAAAAwADABAAAAACAAIAEwAAAAWABYAVA
        AAAAAAAACaAAAAAQIAAEQATwBNAEEASQBOAHUAcwBlAHIAVwBPAFIASwBTAFQAQQBU
        AEkATwBOAMM3zVy9RPyXgqZnr21CfG3mfCDC0+d8ViWpjBwx6BhHRmspst9GgPOZWP
        uMITqcxg==
    
  8. The server validates the response and indicates the result of authentication:
        0001 OK AUTHENTICATE NTLM completed.
    
After authentication has completed, the IMAP session enters the authenticated state.

NTLM SMTP Authentication

In addition to the NTLM authentication mechanisms provided for POP3 and IMAP, Exchange provides similar functionality for the SMTP protocol. This allows NTLM authentication of users sending outgoing mail messages. This is a proprietary extension used with the SMTP AUTH command (documented in RFC 2554).

The SMTP NTLM authentication handshake operates as follows:

  1. The server may indicate support for NTLM as an authentication mechanism in the EHLO reply. Upon connecting to the SMTP server, the client would send the initial EHLO message:
        EHLO client.example.com
    
  2. The server responds with the list of supported extensions; the NTLM authentication extension is indicated by its presence in the list of AUTH mechanisms as shown below. Note that the AUTH list is sent twice (once with an "=" and once without). The "AUTH=" form was apparently specified in a draft of the RFC; sending both forms ensures that clients implemented against this draft are supported.
        250-server.example.com Hello [10.10.2.20]
        250-HELP
        250-AUTH LOGIN NTLM
        250-AUTH=LOGIN NTLM
        250 SIZE 10240000
    
  3. The client initiates NTLM authentication by sending an AUTH command specifying NTLM as the authentication mechanism and providing the Base-64 encoded Type 1 message as a parameter:
        AUTH NTLM TlRMTVNTUAABAAAABzIAAAYABgArAAAACwALACAAAABXT1JLU1RBVElPTkRPTUFJTg==
    

    According to RFC 2554, the client may opt not to send the initial response parameter (instead merely sending "AUTH NTLM" and waiting for an empty server challenge before replying with the Type 1 message). However, this did not appear to work properly when tested against Exchange.

  4. The server replies with a 334 response containing the Type 2 challenge message (again, Base-64 encoded). This is shown below; the line breaks are for editorial clarity and are not present in the server's reply:
        334 TlRMTVNTUAACAAAADAAMADAAAAABAoEAASNFZ4mrze8AAAAAAAAAAGIAYgA8AAAA
        RABPAE0AQQBJAE4AAgAMAEQATwBNAEEASQBOAAEADABTAEUAUgBWAEUAUgAEABQAZA
        BvAG0AYQBpAG4ALgBjAG8AbQADACIAcwBlAHIAdgBlAHIALgBkAG8AbQBhAGkAbgAu
        AGMAbwBtAAAAAAA=
    
  5. The client calculates and sends the Base-64 encoded Type 3 response (the line breaks below are for display purposes only):
        TlRMTVNTUAADAAAAGAAYAGoAAAAYABgAggAAAAwADABAAAAACAAIAEwAAAAWABYAVA
        AAAAAAAACaAAAAAQIAAEQATwBNAEEASQBOAHUAcwBlAHIAVwBPAFIASwBTAFQAQQBU
        AEkATwBOAMM3zVy9RPyXgqZnr21CfG3mfCDC0+d8ViWpjBwx6BhHRmspst9GgPOZWP
        uMITqcxg==
    
  6. The server validates the response and indicates the result of authentication:
        235 NTLM authentication successful.
    

After authenticating, the client is able to send messages normally.

Appendix C: Sample NTLMSSP Operation Decompositions

This section contains detailed analysis and decomposition of various authentication and signing/sealing operations. This is by no means a comprehensive catalog of possible scenarios, but does include some of the more interesting variants. These were produced by calling the InitializeSecurityContext and AcceptSecurityContext SSPI functions between two peers, and applying subtle manipulations to the resulting NTLM messages. After the context was established, the ExportSecurityContext function was called to dump the contents of the context to a file, for use in subsequent offline analysis. Additionally, the MakeSignature and EncryptMessage functions were used to perform signing and sealing, respectively.

NTLMv1 Authentication; NTLM1 Signing and Sealing Using the NTLM User Session Key

Demonstration of NTLMv1 authentication with NTLM User Session Key NTLM1 signing and sealing (without key exchange).

LMCompatibilityLevel set to 0 (LM/NTLM).

AcquireCredentialsHandle called with domain "TESTNT", user "test", password
"test1234".

--------------------------------------------------------------------------------
InitializeSecurityContext called with ISC_REQ_INTEGRITY and
ISC_REQ_CONFIDENTIALITY.  Following flags were masked off of resulting Type 1
message:

    Negotiate Lan Manager Key      (0x00000080)
    Negotiate NTLM2 Key            (0x00080000)
    Negotiate 128                  (0x20000000)
    Negotiate Key Exchange         (0x40000000)
    Negotiate 56                   (0x80000000)

4e544c4d53535000010000003782000000000000000000000000000000000000

4e544c4d53535000    "NTLMSSP"
01000000            Type 1 message
37820000            Flags
    Negotiate Unicode              (0x00000001)
    Negotiate OEM                  (0x00000002)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
0000000000000000    Supplied Domain header (empty, supplied credentials)
0000000000000000    Supplied Workstation header (empty, supplied credentials)

--------------------------------------------------------------------------------
AcceptSecurityContext called with ASC_REQ_INTEGRITY and ASC_REQ_CONFIDENTIALITY.
Produces Type 2 message:

4e544c4d53535000020000000c000c003000000035828100b019d38bad875c9d
0000000000000000460046003c00000054004500530054004e00540002000c00
54004500530054004e00540001000c004d0045004d0042004500520003001e00
6d0065006d006200650072002e0074006500730074002e0063006f006d000000
0000

4e544c4d53535000    "NTLMSSP"
02000000            Type 2 message
0c000c0030000000    Target Name header (length 12, offset 48)
35828100            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Target Type Domain             (0x00010000)
    Negotiate Target Info          (0x00800000)
b019d38bad875c9d    Challenge
0000000000000000    Context
460046003c000000    Target Information header (length 70, length 60)
54004500530054004e005400    Target Name ("TESTNT")
Target Information block:
    02000c00    NetBIOS Domain Name (length 12)
    54004500530054004e005400    "TESTNT"
    01000c00    NetBIOS Server Name (length 12)
    4d0045004d00420045005200    "MEMBER"
    03001e00    DNS Server Name (length 30)
    6d0065006d006200650072002e0074006500730074002e0063006f006d00
        "member.test.com"
    00000000    Target Information Terminator

--------------------------------------------------------------------------------
InitializeSecurityContext called.  Produces a Type 3 message:

4e544c4d5353500003000000180018006000000018001800780000000c000c00
40000000080008004c0000000c000c0054000000000000009000000035828000
54004500530054004e00540074006500730074004d0045004d00420045005200
1879f60127f8a877022132ec221bcbf3ca016a9f76095606e6285df3287c5d19
4f84df1a94817c7282d09754b6f9e02a

4e544c4d53535000    "NTLMSSP"
03000000            Type 3 message
1800180060000000    LM/LMv2 Response header (length 24, offset 96)
1800180078000000    NTLM/NTLMv2 Response header (length 24, offset 120)
0c000c0040000000    Domain Name header (length 12, offset 64)
080008004c000000    User Name header (length 8, offset 76)
0c000c0054000000    Workstation Name header (length 12, offset 84)
0000000090000000    Session Key header (empty)
35828000            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Negotiate Target Info          (0x00800000)
54004500530054004e005400                            Domain Name ("TESTNT")
7400650073007400                                    User Name ("test")
4d0045004d00420045005200                            Workstation Name ("MEMBER")
1879f60127f8a877022132ec221bcbf3ca016a9f76095606    LM/LMv2 Response
e6285df3287c5d194f84df1a94817c7282d09754b6f9e02a    NTLM/NTLMv2 Response

--------------------------------------------------------------------------------
AcceptSecurityContext called to complete the server-side context.

Server Context Export:

40a42e7840a42e7800000000000000000000000000000000
08ee0b00    server context handle dwUpper
35828101    flags
0000000000000000e8290900e8290900682a0900682a09000000000000000000
d002000000000000000000000000000000000000000000000200000000000000
ffffffffffffff7f20010000
ae33a32dca8c9821844f740d5b3f4d6c    outbound signing key
ae33a32dca8c9821844f740d5b3f4d6c    inbound verifying key
ae33a32dca8c9821844f740d5b3f4d6c    outbound encrypting key
ae33a32dca8c9821844f740d5b3f4d6c    inbound decrypting key
000000000000000000000000
ae3787b72ff94884680d3e5658c064df9d9e5d8f0655f22a002ebc7e9f944e29
08cf90e0057f622d31a92b7d0ca6f586d5d36e24af70cdbe52ea49d067aa4ffa
e85a5cb1a41e3241a288f8de8a4c8909593cc698b657750af014b26f13778eee
855310d716f61ce5c795a0a3bbac358bb02611c954a54b2791d6e297f1fd8c6d
18fffc190b9c69b80122f7c8fb036146c2b581443960fe239b967b17e33de15b
73e445401f1db3a8c5ad51f48d665e38796b8263b9ca363f763aef71d1ec12d8
a76cb46a333b0fddab7850ba3493dcd4077299d22515eb5f300221e9e79a80d9
1a1b4d2865e6ccc3470eda7c4ace04bfbddbedc1cb207483f343c4a1422c7a92
00000000000000000000000000000000
ae3787b72ff94884680d3e5658c064df9d9e5d8f0655f22a002ebc7e9f944e29
08cf90e0057f622d31a92b7d0ca6f586d5d36e24af70cdbe52ea49d067aa4ffa
e85a5cb1a41e3241a288f8de8a4c8909593cc698b657750af014b26f13778eee
855310d716f61ce5c795a0a3bbac358bb02611c954a54b2791d6e297f1fd8c6d
18fffc190b9c69b80122f7c8fb036146c2b581443960fe239b967b17e33de15b
73e445401f1db3a8c5ad51f48d665e38796b8263b9ca363f763aef71d1ec12d8
a76cb46a333b0fddab7850ba3493dcd4077299d22515eb5f300221e9e79a80d9
1a1b4d2865e6ccc3470eda7c4ace04bfbddbedc1cb207483f343c4a1422c7a92
0000000000000000
54004500530054004e0054005c007400650073007400    "TESTNT\test"

ntlmHash = md4(password) = 0x3b1b47e42e0463276e3ded6cef349f93
NTLMUserSessionKey = md4(ntlmHash) = 0xae33a32dca8c9821844f740d5b3f4d6c

Key is *not* weakened (NTLM1 only weakens Lan Manager Session Keys).

Called MakeSignature on the server-side context for message
"0x0102030405060708".

Yields signature:

0100000090010700087de41e039ae5c5

CRC32(0x0102030405060708) = 0xc588ca3f
Sequence number is 0.
0x00000000 + crc32 + seqnum = 0x00000000c588ca3f00000000

RC4(key, 0x00000000c588ca3f00000000) = 0x20961389087de41e039ae5c5

version num + first 4 bytes overwritten with counter value (0x90010700 here):

0100000090010700087de41e039ae5c5 = signature

--------------------------------------------------------------------------------
Called EncryptMessage twice on the server-side context for message
"0x0102030405060708".

Yields encrypted messages:

3ec555aea59eb55001000000a0030700f64393466a9317f7
1caf3c9a114ca2f4010000008803070095c1958123ecafce

same RC4 cipher is used from previous signing operation (i.e., not reset):

RC4(0x0102030405060708) = sealed message = 0x3ec555aea59eb550

trailer buffer gets signature; again uses same RC4 cipher
(sequence number is now 1 because of previous signing):

RC4(0x00000000c588ca3f01000000) = 0x8e8adf2bf64393466a9317f7
version num + first 4 bytes overwritten w/counter (0xa0030700):
01000000a0030700f64393466a9317f7 = trailer signature

second message is same:

RC4(0x0102030405060708) = sealed message = 0x1caf3c9a114ca2f4

trailer buffer signature with sequence 2:

RC4(0x00000000c588ca3f02000000) = 0xf23fc1e495c1958123ecafce
version num + first 4 bytes overwritten w/counter (0x88030700)
010000008803070095c1958123ecafce = trailer signature

NTLMv1 Authentication; NTLM1 Signing and Sealing Using the LM User Session Key

Demonstration of NTLMv1 authentication with LM User Session Key NTLM1 signing and sealing (without key exchange). NTLM response is manually removed from the Type 3 message to force the server-side context to use the LM User Session Key.

LMCompatibilityLevel set to 0 (LM/NTLM).

AcquireCredentialsHandle called with domain "TESTNT", user "test", password
"test1234".

--------------------------------------------------------------------------------
InitializeSecurityContext called with ISC_REQ_INTEGRITY and
ISC_REQ_CONFIDENTIALITY.  Following flags were masked off of resulting Type 1
message:

    Negotiate Lan Manager Key      (0x00000080)
    Negotiate NTLM2 Key            (0x00080000)
    Negotiate 128                  (0x20000000)
    Negotiate Key Exchange         (0x40000000)
    Negotiate 56                   (0x80000000)

4e544c4d53535000010000003782000000000000000000000000000000000000

4e544c4d53535000    "NTLMSSP"
01000000            Type 1 message
37820000            Flags
    Negotiate Unicode              (0x00000001)
    Negotiate OEM                  (0x00000002)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
0000000000000000    Supplied Domain header (empty, supplied credentials)
0000000000000000    Supplied Workstation header (empty, supplied credentials)

--------------------------------------------------------------------------------
AcceptSecurityContext called with ASC_REQ_INTEGRITY and ASC_REQ_CONFIDENTIALITY.
Produces Type 2 message:

4e544c4d53535000020000000c000c0030000000358281006da297169f7aa9c2
0000000000000000460046003c00000054004500530054004e00540002000c00
54004500530054004e00540001000c004d0045004d0042004500520003001e00
6d0065006d006200650072002e0074006500730074002e0063006f006d000000
0000

4e544c4d53535000    "NTLMSSP"
02000000            Type 2 message
0c000c0030000000    Target Name header (length 12, offset 48)
35828100            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Target Type Domain             (0x00010000)
    Negotiate Target Info          (0x00800000)
6da297169f7aa9c2    Challenge
0000000000000000    Context
460046003c000000    Target Information header (length 70, offset 60)
54004500530054004e005400    Target Name ("TESTNT")
Target Information block:
    02000c00    NetBIOS Domain Name (length 12)
    54004500530054004e005400    "TESTNT"
    01000c00    NetBIOS Server Name (length 12)
    4d0045004d00420045005200    "MEMBER"
    03001e00    DNS Server Name (length 30)
    6d0065006d006200650072002e0074006500730074002e0063006f006d00
        "member.test.com"
    00000000    Target Information Terminator

--------------------------------------------------------------------------------
InitializeSecurityContext called.  Produces a Type 3 message; NTLM response
is removed to force usage of the LM User Session Key:

4e544c4d5353500003000000180018004000000000000000000000000c000c00
5800000008000800640000000c000c006c000000000000000000000035828000
2e17884ea16177e2b751d53b5cc756c3cd57cdfd6e3bf8b95400450053005400
4e00540074006500730074004d0045004d00420045005200

4e544c4d53535000    "NTLMSSP"
03000000            Type 3 message
1800180040000000    LM/LMv2 Response (length 24, offset 64)
0000000000000000    NTLM/NTLMv2 Response (empty, removed)
0c000c0058000000    Domain Name header (length 12, offset 88)
0800080064000000    User Name header (length 8, offset 100)
0c000c006c000000    Workstation Name header (length 12, offset 108)
0000000000000000    Session Key header (empty)
35828000            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Negotiate Target Info          (0x00800000)
2e17884ea16177e2b751d53b5cc756c3cd57cdfd6e3bf8b9    LM/LMv2 Response
54004500530054004e005400                            Domain Name ("TESTNT")
7400650073007400                                    User Name ("test")
4d0045004d00420045005200                            Workstation Name ("MEMBER")

--------------------------------------------------------------------------------
AcceptSecurityContext called to complete the server-side context.

Server Context Export:

40a42e7840a42e7800000000000000000000000000000000
08ee0b00    server context handle dwUpper
35828101    flags
0000000000000000f8290900f8290900782a0900782a09000000000000000000
d002000000000000000000000000000000000000000000000200000000000000
ffffffffffffff7f28010000
624aac413795cdc10000000000000000    outbound signing key
624aac413795cdc10000000000000000    inbound verifying key
624aac413795cdc10000000000000000    outbound encrypting key
624aac413795cdc10000000000000000    inbound decrypting key
000000000000000000000000
59ad15f0da768c3d17b6c57d41885c21d530a998e4140743f86c0a45067994a3
4a91002db96aae962b0b7abe77feaf1651ccaa249ae754563ab8abe6c9869ddc
1d1052e3328a6f2564b0f7408eeb6b57e9d268dd73198b5bf3c75a995e1fbffa
bcdf851a958fc2ea49a8d839fc5dd755fb44c4a258600523ed7ea1ee38351bca
29b72f37d075b567a5d4123ee20de5a09b63ffd633183bfd660ef5780ceccb28
6e97c8e0e84e48c16d7b114cbaa622b4c62708655f1e20c32cf2bb7fb136f672
accf84027c3101d1902eb2932ab3e13f4271826209343c1c61269cd3f4509253
80cd47f946f1efc00313cedb4fa49e879fbd04a7748969d970830f4b8dde814d
00000000000000000000000000000000
59ad15f0da768c3d17b6c57d41885c21d530a998e4140743f86c0a45067994a3
4a91002db96aae962b0b7abe77feaf1651ccaa249ae754563ab8abe6c9869ddc
1d1052e3328a6f2564b0f7408eeb6b57e9d268dd73198b5bf3c75a995e1fbffa
bcdf851a958fc2ea49a8d839fc5dd755fb44c4a258600523ed7ea1ee38351bca
29b72f37d075b567a5d4123ee20de5a09b63ffd633183bfd660ef5780ceccb28
6e97c8e0e84e48c16d7b114cbaa622b4c62708655f1e20c32cf2bb7fb136f672
accf84027c3101d1902eb2932ab3e13f4271826209343c1c61269cd3f4509253
80cd47f946f1efc00313cedb4fa49e879fbd04a7748969d970830f4b8dde814d
0000000000000000
54004500530054004e0054005c007400650073007400    "TESTNT\test"

lmHash = lmEncrypt(password, "KGS!@#$%") = 0x624aac413795cdc1ff17365faf1ffe89
LMUserSessionKey = trunc(lmHash) = 0x624aac413795cdc10000000000000000

Key is *not* weakened (NTLM1 only weakens Lan Manager Session Keys).

Called MakeSignature on the server-side context for message
"0x0102030405060708".

Yields signature:

0100000090010700cacc888006466cb5

CRC32(0x0102030405060708) = 0xc588ca3f
Sequence number is 0.
0x00000000 + crc32 + seqnum = 0x00000000c588ca3f00000000

RC4(key, 0x00000000c588ca3f00000000) = 0xdd0e70b1cacc888006466cb5

version num + first 4 bytes overwritten with counter value (0x90010700 here):

0100000090010700cacc888006466cb5 = signature

--------------------------------------------------------------------------------
Called EncryptMessage twice on the server-side context for message
"0x0102030405060708".

Yields encrypted messages:

48793abbf0145ddb01000000a0030700e286c6021ffc3742
09613b9790f7d40e0100000088030700fb8e614d1cf2284c

same RC4 cipher is used from previous signing operation (i.e., not reset):

RC4(0x0102030405060708) = sealed message = 0x48793abbf0145ddb

trailer buffer gets signature; again uses same RC4 cipher
(sequence number is now 1 because of previous signing):

RC4(0x00000000c588ca3f01000000) = 0x623bc698e286c6021ffc3742
version num + first 4 bytes overwritten w/counter (0xa0030700):
01000000a0030700e286c6021ffc3742 = trailer signature

second message is same:

RC4(0x0102030405060708) = sealed message = 0x09613b9790f7d40e

trailer buffer signature with sequence 2:

RC4(0x00000000c588ca3f02000000) = 0x85433470fb8e614d1cf2284c
version num + first 4 bytes overwritten w/counter (0x88030700)
0100000088030700fb8e614d1cf2284c = trailer signature

NTLMv1 Authentication; NTLM1 Signing and Sealing Using the 56-bit Lan Manager Session Key

Demonstration of NTLMv1 authentication with 56-bit Lan Manager Session Key NTLM1 signing and sealing (without key exchange).

LMCompatibilityLevel set to 0 (LM/NTLM).

AcquireCredentialsHandle called with domain "TESTNT", user "test", password
"test1234".

--------------------------------------------------------------------------------
InitializeSecurityContext called with ISC_REQ_INTEGRITY and
ISC_REQ_CONFIDENTIALITY.  Following flags were masked off of resulting Type 1
message:

    Negotiate NTLM2 Key            (0x00080000)
    Negotiate 128                  (0x20000000)
    Negotiate Key Exchange         (0x40000000)

4e544c4d5353500001000000b782008000000000000000000000000000000000

4e544c4d53535000    "NTLMSSP"
01000000            Type 1 message
b7820080            Flags
    Negotiate Unicode              (0x00000001)
    Negotiate OEM                  (0x00000002)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate Lan Manager Key      (0x00000080)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Negotiate 56                   (0x80000000)
0000000000000000    Supplied Domain header (empty, supplied credentials)
0000000000000000    Supplied Workstation header (empty, supplied credentials)

--------------------------------------------------------------------------------
AcceptSecurityContext called with ASC_REQ_INTEGRITY and ASC_REQ_CONFIDENTIALITY.
Produces Type 2 message:

4e544c4d53535000020000000c000c0030000000b5828180c77c1fcdb77ad042
0000000000000000460046003c00000054004500530054004e00540002000c00
54004500530054004e00540001000c004d0045004d0042004500520003001e00
6d0065006d006200650072002e0074006500730074002e0063006f006d000000
0000

4e544c4d53535000    "NTLMSSP"
02000000            Type 2 message
0c000c0030000000    Target Name header (length 12, offset 48)
b5828180            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate Lan Manager Key      (0x00000080)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Target Type Domain             (0x00010000)
    Negotiate Target Info          (0x00800000)
    Negotiate 56                   (0x80000000)
c77c1fcdb77ad042    Challenge
0000000000000000    Context
460046003c000000    Target Information header (length 70, offset 60)
54004500530054004e005400    Target Name ("TESTNT")
Target Information block:
    02000c00    NetBIOS Domain Name (length 12)
    54004500530054004e005400    "TESTNT"
    01000c00    NetBIOS Server Name (length 12)
    4d0045004d00420045005200    "MEMBER"
    03001e00    DNS Server Name (length 30)
    6d0065006d006200650072002e0074006500730074002e0063006f006d00
        "member.test.com"
    00000000    Target Information Terminator

--------------------------------------------------------------------------------
InitializeSecurityContext called.  Produces a Type 3 message:

4e544c4d5353500003000000180018006000000018001800780000000c000c00
40000000080008004c0000000c000c00540000000000000090000000b5828080
54004500530054004e00540074006500730074004d0045004d00420045005200
2e1580af209c1579bbd95a0c9568e2a7455764064cd8ff8c75791b1820178018
c9d00365a5dedfaa455ef8c3b3ad1c1c

4e544c4d53535000    "NTLMSSP"
03000000            Type 3 message
1800180060000000    LM/LMv2 Response header (length 24, offset 96)
1800180078000000    NTLM/NTLMv2 Response header (length 24, offset 120)
0c000c0040000000    Domain Name header (length 12, offset 64)
080008004c000000    User Name header (length 8, offset 76)
0c000c0054000000    Workstation Name header (length 12, offset 84)
0000000090000000    Session Key header (empty)
b5828080            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate Lan Manager Key      (0x00000080)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Negotiate Target Info          (0x00800000)
    Negotiate 56                   (0x80000000)
54004500530054004e005400                            Domain Name ("TESTNT")
7400650073007400                                    User Name ("test")
4d0045004d00420045005200                            Workstation Name ("MEMBER")
2e1580af209c1579bbd95a0c9568e2a7455764064cd8ff8c    LM/LMv2 Response
75791b1820178018c9d00365a5dedfaa455ef8c3b3ad1c1c    NTLM/NTLMv2 Response


--------------------------------------------------------------------------------
AcceptSecurityContext called to complete the server-side context.

Server Context Export:

40a42e7840a42e7800000000000000000000000000000000
08ee0b00    server context handle dwUpper
b5828181    flags, also has an unknown flag set
0000000000000000e8290900e8290900682a0900682a09000000000000000000
d002000000000000000000000000000000000000000000000200000000000000
ffffffffffffff7f20010000
f41c7848bec59daa4cfe52156645f77b
f41c7848bec59daa4cfe52156645f77b
f41c7848bec59daa4cfe52156645f77b
f41c7848bec59daa4cfe52156645f77b
000000000000000000000000
f41115be030662aca4a022504869d30421ae431964da92b42af589ea8a4e5f5e
4c140ab6b342bacb3405ce25e787e5176f30108229c538b5db44e86b1367ad86
573b5294818d6e5174f683c10ecf2ec7a27831dd1efbeeb2fe7302e48b402061
af07bf45d5bcfacc36b81c3e3d6018128e79a54b93998097ab66b798720bbd47
d96a6890d2c2f0ffcdc985a9955ae09fc36c54f17f71d0287d8fdea34df35688
6dc6bb1dc823241a7e7ac4edefa10d7c26d18c77639675d40ce37bebf75cd62c
ecfd84769a3fb15ba82d2f53d74f32fca7e6aa0f279bb02b41084ae1f8dff2e9
e2399c003aa6b95d5833ca1b37dc65593c914916099e7001551f9dd8c04635f9
00000000000000000000000000000000
f41115be030662aca4a022504869d30421ae431964da92b42af589ea8a4e5f5e
4c140ab6b342bacb3405ce25e787e5176f30108229c538b5db44e86b1367ad86
573b5294818d6e5174f683c10ecf2ec7a27831dd1efbeeb2fe7302e48b402061
af07bf45d5bcfacc36b81c3e3d6018128e79a54b93998097ab66b798720bbd47
d96a6890d2c2f0ffcdc985a9955ae09fc36c54f17f71d0287d8fdea34df35688
6dc6bb1dc823241a7e7ac4edefa10d7c26d18c77639675d40ce37bebf75cd62c
ecfd84769a3fb15ba82d2f53d74f32fca7e6aa0f279bb02b41084ae1f8dff2e9
e2399c003aa6b95d5833ca1b37dc65593c914916099e7001551f9dd8c04635f9
0000000000000000
54004500530054004e0054005c007400650073007400    "TESTNT\test"

lmHash = lmEncrypt(password, "KGS!@#$%") = 0x624aac413795cdc1ff17365faf1ffe89
trunc(lmHash + pad) = 0x624aac413795cdc1bdbdbdbdbdbd
lmResponse[0-7] = 0x2e1580af209c1579
LanManagerSessionKey =
    lmEncrypt(0x624aac413795cdc1bdbdbdbdbdbd, 0x2e1580af209c1579) =
        0xf41c7848bec59daa4cfe52156645f77b

Key is weakened to 56-bit w/0xa0 = 0xf41c7848bec59da0

Called MakeSignature on the server-side context for message
"0x0102030405060708".

Yields signature:

0100000090010700598d18d8150514cc

CRC32(0x0102030405060708) = 0xc588ca3f
Sequence number is 0.
0x00000000 + crc32 + seqnum = 0x00000000c588ca3f00000000

RC4(key, 0x00000000c588ca3f00000000) = 0x2cfc55af598d18d8150514cc

version num + first 4 bytes overwritten with counter value (0x90010700 here):

0100000090010700598d18d8150514cc = signature

--------------------------------------------------------------------------------
Called EncryptMessage twice on the server-side context for message
"0x0102030405060708".

Yields encrypted messages:

357f77b267a494c101000000a0030700fb2ce7d1bfd23a0a
4db804533e6ffc2301000000880307003736d2b43c149c48

same RC4 cipher is used from previous signing operation (i.e., not reset):

RC4(0x0102030405060708) = sealed message = 0x357f77b267a494c1

trailer buffer gets signature; again uses same RC4 cipher
(sequence number is now 1 because of previous signing):

RC4(0x00000000c588ca3f01000000) = 0x757b9976fb2ce7d1bfd23a0a
version num + first 4 bytes overwritten w/counter (0xa0030700):
01000000a0030700fb2ce7d1bfd23a0a = trailer signature

second message is same:

RC4(0x0102030405060708) = sealed message = 0x4db804533e6ffc23

trailer buffer signature with sequence 2:

RC4(0x00000000c588ca3f02000000) = 0x5eb9ab2f3736d2b43c149c48
version num + first 4 bytes overwritten w/counter (0x88030700)
01000000880307003736d2b43c149c48 = trailer signature

NTLMv1 Authentication; NTLM1 Signing and Sealing Using the 40-bit Lan Manager Session Key

Demonstration of NTLMv1 authentication with 40-bit Lan Manager Session Key NTLM1 signing and sealing (without key exchange).

LMCompatibilityLevel set to 0 (LM/NTLM).

AcquireCredentialsHandle called with domain "TESTNT", user "test", password
"test1234".

--------------------------------------------------------------------------------
InitializeSecurityContext called with ISC_REQ_INTEGRITY and
ISC_REQ_CONFIDENTIALITY.  Following flags were masked off of resulting Type 1
message:

    Negotiate NTLM2 Key            (0x00080000)
    Negotiate 128                  (0x20000000)
    Negotiate Key Exchange         (0x40000000)
    Negotiate 56                   (0x80000000)

4e544c4d5353500001000000b782000000000000000000000000000000000000

4e544c4d53535000    "NTLMSSP"
01000000            Type 1 message
b7820000            Flags
    Negotiate Unicode              (0x00000001)
    Negotiate OEM                  (0x00000002)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate Lan Manager Key      (0x00000080)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
0000000000000000    Supplied Domain header (empty, supplied credentials)
0000000000000000    Supplied Workstation header (empty, supplied credentials)

--------------------------------------------------------------------------------
AcceptSecurityContext called with ASC_REQ_INTEGRITY and ASC_REQ_CONFIDENTIALITY.
Produces Type 2 message:

4e544c4d53535000020000000c000c0030000000b58281007116b94341ee4e70
0000000000000000460046003c00000054004500530054004e00540002000c00
54004500530054004e00540001000c004d0045004d0042004500520003001e00
6d0065006d006200650072002e0074006500730074002e0063006f006d000000
0000

4e544c4d53535000    "NTLMSSP"
02000000            Type 2 message
0c000c0030000000    Target Name header (length 12, offset 48)
b5828100            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate Lan Manager Key      (0x00000080)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Target Type Domain             (0x00010000)
    Negotiate Target Info          (0x00800000)
7116b94341ee4e70    Challenge
0000000000000000    Context
460046003c000000    Target Information header (length 70, offset 60)
54004500530054004e005400    Target Name ("TESTNT")
Target Information block:
    02000c00    NetBIOS Domain Name (length 12)
    54004500530054004e005400    "TESTNT"
    01000c00    NetBIOS Server Name (length 12)
    4d0045004d00420045005200    "MEMBER"
    03001e00    DNS Server Name (length 30)
    6d0065006d006200650072002e0074006500730074002e0063006f006d00
        "member.test.com"
    00000000    Target Information Terminator

--------------------------------------------------------------------------------
InitializeSecurityContext called.  Produces a Type 3 message:

4e544c4d5353500003000000180018006000000018001800780000000c000c00
40000000080008004c0000000c000c00540000000000000090000000b5828000
54004500530054004e00540074006500730074004d0045004d00420045005200
66271e46d60b246d25fcc3340235841057c2821f490d073304c6e94c5624abad
6c922d8e64b6c86d43138f8f0d94fc3f

4e544c4d53535000    "NTLMSSP"
03000000            Type 3 message
1800180060000000    LM/LMv2 Response header (length 24, offset 96)
1800180078000000    NTLM/NTLMv2 Response header (length 24, offset 120)
0c000c0040000000    Domain Name header (length 12, offset 64)
080008004c000000    User Name header (length 8, offset 76)
0c000c0054000000    Workstation Name header (length 12, offset 84)
0000000090000000    Session Key header (empty)
b5828000            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate Lan Manager Key      (0x00000080)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Negotiate Target Info          (0x00800000)
54004500530054004e005400                            Domain Name ("TESTNT")
7400650073007400                                    User Name ("test")
4d0045004d00420045005200                            Workstation Name ("MEMBER")
66271e46d60b246d25fcc3340235841057c2821f490d0733    LM/LMv2 Response
04c6e94c5624abad6c922d8e64b6c86d43138f8f0d94fc3f    NTLM/NTLMv2 Response

--------------------------------------------------------------------------------
AcceptSecurityContext called to complete the server-side context.

Server Context Export:

40a42e7840a42e7800000000000000000000000000000000
08ee0b00    server context handle dwUpper
b5828101    flags
0000000000000000182e0900182e0900982e0900982e09000000000000000000
d002000000000000000000000000000000000000000000000200000000000000
ffffffffffffff7f20010000
b98a3a22c81e31f99e7eca1e123c04d1    outbound signing key
b98a3a22c81e31f99e7eca1e123c04d1    inbound verifying key
b98a3a22c81e31f99e7eca1e123c04d1    outbound encrypting key
b98a3a22c81e31f99e7eca1e123c04d1    inbound decrypting key
000000000000000000000000
b94480a5718a4f50e1a4e815e91021e0a9a387263fbbd69d6e3b03a2027c0e56
1c47582cab375deacb92462f4db09bb32965670de5dc573e7bf20a901fb68ecd
6d697800a1ced9de7a9a79091b5318b104c827bf7791ad3448c606c5e4bca6eb
7da0949e28ec137596fd5cbaeedb08af52898845a75a95e78d63c36bfe054af0
703df1432aef32f3b2d8594e9961b5251d33f9ae8b2b8fc46a2ef520140fc1d1
d3f785428493a8ff3af8cad216da734c556fdfb4384bb8acf4687672367f1a23
835fc20bcfc05bd0fadd31edfb98b78c823cc9cc629faa1924e3d4300c8681bd
7411e6e235be49396601419cd7541251f6605ed51e6cfcc7407e97176407222d
00000000000000000000000000000000
b94480a5718a4f50e1a4e815e91021e0a9a387263fbbd69d6e3b03a2027c0e56
1c47582cab375deacb92462f4db09bb32965670de5dc573e7bf20a901fb68ecd
6d697800a1ced9de7a9a79091b5318b104c827bf7791ad3448c606c5e4bca6eb
7da0949e28ec137596fd5cbaeedb08af52898845a75a95e78d63c36bfe054af0
703df1432aef32f3b2d8594e9961b5251d33f9ae8b2b8fc46a2ef520140fc1d1
d3f785428493a8ff3af8cad216da734c556fdfb4384bb8acf4687672367f1a23
835fc20bcfc05bd0fadd31edfb98b78c823cc9cc629faa1924e3d4300c8681bd
7411e6e235be49396601419cd7541251f6605ed51e6cfcc7407e97176407222d
0000000000000000
54004500530054004e0054005c007400650073007400    "TESTNT\test"

lmHash = lmEncrypt(password, "KGS!@#$%") = 0x624aac413795cdc1ff17365faf1ffe89
trunc(lmHash + pad) = 0x624aac413795cdc1bdbdbdbdbdbd
lmResponse[0-7] = 0x66271e46d60b246d
LanManagerSessionKey =
    lmEncrypt(0x624aac413795cdc1bdbdbdbdbdbd, 0x66271e46d60b246d) =
        0xb98a3a22c81e31f99e7eca1e123c04d1

Key is weakened to 40-bit w/0xe538b0 = 0xb98a3a22c8e538b0

Called MakeSignature on the server-side context for message
"0x0102030405060708".

Yields signature:

01000000ffffff001a7599e9ad0ad460

CRC32(0x0102030405060708) = 0xc588ca3f
Sequence number is 0.
0x00000000 + crc32 + seqnum = 0x00000000c588ca3f00000000

RC4(key, 0x00000000c588ca3f00000000) = 0xbeb185ce1a7599e9ad0ad460

version num + first 4 bytes overwritten with counter value (0xffffff00 here):

01000000ffffff001a7599e9ad0ad460 = signature

--------------------------------------------------------------------------------
Called EncryptMessage twice on the server-side context for message
"0x0102030405060708".

Yields encrypted messages:

075c81a318754894010000006003070033df86be9d65813d
da731ecef152bd750100000048030700a61d753437944ee5

same RC4 cipher is used from previous signing operation (i.e., not reset):

RC4(0x0102030405060708) = sealed message = 0x075c81a318754894

trailer buffer gets signature; again uses same RC4 cipher
(sequence number is now 1 because of previous signing):

RC4(0x00000000c588ca3f01000000) = 0x0004c5b033df86be9d65813d
version num + first 4 bytes overwritten w/counter (0x60030700):
010000006003070033df86be9d65813d = trailer signature

second message is same:

RC4(0x0102030405060708) = sealed message = 0xda731ecef152bd75

trailer buffer signature with sequence 2:

RC4(0x00000000c588ca3f02000000) = 0xf012a98ca61d753437944ee5
version num + first 4 bytes overwritten w/counter (0x48030700)
0100000048030700a61d753437944ee5 = trailer signature

NTLMv1 Datagram-Style Authentication; NTLM1 Signing and Sealing Using the 40-bit Lan Manager Session Key With Key Exchange Negotiated

Demonstration of datagram-style authentication with default options (defaults to 40-bit Lan Manager Session Key NTLM1 with key exchange when used with NTLMv1).

LMCompatibilityLevel set to 0 (LM/NTLM).

AcquireCredentialsHandle called with domain "TESTNT", user "test", password
"test1234".

--------------------------------------------------------------------------------
InitializeSecurityContext called with:
    ISC_REQ_INTEGRITY | ISC_REQ_CONFIDENTIALITY | ISC_REG_DATAGRAM

Produces no token (datagram-style).  Client context can be used for signing
and sealing immediately.

--------------------------------------------------------------------------------
AcceptSecurityContext called with:
    ASC_REQ_INTEGRITY | ASC_REQ_CONFIDENTIALITY | ASC_REG_DATAGRAM

Produces a Type 2 message:

4e544c4d53535000020000000000000030000000f38298e0ada5839570b5cb99
00000000000000000000000030000000

4e544c4d53535000    "NTLMSSP"
02000000            Type 2 message
0000000030000000    Target Name header (empty)
f38298e0            Flags
    Negotiate Unicode              (0x00000001)
    Negotiate OEM                  (0x00000002)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate Datagram Style       (0x00000040)
    Negotiate Lan Manager Key      (0x00000080)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Negotiate NTLM2 Key            (0x00080000)
    Request Init Response          (0x00100000)
    Negotiate Target Info          (0x00800000)
    Negotiate 128                  (0x20000000)
    Negotiate Key Exchange         (0x40000000)
    Negotiate 56                   (0x80000000)
ada5839570b5cb99    Challenge
0000000000000000    Context
0000000030000000    Target Information header (empty)

--------------------------------------------------------------------------------
InitializeSecurityContext called.  Produces a Type 3 message:

4e544c4d5353500003000000180018006000000018001800780000000c000c00
40000000080008004c0000000c000c00540000001000100090000000f5828040
54004500530054004e00540074006500730074004d0045004d00420045005200
e8cff653006525da77c6bef2fed79bc6d7d839f598ead91a4e37300050075eeb
aa5915480c3620b8ee6fa869cdf16e7c9227ebee8b19a312664fa4ed44bd3377

4e544c4d53535000    "NTLMSSP"
03000000            Type 3 message
1800180060000000    LM/LMv2 Response header (length 24, offset 96)
1800180078000000    NTLM/NTLMv2 Response header (length 24, offset 120)
0c000c0040000000    Domain Name header (length 12, offset 64)
080008004c000000    User Name header (length 8, offset 76)
0c000c0054000000    Workstation Name header (length 12, offset 84)
1000100090000000    Session Key header (length 16, offset 144)
f5828040            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate Datagram Style       (0x00000040)
    Negotiate Lan Manager Key      (0x00000080)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Negotiate Target Info          (0x00800000)
    Negotiate Key Exchange         (0x40000000)
54004500530054004e005400                            Domain Name ("TESTNT")
7400650073007400                                    User Name ("test")
4d0045004d00420045005200                            Workstation Name ("MEMBER")
e8cff653006525da77c6bef2fed79bc6d7d839f598ead91a    LM/LMv2 Response
4e37300050075eebaa5915480c3620b8ee6fa869cdf16e7c    NTLM/NTLMv2 Response
9227ebee8b19a312664fa4ed44bd3377                    Session Key

--------------------------------------------------------------------------------
AcceptSecurityContext called to complete the server-side context.

Server Context Export:

40a42e7840a42e7800000000000000000000000000000000
08ee0b00    server context handle dwUpper
f5828041    flags
000000000000000080740a0080740a0000750a0000750a000000000000000000
d002000000000000000000000000000000000000000000000200000000000000
ffffffffffffff7f20010000
d56070a4c355c2d91693d8f3406d4d82    outbound signing key
d56070a4c355c2d91693d8f3406d4d82    inbound verifying key
d56070a4c355c2d91693d8f3406d4d82    outbound encrypting key
d56070a4c355c2d91693d8f3406d4d82    inbound decrypting key
000000000000000000000000
05f9b27f16db3ea4563b296433256b1076cdd372908ac60367f37d5e495c11ab
378f70d165ea3d633ca5f819e2f45a3906328b8993718c7726d78145042099a7
b0dde1c831986f661ef6bc9dc7de558d80ed447e4cdf749b02b346c4227915cc
09cb75c9430fa3ba53c018fa78b7daff9f62b9efd2a92a60845fe5e0278692dc
e983be951f24b6a2ec592194bd352c0cb596fd7ae747fba0a1c5340861b85dc1
91f1aad9fc14e801858251d687a61dbbb157303fd0bf73e4ce526a9c0d0ec250
d454cf2e38ad4dac6c42f0b41223079ef21b7ba83a0a7c5b2debca404f1300e6
d58e582b692f68eee31a88c3ae4a17fe4b484e419a1c280b6e36afd8f56d97f7
00000000000000000000000000000000
05f9b27f16db3ea4563b296433256b1076cdd372908ac60367f37d5e495c11ab
378f70d165ea3d633ca5f819e2f45a3906328b8993718c7726d78145042099a7
b0dde1c831986f661ef6bc9dc7de558d80ed447e4cdf749b02b346c4227915cc
09cb75c9430fa3ba53c018fa78b7daff9f62b9efd2a92a60845fe5e0278692dc
e983be951f24b6a2ec592194bd352c0cb596fd7ae747fba0a1c5340861b85dc1
91f1aad9fc14e801858251d687a61dbbb157303fd0bf73e4ce526a9c0d0ec250
d454cf2e38ad4dac6c42f0b41223079ef21b7ba83a0a7c5b2debca404f1300e6
d58e582b692f68eee31a88c3ae4a17fe4b484e419a1c280b6e36afd8f56d97f7
0000000000000000
54004500530054004e0054005c007400650073007400    "TESTNT\test"

lmHash = lmEncrypt(password, "KGS!@#$%") = 0x624aac413795cdc1ff17365faf1ffe89
trunc(lmHash + pad) = 0x624aac413795cdc1bdbdbdbdbdbd
lmResponse[0-7] = 0xe8cff653006525da
LanManagerSessionKey =
    lmEncrypt(0x624aac413795cdc1bdbdbdbdbdbd, 0xe8cff653006525da) =
        0x97dba8c110cd6b7976c02c203c6be07a

Key exchange performed:
type3Key (from Type 3) = 0x9227ebee8b19a312664fa4ed44bd3377
key = RC4(LanManagerSessionKey, type3Key) =
    0xd56070a4c355c2d91693d8f3406d4d82

Key is weakened to 40-bit w/0xe538b0 = 0xd56070a4c3e538b0

Called MakeSignature on the server-side context for message
"0x0102030405060708".

Yields signature:

010000009801070012c00705ba25a7ec

CRC32(0x0102030405060708) = 0xc588ca3f
Sequence number is 0.
0x00000000 + crc32 + seqnum = 0x00000000c588ca3f00000000

RC4(key, 0x00000000c588ca3f00000000) = 0x39ec604d12c00705ba25a7ec

version num + first 4 bytes overwritten with counter value (0x98010700 here):

010000009801070012c00705ba25a7ec = signature

--------------------------------------------------------------------------------
Called EncryptMessage twice on the server-side context for message
"0x0102030405060708".

Yields encrypted messages:

38ee6349d24eca32010000008803070012c00705ba25a7ec
38ee6349d24eca32010000007003070012c00705ba25a7ec

RC4 cipher is reset after each signing/sealing operation in datagram-style:

RC4(key, 0x0102030405060708) = sealed message = 0x38ee6349d24eca32

trailer buffer gets signature; RC4 cipher is reset and sequence number is
*not* incremented in datagram-style:

RC4(key, 0x00000000c588ca3f00000000) = 0x39ec604d12c00705ba25a7ec
version num + first 4 bytes overwritten w/counter (0x88030700):
010000008803070012c00705ba25a7ec = trailer signature

second message is same:

RC4(key, 0x00000000c588ca3f00000000) = 0x39ec604d12c00705ba25a7ec
version num + first 4 bytes overwritten w/counter (0x70030700):
010000007003070012c00705ba25a7ec = trailer signature

NTLMv1 Authentication; NTLM1 "Dummy" Signing and Sealing Using the NTLM User Session Key

Demonstration of "dummy" signing and sealing. Context is *not* initialized with support for integrity or confidentiality. "Negotiate Always Sign" is negotiated, which allows the context to be used in dummy signing and sealing.

LMCompatibilityLevel set to 0 (LM/NTLM).

AcquireCredentialsHandle called with domain "TESTNT", user "test", password
"test1234".

--------------------------------------------------------------------------------
InitializeSecurityContext called with default options.  Produces Type 1 message:

4e544c4d5353500001000000078200a000000000000000000000000000000000

4e544c4d53535000    "NTLMSSP"
01000000            Type 1 message
078200a0            Flags
    Negotiate Unicode              (0x00000001)
    Negotiate OEM                  (0x00000002)
    Request Target                 (0x00000004)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Negotiate 128                  (0x20000000)
    Negotiate 56                   (0x80000000)
0000000000000000    Supplied Domain header (empty, supplied credentials)
0000000000000000    Supplied Workstation header (empty, supplied credentials)

--------------------------------------------------------------------------------
AcceptSecurityContext called with default options. Produces Type 2 message:

4e544c4d53535000020000000c000c0030000000058281a0eacf7d5a2a6fa7d4
0000000000000000460046003c00000054004500530054004e00540002000c00
54004500530054004e00540001000c004d0045004d0042004500520003001e00
6d0065006d006200650072002e0074006500730074002e0063006f006d000000
0000

4e544c4d53535000    "NTLMSSP"
02000000            Type 2 message
0c000c0030000000    Target Name header (length 12, offset 48)
058281a0            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Target Type Domain             (0x00010000)
    Negotiate Target Info          (0x00800000)
    Negotiate 128                  (0x20000000)
    Negotiate 56                   (0x80000000)
eacf7d5a2a6fa7d4    Challenge
0000000000000000    Context
460046003c000000    Target Information header (length 70, offset 60)
54004500530054004e005400    Target Name ("TESTNT")
Target Information block:
    02000c00    NetBIOS Domain Name (length 12)
    54004500530054004e005400    "TESTNT"
    01000c00    NetBIOS Server Name (length 12)
    4d0045004d00420045005200    "MEMBER"
    03001e00    DNS Server Name (length 30)
    6d0065006d006200650072002e0074006500730074002e0063006f006d00
        "member.test.com"
    00000000    Target Information Terminator

--------------------------------------------------------------------------------
InitializeSecurityContext called.  Produces a Type 3 message:

4e544c4d53535000    "NTLMSSP"
03000000            Type 3 message
1800180060000000    LM/LMv2 Response header (length 24, offset 96)
1800180078000000    NTLM/NTLMv2 Response header (length 24, offset 120)
0c000c0040000000    Domain Name header (length 12, offset 64)
080008004c000000    User Name header (length 8, offset 76)
0c000c0054000000    Workstation Name header (length 12, offset 84)
0000000090000000    Session Key header (empty)
058280a0            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Negotiate Target Info          (0x00800000)
    Negotiate 128                  (0x20000000)
    Negotiate 56                   (0x80000000)
54004500530054004e005400                            Domain Name ("TESTNT")
7400650073007400                                    User Name ("test")
4d0045004d00420045005200                            Workstation Name ("MEMBER")
6c454794b50321a067fdf78e92ee5085a5b0a23057e9125b    LM/LMv2 Response
d2025bc5d6c201af7472550a677ca9904245a16ebb542a8e    NTLM/NTLMv2 Response

--------------------------------------------------------------------------------
AcceptSecurityContext called to complete the server-side context.

Server Context Export:

40a42e7840a42e7800000000000000000000000000000000
08ee0b00    server context handle dwUpper
058281a1    flags
000000000000000028f5080028f50800a8f50800a8f508000000000000000000
d002000000000000000000000000000000000000000000000200000000000000
ffffffffffffff7f20010000
ae33a32dca8c9821844f740d5b3f4d6c    outbound signing key
ae33a32dca8c9821844f740d5b3f4d6c    inbound verifying key
ae33a32dca8c9821844f740d5b3f4d6c    outbound encrypting key
ae33a32dca8c9821844f740d5b3f4d6c    inbound decrypting key
000000000000000000000000
ae3787b72ff94884680d3e5658c064df9d9e5d8f0655f22a002ebc7e9f944e29
08cf90e0057f622d31a92b7d0ca6f586d5d36e24af70cdbe52ea49d067aa4ffa
e85a5cb1a41e3241a288f8de8a4c8909593cc698b657750af014b26f13778eee
855310d716f61ce5c795a0a3bbac358bb02611c954a54b2791d6e297f1fd8c6d
18fffc190b9c69b80122f7c8fb036146c2b581443960fe239b967b17e33de15b
73e445401f1db3a8c5ad51f48d665e38796b8263b9ca363f763aef71d1ec12d8
a76cb46a333b0fddab7850ba3493dcd4077299d22515eb5f300221e9e79a80d9
1a1b4d2865e6ccc3470eda7c4ace04bfbddbedc1cb207483f343c4a1422c7a92
00000000000000000000000000000000
ae3787b72ff94884680d3e5658c064df9d9e5d8f0655f22a002ebc7e9f944e29
08cf90e0057f622d31a92b7d0ca6f586d5d36e24af70cdbe52ea49d067aa4ffa
e85a5cb1a41e3241a288f8de8a4c8909593cc698b657750af014b26f13778eee
855310d716f61ce5c795a0a3bbac358bb02611c954a54b2791d6e297f1fd8c6d
18fffc190b9c69b80122f7c8fb036146c2b581443960fe239b967b17e33de15b
73e445401f1db3a8c5ad51f48d665e38796b8263b9ca363f763aef71d1ec12d8
a76cb46a333b0fddab7850ba3493dcd4077299d22515eb5f300221e9e79a80d9
1a1b4d2865e6ccc3470eda7c4ace04bfbddbedc1cb207483f343c4a1422c7a92
0000000000000000
54004500530054004e0054005c007400650073007400    "TESTNT\test"

ntlmHash = md4(password) = 0x3b1b47e42e0463276e3ded6cef349f93
NTLMUserSessionKey = md4(ntlmHash) = 0xae33a32dca8c9821844f740d5b3f4d6c

Key is *not* weakened (NTLM1 only weakens Lan Manager Session Keys).

Called MakeSignature on the server-side context for message
"0x0102030405060708".

Yields signature:

01000000000000000000000000000000 ("dummy" signature)

--------------------------------------------------------------------------------
Called EncryptMessage twice on the server-side context for message
"0x0102030405060708".

Yields encrypted messages:

2194108dc8f329290100000048020700fa4f9c95a098b258
8f88dc2f36cd5e710100000030020700d825f5a1154aa5fc

RC4(key, 0x0102030405060708) = sealed message = 0x2194108dc8f32929

trailer buffer gets signature; uses same RC4 cipher as sealing
(sequence number is 0, previous dummy signing doesn't count):

RC4(0x00000000c588ca3f00000000) = 0x039ae5c5fa4f9c95a098b258
version num + first 4 bytes overwritten w/counter (0x48020700):
0100000048020700fa4f9c95a098b258 = trailer signature

second message is same:

RC4(0x0102030405060708) = sealed message = 0x8f88dc2f36cd5e71

trailer buffer signature with sequence 1 (previous trailer signature
incremented it):

RC4(0x00000000c588ca3f01000000) = 0x6b9317f7d825f5a1154aa5fc
version num + first 4 bytes overwritten w/counter (0x30020700)
0100000030020700d825f5a1154aa5fc = trailer signature

NTLM2 Session Response Authentication; NTLM2 Signing and Sealing Using the 128-bit NTLM2 Session Response User Session Key With Key Exchange Negotiated

Demonstration of NTLMv1 authentication with 128-bit NTLM2 Session Response User Session Key NTLM2 signing and sealing, with key exchange enabled.

LMCompatibilityLevel set to 0 (LM/NTLM).

AcquireCredentialsHandle called with domain "TESTNT", user "test", password
"test1234".

--------------------------------------------------------------------------------
InitializeSecurityContext called with ISC_REQ_INTEGRITY and
ISC_REQ_CONFIDENTIALITY.

4e544c4d5353500001000000b78208e000000000000000000000000000000000

4e544c4d53535000    "NTLMSSP"
01000000            Type 1 message
b78208e0            Flags
    Negotiate Unicode              (0x00000001)
    Negotiate OEM                  (0x00000002)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate Lan Manager Key      (0x00000080)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Negotiate NTLM2 Key            (0x00080000)
    Negotiate 128                  (0x20000000)
    Negotiate Key Exchange         (0x40000000)
    Negotiate 56                   (0x80000000)
0000000000000000    Supplied Domain header (empty, supplied credentials)
0000000000000000    Supplied Workstation header (empty, supplied credentials)

--------------------------------------------------------------------------------
AcceptSecurityContext called with ASC_REQ_INTEGRITY and ASC_REQ_CONFIDENTIALITY.
Produces Type 2 message:

4e544c4d53535000020000000c000c0030000000358289e0677f1c557a5ee96c
0000000000000000460046003c00000054004500530054004e00540002000c00
54004500530054004e00540001000c004d0045004d0042004500520003001e00
6d0065006d006200650072002e0074006500730074002e0063006f006d000000
0000

4e544c4d53535000    "NTLMSSP"
02000000            Type 2 message
0c000c0030000000    Target Name header (length 12, offset 48)
358289e0            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Target Type Domain             (0x00010000)
    Negotiate NTLM2 Key            (0x00080000)
    Negotiate Target Info          (0x00800000)
    Negotiate 128                  (0x20000000)
    Negotiate Key Exchange         (0x40000000)
    Negotiate 56                   (0x80000000)
677f1c557a5ee96c    Challenge
0000000000000000    Context
460046003c000000    Target Information header (length 70, offset 60)
54004500530054004e005400    Target Name ("TESTNT")
Target Information block:
    02000c00    NetBIOS Domain Name (length 12)
    54004500530054004e005400    "TESTNT"
    01000c00    NetBIOS Server Name (length 12)
    4d0045004d00420045005200    "MEMBER"
    03001e00    DNS Server Name (length 30)
    6d0065006d006200650072002e0074006500730074002e0063006f006d00
        "member.test.com"
    00000000    Target Information Terminator

--------------------------------------------------------------------------------
InitializeSecurityContext called.  Produces a Type 3 message:

4e544c4d5353500003000000180018006000000018001800780000000c000c00
40000000080008004c0000000c000c00540000001000100090000000358288e0
54004500530054004e00540074006500730074004d0045004d00420045005200
404d1b6f6915258000000000000000000000000000000000ea8cc49f24da157f
13436637f77693d8b992d619e584c7ee727a5240822ec7af4e9100c43e6fee7f

4e544c4d53535000    "NTLMSSP"
03000000            Type 3 message
1800180060000000    LM/LMv2 Response header (length 24, offset 96)
1800180078000000    NTLM/NTLMv2 Response header (length 24, offset 120)
0c000c0040000000    Domain Name header (length 12, offset 64)
080008004c000000    User Name header (length 8, offset 76)
0c000c0054000000    Workstation Name header (length 12, offset 84)
1000100090000000    Session Key header (length 16, offset 144)
358288e0            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Negotiate NTLM2 Key            (0x00080000)
    Negotiate Target Info          (0x00800000)
    Negotiate 128                  (0x20000000)
    Negotiate Key Exchange         (0x40000000)
    Negotiate 56                   (0x80000000)
54004500530054004e005400                            Domain Name ("TESTNT")
7400650073007400                                    User Name ("test")
4d0045004d00420045005200                            Workstation Name ("MEMBER")
404d1b6f6915258000000000000000000000000000000000    LM/LMv2 Response
ea8cc49f24da157f13436637f77693d8b992d619e584c7ee    NTLM/NTLMv2 Response
727a5240822ec7af4e9100c43e6fee7f                    Session Key

--------------------------------------------------------------------------------
AcceptSecurityContext called to complete the server-side context.

Server Context Export:

48a42e7848a42e7800000000000000000000000000000000
70f10b00    server context handle dwUpper
358289e1    flags
0000000000000000382e09003c2e0900b82e0900c82f09000000000000000000
d002000000000000000000000000000000000000000000000200000000000000
ffffffffffffff7f20010000
6c713b60e6571035c9396ece1e456395    outbound signing key
e775c02a63d159ec64185f6d7d993344    inbound verifying key
e9b0f8e2cbf7b453b8389e8d2d7bb4ba    outbound encrypting key
cc0fc51f360b7da837cde6cb417fd735    inbound decrypting key
000000000000000000000000
e932727927bbfe589b599a99d212bf23479fa99e7d8953bd6764862e690a6fac
b5f935ba02df8a75e415ddf7d30fc9a89778a2b7d4f0cc0c032b8757b4312663
8c0b39136536b8af1c3a774fc890cf30fbd16b18059c5eec7b3b3782efe06628
216aeda7e83fcb1446344bdeeb1ef5914ad894333d96ea51fdfc8311ad175b52
254ed93ce58bff50d0c78561aeb36ef8952c205acef3cad506085d5c700080ab
c6d77c22b1c22fb9c32a73a0481d100e298e929dc0e1a671ee1f8d4438a5c476
f22d847ec1196ce6094d5f3edc4201b28f6d43aaf4cdf1e362d6fa98a19307b0
55f640e7544c457424bc04c5dadb41160d7f88beb656a41be21a607a688149a3
00000000000000000000000000000000
cc094487604571968040c0ac1fe2da492938751932bc4139040def8c27635807
ad4e68b5ab6c6a65897f8f2df24f02164cc35466d0111d81f026a23d6d7221fd
34c9cb885e52b10ec88e532ec57a8ba5a6eb3f769446b62ab8a3840548220cd8
ff3b9bb2b731e1e64a50ae08917dc28d869215cf5a677920a801a493c143ec97
1efb576bd717b0303ea9be9fdb9a5dd55b1b8a77aaf42f9ccea183ea6eb36428
f7984bf9d39e9524a7eedd00cae5425533d9bded0b51ded2e43769c7c41a7bc6
af595ff1e33612e8614ddfe9f523785673a085fcd1d67ed4356f5ccd9ddc9003
0a4799bb2b70e71418823cfa06e0f62cbffe133a7cb4baf8101cf325620fb974
0000000000000000
54004500530054004e0054005c007400650073007400    "TESTNT\test"

ntlmHash = md4(password) = 0x3b1b47e42e0463276e3ded6cef349f93
NTLMUserSessionKey = md4(ntlmHash) = 0xae33a32dca8c9821844f740d5b3f4d6c
challenge (from Type 2) = 0x677f1c557a5ee96c
nonce (from Type 3) = 0x404d1b6f69152580
NTLM2SessionResponseUserSessionKey =
    HMAC(NTLMUserSessionKey, challenge + nonce) =
        0x0d4b30a8750b73ab2dab39e889455fcd

Key exchange performed:
type3Key (from Type 3) = 0x727a5240822ec7af4e9100c43e6fee7f
key = RC4(NTLM2SessionResponseUserSessionKey, type3Key) =
    0x5764dc0a93b1292fa898c29524c30a54

We are using server context:

serverSigningConstant =
    "session key to server-to-client signing key magic constant" =
        0x73657373696f6e206b657920746f207365727665722d746f2d636c69656e74
        207369676e696e67206b6579206d6167696320636f6e7374616e7400

serverSealingConstant =
    "session key to server-to-client sealing key magic constant" =
        0x73657373696f6e206b657920746f207365727665722d746f2d636c69656e74
        207365616c696e67206b6579206d6167696320636f6e7374616e7400

signingKey = MD5(key + serverSigningConstant) =
    0x6c713b60e6571035c9396ece1e456395

User Session Key is not weakened (128-bit negotiated).

sealingKey = MD5(key + serverSealingConstant) =
    0xe9b0f8e2cbf7b453b8389e8d2d7bb4ba

Called MakeSignature on the server-side context for message
"0x0102030405060708".

Yields signature:

0100000069de1aff9cbee43100000000

Sequence number is 0.
seqnum + message = 0x000000000102030405060708

HMAC(signingKey, 0x000000000102030405060708) =
    0x9d642651faec52f2164297dcaaa1ff6e

sig = RC4(sealingKey, first 8 bytes) = 0x69de1aff9cbee431
version num + sig + seqnum:

0100000069de1aff9cbee43100000000 = signature

--------------------------------------------------------------------------------
Called EncryptMessage twice on the server-side context for message
"0x0102030405060708".

Yields encrypted messages:

5b4cbbd3b2d8e8a401000000272c6dee5b236fe201000000
29535954c1e00fb9010000002922b8fcada4cda202000000

Uses RC4 cipher from previous signing operation (key exchange encrypts
signature with sealing key as well).

RC4(0x0102030405060708) = sealed message = 0x5b4cbbd3b2d8e8a4

trailer buffer gets signature (sequence number is now 1 because of previous
signing, same RC4 cipher used for this signature too):

HMAC(signingKey, 0x010000000102030405060708) =
    0x1b7fc502e4cc73b6d85360d7ee052800
sig = RC4(first 8 bytes) = 0x272c6dee5b236fe2
version num + sig + seqnum:
01000000272c6dee5b236fe201000000 = trailer signature

second message is same, using RC4 cipher from previous operations:

RC4(0x0102030405060708) = sealed message = 0x29535954c1e00fb9

trailer buffer signature with sequence 2:

HMAC(signingKey, 0x020000000102030405060708) =
   0x3e46a45716671a6e0d056636f77db4bb
sig = RC4(first 8 bytes) = 0x2922b8fcada4cda2
version num + sig + seqnum:
010000002922b8fcada4cda202000000 = trailer signature

NTLM2 Session Response Authentication; NTLM2 Signing and Sealing Using the 40-bit NTLM2 Session Response User Session Key

Demonstration of NTLMv1 authentication with 40-bit NTLM2 Session Response User Session Key NTLM2 signing and sealing (without key exchange).

LMCompatibilityLevel set to 0 (LM/NTLM).

AcquireCredentialsHandle called with domain "TESTNT", user "test", password
"test1234".

--------------------------------------------------------------------------------
InitializeSecurityContext called with ISC_REQ_INTEGRITY and
ISC_REQ_CONFIDENTIALITY.  Following flags were masked off of resulting Type 1
message:

    Negotiate 128                  (0x20000000)
    Negotiate Key Exchange         (0x40000000)
    Negotiate 56                   (0x80000000)

4e544c4d5353500001000000b782080000000000000000000000000000000000

4e544c4d53535000    "NTLMSSP"
01000000            Type 1 message
b7820800            Flags
    Negotiate Unicode              (0x00000001)
    Negotiate OEM                  (0x00000002)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate Lan Manager Key      (0x00000080)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Negotiate NTLM2 Key            (0x00080000)
0000000000000000    Supplied Domain (empty, supplied credentials)
0000000000000000    Supplied Workstation (empty, supplied credentials)

--------------------------------------------------------------------------------
AcceptSecurityContext called with ASC_REQ_INTEGRITY and ASC_REQ_CONFIDENTIALITY.
Produces Type 2 message:

4e544c4d53535000020000000c000c003000000035828900919013ccde5c4d16
0000000000000000460046003c00000054004500530054004e00540002000c00
54004500530054004e00540001000c004d0045004d0042004500520003001e00
6d0065006d006200650072002e0074006500730074002e0063006f006d000000
0000

4e544c4d53535000    "NTLMSSP"
02000000            Type 2 message
0c000c0030000000    Target Name header (length 12, offset 48)
35828900            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Target Type Domain             (0x00010000)
    Negotiate NTLM2 Key            (0x00080000)
    Negotiate Target Info          (0x00800000)
919013ccde5c4d16    Challenge
0000000000000000    Context
460046003c000000    Target Information header (length 70, offset 60)
54004500530054004e005400    Target Name ("TESTNT")
Target Information block:
    02000c00    NetBIOS Domain Name (length 12)
    54004500530054004e005400    "TESTNT"
    01000c00    NetBIOS Server Name (length 12)
    4d0045004d00420045005200    "MEMBER"
    03001e00    DNS Server Name (length 30)
    6d0065006d006200650072002e0074006500730074002e0063006f006d00
        "member.test.com"
    00000000    Target Information Terminator

--------------------------------------------------------------------------------
InitializeSecurityContext called.  Produces a Type 3 message:

4e544c4d5353500003000000180018006000000018001800780000000c000c00
40000000080008004c0000000c000c0054000000000000009000000035828800
54004500530054004e00540074006500730074004d0045004d00420045005200
02a668799b43b02600000000000000000000000000000000191c91d68a26a933
82ec89178c1e496d8f2f63a1c7dc0b54

4e544c4d53535000    "NTLMSSP"
03000000            Type 3 message
1800180060000000    LM/LMv2 Response header (length 24, offset 96)
1800180078000000    NTLM/NTLMv2 Response header (length 24, offset 120)
0c000c0040000000    Domain Name header (length 12, offset 64)
080008004c000000    User Name header (length 8, offset 76)
0c000c0054000000    Workstation Name header (length 12, offset 84)
0000000090000000    Session Key header (empty)
35828800            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Negotiate NTLM2 Key            (0x00080000)
    Negotiate Target Info          (0x00800000)
54004500530054004e005400                            Domain Name ("TESTNT")
7400650073007400                                    User Name ("test")
4d0045004d00420045005200                            Workstation Name ("MEMBER")
02a668799b43b02600000000000000000000000000000000    LM/LMv2 Response
191c91d68a26a93382ec89178c1e496d8f2f63a1c7dc0b54    NTLM/NTLMv2 Response

--------------------------------------------------------------------------------
AcceptSecurityContext called to complete the server-side context.

Server Context Export:

40a42e7840a42e7800000000000000000000000000000000
08ee0b00    server context handle dwUpper
35828901    flags
0000000000000000f8290900fc290900782a0900882b09000000000000000000
d002000000000000000000000000000000000000000000000200000000000000
ffffffffffffff7f20010000
605b738984f36aea7d2ccc5678670f2c    outbound signing key
94d75dd6591eb8569d8480b5c9c25136    inbound verifying key
e4c55ca209611e9e007009731b7103d5    outbound encrypting key
738e75e9b0df0ac9139839abf5cc8354    inbound decrypting key
000000000000000000000000
37aa90adbac5442beb5c77f553b782d01859687c2e421e524e2fbc4ad5ff0555
43657a283af2366b3f3cafa80372a3a781b123dd6f2c22e45e0c57d23bd78399
f64935c94bbf9112156a67a2dc843e1a7069f8ec30f99388fa61c4cf4c3d3824
b046df9c31fc0a0150d6638ca17fb651c79db25d07efbea5dea02580fe406211
ea9b1341b41f76e366857d5afbe92adb6ee2940bfd6c4fe12995b5acc05fbb73
a98bbd33b906ae14a4da00cb0dcc1b75f0edc2792d9e60cef1c192741d8a1039
8d7b479a97b30e20f4217ef39fe6c30948199604c8f79856d1ee4dd9e589648e
26ca86c67802e78f5b34e8a617d3ab5408582745cdd416711c32e06d87b80fd8
00000000000000000000000000000000
eb024b64187446dcf798db69a299356807ba78fec2b642e6cd77a097a80bb9a5
38e7548a935d923dbd22e1b7d80127fc1cc9fad61e404eac033f6bab10e57923
878f729e84500ce97139d5cb8c11c7b21741e2325f56a34aad757a804f34ed19
a747bf05af9b912f94ffea700dd43a8806d73eb4458bd97e1a375c6d9633f3c6
49092dc8635a9a589ce35221c5dda1f926ef1f6a5bc03bb1ce65e089149d2baa
28b3cab59f448655306c25133629bc812c57be592a1b0e1204537bcf00d176b0
3c0faecce8f6c4dfd0674cfbd27d95fdf1da318e8d8582bbec7f16f0c162eea6
0a8324f26660151d2eb851736edea9e4f86f08a45e4dc3d37c48f54390f46120
0000000000000000
54004500530054004e0054005c007400650073007400    "TESTNT\test"

ntlmHash = md4(password) = 0x3b1b47e42e0463276e3ded6cef349f93
NTLMUserSessionKey = md4(ntlmHash) = 0xae33a32dca8c9821844f740d5b3f4d6c
challenge (from Type 2) = 0x919013ccde5c4d16
nonce (from Type 3) = 0x02a668799b43b026
NTLM2SessionResponseUserSessionKey =
    HMAC(NTLMUserSessionKey, challenge + nonce) =
        0x6b60097a8f9dbbff2d23f5b15377ca28

We are using server context:

serverSigningConstant =
    "session key to server-to-client signing key magic constant" =
        0x73657373696f6e206b657920746f207365727665722d746f2d636c69656e74
        207369676e696e67206b6579206d6167696320636f6e7374616e7400

serverSealingConstant =
    "session key to server-to-client sealing key magic constant" =
        0x73657373696f6e206b657920746f207365727665722d746f2d636c69656e74
        207365616c696e67206b6579206d6167696320636f6e7374616e7400

signingKey = MD5(key + serverSigningConstant) =
    0x605b738984f36aea7d2ccc5678670f2c

User Session Key is weakened to 40-bit for sealing by truncating =
    0x6b60097a8f

sealingKey = MD5(weakenedKey + serverSealingConstant) =
    0xe4c55ca209611e9e007009731b7103d5

Called MakeSignature on the server-side context for message
"0x0102030405060708".

Yields signature:

01000000d1e2d811145d81ec00000000

Sequence number is 0.
seqnum + message = 0x000000000102030405060708

HMAC(signingKey, 0x000000000102030405060708) =
    0xd1e2d811145d81ecf5f8723312c75e3c

version num + first 8 bytes + seqnum:

01000000d1e2d811145d81ec00000000 = signature

--------------------------------------------------------------------------------
Called EncryptMessage twice on the server-side context for message
"0x0102030405060708".

Yields encrypted messages:

ab8d38bb0cad7dd601000000eed64de8afb80c8001000000
b011cc07a7f6127b01000000644a8509d73ac48c02000000

RC4(sealingKey, 0x0102030405060708) = sealed message = 0xab8d38bb0cad7dd6

trailer buffer gets signature (sequence number is now 1 because of previous
signing):

HMAC(signingKey, 0x010000000102030405060708) =
    0xeed64de8afb80c801ea5ddd1d98cbdc8
version num + first 8 bytes + seqnum:
01000000eed64de8afb80c8001000000 = trailer signature

second message is same, using RC4 cipher from previous sealing operation:

RC4(0x0102030405060708) = sealed message = 0xb011cc07a7f6127b

trailer buffer signature with sequence 2:

HMAC(signingKey, 0x020000000102030405060708) =
    0x644a8509d73ac48c8f5a7f7f65bc8381
version num + first 8 bytes + seqnum:
01000000644a8509d73ac48c02000000 = trailer signature

NTLMv2 Authentication; NTLM1 Signing and Sealing Using the 40-bit NTLMv2 User Session Key

Demonstration of NTLMv2 authentication with NTLMv2 User Session Key NTLM1 signing and sealing (without key exchange).

LMCompatibilityLevel set to 3 (LMv2/NTLMv2).

AcquireCredentialsHandle called with domain "TESTNT", user "test", password
"test1234".

--------------------------------------------------------------------------------
InitializeSecurityContext called with ISC_REQ_INTEGRITY and
ISC_REQ_CONFIDENTIALITY.  Following flags were masked off of resulting Type 1
message:

    Negotiate Lan Manager Key      (0x00000080)
    Negotiate NTLM2 Key            (0x00080000)
    Negotiate 128                  (0x20000000)
    Negotiate Key Exchange         (0x40000000)
    Negotiate 56                   (0x80000000)

4e544c4d53535000010000003782000000000000000000000000000000000000

4e544c4d53535000    "NTLMSSP"
01000000            Type 1 message
37820000            Flags
    Negotiate Unicode              (0x00000001)
    Negotiate OEM                  (0x00000002)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
0000000000000000    Supplied Domain header (empty, supplied credentials)
0000000000000000    Supplied Workstation header (empty, supplied credentials)

--------------------------------------------------------------------------------
AcceptSecurityContext called with ASC_REQ_INTEGRITY and ASC_REQ_CONFIDENTIALITY.
Produces Type 2 message:

4e544c4d53535000020000000c000c0030000000358281000033b02d17275b77
0000000000000000460046003c00000054004500530054004e00540002000c00
54004500530054004e00540001000c004d0045004d0042004500520003001e00
6d0065006d006200650072002e0074006500730074002e0063006f006d000000
0000

4e544c4d53535000    "NTLMSSP"
02000000            Type 2 message
0c000c0030000000    Target Name header (length 12, offset 48)
35828100            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Target Type Domain             (0x00010000)
    Negotiate Target Info          (0x00800000)
0033b02d17275b77    Challenge
0000000000000000    Context
460046003c000000    Target Information header (length 70, offset 60)
54004500530054004e005400    Target Name ("TESTNT")
Target Information block:
    02000c00    NetBIOS Domain Name (length 12)
    54004500530054004e005400    "TESTNT"
    01000c00    NetBIOS Server Name (length 12)
    4d0045004d00420045005200    "MEMBER"
    03001e00    DNS Server Name (length 30)
    6d0065006d006200650072002e0074006500730074002e0063006f006d00
        "member.test.com"
    00000000    Target Information Terminator

--------------------------------------------------------------------------------
InitializeSecurityContext called.  Produces a Type 3 message:

4e544c4d5353500003000000180018006000000076007600780000000c000c00
40000000080008004c0000000c000c005400000000000000ee00000035828000
54004500530054004e00540074006500730074004d0045004d00420045005200
5d55a02b60a40526ac9a1e4d15fa45a0f2e6329726c598e8f77c67dad00b9321
6242b197fe6addfa0101000000000000502db638677bc301f2e6329726c598e8
0000000002000c0054004500530054004e00540001000c004d0045004d004200
4500520003001e006d0065006d006200650072002e0074006500730074002e00
63006f006d000000000000000000

4e544c4d53535000    "NTLMSSP"
03000000            Type 3 message
1800180060000000    LM/LMv2 Response header (length 24, offset 96)
7600760078000000    NTLM/NTLMv2 Response header (length 118, offset 120)
0c000c0040000000    Domain Name header (length 12, offset 64)
080008004c000000    User Name header (length 8, offset 76)
0c000c0054000000    Workstation Name header (length 12, offset 84)
00000000ee000000    Session Key header (empty)
35828000            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Negotiate Target Info          (0x00800000)
54004500530054004e005400                            Domain Name ("TESTNT")
7400650073007400                                    User Name ("test")
4d0045004d00420045005200                            Workstation Name ("MEMBER")
5d55a02b60a40526ac9a1e4d15fa45a0f2e6329726c598e8    LM/LMv2 Response
NTLM/NTLMv2 Response:
f77c67dad00b93216242b197fe6addfa0101000000000000502db638677bc301
f2e6329726c598e80000000002000c0054004500530054004e00540001000c00
4d0045004d0042004500520003001e006d0065006d006200650072002e007400
6500730074002e0063006f006d000000000000000000

--------------------------------------------------------------------------------
AcceptSecurityContext called to complete the server-side context.

Server Context Export:

40a42e7840a42e7800000000000000000000000000000000
08ee0b00    server context handle dwUpper
35828101    flags, also has an unknown flag set
0000000000000000782e0900782e0900f82e0900f82e09000000000000000000
d002000000000000000000000000000000000000000000000200000000000000
ffffffffffffff7f20010000
1c4c7aaa7403acf01b1fa565bc950810    outbound signing key
1c4c7aaa7403acf01b1fa565bc950810    inbound verifying key
1c4c7aaa7403acf01b1fa565bc950810    outbound encrypting key
1c4c7aaa7403acf01b1fa565bc950810    inbound decrypting key
000000000000000000000000
783ee50c1d1209b1cb2ea115e7899fbe9547b2b03c1ef14c20d102e0a7282a00
d4919756821af4ff388a5333c51835fc482c71a5f6bdea3745e2dc6124dd3241
c9a9849d267ebc3d7608554962235fb568d6874699cd141fb7395b801b796650
ca0edaee65d2304afe707504067aefb38669eda3547f7c5d946ecf3aadbf437d
6f4288e1d9a6935e63ae7ba467afaac1ccc3529a1c36d7b49cf2e407779e2985
3173db8d814e9b405cc00d01d5d016a022b6c62be96b90c2f792ecce4dc4f36c
f58b2d74980a6dde17d3d8f8e63b0b7264342f600fab05580344bae88ffa5ab9
27df19f96a51bba8f083eb3f10ac218cfdc8fb8ea2255711c74b4f5913e3b896
00000000000000000000000000000000
783ee50c1d1209b1cb2ea115e7899fbe9547b2b03c1ef14c20d102e0a7282a00
d4919756821af4ff388a5333c51835fc482c71a5f6bdea3745e2dc6124dd3241
c9a9849d267ebc3d7608554962235fb568d6874699cd141fb7395b801b796650
ca0edaee65d2304afe707504067aefb38669eda3547f7c5d946ecf3aadbf437d
6f4288e1d9a6935e63ae7ba467afaac1ccc3529a1c36d7b49cf2e407779e2985
3173db8d814e9b405cc00d01d5d016a022b6c62be96b90c2f792ecce4dc4f36c
f58b2d74980a6dde17d3d8f8e63b0b7264342f600fab05580344bae88ffa5ab9
27df19f96a51bba8f083eb3f10ac218cfdc8fb8ea2255711c74b4f5913e3b896
0000000000000000
54004500530054004e0054005c007400650073007400    "TESTNT\test"

ntlmHash = md4(password) = 0x3b1b47e42e0463276e3ded6cef349f93
ntlmv2Hash = hmac(ntlmHash, "TESTTESTNT") = 0xc4ea95cb148df11bf9d7c3611ad6d722
challenge (from Type 2) = 0x0033b02d17275b77
blob (from Type 3) = 0x0101000000000000502db638677bc301f2e632972
6c598e80000000002000c0054004500530054004e00540001000c004d0045004
d0042004500520003001e006d0065006d006200650072002e007400650073007
4002e0063006f006d000000000000000000

NTLMv2UserSessionKey = HMAC(ntlmv2Hash(HMAC(ntlmv2Hash, challenge + blob))) =
    0x1c4c7aaa7403acf01b1fa565bc950810

Key is *not* weakened (NTLM1 only weakens Lan Manager Session Keys).

Called MakeSignature on the server-side context for message
"0x0102030405060708".

Yields signature:

01000000ffffff0051cefea77f098ee3

CRC32(0x0102030405060708) = 0xc588ca3f
Sequence number is 0.
0x00000000 + crc32 + seqnum = 0x00000000c588ca3f00000000

RC4(key, 0x00000000c588ca3f00000000) = 0x8661cb7d51cefea77f098ee3

version num + first 4 bytes overwritten with counter value (0xffffff00 here):

01000000ffffff0051cefea77f098ee3 = signature

--------------------------------------------------------------------------------
Called EncryptMessage twice on the server-side context for message
"0x0102030405060708".

Yields encrypted messages:

f483b904264d83060100000098010700bd9719c0b34f5362
022cc2127f9e206e01000000800307001855ec8494231273

same RC4 cipher is used from previous signing operation (i.e., not reset):

RC4(0x0102030405060708) = sealed message = 0xf483b904264d8306

trailer buffer gets signature; again uses same RC4 cipher
(sequence number is now 1 because of previous signing):

RC4(0x00000000c588ca3f01000000) = 0x2246e9cbbd9719c0b34f5362
version num + first 4 bytes overwritten w/counter (0x98010700):
0100000098010700bd9719c0b34f5362 = trailer signature

second message is same:

RC4(0x0102030405060708) = sealed message = 0x022cc2127f9e206e

trailer buffer signature with sequence 2:

RC4(0x00000000c588ca3f02000000) = 0x6fde4d031855ec8494231273
version num + first 4 bytes overwritten w/counter (0x80030700)
01000000800307001855ec8494231273 = trailer signature

NTLMv2 Authentication; NTLM2 Signing and Sealing Using the 56-bit NTLMv2 User Session Key

Demonstration of NTLMv2 authentication with 56-bit NTLMv2 User Session Key NTLM2 signing and sealing (without key exchange).

LMCompatibilityLevel set to 3 (LMv2/NTLMv2).

AcquireCredentialsHandle called with domain "TESTNT", user "test", password
"test1234".

--------------------------------------------------------------------------------
InitializeSecurityContext called with ISC_REQ_INTEGRITY and
ISC_REQ_CONFIDENTIALITY.  Following flags were masked off of resulting Type 1
message:

    Negotiate 128                  (0x20000000)
    Negotiate Key Exchange         (0x40000000)

4e544c4d5353500001000000b782088000000000000000000000000000000000

4e544c4d53535000    "NTLMSSP"
01000000            Type 1 message
b7820880            Flags
    Negotiate Unicode              (0x00000001)
    Negotiate OEM                  (0x00000002)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate Lan Manager Key      (0x00000080)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Negotiate NTLM2 Key            (0x00080000)
    Negotiate 56                   (0x80000000)
0000000000000000    Supplied Domain header (empty, supplied credentials)
0000000000000000    Supplied Workstation header (empty, supplied credentials)

--------------------------------------------------------------------------------
AcceptSecurityContext called with ASC_REQ_INTEGRITY and ASC_REQ_CONFIDENTIALITY.
Produces Type 2 message:

4e544c4d53535000020000000c000c003000000035828980514246973ea892c1
0000000000000000460046003c00000054004500530054004e00540002000c00
54004500530054004e00540001000c004d0045004d0042004500520003001e00
6d0065006d006200650072002e0074006500730074002e0063006f006d000000
0000

4e544c4d53535000    "NTLMSSP"
02000000            Type 2 message
0c000c0030000000    Target Name header (length 12, offset 48)
35828980            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Target Type Domain             (0x00010000)
    Negotiate NTLM2 Key            (0x00080000)
    Negotiate Target Info          (0x00800000)
    Negotiate 56                   (0x80000000)
514246973ea892c1    Challenge
0000000000000000    Context
460046003c000000    Target Information header (length 70, offset 60)
54004500530054004e005400    Target Name ("TESTNT")
Target Information block:
    02000c00    NetBIOS Domain Name (length 12)
    54004500530054004e005400    "TESTNT"
    01000c00    NetBIOS Server Name (length 12)
    4d0045004d00420045005200    "MEMBER"
    03001e00    DNS Server Name (length 30)
    6d0065006d006200650072002e0074006500730074002e0063006f006d00
        "member.test.com"
    00000000    Target Information Terminator

--------------------------------------------------------------------------------
InitializeSecurityContext called.  Produces a Type 3 message:

4e544c4d5353500003000000180018006000000076007600780000000c000c00
40000000080008004c0000000c000c005400000000000000ee00000035828880
54004500530054004e00540074006500730074004d0045004d00420045005200
bf2e015119f6bdb3f6fdb768aa12d478f5ce3d2401c8f6e9caa4da8f25d5e840
974ed8976d3ada46010100000000000030fa7e3c677bc301f5ce3d2401c8f6e9
0000000002000c0054004500530054004e00540001000c004d0045004d004200
4500520003001e006d0065006d006200650072002e0074006500730074002e00
63006f006d000000000000000000

4e544c4d53535000    "NTLMSSP"
03000000            Type 3 message
1800180060000000    LM/LMv2 Response header (length 24, offset 96)
7600760078000000    NTLM/NTLMv2 Response header (length 118, offset 120)
0c000c0040000000    Domain Name header (length 12, offset 64)
080008004c000000    User Name header (length 8, offset 76)
0c000c0054000000    Workstation Name header (length 12, offset 84)
00000000ee000000    Session Key header (empty)
35828880            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Negotiate NTLM2 Key            (0x00080000)
    Negotiate Target Info          (0x00800000)
    Negotiate 56                   (0x80000000)
54004500530054004e005400                            Domain Name ("TESTNT")
7400650073007400                                    User Name ("test")
4d0045004d00420045005200                            Workstation Name ("MEMBER")
bf2e015119f6bdb3f6fdb768aa12d478f5ce3d2401c8f6e9    LM/LMv2 Response
NTLM/NTLMv2 Response:
caa4da8f25d5e840974ed8976d3ada46010100000000000030fa7e3c677bc301
f5ce3d2401c8f6e90000000002000c0054004500530054004e00540001000c00
4d0045004d0042004500520003001e006d0065006d006200650072002e007400
6500730074002e0063006f006d000000000000000000

--------------------------------------------------------------------------------
AcceptSecurityContext called to complete the server-side context.

Server Context Export:

40a42e7840a42e7800000000000000000000000000000000
08ee0b00    server context handle dwUpper
35828981    flags
0000000000000000282e09002c2e0900a82e0900b82f09000000000000000000
d002000000000000000000000000000000000000000000000200000000000000
ffffffffffffff7f20010000
f7301e5d23f1d578c51ec0728b67453e    outbound signing key
06403212f9e8c05ce1739938c200eca5    inbound verifying key
3d6483dce52cd6c4d7553545e607d92d    outbound encrypting key
ccc6efbcea980c0ac685753a4c9bbe0c    inbound decrypting key
000000000000000000000000
3a6d27764b2010cdeda24d421b961cb92835eac0ecd6bf50375d308219362975
443ce13be9d2621d1283dc484f3e6ae66c4e8851f12632c3c1d9d5808763770b
9b61ebf7b7152252da1ff484b611732e3dcca15e9567939ce48bac450c7d46df
14ff026557a49db4dbe54cde538c21c6d0a59a24d87a06498dd74340bc4a13ab
6f851aa070a7587f9fa86b560d16d4e3b22d97b33147eefccbc87c6e3479f53f
bab898af09865aa3692f5b330a99f600c2b118cec766fec903a6551ecfe0e225
e77bae642ad3c5fa0fbb0e5caac4bd9e07ef2b602c1754f2908eb501be5991fd
41ad688add8f392308f3f974f881783872b07ee8fb7104055fa99289d1f0ca94
00000000000000000000000000000000
21a58f9635cee06b4f94512adc8125717aa7a877750d646503e17073b1e5c1a6
d874c3a2b0499f905bebef1a3f5f8bee8e8ce69c4b87c900bf2f41ea72167f91
1dfc82a959862708575caf3a0a7bbbd7f337ba5ab6fae7c69734e9a1e367a44e
cfc5292ed9da1f5e0f2d01a0ae0214b58a1eb8619b524c7dbe47d41bc83bb346
0983d533dd40ab76c742ca45c0e4c2cbf5e8f6f7f222b76658a31c795005193e
f17812d0c4247e806e4afddb10cc68d6b90c2807b20e9860549318621130ac06
bc15e2f8232b9aec20fb95decd89d2f43d0b69bdd3136f382644888d533284b4
92feedaa7c9df9393c55316cffd1489ead172cdf43995636636a85f05d6d044d
0000000000000000
54004500530054004e0054005c007400650073007400    "TESTNT\test"

ntlmHash = md4(password) = 0x3b1b47e42e0463276e3ded6cef349f93
ntlmv2Hash = hmac(ntlmHash, "TESTTESTNT") = 0xc4ea95cb148df11bf9d7c3611ad6d722
challenge (from Type 2) = 0x514246973ea892c1
blob (from Type 3) = 0x010100000000000030fa7e3c677bc301f5ce3d240
1c8f6e90000000002000c0054004500530054004e00540001000c004d0045004
d0042004500520003001e006d0065006d006200650072002e007400650073007
4002e0063006f006d000000000000000000

NTLMv2UserSessionKey = HMAC(ntlmv2Hash(HMAC(ntlmv2Hash, challenge + blob))) =
    0x62ff13231f566f5dadf7391e183b5f39

We are using server context:

serverSigningConstant =
    "session key to server-to-client signing key magic constant" =
        0x73657373696f6e206b657920746f207365727665722d746f2d636c69656e74
        207369676e696e67206b6579206d6167696320636f6e7374616e7400

serverSealingConstant =
    "session key to server-to-client sealing key magic constant" =
        0x73657373696f6e206b657920746f207365727665722d746f2d636c69656e74
        207365616c696e67206b6579206d6167696320636f6e7374616e7400

signingKey = MD5(key + serverSigningConstant) =
    0xf7301e5d23f1d578c51ec0728b67453e

User Session Key is weakened to 56-bit for sealing by truncating =
    0x62ff13231f566f

sealingKey = MD5(weakenedKey + serverSealingConstant) =
    0x3d6483dce52cd6c4d7553545e607d92d

Called MakeSignature on the server-side context for message
"0x0102030405060708".

Yields signature:

01000000fa317a333d8f510c00000000

Sequence number is 0.
seqnum + message = 0x000000000102030405060708

HMAC(signingKey, 0x000000000102030405060708) =
    0xfa317a333d8f510cccab257d9f2193c4

version num + first 8 bytes + seqnum:

01000000fa317a333d8f510c00000000 = signature

--------------------------------------------------------------------------------
Called EncryptMessage twice on the server-side context for message
"0x0102030405060708".

Yields encrypted messages:

a8e6671c79cf265701000000673773407fb60b4201000000
2fe89f6c6ea06d4b01000000244e0bcbce6ec16c02000000

RC4(sealingKey, 0x0102030405060708) = sealed message = 0xa8e6671c79cf2657

trailer buffer gets signature (sequence number is now 1 because of previous
signing):

HMAC(signingKey, 0x010000000102030405060708) =
    0x673773407fb60b428f70358ca67720ba
version num + first 8 bytes + seqnum:
01000000673773407fb60b4201000000 = trailer signature

second message is same, using RC4 cipher from previous sealing operation:

RC4(0x0102030405060708) = sealed message = 0x2fe89f6c6ea06d4b

trailer buffer signature with sequence 2:

HMAC(signingKey, 0x020000000102030405060708) =
    0x244e0bcbce6ec16ce3493f55854bcc5c
version num + first 8 bytes + seqnum:
01000000244e0bcbce6ec16c02000000 = trailer signature

Anonymous NTLMv1 Authentication; NTLM2 Signing and Sealing Using the 128-bit Null User Session Key With Key Exchange Negotiated

Demonstration of anonymous authentication with signing and sealing.

LMCompatibilityLevel set to 0 (LM/NTLM).

AcquireCredentialsHandle called with empty string ("") for domain, user, and
password.

--------------------------------------------------------------------------------
InitializeSecurityContext called with ISC_REQ_INTEGRITY and
ISC_REQ_CONFIDENTIALITY.  Produces Type 1 message:

4e544c4d5353500001000000b78208e000000000000000000000000000000000

4e544c4d53535000    "NTLMSSP"
01000000            Type 1 message
b78208e0            Flags
    Negotiate Unicode              (0x00000001)
    Negotiate OEM                  (0x00000002)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate Lan Manager Key      (0x00000080)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Negotiate NTLM2 Key            (0x00080000)
    Negotiate 128                  (0x20000000)
    Negotiate Key Exchange         (0x40000000)
    Negotiate 56                   (0x80000000)
0000000000000000    Supplied Domain header (empty, supplied credentials)
0000000000000000    Supplied Workstation header (empty, supplied credentials)

--------------------------------------------------------------------------------
AcceptSecurityContext called with ASC_REQ_INTEGRITY and ASC_REQ_CONFIDENTIALITY.
Produces Type 2 message:

4e544c4d53535000020000000c000c0030000000358289e05bce6f12f47ddbdf
0000000000000000460046003c00000054004500530054004e00540002000c00
54004500530054004e00540001000c004d0045004d0042004500520003001e00
6d0065006d006200650072002e0074006500730074002e0063006f006d000000
0000

4e544c4d53535000    "NTLMSSP"
02000000            Type 2 message
0c000c0030000000    Target Name header (length 12, offset 48)
358289e0            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Always Sign          (0x00008000)
    Target Type Domain             (0x00010000)
    Negotiate NTLM2 Key            (0x00080000)
    Negotiate Target Info          (0x00800000)
    Negotiate 128                  (0x20000000)
    Negotiate Key Exchange         (0x40000000)
    Negotiate 56                   (0x80000000)
5bce6f12f47ddbdf    Challenge
0000000000000000    Context
460046003c000000    Target Information header (length 70, offset 60)
54004500530054004e005400    Target Name ("TESTNT")
Target Information block:
    02000c00    NetBIOS Domain Name (length 12)
    54004500530054004e005400    "TESTNT"
    01000c00    NetBIOS Server Name (length 12)
    4d0045004d00420045005200    "MEMBER"
    03001e00    DNS Server Name (length 30)
    6d0065006d006200650072002e0074006500730074002e0063006f006d00
        "member.test.com"
    00000000    Target Information Terminator

--------------------------------------------------------------------------------
InitializeSecurityContext called.  Produces a Type 3 message:

4e544c4d5353500003000000010001004c000000000000004d00000000000000
4000000000000000400000000c000c0040000000100010004d000000358a88e0
4d0045004d0042004500520000c1442e6cca8c010e77138430aa35738e

4e544c4d53535000    "NTLMSSP"
03000000            Type 3 message
010001004c000000    LM/LMv2 Response header (length 1, offset 76)
000000004d000000    NTLM/NTLMv2 Response header (empty)
0000000040000000    Domain Name header (empty)
0000000040000000    User Name header (empty)
0c000c0040000000    Workstation Name header (length 12, offset 64)
100010004d000000    Session Key header (length 16, offset 77)
358a88e0            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Anonymous            (0x00000800)
    Negotiate Always Sign          (0x00008000)
    Negotiate NTLM2 Key            (0x00080000)
    Negotiate Target Info          (0x00800000)
    Negotiate 128                  (0x20000000)
    Negotiate Key Exchange         (0x40000000)
    Negotiate 56                   (0x80000000)
4d0045004d00420045005200            Workstation Name ("MEMBER")
00                                  LM/LMv2 Response
c1442e6cca8c010e77138430aa35738e    Session Key

--------------------------------------------------------------------------------
AcceptSecurityContext called to complete the server-side context.

Server Context Export (on Win2k, appears to vary by OS):

40a42e7840a42e7800000000000000000000000000000000
08ee0b00    server context handle dwUpper
358a89e1    flags
0000000000000000e8290900ec290900682a0900782b09000000000000000000
0000000000000000000000000000000000000000000000000200000000000000
ffffffffffffff7f00000000
9128c3e5df618a48a83b44cfd92d58fe    outbound signing key
594757aaa803afd943de25e087e3f9f1    inbound verifying key
fc52e8bf1605ab57e89c6d6b4ffa92f6    outbound encrypting key
96465577ba181d141711572e5e15fe5d    inbound decrypting key
000000000000000000000000
53a979fb1564d02ea0c33a32b0a1b2015f261b6ee6207804aa4f88fc57826b61
5a9fe8764931f9903efea3e1d258cddda292d6da10b536287a9859ff212d6781
f51a0eb439afc1f30cf0a75d4b54145c5bf4e7036a95c573dc0a3b479dcbbb09
6c4c698b1fc22acc8eeb8f7183ea99182274d1e4dfe5bf8d13382941f6ca25b7
7084a56216c906ad7da891fa42082b9b170733b65ef23437a4fd667e5686c6de
87240080ec89d3d4bc194e759aaebde302d55550f83f1d0b46303545c71eb3b1
3c2f6f7b9eb8ab6d1c4011f12c51baf77fcec00fd7e07248e2604485be238aef
77b91265ac5227ee944ded8cd868634a973dc4db439c0dc8a696937ccfd9e905
00000000000000000000000000000000
09dd12ae4213ac358896e19a9d26cfc8957750b5f557bae5f3ef98d891a4059f
f25ed0195d141aea3d62e31fd7a9aa1e07fd83cb4d3f7401825b7e66a14b28cd
52d6e8a2049036756dfcb929d220d5463499ca3368a071634c0c9cd10dcc4ef9
11d30f108a45648979477f0641c2b485f6adc0a8922be91dde847c93278040a6
b886c6605ac132fe731c589467a76131c9498db13beb2f9baf2c59e06f6c6af0
bbc4b00e6bce78da2de602e797f103b2b6bf4f1b388c0816dfbde2258bd9a3b7
157b5600c55ffaf79e3ac78e48ee55308737ff43817d515cf83e6e70c317bcec
2aed21442e24d465a56923be0b53f4fb8fb3e454ab18760a7adc2239723c4adb
0000000000000000

Anonymous User Session Key = 0x00000000000000000000000000000000

Key exchange performed:
type3Key (from Type 3) = 0xc1442e6cca8c010e77138430aa35738e
key = RC4(AnonymousUserSessionKey, type3Key) =
    0x1f5ca72d69bb5c34fd159a57fd5be1e3

We are using server context:

serverSigningConstant =
    "session key to server-to-client signing key magic constant" =
        0x73657373696f6e206b657920746f207365727665722d746f2d636c69656e74
	207369676e696e67206b6579206d6167696320636f6e7374616e7400

serverSealingConstant =
    "session key to server-to-client sealing key magic constant" =
        0x73657373696f6e206b657920746f207365727665722d746f2d636c69656e74
	207365616c696e67206b6579206d6167696320636f6e7374616e7400

signingKey = MD5(key + serverSigningConstant) =
    0x9128c3e5df618a48a83b44cfd92d58fe

sealingKey = MD5(key + serverSealingConstant) =
    0xfc52e8bf1605ab57e89c6d6b4ffa92f6

Called MakeSignature on the server-side context for message
"0x0102030405060708".

Yields signature:

01000000ae0cbe0dd0b2110300000000

Sequence number is 0.
seqnum + message = 0x000000000102030405060708

HMAC(signingKey, 0x000000000102030405060708) =
    0xc14074817421530195b4532d61a4e625

sig = RC4(sealingKey, first 8 bytes) = 0xae0cbe0dd0b21103
version num + sig + seqnum:

01000000ae0cbe0dd0b2110300000000 = signature

--------------------------------------------------------------------------------
Called EncryptMessage twice on the server-side context for message
"0x0102030405060708".

Yields encrypted messages:

fb2e1d6ff8a3569a01000000cc2c5bf59319e7ca01000000
1e2216588e5a7d9801000000e9a3066b8fab0bf102000000

Uses RC4 cipher from previous signing operation (key exchange encrypts
signature with sealing key as well).

RC4(0x0102030405060708) = sealed message = 0xfb2e1d6ff8a3569a

trailer buffer gets signature (sequence number is now 1 because of previous
signing, same RC4 cipher used for this signature too):

HMAC(signingKey, 0x010000000102030405060708) =
    0x25141e76f441b10622cfaf0e61450663
sig = RC4(first 8 bytes) = 0xcc2c5bf59319e7ca
version num + sig + seqnum:
01000000cc2c5bf59319e7ca01000000 = trailer signature

second message is same, using RC4 cipher from previous operations:

RC4(0x0102030405060708) = sealed message = 0x1e2216588e5a7d98

trailer buffer signature with sequence 2:

HMAC(signingKey, 0x020000000102030405060708) =
   0x7efa2ba18ed911696a0f4d571b05a244
sig = RC4(first 8 bytes) = 0xe9a3066b8fab0bf1
version num + sig + seqnum:
01000000e9a3066b8fab0bf102000000 = trailer signature

Local NTLMv1 Authentication; NTLM2 Signing and Sealing Using an Unknown Session Key With Key Exchange Negotiated (Analysis Incomplete)

Demonstration of local authentication with signing and sealing. It is assumed that the User Session Key derivation and Key Exchange processes are performed normally offline within the established local context (in the absence of the required information being provided over-the-wire).

LMCompatibilityLevel set to 0 (LM/NTLM).

AcquireCredentialsHandle called with NULL identity (using default credentials
handle for authenticated local user).

--------------------------------------------------------------------------------
InitializeSecurityContext called with ISC_REQ_INTEGRITY and
ISC_REQ_CONFIDENTIALITY.  Produces Type 1 message:

4e544c4d5353500001000000b7b208e006000600260000000600060020000000
4d454d424552544553544e54

4e544c4d53535000    "NTLMSSP"
01000000            Type 1 message
b7b208e0            Flags
    Negotiate Unicode              (0x00000001)
    Negotiate OEM                  (0x00000002)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate Lan Manager Key      (0x00000080)
    Negotiate NTLM                 (0x00000200)
    Negotiate Domain Supplied      (0x00001000)
    Negotiate Workstation Supplied (0x00002000)
    Negotiate Always Sign          (0x00008000)
    Negotiate NTLM2 Key            (0x00080000)
    Negotiate 128                  (0x20000000)
    Negotiate Key Exchange         (0x40000000)
    Negotiate 56                   (0x80000000)
0600060026000000    Supplied Domain header (length 6, offset 38)
0600060020000000    Supplied Workstation header (length 6, offset 32)
4d454d424552    Supplied Workstation ("MEMBER")
544553544e54    Supplied Domain ("TESTNT")

--------------------------------------------------------------------------------
AcceptSecurityContext called with ASC_REQ_INTEGRITY and ASC_REQ_CONFIDENTIALITY.
Produces Type 2 message:

4e544c4d53535000020000000c000c003000000035c289e0d7ef496afa055352
08ee0b0000000000460046003c00000054004500530054004e00540002000c00
54004500530054004e00540001000c004d0045004d0042004500520003001e00
6d0065006d006200650072002e0074006500730074002e0063006f006d000000
0000

4e544c4d53535000    "NTLMSSP"
02000000            Type 2 message
0c000c0030000000    Target Name header (length 12, offset 48)
35c289e0            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Local Call           (0x00004000)
    Negotiate Always Sign          (0x00008000)
    Target Type Domain             (0x00010000)
    Negotiate NTLM2 Key            (0x00080000)
    Negotiate Target Info          (0x00800000)
    Negotiate 128                  (0x20000000)
    Negotiate Key Exchange         (0x40000000)
    Negotiate 56                   (0x80000000)
d7ef496afa055352    Challenge
08ee0b0000000000    Context (equal to server context handle's dwUpper field)
460046003c000000    Target Information header (length 70, offset 60)
54004500530054004e005400    Target Name ("TESTNT")
Target Information block:
    02000c00    NetBIOS Domain Name (length 12)
    54004500530054004e005400    "TESTNT"
    01000c00    NetBIOS Server Name (length 12)
    4d0045004d00420045005200    "MEMBER"
    03001e00    DNS Server Name (length 30)
    6d0065006d006200650072002e0074006500730074002e0063006f006d00
        "member.test.com"
    00000000    Target Information Terminator

--------------------------------------------------------------------------------
InitializeSecurityContext called.  Produces a Type 3 message:

4e544c4d53535000030000000000000040000000000000004000000000000000
4000000000000000400000000000000040000000000000004000000035c288e0

4e544c4d53535000    "NTLMSSP"
03000000            Type 3 message
0000000040000000    LM/LMv2 Response header (empty, local authentication)
0000000040000000    NTLM/NTLMv2 Response header (empty, local authentication)
0000000040000000    Domain Name header (empty, local authentication)
0000000040000000    User Name header (empty, local authentication)
0000000040000000    Workstation Name header (empty, local authentication)
0000000040000000    Session Key header (empty)
35c288e0            Flags
    Negotiate Unicode              (0x00000001)
    Request Target                 (0x00000004)
    Negotiate Sign                 (0x00000010)
    Negotiate Seal                 (0x00000020)
    Negotiate NTLM                 (0x00000200)
    Negotiate Local Call           (0x00004000)
    Negotiate Always Sign          (0x00008000)
    Negotiate NTLM2 Key            (0x00080000)
    Negotiate Target Info          (0x00800000)
    Negotiate 128                  (0x20000000)
    Negotiate Key Exchange         (0x40000000)
    Negotiate 56                   (0x80000000)

--------------------------------------------------------------------------------
AcceptSecurityContext called to complete the server-side context.

Server Context Export:

40a42e7840a42e7800000000000000000000000000000000
08ee0b00    server context handle dwUpper
35c289e1    flags
0000000000000000182e09001c2e0900982e0900a82f09000000000000000000
d002000000000000000000000000000000000000000000000200000000000000
ffffffffffffff7f00000000
65836771d7bf52df502634e521b3154b    outbound signing key
9ed7ce6558f0f26db1fbf5163d7b24f9    inbound verifying key
f56d6b81749b7adaf3467f37bc36224e    outbound encrypting key
65adf5ede40e84e7338d681e6cbc38ff    inbound decrypting key
000000000000000000000000
7263d05c01f686ab2717e06f35c91b7a10fd0f5289ced6b6c423a213e6256a4d
3d128d30290899cbb502412f2d77ae1d4e55cf3fa6df5a785ded4aa3504c5484
155396d88345ff065beab3b738956e07f2b0ad36b8a80ba9f49305753e14e540
3428b4ccd3641ad18b037e9b67be3c1e70a17d816520565e744bd587bfc5b27f
8558099048ec800af1a5bbef92cdd2afe8c3042e510026f3bac7579ec8db5fbd
eb24bc43a742fc6111def922666dfe9d4791e9c60ef0d431d98cc259e2162b7c
49c0da1c2af5ee8e4f440c9a60ca4668391f3b213288f7a46be1c19f198a9c79
699737aadcfb829476f8d7b17be42c73338f71a0fa986c0dac18b9e3e73add62
00000000000000000000000000000000
651771fae2f5fc6da8973bd149126e92212b2f896101d23c568e40b325a383bd
42ec2752b295e5d09e36c899a94fffb8e053ac1c5c72d4de7c66b14b8d862977
bf5f47cfb76a81201f829098a067df7b78dc51630d8f790e0985316cb459e7d5
7f466b6f5a13948b38434ac54c7ee9ab340a6926d75d2aa523d81d0bc23ae4cc
aa1a419fc303cd88f6a4be04e100bb32e6cbf4feae9ab04808d9a111f937fb76
50104dc1c696b6c0740528f193f87d14cedd3f442e15d324454e64c7733e0f9c
ea0c163de8f3c92d1eebed33ba30f7f2350757d6b98abccafd7568229d1bef7a
5519da065e709be3ad2c8418dbb5f002a2eea68c395891c454af62806087a75b
0000000000000000
54004500530054004e0054005c007400650073007400    "TESTNT\test"

User Session Key = ????

Key exchange performed somehow?  Shows up in signatures.

We are using server context:

serverSigningConstant =
    "session key to server-to-client signing key magic constant" =
        0x73657373696f6e206b657920746f207365727665722d746f2d636c69656e74
        207369676e696e67206b6579206d6167696320636f6e7374616e7400

serverSealingConstant =
    "session key to server-to-client sealing key magic constant" =
        0x73657373696f6e206b657920746f207365727665722d746f2d636c69656e74
        207365616c696e67206b6579206d6167696320636f6e7374616e7400

signingKey = MD5(key + serverSigningConstant) =
    0x65836771d7bf52df502634e521b3154b (from context export)

sealingKey = MD5(key + serverSealingConstant) =
    0xf56d6b81749b7adaf3467f37bc36224e (from context export)

Called MakeSignature on the server-side context for message
"0x0102030405060708".

Yields signature:

01000000adc70c8bd4834ae800000000

Sequence number is 0.
seqnum + message = 0x000000000102030405060708

HMAC(signingKey, 0x000000000102030405060708) =
    0xb0bd637382da53f4ad3edf2c5a2c9592

sig = RC4(sealingKey, first 8 bytes) = 0xadc70c8bd4834ae8
version num + sig + seqnum:

01000000adc70c8bd4834ae800000000 = signature

--------------------------------------------------------------------------------
Called EncryptMessage twice on the server-side context for message
"0x0102030405060708".

Yields encrypted messages:

9c89720008251ab601000000d4af70567f5ab1df01000000
a8950e40b10e9af501000000c5447ccf7102d98c02000000

Uses RC4 cipher from previous signing operation (key exchange encrypts
signature with sealing key as well).

RC4(0x0102030405060708) = sealed message = 0x9c89720008251ab6

trailer buffer gets signature (sequence number is now 1 because of previous
signing, same RC4 cipher used for this signature too):

HMAC(signingKey, 0x010000000102030405060708) =
    0xcd1d04a1962b7d82e6ffd7c37871bf15
sig = RC4(first 8 bytes) = 0xd4af70567f5ab1df
version num + sig + seqnum:
01000000d4af70567f5ab1df01000000 = trailer signature

second message is same, using RC4 cipher from previous operations:

RC4(0x0102030405060708) = sealed message = 0xa8950e40b10e9af5

trailer buffer signature with sequence 2:

HMAC(signingKey, 0x020000000102030405060708) =
   0x3011549106db10de5694f567749cb9eb
sig = RC4(first 8 bytes) = 0xc5447ccf7102d98c
version num + sig + seqnum:
01000000c5447ccf7102d98c02000000 = trailer signature

Appendix D: Java Implementation of the Type 3 Response Calculations

Listed below is an annotated sample implementation of the various Type 3 response calculations in Java. This example requires a JCE provider implementing the MD4 message-digest algorithm; the author recommends GNU Crypto, available at http://www.gnu.org/software/gnu-crypto/.

import java.security.Key;
import java.security.MessageDigest;

import javax.crypto.Cipher;

import javax.crypto.spec.SecretKeySpec;

/**
 * Calculates the various Type 3 responses.
 */
public class Responses {

    /**
     * Calculates the LM Response for the given challenge, using the specified
     * password.
     *
     * @param password The user's password.
     * @param challenge The Type 2 challenge from the server.
     *
     * @return The LM Response.
     */
    public static byte[] getLMResponse(String password, byte[] challenge)
            throws Exception {
        byte[] lmHash = lmHash(password);
        return lmResponse(lmHash, challenge);
    }

    /**
     * Calculates the NTLM Response for the given challenge, using the
     * specified password.
     *
     * @param password The user's password.
     * @param challenge The Type 2 challenge from the server.
     *
     * @return The NTLM Response.
     */
    public static byte[] getNTLMResponse(String password, byte[] challenge)
            throws Exception {
        byte[] ntlmHash = ntlmHash(password);
        return lmResponse(ntlmHash, challenge);
    }

    /**
     * Calculates the NTLMv2 Response for the given challenge, using the
     * specified authentication target, username, password, target information
     * block, and client nonce.
     *
     * @param target The authentication target (i.e., domain).
     * @param user The username. 
     * @param password The user's password.
     * @param targetInformation The target information block from the Type 2
     * message.
     * @param challenge The Type 2 challenge from the server.
     * @param clientNonce The random 8-byte client nonce. 
     *
     * @return The NTLMv2 Response.
     */
    public static byte[] getNTLMv2Response(String target, String user,
            String password, byte[] targetInformation, byte[] challenge,
                    byte[] clientNonce) throws Exception {
        byte[] ntlmv2Hash = ntlmv2Hash(target, user, password);
        byte[] blob = createBlob(targetInformation, clientNonce);
        return lmv2Response(ntlmv2Hash, blob, challenge);
    }

    /**
     * Calculates the LMv2 Response for the given challenge, using the
     * specified authentication target, username, password, and client
     * challenge.
     *
     * @param target The authentication target (i.e., domain).
     * @param user The username.
     * @param password The user's password.
     * @param challenge The Type 2 challenge from the server.
     * @param clientNonce The random 8-byte client nonce.
     *
     * @return The LMv2 Response. 
     */
    public static byte[] getLMv2Response(String target, String user,
            String password, byte[] challenge, byte[] clientNonce)
                    throws Exception {
        byte[] ntlmv2Hash = ntlmv2Hash(target, user, password);
        return lmv2Response(ntlmv2Hash, clientNonce, challenge);
    }

    /**
     * Calculates the NTLM2 Session Response for the given challenge, using the
     * specified password and client nonce.
     *
     * @param password The user's password.
     * @param challenge The Type 2 challenge from the server.
     * @param clientNonce The random 8-byte client nonce.
     *
     * @return The NTLM2 Session Response.  This is placed in the NTLM
     * response field of the Type 3 message; the LM response field contains
     * the client nonce, null-padded to 24 bytes.
     */
    public static byte[] getNTLM2SessionResponse(String password,
            byte[] challenge, byte[] clientNonce) throws Exception {
        byte[] ntlmHash = ntlmHash(password);
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        md5.update(challenge);
        md5.update(clientNonce);
        byte[] sessionHash = new byte[8];
        System.arraycopy(md5.digest(), 0, sessionHash, 0, 8);
        return lmResponse(ntlmHash, sessionHash);
    }

    /**
     * Creates the LM Hash of the user's password.
     *
     * @param password The password.
     *
     * @return The LM Hash of the given password, used in the calculation
     * of the LM Response.
     */
    private static byte[] lmHash(String password) throws Exception {
        byte[] oemPassword = password.toUpperCase().getBytes("US-ASCII");
        int length = Math.min(oemPassword.length, 14);
        byte[] keyBytes = new byte[14];
        System.arraycopy(oemPassword, 0, keyBytes, 0, length);
        Key lowKey = createDESKey(keyBytes, 0);
        Key highKey = createDESKey(keyBytes, 7);
        byte[] magicConstant = "KGS!@#$%".getBytes("US-ASCII");
        Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
        des.init(Cipher.ENCRYPT_MODE, lowKey);
        byte[] lowHash = des.doFinal(magicConstant);
        des.init(Cipher.ENCRYPT_MODE, highKey);
        byte[] highHash = des.doFinal(magicConstant);
        byte[] lmHash = new byte[16];
        System.arraycopy(lowHash, 0, lmHash, 0, 8);
        System.arraycopy(highHash, 0, lmHash, 8, 8);
        return lmHash;
    }

    /**
     * Creates the NTLM Hash of the user's password.
     *
     * @param password The password.
     *
     * @return The NTLM Hash of the given password, used in the calculation
     * of the NTLM Response and the NTLMv2 and LMv2 Hashes.
     */
    private static byte[] ntlmHash(String password) throws Exception {
        byte[] unicodePassword = password.getBytes("UnicodeLittleUnmarked");
        MessageDigest md4 = MessageDigest.getInstance("MD4");
        return md4.digest(unicodePassword);
    }

    /**
     * Creates the NTLMv2 Hash of the user's password.
     *
     * @param target The authentication target (i.e., domain).
     * @param user The username.
     * @param password The password.
     *
     * @return The NTLMv2 Hash, used in the calculation of the NTLMv2
     * and LMv2 Responses. 
     */
    private static byte[] ntlmv2Hash(String target, String user,
            String password) throws Exception {
        byte[] ntlmHash = ntlmHash(password);
        String identity = user.toUpperCase() + target.toUpperCase();
        return hmacMD5(identity.getBytes("UnicodeLittleUnmarked"), ntlmHash);
    }

    /**
     * Creates the LM Response from the given hash and Type 2 challenge.
     *
     * @param hash The LM or NTLM Hash.
     * @param challenge The server challenge from the Type 2 message.
     *
     * @return The response (either LM or NTLM, depending on the provided
     * hash).
     */
    private static byte[] lmResponse(byte[] hash, byte[] challenge)
            throws Exception {
        byte[] keyBytes = new byte[21];
        System.arraycopy(hash, 0, keyBytes, 0, 16);
        Key lowKey = createDESKey(keyBytes, 0);
        Key middleKey = createDESKey(keyBytes, 7);
        Key highKey = createDESKey(keyBytes, 14);
        Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
        des.init(Cipher.ENCRYPT_MODE, lowKey);
        byte[] lowResponse = des.doFinal(challenge);
        des.init(Cipher.ENCRYPT_MODE, middleKey);
        byte[] middleResponse = des.doFinal(challenge);
        des.init(Cipher.ENCRYPT_MODE, highKey);
        byte[] highResponse = des.doFinal(challenge);
        byte[] lmResponse = new byte[24];
        System.arraycopy(lowResponse, 0, lmResponse, 0, 8);
        System.arraycopy(middleResponse, 0, lmResponse, 8, 8);
        System.arraycopy(highResponse, 0, lmResponse, 16, 8);
        return lmResponse;
    }

    /**
     * Creates the LMv2 Response from the given hash, client data, and
     * Type 2 challenge.
     *
     * @param hash The NTLMv2 Hash.
     * @param clientData The client data (blob or client nonce).
     * @param challenge The server challenge from the Type 2 message.
     *
     * @return The response (either NTLMv2 or LMv2, depending on the
     * client data).
     */
    private static byte[] lmv2Response(byte[] hash, byte[] clientData,
            byte[] challenge) throws Exception {
        byte[] data = new byte[challenge.length + clientData.length];
        System.arraycopy(challenge, 0, data, 0, challenge.length);
        System.arraycopy(clientData, 0, data, challenge.length,
                         clientData.length);
        byte[] mac = hmacMD5(data, hash);
        byte[] lmv2Response = new byte[mac.length + clientData.length];
        System.arraycopy(mac, 0, lmv2Response, 0, mac.length);
        System.arraycopy(clientData, 0, lmv2Response, mac.length,
                         clientData.length);
        return lmv2Response;
    }

    /**
     * Creates the NTLMv2 blob from the given target information block and
     * client nonce.
     *
     * @param targetInformation The target information block from the Type 2
     * message.
     * @param clientNonce The random 8-byte client nonce.
     *
     * @return The blob, used in the calculation of the NTLMv2 Response.
     */
    private static byte[] createBlob(byte[] targetInformation,
            byte[] clientNonce) {
        byte[] blobSignature = new byte[] {
            (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x00
        };
        byte[] reserved = new byte[] {
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
        };
        byte[] unknown1 = new byte[] {
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
        };
        byte[] unknown2 = new byte[] {
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
        };
        long time = System.currentTimeMillis();
        time += 11644473600000l; // milliseconds from January 1, 1601 -> epoch.
        time *= 10000; // tenths of a microsecond.
        // convert to little-endian byte array.
        byte[] timestamp = new byte[8];
        for (int i = 0; i < 8; i++) {
            timestamp[i] = (byte) time;
            time >>>= 8;
        }
        byte[] blob = new byte[blobSignature.length + reserved.length +
                               timestamp.length + clientNonce.length +
                               unknown1.length + targetInformation.length +
                               unknown2.length];
        int offset = 0;
        System.arraycopy(blobSignature, 0, blob, offset, blobSignature.length);
        offset += blobSignature.length;
        System.arraycopy(reserved, 0, blob, offset, reserved.length);
        offset += reserved.length;
        System.arraycopy(timestamp, 0, blob, offset, timestamp.length);
        offset += timestamp.length;
        System.arraycopy(clientNonce, 0, blob, offset,
                         clientNonce.length);
        offset += clientNonce.length;
        System.arraycopy(unknown1, 0, blob, offset, unknown1.length);
        offset += unknown1.length;
        System.arraycopy(targetInformation, 0, blob, offset,
                         targetInformation.length);
        offset += targetInformation.length;
        System.arraycopy(unknown2, 0, blob, offset, unknown2.length);
        return blob;
    }

    /**
     * Calculates the HMAC-MD5 hash of the given data using the specified
     * hashing key.
     *
     * @param data The data for which the hash will be calculated. 
     * @param key The hashing key.
     *
     * @return The HMAC-MD5 hash of the given data.
     */
    private static byte[] hmacMD5(byte[] data, byte[] key) throws Exception {
        byte[] ipad = new byte[64];
        byte[] opad = new byte[64];
        for (int i = 0; i < 64; i++) {
            ipad[i] = (byte) 0x36;
            opad[i] = (byte) 0x5c;
        }
        for (int i = key.length - 1; i >= 0; i--) {
            ipad[i] ^= key[i];
            opad[i] ^= key[i];
        }
        byte[] content = new byte[data.length + 64];
        System.arraycopy(ipad, 0, content, 0, 64);
        System.arraycopy(data, 0, content, 64, data.length);
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        data = md5.digest(content);
        content = new byte[data.length + 64];
        System.arraycopy(opad, 0, content, 0, 64);
        System.arraycopy(data, 0, content, 64, data.length);
        return md5.digest(content);
    }

    /**
     * Creates a DES encryption key from the given key material.
     *
     * @param bytes A byte array containing the DES key material.
     * @param offset The offset in the given byte array at which
     * the 7-byte key material starts.
     *
     * @return A DES encryption key created from the key material
     * starting at the specified offset in the given byte array.
     */
    private static Key createDESKey(byte[] bytes, int offset) {
        byte[] keyBytes = new byte[7];
        System.arraycopy(bytes, offset, keyBytes, 0, 7);
        byte[] material = new byte[8];
        material[0] = keyBytes[0];
        material[1] = (byte) (keyBytes[0] << 7 | (keyBytes[1] & 0xff) >>> 1);
        material[2] = (byte) (keyBytes[1] << 6 | (keyBytes[2] & 0xff) >>> 2);
        material[3] = (byte) (keyBytes[2] << 5 | (keyBytes[3] & 0xff) >>> 3);
        material[4] = (byte) (keyBytes[3] << 4 | (keyBytes[4] & 0xff) >>> 4);
        material[5] = (byte) (keyBytes[4] << 3 | (keyBytes[5] & 0xff) >>> 5);
        material[6] = (byte) (keyBytes[5] << 2 | (keyBytes[6] & 0xff) >>> 6);
        material[7] = (byte) (keyBytes[6] << 1);
        oddParity(material);
        return new SecretKeySpec(material, "DES");
    }

    /**
     * Applies odd parity to the given byte array.
     *
     * @param bytes The data whose parity bits are to be adjusted for
     * odd parity.
     */
    private static void oddParity(byte[] bytes) {
        for (int i = 0; i < bytes.length; i++) {
            byte b = bytes[i];
            boolean needsParity = (((b >>> 7) ^ (b >>> 6) ^ (b >>> 5) ^
                                    (b >>> 4) ^ (b >>> 3) ^ (b >>> 2) ^
                                    (b >>> 1)) & 0x01) == 0;
            if (needsParity) {
                bytes[i] |= (byte) 0x01;
            } else {
                bytes[i] &= (byte) 0xfe;
            }
        }
    }

}

SourceForge.net Logo All trademarks mentioned in this document are the property of their respective owners.

Copyright © 2003, 2006 Eric Glass

Permission to use, copy, modify, and distribute this document for any purpose and without any fee is hereby granted, provided that the above copyright notice and this list of conditions appear in all copies.

The most current version of this document may be obtained from http://davenport.sourceforge.net/ntlm.html. The author may be contacted vie e-mail at eric.glass at gmail.com.

翻訳者: たかはしもとのぶ monyo@monyo.com (2006/08/30日時点の英文を翻訳)