EN JA
CRYPTO(9)
CRYPTO(9) FreeBSD Kernel Developer's Manual CRYPTO(9)

名称

cryptoカーネル中の暗号のサービス用の API

書式

#include < opencrypto/cryptodev.h>

int32_t
crypto_get_driverid( uint8_t);

int
crypto_register( uint32_t, int, uint16_t, uint32_t, int (*)(void *, uint32_t *, struct cryptoini *), int (*)(void *, uint64_t), int (*)(void *, struct cryptop *), void *);

int
crypto_kregister( uint32_t, int, uint32_t, int (*)(void *, struct cryptkop *), void *);

int
crypto_unregister( uint32_t, int);

int
crypto_unregister_all( uint32_t);

void
crypto_done( struct cryptop *);

void
crypto_kdone( struct cryptkop *);

int
crypto_newsession( uint64_t *, struct cryptoini *, int);

int
crypto_freesession( uint64_t);

int
crypto_dispatch( struct cryptop *);

int
crypto_kdispatch( struct cryptkop *);

int
crypto_unblock( uint32_t, int);

struct cryptop *
crypto_getreq( int);

void
crypto_freereq( void);

#define CRYPTO_SYMQ 0x1 
#define CRYPTO_ASYMQ 0x2 
 
#define EALG_MAX_BLOCK_LEN      16 
 
struct cryptoini { 
 int                cri_alg; 
 int                cri_klen; 
 int                cri_mlen; 
 caddr_t            cri_key; 
 uint8_t            cri_iv[EALG_MAX_BLOCK_LEN]; 
 struct cryptoini  *cri_next; 
}; 
 
struct cryptodesc { 
 int                crd_skip; 
 int                crd_len; 
 int                crd_inject; 
 int                crd_flags; 
 struct cryptoini   CRD_INI; 
#define crd_iv          CRD_INI.cri_iv 
#define crd_key         CRD_INI.cri_key 
#define crd_alg         CRD_INI.cri_alg 
#define crd_klen        CRD_INI.cri_klen 
 struct cryptodesc *crd_next; 
}; 
 
struct cryptop { 
 TAILQ_ENTRY(cryptop) crp_next; 
 uint64_t           crp_sid; 
 int                crp_ilen; 
 int                crp_olen; 
 int                crp_etype; 
 int                crp_flags; 
 caddr_t            crp_buf; 
 caddr_t            crp_opaque; 
 struct cryptodesc *crp_desc; 
 int              (*crp_callback) (struct cryptop *); 
 caddr_t            crp_mac; 
}; 
 
struct crparam { 
        caddr_t         crp_p; 
        u_int           crp_nbits; 
}; 
 
#define CRK_MAXPARAM    8 
 
struct cryptkop { 
        TAILQ_ENTRY(cryptkop) krp_next; 
        u_int              krp_op;         /* すなわち, CRK_MOD_EXP または 
                                              その他 */ 
        u_int              krp_status;     /* 返り状態 */ 
        u_short            krp_iparams;    /* 入力パラメータの数 */ 
        u_short            krp_oparams;    /* 出力パラメータの数 */ 
 uint32_t    krp_hid; 
        struct crparam     krp_param[CRK_MAXPARAM]; 
        int               (*krp_callback)(struct cryptkop *); 
};

解説

crypto は、“消費者” (他のカーネルサブシステムおよび /dev/crypto デバイスによるユーザ) が、それを利用することができるように、カーネルで登録される暗号ハードウェアのドライバのためのフレームワークです。ドライバは、フレームワークでそれらがサポートするアルゴリズムを登録し、フレームワークが、セッションを確立し、使用し、破壊するために呼ぶかもしれないエントリポイント (関数) を提供します。セッションは、特別のドライバ (あるいは関連するハードウェア) の中の暗号の情報をキャッシュするために使用されます。したがって、初期化は、すべてのリクエストで必要ではありません。暗号のサービスの消費者は、データ (2 つ以上の暗号の操作が要求できます) で適用されるべき操作のフレームワーク (とそれで登録されたドライバ) を指示する 1 組の記述子を渡します。

キー操作は、同じようにサポートされます。上に記述された対称な演算子と異なり、これらのセッションがないコマンドは、入力と出力のパラメータを使用して、数学的な操作を実行します。

消費者がプロセスに関連することができないので、ドライバは、 sleep(9) (スリープ) できません。同じことはフレームワークにも当てはまります。したがって、コールバックメカニズムは、リクエストが完了したことを (コールバックは、リクエスト単位で消費者によって指定されます) 消費者に通知するために使用されます。リクエストが成功して終わっても終わらなかったとしても、コールバックは、フレームワークによって呼び出されます。エラー表示は、後の場合に提供されます。特定のエラーコード、 EAGAIN は、セッション番号が変更され、リクエストが新しいセッション番号で直ちに再提出できることを示すために使用されます。コールバックを呼び出す不十分な情報が利用可能な場合 (引数の検証における致命的なエラーがあることを意味して)、エラーは、呼び出し関数にのみ返されます。セッション初期化と破壊については、コールバックメカニズムが使用されていません。

crypto_newsession() ルーチンは、フレームワークを持った新しいセッションを確立したい、暗号サービス ( ipsec(4) スタックのような) の消費者によって呼び出されます。成功した場合、1 つ目の引数は、セッション識別子 (SID) を含みます。 2 つ目の引数は、ドライバがセッションを確立するために必要な情報をすべて含んでいます。 3 つ目の引数は、ハードウェアドライバが使用されるべき (1) かそうでないか (0) 示します。 cryptoini 構造体中の様々なフィールドは、次のとおりです。

cri_alg
アルゴリズム識別子を含んでいます。現在サポートされたアルゴリズムは、次のとおりです。

CRYPTO_AES_CBC
CRYPTO_ARC4
CRYPTO_BLF_CBC
CRYPTO_CAMELLIA_CBC
CRYPTO_CAST_CBC
CRYPTO_DES_CBC
CRYPTO_3DES_CBC
CRYPTO_SKIPJACK_CBC
CRYPTO_MD5
CRYPTO_MD5_HMAC
CRYPTO_MD5_KPDK
CRYPTO_RIPEMD160_HMAC
CRYPTO_SHA1
CRYPTO_SHA1_HMAC
CRYPTO_SHA1_KPDK
CRYPTO_SHA2_256_HMAC
CRYPTO_SHA2_384_HMAC
CRYPTO_SHA2_512_HMAC
CRYPTO_NULL_HMAC
CRYPTO_NULL_CBC
cri_klen
可変サイズのキーアルゴリズムのために、ビットでキーの長さを指定します。
cri_mlen
計算されたハッシュからのいくつのバイトをコピーして戻されるべきであるかを指定します。 0 は、すべてのハッシュを意味します。
cri_key
アルゴリズムと共に使用されるキーを含んでいます。
cri_iv
それがデータの接頭辞でない場合、明示的な初期化ベクトル (IV) を含んでいます。このフィールドは、初期化中に無視されます。 IV が明示的に渡された場合 (詳細は、下記を参照)、ランダムな IV は、リクエストを処理するデバイスドライバによって使用されます。
cri_next
別の cryptoini 構造体へのポインタを含んでいます。複数のそのような構造は、多重アルゴリズムセッション ( ipsec(4) は、そのような特徴の消費者の例です) を確立するためにリンクされるかもしれません。

cryptoini 構造体およびその内容は、フレームワーク (あるいは使用されるドライバ) によって修正されません。返された SID を使用する処理のための後のリクエストは、ハードウェア (本質的には、SID は、ドライバのセッションキャッシュ中のインデックスの役割をします) を再初期化するコストを回避します。

crypto_freesession() は、セッションを廃止するために crypto_newsession() によって返された SID で呼び出されます。

crypto_dispatch() は、リクエストを処理するために呼び出されます。 cryptop 構造体中の様々なフィールドは、次のとおりです。

crp_sid
SID を含んでいます。
crp_ilen
処理されるバッファのバイトの長さの合計を示します。
crp_olen
返り時に、結果の長さの合計を含んでいます。対称な暗号の操作については、これは、入力の長さと同じになります。フレームワークが、結果のために (あるいは入力を再フォーマットするために) に新しいバッファを割り付ける必要がある場合、これが使用されます。
crp_callback
成功してもしなくても、このルーチンは、リクエストの完了時に呼び出されます。それは、 crypto_done() ルーチンによって呼び出されます。リクエストが成功しなかった場合、エラーコードは、 crp_etype フィールドに設定されます。適切な spl(9) レベルを設定することは、コールバックルーチンの責任です。
crp_etype
何らかのエラーに遭遇した場合、エラータイプを含んでいます。またはリクエストが成功して処理された場合、0 を含んでいます。 EAGAIN エラーコードが返される場合、SID は、変更されています (そして crp_sid フィールドに記録されます)。消費者は、新しい SID を記録し、すべての後のリクエストの中でそれを使用するべきです。この場合、リクエストは、直ちに再提出されるかもしれません。このメカニズムは、セッション移行 (有効性、性能または他の動機のために、あるドライバから他のドライバにセッションを移動させる) を実行するために、フレームワークによって使用されます。

crp_callback の中で指定されたコールバックルーチンによって検査された時、このフィールドのみが意味があることに注意してください。十分な情報がコールバックルーチン (つまり、渡されたポインタが NULL である場合に、あるいはコールバックルーチンが指定されなかった場合に) を呼び出すためには、存在しない場合に限り、エラーは、 crypto_process() の呼び出し側に返されます。

crp_flags
このリクエストに関連したフラグのビットマスクです。現在定義されたフラグは、次のとおりです。
CRYPTO_F_IMBUF
crp_buf によって指されるバッファは、mbuf チェーンです。
CRYPTO_F_IOV
crp_buf によって指されるバッファは、 uio 構造体です。
CRYPTO_F_REL
データを同じ場所に返さなければなりません。
CRYPTO_F_BATCH
可能であれば、バッチ操作。
CRYPTO_F_CBIMM
専用のカーネルスレッドからそれを行う代わりに直ちにコールバックします。
CRYPTO_F_DONE
完了した操作。
CRYPTO_F_CBIFSYNC
操作が同期されているなら、直ちにコールバックしまます。
crp_buf
入力バッファを指します。返る時 (コールバックが呼び出される場合)、それは、リクエストの結果を含んでいます。入力バッファは、 crp_flags に依存する mbuf チェーンあるいは連続するバッファかもしれません。
crp_opaque
これは、手付かずの暗号のフレームワークを通して渡され、呼び出されるアプリケーションの使用のために意図されます。
crp_desc
これは、記述子のリンクしたリストです。各記述子は、入力バッファ上でどのタイプの暗号の操作を行わなければならないかに関する情報を提供します。様々なフィールドは、次のとおりです。
crd_iv
CRD_F_IV_EXPLICIT フラグが与えられるとき、 IV が提供されるべきであるフィールド。
crd_key
CRD_F_KEY_EXPLICIT フラグが与えられるとき、 crd_key は、暗号化または認証キーがあるバッファを指します。
crd_alg
使用するアルゴリズム。新しいセッション時に与えられたものと同じでなければなりません。
crd_klen
crd_key キー長。
crd_skip
処理が開始するべきところで、入力バッファ中のオフセットです。
crd_len
crd_skip, の後に、どれだけのバイトを処理しなければならないかです。
crd_inject
どんな結果も挿入するためのバッファの始めからのオフセットです。暗号化アルゴリズムについては、これが暗号化する時、初期化ベクトル (IV) が挿入される場所、または ( crd_flags に従って) 解読する場合それを見つけることができる場所です。 MAC アルゴリズムについては、これは、鍵のあるハッシュの結果が挿入される場所です。
crd_flags
次のフラグが定義されます。
CRD_F_ENCRYPT
暗号化アルゴリズムについては、暗号化が要求される時 (設定されない場合、解読が実行されます)、このビットは、設定されます。
CRD_F_IV_PRESENT
暗号化アルゴリズムについては、IV が既にデータに先行する場合、このビットは、設定されます。したがって、 crd_inject の値は、無視され、IV は、バッファの中に書き込まれません。そうでなければ、パケットを暗号化するために使用される IV は、 crd_inject によって指される位置に書き込まれます。 IV の長さは、暗号化アルゴリズムのブロックサイズと等しいと仮定されます。 ipsec(4) の中の half-IV モードのような特別の“IV クッキング (料理)”を行ういくつかのアプリケーションは、 IV がパケットに書き込まれてはならないことを示すこのフラグを使用することができます。このフラグは、一般的には、 CRD_F_IV_EXPLICIT フラグと共に使用されます。
CRD_F_IV_EXPLICIT
暗号化アルゴリズムについては、IV が crd_iv フィールドで消費者によって明示的に提供される時、このビットは、設定されます。そうでなければ、暗号化操作については、解読操作については、それが crd_inject フィールドによって指示されるのに対して、 IV は、操作を実行するために使用されるドライバによって提供されます。 IV が消費者によって“急いで”計算される場合、このフラグは、一般的に使用され、データ (いくつかの ipsec(4) 設定、そして暗号化されたスワップは、そのような 2 つの例です) に先行しません。
CRD_F_KEY_EXPLICIT
暗号化と認証 (MAC) アルゴリズムにおいて、このビットは、与えられた操作のために、キーが crd_key フィールドの消費者によって明白に提供されるとき、設定されます。そうでなければ、キーは、新しいセッション時に cri_key フィールドから取られます。
CRD_F_COMP
圧縮アルゴリズムについては、圧縮が要求される時 (設定されない場合、展開 (非圧縮) が実行されます)、このビットは、設定されます。
CRD_INI
この cryptoini 構造体は、フレームワークあるいはデバイスドライバによって修正されません。この情報がすべての暗号の操作リクエストに伴って起こるので、ドライバは、オンデマンド (一般的にの高価な操作) で状態を再初期化することができます。さらに、上に記述されるように、暗号のフレームワークは、キューが満杯になる結果かハードウェアの失敗のようにリクエストを再送できます。
crd_next
次の記述子へのポイントです。リンクした操作は、 ipsec(4) のようなプロトコルにおいて有用です。ここで複数の暗号の変換は、データの同じブロック上で適用されるかもしれません。

crypto_getreq() は、それに渡された引数で指定されたのと同数の cryptodesc 構造体のリンクしたリストで cryptop 構造体を割り付けます。

crypto_freereq() は、構造体 cryptop とそれにリンクされたどんな cryptodesc 構造体も割り付けを解放ます。それが cryptop 構造体で不透明なフィールドに関連した必要なクリーンアップを行うことは、コールバックルーチンの責任であることに注意してください。

crypto_kdispatch() は、キーの操作を実行するために呼び出されます。 cryptkop 構造体中の様々なフィールドは、次のとおりです。

krp_op
CRK_MOD_EXP のようなオペレーションコードです。
krp_status
リターンコードです。この errno スタイル変数は、より低いレベルのオペレーションが失敗した理由かどうか示します。
krp_iparams
指定された操作への入力パラメータの場合、数です。各操作が多くの (一般的には固有の) そのようなパラメータを持っていることに注意してください。
krp_oparams
指定された操作への出力パラメータの場合、数です。各操作が多くの (一般的には固有の) そのようなパラメータを持っていることに注意してください。
krp_kvp
パラメータを含んでいるカーネルメモリブロックの配列です。
krp_hid
どのローレベルのドライバが使用されているか指定する識別子です。
krp_callback
コールバックは、キー操作の完了を呼び出しました。

ドライバ側の API

crypto_get_driverid(), crypto_register(), crypto_kregister(), crypto_unregister(), crypto_unblock() および crypto_done() ルーチンは、カーネル暗号サービスフレームワークで登録と登録取り消しするために暗号の基本をサポートを提供するドライバによって使用されます。ドライバは、引数 (通常 0、しかしソフトウェアのみのドライバは、 CRYPTOCAP_F_SOFTWARE を指定するべきです) として cc_flags を指定して、ドライバ識別子を得る crypto_get_driverid() 関数を最初に使用しなければなりません。ドライバがサポートする各アルゴリズムについては、それは、 crypto_register() を呼び出さなければなりません。最初の 2 つの引数は、ドライバとアルゴリズムの識別子です。次の 2 つの引数は、このアルゴリズム用のできるだけ大きな演算子の (公開暗号キーの操作にとって重要なビット単位の) 長さおよびフラグを指定します。最後の 4 つの引数は、 crypto_register() への最初の呼び出しで提供されなければなりません。そして、すべての後の呼び出しで無視されます。それらは、ドライバで新しい暗号のコンテキストを確立するために、既に確立しているコンテキストを解放し、 (暗号化する、解読するなど) 処理されるリクエストを求めるために、フレームワークが呼び出すかもしれない、 3 つのドライバに提供される関数へのポインタです。またこれらのルーチンの各々を呼び出す場合に渡すべき不透明なパラメータです。 crypto_unregister() は、アルゴリズムのサポートを取り下げたいドライバによって呼び出されます。 2 つの引数は、それぞれドライバとアルゴリズムの識別子です。一般的には、取り出された PCMCIA 暗号カードのためのドライバは、カードでサポートされたすべてのアルゴリズム用にこのルーチンを呼び出します。 crypto_unregister_all() は、ドライバによって登録されたすべてのアルゴリズムの登録取り消しをし、ドライバは、無効になります (新しいセッションは、そのドライバに割り付けられないし、そして任意の既存のセッションは、他のドライバに移動されます)。ドライバに関連したすべてのアルゴリズムが 1 つずつ登録を取り消される場合、同じことが行われます。

3 つのドライバに供給されたルーチンのための呼び出しの仕様は、次のとおりです。

  • int (*newsession)( void *, uint32_t *, struct cryptoini *);
  • int (*freesession)( void *, uint64_t);
  • int (*process)( void *, struct cryptop *);
  • int (*kprocess)( void *, struct cryptkop *);

呼び出しにおいては、すべてのルーチンへの最初の引数は、アルゴリズムが crypto_register() で登録されるときに供給された不透明なデータ値です。 newsession() への 2 つ目の引数は、 crypto_get_driverid() によって得られたドライバ識別子を含んでいます。成功した返りの場合、それは、ドライバに特有のセッション識別子を含んでいるべきです。 3 つ目の引数は、 crypto_newsession() のそれと同一です。

freesession() ルーチンは、引数として不透明なデータ値と SID (それは、ドライバ識別子とドライバ特有のセッション識別子の連結です) をとります。それは、セッション (ハードウェアレジスタ、メモリなどをクリア) に関連したどんなコンテキストもクリアすべきです。

process() ルーチンは、暗号処理を実行するリクエストで呼び出されます。このルーチンは、ブロックしてはなりません、しかしリクエストをキューにするべきであり、直ちに返ります。リクエストを処理する場合、コールバックルーチンは、呼び出されるべきです。回復不能のエラーの場合には、エラー表示は、 cryptop 構造体の crp_etype フィールドに置かれなければなりません。リクエストが終了するか、エラーが検知される時、 process() ルーチンは、 crypto_done() を呼び出すべきです。前述のように、セッション移動が実行されるかもしれません。

一時的リソース消耗の場合には、 process() ルーチンが ERESTART を返すかもしれません、その場合には、暗号のサービスは、リクエストを再度キューにし、ドライバを“ブロックした”としてマークし、そして処理のリクエストを提出することをやめます。ドライバは、それが crypto_unblock() ルーチンによってリクエストを再び処理することができる時に、暗号サービスに通知することに責任を負います。この単純なフロー制御メカニズムは、それが暗号のレイヤ (層) の中でキューにされる操作のように短命のリソース消耗のために単に使われるべきです。そうすることは、失われたパケットのような失敗の扱いによりネットワークプロトコルに性能を低下させるような場合エラーを返すことより望ましい。

kprocess() ルーチンは、暗号のキー処理を実行するリクエストで呼び出されます。このルーチンは、ブロックしてはなりません。しかしリクエストをキューにするべきであり、直ちに返ります。リクエストを処理する際、コールバックルーチンは、呼び出されるべきです。回復不能のエラーの場合には、エラー表示が、 cryptkop 構造体の krp_status フィールドに置かれなければなりません。リクエストが終了するか、エラーが検知される場合、 kprocess() ルーチンは、 crypto_kdone() を呼び出すべきです。

戻り値

crypto_register(), crypto_kregister(), crypto_unregister(), crypto_newsession(), crypto_freesession() および crypto_unblock() は、成功すれば 0 を返し、失敗すればエラーコードを返します。 crypto_get_driverid() は、エラーの場合、負ではない値を返し、失敗すれば-1 を返します。 crypto_getreq() は、 cryptop 構造体へのポインタを返し、失敗すれば NULL を返します。その引数またはコールバック関数が NULL だった場合、 crypto_dispatch() は、 EINVAL を返し、そうでなければ 0 を返します。コールバックは、 crp_etype フールドで、失敗の場合のエラーコードが提供されます。

関連ファイル

sys/opencrypto/crypto.c
ほとんどのフレームワークコード

関連項目

ipsec(4), malloc(9), sleep(9)

歴史

暗号のフレームワークは、 OpenBSD 2.7 ではじめて登場し、 Angelos D. Keromytis <angelos@openbsd.org>によって書かれました。

バグ

フレームワークは、現在、 crypto_newsession() 操作中のすべてのアルゴリズムが同じドライバによって利用可能でなければならないと仮定します。その場合、セッション初期化は、失敗するでしょう。

フレームワークは、さらに、どのドライバがセッションに関連したアルゴリズムの特定のセットには、最良かを決めるためのメカニズムを必要とします。あるタイプのベンチマークは、ここですぐ使える状態です。

同じセッションで同じアルゴリズムの複数のインスタンスは、サポートされません。 3DES が 1 つの (そして DES の 3 つのインスタンスではない) アルゴリズムと考えられることに注意してください。したがって、同じリクエストで 3DES と DES を混合することができます。

September 19, 2007 FreeBSD