CWE Rule 311
説明
ルールの説明
The software does not encrypt sensitive or critical information before storage or transmission.
Polyspace 実装
ルール チェッカーは以下の問題をチェックします。
暗号アルゴリズムがありません
処理する暗号データがありません
暗号化の最終ステップがありません
暗号キーがありません
例
この問題は、暗号コンテキストの設定時に暗号アルゴリズムを割り当てなかった場合に発生します。
暗号コンテキストは、アルゴリズムを指定しないで初期化することができます。ただし、データを暗号化または復号化する前には、暗号コンテキストに暗号アルゴリズムを関連付けなければなりません。
暗号アルゴリズムがないと、ランタイム エラーが発生するか、少なくとも安全ではない暗号文になる可能性があります。
暗号化または復号化の前には、暗号アルゴリズムとモード、暗号化または復号化のキー、初期化ベクトル (初期化ベクトルが必要なモードの場合) など、暗号化に必要な情報をもつ暗号コンテキストを設定します。
ret = EVP_EncryptInit(&ctx, EVP_aes_128_cbc(), key, iv)
EVP_aes_128_cbc()
は、暗号化に高度暗号化標準 (AES) アルゴリズムを使用しなければならないことを指定します。また、128 ビットのブロック サイズと、Cipher Block Chaining (CBC) モードも指定しています。アルゴリズムを指定する代わりに、初期化ステップで NULL を使用することができます。ただし、暗号化または復号化に暗号コンテキストを使用する前に、アルゴリズムを暗号コンテキストに関連付ける追加の初期化を実行しなければなりません。そうでない場合、暗号化または復号化の更新ステップでランタイム エラーが発生する可能性があります。
暗号化または復号化のステップの前
ret = EVP_EncryptUpdate(&ctx, out_buf, &out_len, src, len)
ctx
にアルゴリズムを関連付けます。ret = EVP_EncryptInit(ctx, EVP_aes_128_cbc(), key, iv)
#include <openssl/evp.h>
#include <stdlib.h>
#define SIZE16 16
unsigned char key[SIZE16];
unsigned char iv[SIZE16];
void func(void) {
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(ctx);
EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv); //Noncompliant
}
この例では、暗号コンテキスト ctx
を初期化するときにアルゴリズムを指定していません。
データを暗号化または復号化する前に、暗号アルゴリズムを指定しなければなりません。2 回目の初期化を実行してアルゴリズムを指定する場合、この暗号コンテキストは完全に再初期化されます。そのため、EVP_EncryptInit_ex
を使用する現在の初期化ステートメントは冗長になります。
1 つの修正方法として、暗号コンテキストの初期化時にアルゴリズムを指定します。修正した次のコードでは、ルーチン EVP_aes_128_cbc
が高度暗号化標準 (AES) アルゴリズムを呼び出します。このルーチンでは、暗号化に 128 ビットのブロック サイズと、Cipher Block Chaining (CBC) モードも指定しています。
#include <openssl/evp.h>
#include <stdlib.h>
#define SIZE16 16
unsigned char key[SIZE16];
unsigned char iv[SIZE16];
void func(unsigned char *src, int len, unsigned char *out_buf, int out_len) {
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(ctx);
/* Initialization of cipher context */
EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv); //Compliant
/* Update steps for encryption */
EVP_EncryptUpdate(ctx, out_buf, &out_len, src, len);
}
この問題は、ブロック暗号の暗号化または復号化の最終ステップを不適切に実行した場合に発生します。
たとえば、次のいずれかを行います。
最終ステップを実行する前に、データの暗号化または復号化の更新ステップを実行していない。
/* Initialization of cipher context */ ret = EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv); ... /* Missing update step */ ... /* Final step */ ret = EVP_EncryptFinal_ex(ctx, out_buf, &out_len);
初期化と更新のステップを挟まずに、連続して最終ステップを実行している。
/* Initialization of cipher context */ ret = EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv); ... /* Update step(s) */ ret = EVP_EncryptUpdate(ctx, out_buf, &out_len, src, len); ... /* Final step */ ret = EVP_EncryptFinal_ex(ctx, out_buf, &out_len); ... /* Missing initialization and update */ ... /* Second final step */ ret = EVP_EncryptFinal_ex(ctx, out_buf, &out_len);
暗号コンテキストのクリーンアップを実行してから、最終ステップを実行している。
/* Initialization of cipher context */ ret = EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv); ... /* Update step(s) */ ret = EVP_EncryptUpdate(ctx, out_buf, &out_len, src, len); ... /* Cleanup of cipher context */ EVP_CIPHER_CTX_cleanup(ctx); ... /* Second final step */ ret = EVP_EncryptFinal_ex(ctx, out_buf, &out_len);
ブロック暗号は、データを固定サイズのブロックに分割します。暗号化または復号化時は、更新ステップでブロック内のデータの暗号化または復号化が行われます。最終ステップでは、残りのデータがある場合にそのデータの暗号化または復号化が行われます。最終ステップでは、1 ブロックが埋まるように残りのデータにパディングが追加され、パディング後のデータの暗号化または復号化が行われます。
最終ステップを更新ステップの前に実行したり、処理するデータが存在しないときに最終ステップを実行する場合、未定義の動作になります。また、ランタイム エラーが発生する可能性もあります。
次の順序で暗号化または復号化を実行します。
暗号コンテキストの初期化
更新ステップ
最終ステップ
コンテキストのクリーンアップ
#include <openssl/evp.h>
#include <stdlib.h>
#define SIZE16 16
unsigned char *out_buf;
int out_len;
unsigned char key[SIZE16];
unsigned char iv[SIZE16];
void func(void) {
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(ctx);
/* Initialization of cipher context */
EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv);
/* Missing update steps for encryption */
/* Final encryption step */
EVP_EncryptFinal_ex(ctx, out_buf, &out_len); //Noncompliant
}
この例には、暗号コンテキストを初期化後、データを暗号化する更新ステップがありません。更新ステップではデータの 1 つ以上のブロックを暗号化しなければなりません。最後の部分ブロックに残ったデータは最終ステップで暗号化します。最終ステップの前に更新ステップを実行しない場合、未定義の動作になります。
最終ステップの前に暗号化の更新ステップを実行します。修正した次のコードでは、ルーチン EVP_EncryptUpdate
が更新ステップを実行します。
#include <openssl/evp.h>
#include <stdlib.h>
#define SIZE16 16
unsigned char *out_buf;
int out_len;
unsigned char key[SIZE16];
unsigned char iv[SIZE16];
void func(unsigned char *src, int len) {
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(ctx);
/* Initialization of cipher context */
EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv);
/* Update steps for encryption */
EVP_EncryptUpdate(ctx, out_buf, &out_len, src, len);
/* Final encryption step */
EVP_EncryptFinal_ex(ctx, out_buf, &out_len); //Compliant
}
この問題は、データの暗号化または復号化の更新ステップ後に最終ステップを実行しなかった場合に発生します。
たとえば、次を行います。
/* Initialization of cipher context */
ret = EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv);
...
/* Update step */
ret = EVP_EncryptUpdate(&ctx, out_buf, &out_len, src, len);
...
/* Missing final step */
...
/* Cleanup of cipher context */
EVP_CIPHER_CTX_cleanup(ctx);
ブロック暗号は、データを固定サイズのブロックに分割します。暗号化または復号化時は、更新ステップでブロック内のデータの暗号化または復号化が行われます。最終ステップでは、残りのデータがある場合にそのデータの暗号化または復号化が行われます。最終ステップでは、1 ブロックが埋まるように残りのデータにパディングが追加され、パディング後のデータの暗号化または復号化が行われます。
最終ステップを実行しないと、部分ブロック内の残りのデータが暗号化または復号化されません。不完全な出力や、予期しない出力になる可能性があります。
暗号化または復号化の更新ステップの後に、最終ステップを実行して残りのデータを暗号化または復号化します。
/* Initialization of cipher context */
ret = EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv);
...
/* Update step(s) */
ret = EVP_EncryptUpdate(&ctx, out_buf, &out_len, src, len);
...
/* Final step */
ret = EVP_EncryptFinal_ex(&ctx, out_buf, &out_len);
...
/* Cleanup of cipher context */
EVP_CIPHER_CTX_cleanup(ctx);
#include <openssl/evp.h>
#include <stdlib.h>
#define SIZE16 16
unsigned char *out_buf;
int out_len;
unsigned char key[SIZE16];
unsigned char iv[SIZE16];
void func(unsigned char *src, int len) {
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(ctx);
/* Initialization of cipher context */
EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv);
/* Update steps for encryption */
EVP_EncryptUpdate(ctx, out_buf, &out_len, src, len);
/* Missing final encryption step */
/* Cleanup of cipher context */
EVP_CIPHER_CTX_cleanup(ctx); //Noncompliant
}
この例では、暗号化の最終ステップの前に暗号コンテキスト ctx
をクリーンアップしています。最終ステップは、残りのデータを暗号化しなければなりません。最終ステップを実行しないと、暗号化は不完全になります。
暗号化の更新ステップの後に、暗号化の最終ステップを実行して残りのデータを暗号化します。修正した次のコードでは、ルーチン EVP_EncryptFinal_ex
が最終ステップを実行します。
#include <openssl/evp.h>
#include <stdlib.h>
#define SIZE16 16
unsigned char *out_buf;
int out_len;
unsigned char key[SIZE16];
unsigned char iv[SIZE16];
void func(unsigned char *src, int len) {
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(ctx);
/* Initialization of cipher context */
EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv);
/* Update steps for encryption */
EVP_EncryptUpdate(ctx, out_buf, &out_len, src, len);
/* Final encryption step */
EVP_EncryptFinal_ex(ctx, out_buf, &out_len);
/* Cleanup of cipher context */
EVP_CIPHER_CTX_cleanup(ctx); //Compliant
}
この問題は、NULL 暗号化キーまたは NULL 復号化キーを使用して暗号化または復号化した場合に発生します。
メモ
暗号コンテキストは NULL キーを使用して初期化できます。ただし、データを暗号化または復号化する前には、暗号コンテキストに非 NULL のキーを関連付けなければなりません。
NULL キーを使用して暗号化または復号化を行うと、ランタイム エラーが発生するか、少なくとも安全でない暗号文になる可能性があります。
暗号化または復号化のステップの前
ret = EVP_EncryptUpdate(&ctx, out_buf, &out_len, src, len)
ctx
に非 NULL のキーを関連付けます。ret = EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv)
暗号コンテキストの初期化に非 NULL のキーを使用する場合もあります。
ret = EVP_EncryptInit_ex(&ctx, cipher_algo_1, NULL, key, iv)
ret = EVP_EncryptInit_ex(&ctx, cipher_algo_2, NULL, NULL, NULL)
#include <openssl/evp.h>
#include <stdlib.h>
#define fatal_error() abort()
unsigned char *out_buf;
int out_len;
int func(EVP_CIPHER_CTX *ctx, unsigned char *iv, unsigned char *src, int len){
if (iv == NULL)
fatal_error();
/* Fourth argument is cipher key */
EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, NULL, iv);
/* Update step with NULL key */
return EVP_EncryptUpdate(ctx, out_buf, &out_len, src, len); //Noncompliant
}
この例では、コンテキスト ctx
に関連付けている暗号キーは NULL です。このコンテキストを使用してデータを暗号化すると、ランタイム エラーが発生する可能性があります。
強力な乱数発生器を使用して暗号キーを作成します。修正した次のコードでは、openssl/rand.h
で宣言されている関数 RAND_bytes
を使用します。
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <stdlib.h>
#define fatal_error() abort()
#define SIZE16 16
unsigned char *out_buf;
int out_len;
int func(EVP_CIPHER_CTX *ctx, unsigned char *iv, unsigned char *src, int len){
if (iv == NULL)
fatal_error();
unsigned char key[SIZE16];
RAND_bytes(key, 16);
/* Fourth argument is cipher key */
EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv);
/* Update step with non-NULL cipher key */
return EVP_EncryptUpdate(ctx, out_buf, &out_len, src, len); //Compliant
}
チェック情報
カテゴリ: その他 |
バージョン履歴
R2023b で導入
MATLAB Command
You clicked a link that corresponds to this MATLAB command:
Run the command by entering it in the MATLAB Command Window. Web browsers do not support MATLAB commands.
Web サイトの選択
Web サイトを選択すると、翻訳されたコンテンツにアクセスし、地域のイベントやサービスを確認できます。現在の位置情報に基づき、次のサイトの選択を推奨します:
また、以下のリストから Web サイトを選択することもできます。
最適なサイトパフォーマンスの取得方法
中国のサイト (中国語または英語) を選択することで、最適なサイトパフォーマンスが得られます。その他の国の MathWorks のサイトは、お客様の地域からのアクセスが最適化されていません。
南北アメリカ
- América Latina (Español)
- Canada (English)
- United States (English)
ヨーロッパ
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)