ホームSora neko ブロックチェーン開発→Secure ZeroMemoryとは?

Secure ZeroMemoryとは?

ブロックチェーンでは「鍵」を扱うため、
Secure ZeroMemory、メモリロック、メモリプロテクト、ならびにSecure Allocatorの実装が必須です。
このうちここでは、Secure ZeroMemoryを扱います。

メモリアロケータとは?

メモリの動的確保および解放を行う仕組みは「メモリアロケータ」と呼ばれております。
最も探索が早い2のべき乗を利用して指定されたサイズ以上を次々と効率よく確保していく仕組みです。
その確保されたメモリを解放したとき、
その内容を「ゼロで塗り潰す作業」が、このSecure ZeroMemoryです。
ここで……この「メモリアロケータ」が塗り潰しを担当しそうですが、そうではないので注意です。
まず「メモリの確保」については、チャンクで分割されたテーブルを参照して割り当てる作業が行われており、
次に「メモリの解放」については、テーブル側を操作して空きサイズを「マージするだけ」となっております。
すなわち、実際に使用されていたメモリについては、解放しても「中身はそのまま」になっております。
よく……delete演算子後でも、アクセスして読めてしまうという「バグ」は、これが原因です。

中身はそのまま?

わざわざテーブルまで持ち出して、最速でメモリを動的確保するのですから、
解放するときに、メモリの中身までを消去するという作業を行うはずがありません。
よって、使用されていたメモリの内容がそのまま残っています。
そして、次にどこかの場面で使用されるまでは「そのまま」です。
しかし、それでは困る場合があります。
これが……「鍵」はもちろん「パスフレーズ」だった場合であっても、
それらの内容が使用後でもメモリ上に残ってしまうことになります。

ではメモリ解放前に::memsetですね?

コード上は、::memsetを行い、メモリの内容にゼロでも整数でも埋めてあげれば問題ないはずでした。
しかし、単に::memsetをするだけでは、その作用は取り除かれてしまいます。
なぜなら、解放前に::memsetする作用は一般的に「必要がない」ために、
コンパイラの最適化により、自動的にその::memsetが「取り除かれて」しまうためです。

そのため、コンパイラ最適化で取り除かれない手法を使います

1: OpenSSL
::OPENSSL_cleanse()という関数が用意されております。
実装の方は、埋め込む数値をグローバル変数に置いて乱雑化させる仕組みでした。
グローバル変数から変化させる数値の埋め込みになるため、コンパイラの最適化では除去されません。
ただ、マルチスレッドでは問題ないの? という議論はありました。
もちろん、そのグローバルの数値自体には意味がないため、問題はありません。
しかし、そのようなスレッドバグを検知できるシステムで、これを検証させたら「エラー」扱いですね。(^^;

2: SecureZeroMemory()
実は……専用のAPIがあります。ただし「WindowsAPI」です。つまり、Windows版に限ります。(^^;

3: volatileで::memsetを別の関数で再定義
ハッシュ関数Blake2の実装で、興味深い実装方法がありました。ご紹介いたします。
※ シンプルでわかりやすく、別に定義されたmemset_vを呼び出すだけです。
static void *(*const volatile memset_v)(void *, int, size_t) = &memset;
memset_v(v, 0, n);

サンプルコード(Blake2より)

inline void secure_memzero(void *v, size_t n)
{
    static void *(*const volatile memset_v)(void *, int, size_t) = &memset;
    memset_v(v, 0, n);
}
		
□ 本ページをご覧いただきました方は、以下のページもよくご覧いただいております。
■ 集計中.....