[0]イントロ
カーネルバージョン2.5.45から導入されたLinux暗号化API 。 それ以来、 Crypto APIはすべての一般的な(だけでなく)国際標準を超えて成長しました。
- 対称暗号化: AES 、 Blowfish 、...
- ハッシュ: SHA1 / 256/512 、 MD5 、...
- 模造品 : hMAC-SHA1 / 256 / 512 、 hMAC-MD5 、...
- AEAD : AES-GCM 、 ChaCha20-Poly1305 、...
- 擬似乱数生成: FIPS 、...
- 非対称暗号化: RSA
- 鍵合意: DH 、 ECDH
- 圧縮: Deflate 、 ZLIB
この暗号化は、 IPsec 、 dm-cryptなど、さまざまなカーネルサブシステム( カーネルスペース内 )で主に使用されます。 ユーザー空間からのCrypto API関数の使用は、バージョンから始まるNetlinkインターフェースでも可能です。 2.6.38カーネルは、_AF ALGファミリーを導入し、 ユーザー空間コードからカーネル暗号化へのアクセスを提供します。 ただし、既存の機能では十分でない場合があるため、新しいアルゴリズムを使用してCrypto APIを拡張する必要があります。
そのため、約2年前、私はLinuxカーネル (バージョン3.13)のIPsec実装に(ベラルーシ共和国の)国家暗号化を組み込むという課題に直面しました。 当時、私はカーネル空間でプログラミングを行ったことがなく、これがカーネルモジュールを書いた初めての経験であり、 Robert Loveの著書 『 The Linux Kernel。Development Processの説明』は私を大いに助けてくれました。 Crypto API自体に対処することははるかに困難でした-言及された本では、この問題は原則としてカバーされておらず、 公式ドキュメントでは、アーキテクチャのかなり詳細な説明が提供されていますが、新しいアルゴリズムの実装に関する情報は実質的にありません。 私の検索では、Hackerマガジンで、Crypto APIの使用方法について一般的に語る素晴らしい記事に出会いましたが、その拡張についての言葉はありません。 最後に、必要な知識を得るために、ソース(カーネルコード)に目を向け、問題を解決しました。
それからしばらく経ちましたが、今になってようやく知識を更新し、このテキストを書き始めました。 Crypto APIについてです。 具体的な例として、任意のアルゴリズムをCrypto APIに埋め込む方法、およびカーネル空間とユーザー空間の両方からそれらにアクセスする方法を確認します。 この資料は、同様の問題に直面している開発者にとって非常に役立つと確信していますが、カジュアルな読者がここで自分にとって興味深いものを見つけられることを願っています。 猫へようこそ!
PS私のプログラムのコンパイルされたソースは、その断片は以下にありますが、 githubで入手できます。 この記事のソースがあります。 すべてのコードは、カーネルバージョン4.13.0-32-genericを使用したデスクトップUbuntu 16.04 LTSで作成およびテストされています。 モジュールで使用したインターフェイスのいくつかは4つのカーネルバージョンで導入されたため、3。カーネル*間違いなくコンパイルされません 。
[1] Crypto APIアーキテクチャ
コードを書き始める前に、 Crypto APIですべてがどのように機能するかについて少し話しましょう。 しかし、それらは私の前のドキュメントで詳細に説明されていましたが、私は順番に、材料を理解するのに十分なはずである圧搾を与えるだけです。 すぐに予約します。その後、主に対称暗号化、他のタイプの暗号変換を主に処理しますが、一般的には同様に機能しますが、多くのニュアンスがすべてを非常に複雑にします。
したがって、導入から、カーネルの暗号化サブシステムには暗号化アルゴリズムの多くの実装が含まれており、ユーザーがアクセスできるインターフェースを提供していることがすでにわかっています(以下、ユーザーと開発者はそれぞれAPIユーザーとAPI開発 者を意味します )。 Crypto APIに関しては、アルゴリズムは「変換」と呼ばれるため、さまざまなタイプの変換には独自のサブAPIがあり、変換記述子(ハンドル)には通常「 tfm 」という名前が付けられます。
struct crypto_cipher *tfm = crypto_alloc_cipher("aes", 0, 0);
ここで、 tfmは何らかの変換、この場合はAESアルゴリズムを使用したデータブロックの暗号化のハンドルです。 Crypto APIハンドルのライフサイクルは3段階に短縮されます 。
- ハンドルの作成/初期化
- ハンドルを介してアクセス可能な必要な暗号化操作を実行する
- 破壊を扱う
使用されるアルゴリズムに関係なく、 1つのデータブロックの基本的な暗号化機能の実装は、 crypto_cipher
タイプのハンドルを介して利用できます。対応するAPI ( シングルブロック暗号API )は、キーを設定し、ブロックを暗号化/復号化するためのメソッドを提供します。 独立したAPIであるため、ユーザーにとって大きな関心はありませんが、開発者の観点からは、 Crypto APIの重要な概念、いわゆる「テンプレート」を使用するため、重要です。 テンプレートは基本機能と組み合わせて使用され、以下を実装します。
- ブロック暗号化モード( ECB 、 CBC 、 CFB 、 CTR 、...)
- キーハッシュモード( hMAC )
- AEAD暗号化モード
- 並列化( pcrypt )など、データの直接暗号処理に関連しない機能
ハンドルを作成するとき(上記の例を参照)、必要なアルゴリズムは行で指定されます-アルゴリズムの名前。この行には次のセマンティクスがあります。
template(single block cipher/message digest)
さらに、必要に応じて、テンプレートを他のテンプレートに「ラップ」できます。
template_a(template_b(single block cipher/message digest))
ただし、基本的なアルゴリズムなしでテンプレートを使用することはできません。 いくつか例を挙げます。
- aes-基本的なAESブロック暗号化アルゴリズム
- cbc(aes) -結合ブロック暗号( CBC )モードのAES暗号化アルゴリズム
- sha1 - SHA1ハッシュアルゴリズム
- hmac(sha1) -SHA1ハッシュ関数を使用したキーハッシュアルゴリズム(セキュリティ)
- authenc(hmac(sha1)、cbc(aes)) - AES-CBC暗号化アルゴリズムとhMAC(SHA1)セキュリティアルゴリズムを使用したAEAD
任意のモードでの対称ブロック暗号の使用は、別個のAPIを介して実行されます 。 カーネルにはこのようなAPIが3つありますが、そのうち2つは非推奨であり、 Symmetric Key Cipher APIが関連していることに注意してください。 このAPIは、任意の長さのキー/同期および暗号化/復号化のデータを設定するメソッドをユーザーに提供します。また、 非ブロッキング (非同期)です。暗号化メソッドは、通知に使用される暗号操作とコールバック関数のリクエストを呼び出し元にできるだけ早く制御を返します操作の完了に関するユーザーは、システムスケジューラに送信されます。 Symmetric Key Cipher APIは、組み込みアルゴリズムをテストするカーネルモジュールの作成に進むときに詳細に検討されます。
2つの名前に加えて、 Crypto APIには次のサブAPIがあります 。
- AEAD暗号化( 関連データ(AEAD)暗号APIを使用した認証済み暗号化 )
- ブロッキングハッシュ/シミュレーション( 同期メッセージダイジェストAPI )
- ノンブロッキングハッシュ/模倣保護( 非同期メッセージダイジェストAPI )
- 擬似乱数生成( 乱数API )
- 非対称暗号化( 非対称暗号API )
- キー合意プロトコルプリミティブ(KPP)暗号API )
開発者にとって、 Crypto APIにテンプレートが存在するということは、新しい対称暗号化アルゴリズムを組み込むことで、基本的なブロック暗号化機能のみを実装すれば十分であり、対応するテンプレートにカプセル化して必要なモードを取得できることを意味します。 しかし、これは完全に真実ではありません。 実際、カーネルに含まれるアルゴリズムのソースコード( crypto / aes_generic.c 、 crypto / blowfish_generic.c 、...)を見ると、基本的な機能のみが実装されていることがわかります。 ただし、同じ方法で従来のGOST 28147-89ブロックの暗号化機能を実装し、それをゲーミングモード( CTRテンプレート)で「ラップ」し、テストシーケンスで結果のアルゴリズムをチェックすると、間違った結果が得られます。 問題は、 GOSTで説明されているガンマモードが、 CTRテンプレートに実装されているガンマアルゴリズムと異なることです。 私が扱った他の国家アルゴリズムについても同じことが言えます。 そのような場合、たとえばAESアルゴリズムの最適化された実装( AES-NI - arch / x86 / crypto / aesni-intel_glue.c )で行われているように、必要なモードで本格的なブロック暗号を埋め込む必要があります。 後で、埋め込みの両方のオプションを検討します。
おそらくこれが私が建築について言いたかったことのすべてです。 より詳細な説明に興味がある人は、 ドキュメントを参照する必要があり、私のプレゼンテーションは私たちが先に進むことができるように十分でなければなりません。
[2]土壌の準備
したがって、 Crpyto APIにいくつかの新しいアルゴリズムを組み込む準備が整いました。統合できるアルゴリズムはまだないという警告があります。 この記事では、「実際の」暗号化アルゴリズムを実装することを気にしませんでした。定性的に行うことはほとんどできなかったからです(暗号作成者に任せてください)。 一方、 ヌル暗号を作成することは、特にカーネルにすでにあるため、それほど興味深いものではありません。 したがって、基本暗号化アルゴリズムの実装を妥協して記述します。
どこで:
- -暗号文ブロック
- -平文ブロック
- -キー
- -排他的OR演算( XOR )
このアルゴリズムのブロックとキーのサイズは、128ビット(16バイト)に等しいと想定されています。
実装を開始できます。 アルゴリズムの暗号コンテキストと、コンテキストを作成/破棄する機能を定義します。
#define XOR_CIPHER_KEY_SIZE 16 typedef struct xor_cipher_ctx xor_cipher_ctx; struct xor_cipher_ctx { uint8_t key[XOR_CIPHER_KEY_SIZE]; }; xor_cipher_ctx* xor_cipher_allocate() { xor_cipher_ctx *cipher = calloc(1, sizeof(xor_cipher_ctx)); return cipher; } void xor_cipher_free(xor_cipher_ctx *ctx) { memset(ctx->key, 0xFF, XOR_CIPHER_KEY_SIZE); free(ctx); }
キーを設定し、ブロックを暗号化/復号化するメソッドを追加します。
#define XOR_CIPHER_BLOCK_SIZE 16 void xor_cipher_set_key(xor_cipher_ctx *ctx, uint8_t *key) { memmove(ctx->m_key, key, XOR_CIPHER_KEY_SIZE); } void xor_cipher_crypt_block(xor_cipher_ctx *ctx, uint8_t *dst, uint8_t *src) { for (int i = 0; i < XOR_CIPHER_BLOCK_SIZE; i++) { dst[i] = src[i] ^ ctx->key[i]; } }
XOR操作の可逆性を考えると、 xor_cipher_crypt_block
メソッドxor_cipher_crypt_block
使用して暗号化と復号化を同時に行います。
ブロック暗号化は優れていますが、ブロック暗号化モードの一部、たとえば暗号ブロックブロック結合モード( CBC )を実装するとさらに良くなります 。
どこで:
- -同期パッケージ
- 、 -キー上のブロックの暗号化および復号化の機能 それに応じて
引き続き動作します。暗号のブロックを結合するモードで暗号化および復号化のメソッドを実装します。
void xor_cipher_encrypt_cbc(xor_cipher_ctx *ctx, uint8_t *_dst, uint32_t len, uint8_t *_src, uint8_t *_iv) { uint32_t blocks = len / XOR_CIPHER_BLOCK_SIZE; uint32_t leftover = len - (blocks * XOR_CIPHER_BLOCK_SIZE); uint8_t *dst = _dst, *src = _src, *iv = _iv; for (uint32_t i = 0; i < blocks; i++) { memmove(dst, src, XOR_CIPHER_BLOCK_SIZE); for (int j = 0; j < XOR_CIPHER_BLOCK_SIZE; j++) { dst[j] ^= iv[j]; } xor_cipher_crypt_block(ctx, dst, dst); iv = dst; dst += XOR_CIPHER_BLOCK_SIZE; src += XOR_CIPHER_BLOCK_SIZE; } if (leftover) { memmove(dst, src, leftover); for (uint32_t i = 0; i < leftover; i++) { dst[i] ^= iv[i]; dst[i] ^= ctx->key[i]; } } }
void xor_cipher_decrypt_cbc(xor_cipher_ctx *ctx, uint8_t *_dst, uint32_t len, uint8_t *_src, uint8_t *_iv) { uint32_t blocks = len / XOR_CIPHER_BLOCK_SIZE; uint32_t leftover = len - (blocks * XOR_CIPHER_BLOCK_SIZE); uint8_t u[XOR_CIPHER_BLOCK_SIZE], iv[XOR_CIPHER_IV_SIZE]; uint8_t *dst = _dst, *src = _src; memmove(iv, _iv, XOR_CIPHER_IV_SIZE); for (uint32_t i = 0; i < blocks; i++) { memmove(u, src, XOR_CIPHER_BLOCK_SIZE); xor_cipher_crypt_block(ctx, dst, src); for (int j = 0; j < XOR_CIPHER_BLOCK_SIZE; j++) { dst[j] ^= iv[j]; } memmove(iv, u, XOR_CIPHER_IV_SIZE); dst += XOR_CIPHER_BLOCK_SIZE; src += XOR_CIPHER_BLOCK_SIZE; } if (leftover) { for (uint32_t i = 0; i < leftover; i++) { dst[i] = src[i] ^ ctx->key[i]; dst[i] ^= iv[i]; } } }
これはすでにもっと面白いです! これで、この実装を使用して、テストシーケンスを準備できます。テストシーケンスでは、将来、カーネル内の同じアルゴリズムの実装を確認します。 ネタバレの下に使用した値があります。
ブロック暗号化 | |
---|---|
キー | 2f 1b 1a c6 d1 be cb a2 f8 45 66 0d d2 97 5c a3
|
テスト番号1 | |
入力データ | cc 6b 79 0c db 55 4f e5 a0 69 05 96 11 be 8c 15
|
インプリント | e3 70 63 ca 0a eb 84 47 58 2c 63 9b c3 29 d0 b6
|
テスト番号2 | |
入力データ | 53 f5 f1 ef 67 a5 ba 6c 68 09 b5 7a 24 de 82 5f
|
インプリント | 7c ee eb 29 b6 1b 71 ce 90 4c d3 77 f6 49 de fc
|
CBC暗号化 | |
---|---|
キー | ec 8d 93 30 69 7e f8 63 0b f5 58 ec de 78 24 f2
|
同期パッケージ | db 02 1f a8 5a 22 15 cf 49 f7 80 8b 7c 24 a1 f3
|
平文 | 6e 96 50 42 84 d2 7e e8 44 9b 75 1d e0 ac 0a 58 ee 40 24 cc 32 fc 6e c4 e2 fc d1 f5 76 6a 45 9a e4 88 ba d6 12 07 28 86
|
暗号文 | 59 19 dc da b7 8e 93 44 06 99 ad 7a 42 f0 8f 59 5b d4 6b 26 ec 0c 05 e3 ef 90 24 63 ea e2 ee 31 53 d1 42 c0 97 75 d5 06
|
CBC復号化 | |
---|---|
キー | ec 8d 93 30 69 7e f8 63 0b f5 58 ec de 78 24 f2
|
同期パッケージ | db 02 1f a8 5a 22 15 cf 49 f7 80 8b 7c 24 a1 f3
|
暗号文 | db e9 1d c6 1f 13 1a 5a 34 2b 90 1e c3 b1 6f e9 52 1b 91 7f 8d 8f 6d b4 42 87 ad 85 5f 2d 89 7d
|
平文 | ec 66 91 5e 2c 4f f7 f6 76 29 48 79 61 ed ea e8 65 7f 1f 89 fb e2 8f 8d 7d 59 65 77 42 e4 c2 66
|
アルゴリズムとテストプログラムの実装のソースコードはここから入手できます 。 カーネルスペースに行く準備はほぼ整っていますが 、その前に重要なポイントに注意を向けたいと思います。 実際、多くの有名な暗号化アルゴリズムは、入力データの最後の不完全なブロックの処理を必要としません。 したがって、たとえば、入力データのサイズがブロックサイズの倍数でない場合、 GOST 28147-89アルゴリズムの実装はエラーフラグを返さなければなりませんが 、 ベルトベラルーシ語はそのような処理を提供します。 私のアルゴリズムもそれを提供します(クロックパッケージのキーと現在の値は、不完全なブロックのサイズに切り捨てられます)。 この事実は少し後で役割を果たしますが、あなたはこれを覚えておく必要があります。
[3]コアへの浸漬
アクションはカーネル空間に転送されます。 カーネルでのプログラミングは、ユーザー空間でのプログラミングとは多少異なり、デバッグの複雑さのために、かなり時間がかかるプロセスです。 ただし、この資料に取り組んでいる間、私は読者にカーネルモジュールのプログラミングの基本を理解するというタスクを設定しませんでした。これは、 Habré ( more ; and more )など、私なしでこれに関する多くの情報があるためです。 したがって、読者がモジュールの作成に完全に慣れていない場合は、最初に上記で引用した資料を確認するか、自分で確認することをお勧めします(これには時間がかかりません)。 そして、さらに先へ進む準備ができている人たちと一緒に、 Crypto APIを深く研究し始めます 。
それで、アルゴリズムがあり、それをカーネルに埋め込みたいのですが、どこから始めればいいのでしょうか? もちろん、ドキュメント付き。 残念なことに、 アルゴリズムの開発/埋め込みに関するセクションでは、このプロセスに関する非常に一般的な知識しか得られませんが、少なくとも正しい方向に進むには役立ちます。 具体的には、カーネル内のアルゴリズムの登録および登録解除に関与する関数の存在について学習します。 理解しましょう:
/* include/linux/crypto.h */ int crypto_register_alg(struct crypto_alg *alg); int crypto_register_algs(struct crypto_alg *algs, int count); int crypto_unregister_alg(struct crypto_alg *alg); int crypto_unregister_algs(struct crypto_alg *algs, int count);
これらの関数は、エラーの場合は負の値を返し、成功した場合は0を返します。登録されたアルゴリズムは、 crypto_alg
構造体によって記述されます(その定義( include / linux / crypto.h )を参照 )。
/* include/linux/crypto.h */ struct crypto_alg { struct list_head cra_list; struct list_head cra_users; u32 cra_flags; unsigned int cra_blocksize; unsigned int cra_ctxsize; unsigned int cra_alignmask; int cra_priority; atomic_t cra_refcnt; char cra_name[CRYPTO_MAX_ALG_NAME]; char cra_driver_name[CRYPTO_MAX_ALG_NAME]; const struct crypto_type *cra_type; union { struct ablkcipher_alg ablkcipher; struct blkcipher_alg blkcipher; struct cipher_alg cipher; struct compress_alg compress; } cra_u; int (*cra_init)(struct crypto_tfm *tfm); void (*cra_exit)(struct crypto_tfm *tfm); void (*cra_destroy)(struct crypto_alg *alg); struct module *cra_module; } CRYPTO_MINALIGN_ATTR;
幸いなことに、この構造は非常によく文書化されており、このフィールドまたはそのフィールドの値を推測する必要はありません。
-
cra_flags
:アルゴリズムを記述するフラグのセット。 フラグは、 include / linux / crypto.hの 「CRYPTO_ALG_
」で始まる定数によって定義され、アルゴリズムの説明を微調整するために使用されます -
cra_blocksize
:アルゴリズムのバイトブロックサイズ。 ハッシュを除くすべてのタイプの変換は、この値より小さいデータを処理しようとするとエラーを返します -
cra_ctxsize
:cra_ctxsize
バイトサイズ。 カーネルは、コンテキストにメモリを割り当てるときにこの値を使用します。 -
cra_alignmask
:入力および出力のアライメントマスク。 アルゴリズムの入力および出力用のバッファは、このマスクに揃える必要があります。 これは、任意のアドレスのデータにアクセスできないハードウェアで実行されるアルゴリズムに必要です。 -
cra_priority
:このアルゴリズムの実装の優先度。 同じcra_name
持つ複数のトランスフォームがカーネルに登録されている場合、この名前でアクセスすると、最高の優先度を持つアルゴリズムが返されます -
cra_name
:アルゴリズムの名前。 カーネルはこのフィールドを使用して実装を検索します。 -
cra_driver_name
:アルゴリズムの実装の一意の名前。 同じcra_name
複数の変換がカーネルに登録されており、より低い優先度のアルゴリズムを要求する必要がある場合、この名前を使用する必要があります -
cra_type
:暗号cra_type
タイプ。 すべてのタイプの変換に共通のコールバック関数を実装するタイプcrypto_type
構造体のインスタンスへのポインター。 利用可能なオプション:&crypto_blkcipher_type
、&crypto_ablkcipher_type
、&crypto_ahash_type
、&crypto_rng_type
。 次のタイプの変換の場合、このフィールドは空白のままにしてください:ブロック暗号化(cipher
)、圧縮(compress
)、ブロッキングハッシュ(shash
) -
cra_u
:実際には、アルゴリズムの実装。 ユニオンの構造の1つは、変換のタイプによって決定される特定の関数で満たされる必要があります。 このフィールドは、ブロックおよび非ブロックハッシュ(ahash
)のために空白のままにしてください。 -
cra_init
:インスタンス初期化関数を変換します。 この関数は、インスタンスの作成中(暗号コンテキストにメモリを割り当てた直後)に1回呼び出されます。 この機能では、必要に応じてさまざまな準備アクションを実行する必要があります(たとえば、追加メモリの割り当て、ハードウェア機能の確認)。 それ以外の場合、フィールドは空白のままにできます。 -
cra_exit
:変換インスタンスの初期化解除。 この関数では、cra_init
で行われたことと反対のことを実行する必要があります(存在する場合)。 それ以外の場合、フィールドは空白のままにできます。 -
cra_module
:この変換実装の所有者。 値をTHIS_MODULE
設定します
文書化されていない残りのフィールドは内部使用のためのものであり、入力しないでください。 複雑なことは何もないようです。 まず、ブロック暗号化アルゴリズムの実装を組み込みたいので、 cra_u
ユニオンのcipher_alg
構造を見てみましょう。
/* include/linux/crypto.h */ struct cipher_alg { unsigned int cia_min_keysize; unsigned int cia_max_keysize; int (*cia_setkey)(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen); void (*cia_encrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); };
ここではまだ簡単で、私には思えるので説明は不要です。 これで、これらすべてが実際にどのように機能するかを確認する準備ができました。 ちなみに、 cipher_alg
構造体の関数のシグネチャは 、2パートアルゴリズムのAPIの関数のシグネチャに似ていることに注意してください。
カーネルモジュールを作成します。 署名cipher_alg.cia_setkey
に従って、 cipher_alg.cia_setkey
とキーインストール関数を決定します。
#define XOR_CIPHER_KEY_SIZE 16 struct xor_cipher_ctx { u8 key[XOR_CIPHER_KEY_SIZE]; }; static int xor_cipher_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int len) { struct xor_cipher_ctx *ctx = crypto_tfm_ctx(tfm); u32 *flags = &tfm->crt_flags; if (len != XOR_CIPHER_KEY_SIZE) { *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; return -EINVAL; } memmove(ctx->key, key, XOR_CIPHER_KEY_SIZE); return 0; }
アルゴリズムのAPIでは、cryptocontextが関数に直接渡されました。ここで、関数はtfm
アルゴリズムのハンドルをtfm
ますtfm
アルゴリズムから、 crypto_tfm_ctx
関数を使用してコンテキストが抽出されます。 また、ここでは、送信されたキーの長さを確認します。 長さが正しくない場合、対応するフラグ( CRYPTO_TFM_RES_BAD_KEY_LEN
)を設定し、 EINVAL
コード(22: Invalid argument )を返します 。
次に、 cipher_alg.cia_encrypt
に従ってブロック暗号化関数を定義します。
static void xor_cipher_crypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct xor_cipher_ctx *ctx = crypto_tfm_ctx(tfm); int i; for (i = 0; i < XOR_CIPHER_BLOCK_SIZE; i++) { out[i] = in[i] ^ ctx->key[i]; } }
ここに新しいものはありません。 元のAPIのように、復号化のための追加の関数は定義せず、 cipher_alg.cia_decrypt
ポインターをcipher_alg.cia_decrypt
関数で初期化します。
最後に、モジュールのロード後およびアンロード前に、 crypto_alg
構造体のインスタンスを定義し、それを入力して、アルゴリズムの登録および登録crypto_alg
関数をそれぞれ呼び出します。
static struct crypto_alg xor_cipher = { .cra_name = "xor-cipher", .cra_driver_name = "xor-cipher-generic", .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = XOR_CIPHER_BLOCK_SIZE, .cra_ctxsize = sizeof(struct xor_cipher_ctx), .cra_module = THIS_MODULE, .cra_u = { .cipher = { .cia_min_keysize = XOR_CIPHER_KEY_SIZE, .cia_max_keysize = XOR_CIPHER_KEY_SIZE, .cia_setkey = xor_cipher_setkey, .cia_encrypt = xor_cipher_crypt, .cia_decrypt = xor_cipher_crypt } } }; static int __init xor_cipher_init(void) { return crypto_register_alg(&xor_cipher); } static void __exit xor_cipher_exit(void) { crypto_unregister_alg(&xor_cipher); }
上記のすべてを考慮すると、ここで疑問が生じることはありません。 そのようなモジュールをコンパイルおよびダウンロードした後、ターミナルでコマンド「 cat /proc/crypto
」を実行すると、登録済みアルゴリズムのリストで独自のアルゴリズムを見つけることができます。
name : xor-cipher driver : xor-cipher-generic module : xor_cipher priority : 100 refcnt : 1 selftest : passed internal : no type : cipher blocksize : 16 min keysize : 16 max keysize : 16
悪くないでしょ? しかし、これはほんの始まりに過ぎず、理論的には、アルゴリズムをテストするモジュールの作成に進む必要がありましたが、それでも、埋め込みと使用の問題を混同しないことにしました。 したがって、後でテストします。次のパートでは、暗号のブロックを結合するモードでアルゴリズムの実装をどのように組み込むことができるかを説明します。
[3.1]コアへの「もう少し深い」浸漬
少し先に走ります。 注意深い読者は、パターンの存在を覚えています。 したがって、最後の部分でブロック暗号化を実装すると、この実装をCBCテンプレートで簡単にラップし、暗号ブロックをブロックするモードでアルゴリズムの実装を取得できますが、シーケンスでテストすることにより、 CBCモードで暗号化を呼び出すとエラーコード22( EINVAL
) 次に、入力データの不完全なブロックとcrypto_alg.cra_blocksize
フィールドの処理について言ったことを思い出します。 実際、 CBCカーネルモードの実装には、不完全なブロックを処理する方法がわかりません。 さらに、アルゴリズムをCBCモードに変更すると、カーネルは新しいアルゴリズムを登録します。そのブロックサイズは、基本アルゴリズムのブロックサイズと同じです。 cbc(xor-cipher)アルゴリズムを使用して「暗号化」暗号化関数を呼び出した後、入力データのサイズはブロックサイズによって多重度がチェックされ、複数でない場合、関数はEINVAL
返します。 CBCモードでの暗号化のテストベクトルのサイズ(40バイト)は、ブロックサイズの倍数ではないように意図的に選択されています。 私の意見では、暗号化標準が不完全なブロックの処理を提供し、実装がそうしない場合、そのような実装は、多重度条件が満たされたときに実装が正しい結果を与えたとしても、標準への準拠のチェックに合格する可能性は低いです(この場合、これはそうです)。 したがって、ここで、アルゴリズムの暗号ブロックの結合モードを完全に実装します。 2年前にこれを行ったとき、今では時代遅れのブロッキング対称暗号化 APIを介してそれらを使用することを期待してアルゴリズムを組み込みましたが、当時は非ブロッキングAPIが望ましいと考えられていましたが、これも今では時代遅れです。 Symmetric Key Cipher API .
, , , , Crypto API , . , ( arch/x86/crypto/aesni-intel_glue.c ), , , . , / :
/* include/crypto/internal/skcipher.h */ int crypto_register_skcipher(struct skcipher_alg *alg); int crypto_register_skciphers(struct skcipher_alg *algs, int count); void crypto_unregister_skcipher(struct skcipher_alg *alg); void crypto_unregister_skciphers(struct skcipher_alg *algs, int count);
skcipher_alg
:
/* include/crypto/skcipher.h */ struct skcipher_alg { int (*setkey)(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen); int (*encrypt)(struct skcipher_request *req); int (*decrypt)(struct skcipher_request *req); int (*init)(struct crypto_skcipher *tfm); void (*exit)(struct crypto_skcipher *tfm); unsigned int min_keysize; unsigned int max_keysize; unsigned int ivsize; unsigned int chunksize; unsigned int walksize; struct crypto_alg base; };
, include/crypto/skcipher.h . , struct crypto_alg
, , , init
exit
, crypto_alg
. , , chunksize
walksize
:
-
chunksize
: , , ( stream cipher ), , , , ( underlying ) . , , . (skcipher_alg.base.cra_blocksize
) ,chunksize
, -
walksize
:chunksize
, , ,walksize
,chunksize
,
encrypt
decrypt
. skcipher_request
, : / , . , - API , , , , .
, Crypto API . , - API / ( API ), scatterlist
. , , Synchronous Block Cipher API :
/* include/linux/crypto.h */ int crypto_blkcipher_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes);
skcipher_request
struct scatterlist *src
struct scatterlist *dst
. scatterlist
:
/* include/linux/scatterlist.h */ struct scatterlist { /* ... */ unsigned long page_link; unsigned int offset; unsigned int length; /* ... */ };
. , sg_init_one
:
/* include/linux/scatterlist.h */ void sg_init_one(struct scatterlist *sg, const void *buf, unsigned int buflen);
, "" buf (page_link
), buf (offset
).
, . , :
struct crypto_blkcipher *tfm; struct blkcipher_dest desc; struct scatterlist sg[2]; u8 *first_segment, *second_segment; /* crypto and data allocation... */ sg_init_table(sg, 2); sg_set_buf(&sg[0], first_segment, len); sg_set_buf(&sg[1], second_segment, len); crypto_blkcipher_encrypt(&desc, &sg, &sg, 2*len);
, first_segment
second_segment
, . , Crypto API ( ) "" scatterlist
-, "" ( scattered ) . Crypto API IPsec :
One of the initial goals of this design was to readily support IPsec, so that processing can be applied to paged skb's without the need for linearization.
, scatterlist
API / ( Direct Memory Access , DMA I/O ). / , "" , , , .
. , :
static int xor_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int len) { return xor_cipher_setkey(crypto_skcipher_tfm(tfm), key, len); }
. CBC ( struct xor_cipher_ctx
), , , .
.
static int cbc_encrypt(struct skcipher_request *req) { struct crypto_tfm *tfm = crypto_skcipher_tfm(crypto_skcipher_reqtfm(req)); struct xor_cipher_ctx *ctx = crypto_tfm_ctx(tfm); struct skcipher_walk walk; u32 nbytes; int i, blocks; u8 *src, *dst, *iv; skcipher_walk_virt(&walk, req, true); iv = walk.iv; while ((nbytes = walk.nbytes) >= XOR_CIPHER_BLOCK_SIZE) { src = (u8*)walk.src.virt.addr; dst = (u8*)walk.dst.virt.addr; blocks = nbytes / XOR_CIPHER_BLOCK_SIZE; while (blocks) { for (i = 0; i < XOR_CIPHER_BLOCK_SIZE; i++) { dst[i] = src[i] ^ iv[i]; } xor_cipher_crypt(tfm, dst, dst); iv = dst; src += XOR_CIPHER_BLOCK_SIZE; dst += XOR_CIPHER_BLOCK_SIZE; blocks--; } nbytes &= XOR_CIPHER_BLOCK_SIZE - 1; skcipher_walk_done(&walk, nbytes); } if ((nbytes = walk.nbytes)) { src = (u8*)walk.src.virt.addr; dst = (u8*)walk.dst.virt.addr; for (i = 0; i < nbytes; i++) { dst[i] = src[i] ^ iv[i]; dst[i] ^= ctx->key[i]; } skcipher_walk_done(&walk, 0); } return 0; }
#define XOR_CIPHER_IV_SIZE 16 static int cbc_decrypt(struct skcipher_request *req) { struct crypto_tfm *tfm = crypto_skcipher_tfm(crypto_skcipher_reqtfm(req)); struct xor_cipher_ctx *ctx = crypto_tfm_ctx(tfm); struct skcipher_walk walk; u8 u[XOR_CIPHER_BLOCK_SIZE], iv[XOR_CIPHER_BLOCK_SIZE]; u32 nbytes; int i, blocks; u8 *src, *dst; skcipher_walk_virt(&walk, req, true); memmove(iv, walk.iv, XOR_CIPHER_IV_SIZE); while ((nbytes = walk.nbytes) >= XOR_CIPHER_BLOCK_SIZE) { src = (u8*)walk.src.virt.addr; dst = (u8*)walk.dst.virt.addr; blocks = nbytes / XOR_CIPHER_BLOCK_SIZE; while (blocks) { memmove(u, src, XOR_CIPHER_BLOCK_SIZE); xor_cipher_crypt(tfm, dst, src); for (i = 0; i < XOR_CIPHER_BLOCK_SIZE; i++) { dst[i] ^= iv[i]; } memmove(iv, u, XOR_CIPHER_IV_SIZE); dst += XOR_CIPHER_BLOCK_SIZE; src += XOR_CIPHER_BLOCK_SIZE; blocks--; } nbytes &= XOR_CIPHER_BLOCK_SIZE - 1; skcipher_walk_done(&walk, nbytes); } if ((nbytes = walk.nbytes)) { src = (u8*)walk.src.virt.addr; dst = (u8*)walk.dst.virt.addr; for (i = 0; i < nbytes; i++) { dst[i] = src[i] ^ ctx->key[i]; dst[i] ^= iv[i]; } skcipher_walk_done(&walk, 0); } return 0; }
, , , "" skcipher_walk
. , skcipher_walk
skcipher_walk_virt
, skcipher_walk_done
"" / ( walk.src.virt.addr
walk.dst.virt.addr
) walk.nbytes
, scatterlist
-.
skcipher_alg
, / :
static struct skcipher_alg cbc_xor_cipher = { .base = { .cra_name = "cbc(xor-cipher)", .cra_driver_name = "cbc-xor-cipher", .cra_priority = 400, .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = 1, .cra_ctxsize = sizeof(struct xor_cipher_ctx), .cra_module = THIS_MODULE, }, .min_keysize = XOR_CIPHER_KEY_SIZE, .max_keysize = XOR_CIPHER_KEY_SIZE, .ivsize = XOR_CIPHER_IV_SIZE, .setkey = xor_skcipher_setkey, .encrypt = cbc_encrypt, .decrypt = cbc_decrypt, .chunksize = XOR_CIPHER_BLOCK_SIZE, }; static int __init xor_cipher_init(void) { crypto_register_alg(&xor_cipher); return crypto_register_skcipher(&cbc_xor_cipher); } static void __exit xor_cipher_exit(void) { crypto_unregister_alg(&xor_cipher); crypto_unregister_skcipher(&cbc_xor_cipher); }
cra_blocksize
. , , skcipher_walk_done
"" , .
, /proc/crypto
:
name : cbc(xor-cipher) driver : cbc-xor-cipher module : xor_cipher priority : 400 refcnt : 1 selftest : passed internal : no type : skcipher async : yes blocksize : 1 min keysize : 16 max keysize : 16 ivsize : 16 chunksize : 16
( ) : " xor-cipher
" ( ) " cbc(xor-cipher)
" ( ). , , . , ( arch/x86/crypto ), .
[4]
, , "", , , , . , , — , : , , Crypto API . , , , .
. cipher_testvec_t
:
typedef enum test_t { TEST_BLK_ENCRYPT = 0, TEST_BLK_DECRYPT, TEST_CBC_ENCRYPT, TEST_CBC_DECRYPT, TEST_END, } test_t; struct cipher_testvec_t { test_t test; u32 len; char *key; char *iv; char *in; char *result; };
: in
, len
, ( .test = TEST_BLK_*
) ( .test = TEST_CBC_*
), key
, , iv
. result
. TEST_END
cipher_testvec_t
.
— :
static int test_blk(cipher_testvec_t *testvec) { struct crypto_cipher *tfm = NULL; int encrypt = (testvec->test == TEST_BLK_ENCRYPT) ? 1 : 0; u8 dst[16]; tfm = crypto_alloc_cipher("xor-cipher", 0, 0); if (IS_ERR(tfm)) { pr_err("error allocating xor-cipher: %ld\n", PTR_ERR(tfm)); return 0; } crypto_cipher_setkey(tfm, (u8*)testvec->key, 16); if (encrypt) { crypto_cipher_encrypt_one(tfm, dst, (u8*)testvec->in); } else { crypto_cipher_decrypt_one(tfm, dst, (u8*)testvec->in); } crypto_free_cipher(tfm); if (memcmp(dst, testvec->result, 16)) { pr_err("block %sciphering test failed!\n", encrypt ? "" : "de"); dumpb((u8*)testvec->key, 16, "key"); dumpb((u8*)testvec->in, 16, "in"); dumpb(dst, 16, "result"); dumpb((u8*)testvec->result, 16, "should be"); return 0; } return 1; }
, Single Block Cipher API . , crypto_alloc_cipher
, " xor-cpher ". , ( crypto_cipher_setkey
), , , ( crypto_cipher_encrypt_one
) ( crypto_cipher_decrypt_one
) . , ( crypto_free_cipher
) .
CBC .
static int test_cbc(cipher_testvec_t *testvec) { struct scatterlist sg; struct cb_data_t cb_data; struct crypto_skcipher *tfm = NULL; struct skcipher_request *req = NULL; int encrypt = (testvec->test == TEST_CBC_ENCRYPT) ? 1 : 0; u32 err; u8 *buf = NULL; tfm = crypto_alloc_skcipher("cbc-xor-cipher", 0, 0); if (IS_ERR(tfm)) { pr_err("error allocating cbc-xor-cipher: %ld\n", PTR_ERR(tfm)); goto exit; } req = skcipher_request_alloc(tfm, GFP_KERNEL); if (!req) { pr_err("error allocating skcipher request\n"); goto exit; } buf = kmalloc(testvec->len, GFP_KERNEL); if (!buf) { pr_err("memory allocation error\n"); goto exit; } memmove(buf, (u8*)testvec->in, testvec->len); sg_init_one(&sg, buf, testvec->len); crypto_skcipher_setkey(tfm, (u8*)testvec->key, 16); skcipher_request_set_crypt(req, &sg, &sg, testvec->len, (u8*)testvec->iv); skcipher_request_set_callback(req, 0, skcipher_cb, &cb_data); init_completion(&cb_data.completion); err = (encrypt) ? crypto_skcipher_encrypt(req) : crypto_skcipher_decrypt(req); switch (err) { case 0: break; case -EINPROGRESS: case -EBUSY: wait_for_completion(&cb_data.completion); err = cb_data.err; if (!err) { break; } default: pr_err("failed with error: %d\n", err); goto exit; } if (memcmp(buf, testvec->result, testvec->len)) { pr_err("cbc %sciphering test failed!\n", encrypt ? "" : "de"); dumpb((u8*)testvec->key, 16, "key"); dumpb((u8*)testvec->iv, 16, "iv"); dumpb((u8*)testvec->in, testvec->len, "in"); dumpb(buf, testvec->len, "result"); dumpb((u8*)testvec->result, testvec->len, "should be"); goto exit; } skcipher_request_free(req); crypto_free_skcipher(tfm); kfree(buf); return 1; exit: if (buf) { kfree(buf); } if (req) { skcipher_request_free(req); } if (tfm) { crypto_free_skcipher(tfm); } return 0; }
: API ( Symmetric Key Cipher API ), .
test_cbc
:
- , :
cb_data_t
, - : " cbc-xor-cipher " (
crypto_alloc_skcipher
)skcipher_requset
(skcipher_request_alloc
) - / : (
kmalloc
) , , ;scatterlist
(sg_init_one
) - (
crypto_skcipher_setkey
)skcipher_requset
(skcipher_request_set_crypt
).skcipher_request_set_crypt
, , .scatterlist
, , " ",buf
- , (
skcipher_request_set_callback
)
. API , , , . , , , . skcipher_request_set_callback
. cb_data_t
, ( skcipher_cb
) :
struct cb_data_t { struct completion completion; int err; }; static void skcipher_cb(struct crypto_async_request *req, int error) { struct cb_data_t *data = req->data; if (error == -EINPROGRESS) { return; } data->err = error; complete(&data->completion); }
completion
test_cbc
, . , , test_cbc
. , test_cbc
, :
-
completion
(init_completion
), - , (
crypto_skcipher_encrypt
) (crypto_skcipher_decrypt
) - :
- 0 ,
-
-EINPROGRESS
-EBUSY
, . ,completion
(complete
wait_for_completion
),
-
-
crypto_skcipher_encrypt
-
insmod: ERROR: could not insert module xor_cipher_testing.ko: Operation not permitted
( dmesg
) :
[---] done 4 tests, passed: 4, failed: 0
, SK Cipher API , . — "", Asynchronous Block Cipher API , . -, -, , .
[4.1] user-space
, . , , , , , , Linux . libkcapi , Crypto API ( ). "" Netlink -, "" Netlink API . , , , , , ( 1.0.3).
, . , , , ( ), Crypto API . af_alg Strongswan , .
, . , , . , , . , test_cbc
.
static int test_cbc(cipher_testvec_t *testvec) { uint8_t dst[testvec->len]; int encrypt = (testvec->test == TEST_CBC_ENCRYPT) ? 1 : 0; struct af_alg_skcipher *tfm = NULL; tfm = af_alg_allocate_skcipher("cbc-xor-cipher"); if (!tfm) { fprintf(stderr, "error allocating \"cbc-xor-cipher\"\n"); goto err; } if (!af_alg_skcipher_setkey(tfm, (uint8_t*)testvec->key, XOR_CIPHER_KEY_SIZE)) { fprintf(stderr, "can't set \"cbc-xor-cipher\" key\n"); goto err; } if (!af_alg_skcipher_crypt(tfm, encrypt, dst, testvec->len, (uint8_t*)testvec->in, (uint8_t*)testvec->iv, XOR_CIPHER_IV_SIZE)) { goto err; } af_alg_free_skcipher(tfm); if (memcmp(dst, (uint8_t*)testvec->result, testvec->len)) { fprintf(stderr, "cbc %sciphering test failed!\n", encrypt ? "" : "de"); dumpb((uint8_t*)testvec->key, XOR_CIPHER_KEY_SIZE, "key"); dumpb((uint8_t*)testvec->iv, XOR_CIPHER_IV_SIZE, "iv"); dumpb((uint8_t*)testvec->in, testvec->len, "in"); dumpb(dst, testvec->len, "result"); dumpb((uint8_t*)testvec->result, testvec->len, "should be"); return 0; } return 1; err: if (tfm) { af_alg_free_skcipher(tfm); } return 0; }
. , , , , , . af_alg_skcipher
af_alg_*
. .
struct af_alg_skcipher { int sockfd; }; static struct af_alg_skcipher* af_alg_allocate_skcipher(char *name) { struct af_alg_skcipher *tfm = NULL; struct sockaddr_alg sa = { .salg_family = AF_ALG, .salg_type = "skcipher", }; strncpy((char*)sa.salg_name, name, sizeof(sa.salg_name)); tfm = calloc(1, sizeof(struct af_alg_skcipher)); if (!tfm) { errno = ENOMEM; goto err; } tfm->sockfd = socket(AF_ALG, SOCK_SEQPACKET, 0); if (tfm->sockfd == -1) { goto err; } if (bind(tfm->sockfd, (struct sockaddr*)&sa, sizeof(sa)) == -1) { goto err; } return tfm; err: if (tfm->sockfd > 0) { close(tfm->sockfd); } if (tfm) { free(tfm); } return NULL; }
:
-
sockaddr_alg
( ) - (
calloc
) - Crypto API (
socket
)
socket
, "" . AF_ALG Crypto API . AF_ALG , , sys/socket.h , , :
#ifndef AF_ALG #define AF_ALG 38 #endif
- , (
bind
)
sockaddr_alg
, bind
:
/* sys/socket.h */ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockadr
:
struct sockaddr { sa_family_t sa_family; char sa_data[14]; }
, , ( sa_family
), AF_ALG :
/* linux/if_alg.h */ struct sockaddr_alg { __u16 salg_family; __u8 salg_type[14]; __u32 salg_feat; __u32 salg_mask; __u8 salg_name[64]; };
:
-
salg_family
: . -
salg_type
: : "skcipher
" — , "hash
" — , "aead
" — , AEAD , "rng" — -
salg_name
: (cra_name
cra_driver_name
)
, bind
-1, errno
ENOENT
.
, af_alg_allocate_skcipher
, . .
:
static int af_alg_skcipher_setkey(struct af_alg_skcipher *tfm, uint8_t *key, uint32_t keylen) { return (setsockopt(tfm->sockfd, SOL_ALG, ALG_SET_KEY, key, keylen) == -1) ? 0 : 1; }
setsockopt
, man - . , SOL_ALG
ALG_SET_KEY
, , sys/socket.h linux/af_alg.h , , , , :
#ifndef SOL_ALG #define SOL_ALG 279 #endif #ifndef ALG_SET_KEY #define ALG_SET_KEY 1 #endif
, .
static int af_alg_skcipher_crypt(struct af_alg_skcipher *tfm, int encrypt, uint8_t *_dst, uint32_t _len, uint8_t *_src, uint8_t *iv, uint32_t ivlen) { int type = encrypt ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT; struct msghdr msg = {}; struct cmsghdr *cmsg; struct af_alg_iv *ivm; struct iovec iov; char buf[CMSG_SPACE(sizeof(type)) + CMSG_SPACE(offsetof(struct af_alg_iv, iv) + ivlen)]; int op = 0; ssize_t len, remainig = _len; uint8_t *src = _src, *dst = _dst; op = accept(tfm->sockfd, NULL, 0); if (op == -1) { goto end; } memset(buf, 0, sizeof(buf)); /* fill in af_alg cipher controll data */ msg.msg_control = buf; msg.msg_controllen = sizeof(buf); /* operation type: encrypt or decrypt */ cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_ALG; cmsg->cmsg_type = ALG_SET_OP; cmsg->cmsg_len = CMSG_LEN(sizeof(type)); memmove(CMSG_DATA(cmsg), &type, sizeof(type)); /* initialization vector */ cmsg = CMSG_NXTHDR(&msg, cmsg); cmsg->cmsg_level = SOL_ALG; cmsg->cmsg_type = ALG_SET_IV; cmsg->cmsg_len = CMSG_LEN(offsetof(struct af_alg_iv, iv) + ivlen); ivm = (void*)CMSG_DATA(cmsg); ivm->ivlen = ivlen; memmove(ivm->iv, iv, ivlen); /* set data stream (scatter/gather list) */ msg.msg_iov = &iov; msg.msg_iovlen = 1; while (remainig) { iov.iov_base = src; iov.iov_len = remainig; len = sendmsg(op, &msg, 0); if (len == -1) { if (errno == EINTR) { continue; } goto end; } while (read(op, dst, len) != len) { if (errno != EINTR) { goto end; } } src += len; remainig -= len; /* no iv for subsequent data chunks */ msg.msg_controllen = 0; } /* done */ close(op); return 1; end: if (op > 0) { close(op); } return 0; }
, . , , , , , . , 3 :
- ,
accept
, , , , - , (
msghdr
), (cmsghdr
) , , / (iovec
)
( ALG_SET_OP
): ( ALG_OP_ENCRYPT
) ( ALG_OP_DECRYPT
), ( ALG_SET_IV
, af_alg_iv
). , , linux/if_alg.h , , , :
#ifndef ALG_SET_IV #define ALG_SET_IV 2 #endif #ifndef ALG_SET_OP #define ALG_SET_OP 3 #endif #ifndef ALG_OP_DECRYPT #define ALG_OP_DECRYPT 0 #endif #ifndef ALG_OP_ENCRYPT #define ALG_OP_ENCRYPT 1 #endif
- , ,
sendmsg
read
, ,accept
, , , /
done 2 tests, passed: 2, failed: 0
— , .
[5] ?
, , , , , , , , . , , . .
— . , , , . , Crypto API . , - API , . , , , , .
, : , , , . , github . !
, "" , — . ! . , xor-cipher , , CBC , ( SK Cipher API , — ):
struct crypto_skcipher *tfm = crypto_alloc_skcipher("cbc(xor-cipher)", 0, 0);
xor-cipher , ( crypto/cbc.c ).
" ! — . — , cbc(xor-cipher) ?". " ", — . , .
, :
- ,
- , " "
. "" . , " cbc ", :
.cra_name = "xor-cipher"; .cra_driver_name = "xor-cipher-generic";
:
.cra_name = "cbc(xor-cipher)"; .cra_driver_name = "cbc(xor-cipher-generic)";
, crypto_alg
, , cra_driver_name
, . , , cra_driver_name
" cbc(xor-cipher-generic) ", :
struct crypto_skcipher *tfm = crypto_alloc_skcipher("cbc(xor-cipher-generic)", 0, 0);
, , , . , Crypto API , , .
tcrypt ( crypto/tcrypt.c ) . , crypto/tcrypt.c , , crypto/testmgr.c . , testmgr , ( ).
, tcrypt . "" tcrypt testmgr , Makefile , — tcryptext (tcrypt External) . .
tcryptext ( tcrypt , ), - , . ( README.md , ).
testmgr.c Crypto API .
, Linux-based . ( ) .
. " crypto " crypto/Kconfig Makefile . , crypto xor_cipher.c , crypto/Kconfig ( comment "Ciphers" ) :
... config CRYPTO_XOR_CIPHER tristate "XOR cipher algorithm" help Custom XOR cipher algorithm. ...
crypto/Makefile :
... obj-$(CONFIG_CRYPTO_XOR_CIPHER) += xor_cipher.o ...
( " Cryptographic API ") . , .
tcrypt testmgr .
便利なリンク
:
- Authenticated encryption
- Linux Kernel Crypto API
- Crypto API Linux
- Linux
- Linux
- (Netfilter) HTTPS
- Scatterlist Cryptographic API
- How SKBs work
- The chained scatterlist API
- libkcapi — Linux Kernel Crypto API User Space Interface Library
- setsockopt(2) — Linux man page
Git: