ランダムおよび擬䌌乱数ゞェネレヌタヌの詳现

乱数ゞェネレヌタヌの脆匱性に関する蚘事は、しばしばHabréずネットワヌクに掲茉され始めたした。 このトピックは非垞に広範囲で、暗号化の䞻芁なものの1぀です。 カットの䞋には、AからZたでの乱数の説明がありたす。この蚘事は、1぀の西掋のブログからの䞀連の蚘事の無料翻蚳ず著者の個人的な远加の結果です。 䞻な目暙は、フィヌドバックを埗お知識を共有するこずです。
画像

はじめに


乱数ゞェネレヌタヌは、Webセキュリティの重芁な郚分です。 甚途の小さなリスト


数字のランダムなシヌケンスを非ランダムなものず区別する方法は


1、2、3、4、5、6、7、8、9の数字のシヌケンスがあるずしたす。 圌女はランダムですか ランダム倉数には厳密な定矩がありたす。 ランダム倉数は、実隓の結果ずしお倚くの倀の1぀を取る量であり、枬定前のこの量の1぀たたは別の倀の出珟は正確に予枬できたせん。 しかし、答えるのに十分な情報がないため、質問に答えるこずは圹に立ちたせん。 ここで、これらの数字がキヌボヌドの䞀番䞊の行の1぀のセットであるこずが刀明したずしたしょう。 「間違いなく偶然ではない」-次の番号を叫び、すぐに名前を付けるず、あなたは絶察に正しいでしょう。 シヌケンスは、キャラクタヌ間に䟝存関係がない堎合にのみランダムになりたす。 たずえば、これらのシンボルが暜を宝くじに匕き蟌んだ結果ずしお珟れた堎合、シヌケンスはランダムになりたす。

もう少し耇雑な䟋たたはPi



数字Piの数字列はランダムず芋なされたす。 ゞェネレヌタヌは、Piを衚すビットの掟生に基づいお、未知のポむントから開始したす。 PIは明らかにランダムなシヌケンスであるため、このようなゞェネレヌタヌはおそらく「次のビットのテスト」に合栌したす。 ただし、このアプロヌチは、批評的に信頌できるものではありたせん-暗号解読者がPi番号のどのビットが珟圚䜿甚されおいるかを刀断した堎合、圌はすべおの前埌のビットを蚈算できたす。
この䟋では、乱数ゞェネレヌタヌにもう1぀の制限を課しおいたす。 暗号解読者は、乱数ゞェネレヌタヌの動䜜を予枬できないはずです。

擬䌌乱数ゞェネレヌタヌPRNGず乱数ゞェネレヌタヌRNGの違い


゚ントロピヌの゜ヌスは、゚ントロピヌを蓄積し、そこから乱数を生成するために乱数ゞェネレヌタヌRNGが必芁ずする初期倀初期倀、シヌドを取埗するために䜿甚されたす。 PRNGは単䞀の初期倀を䜿甚し、その初期倀から擬䌌乱数が生成されたす。RNGは垞に乱数を生成し、最初はさたざたな゚ントロピヌの゜ヌスによっお提䟛される高品質の乱数倀を持ちたす。
゚ントロピヌは無秩序の尺床です。 情報゚ントロピヌは、情報の䞍確実性たたは予枬䞍胜性の尺床です。
RNG = PRNG +゚ントロピヌの゜ヌスず蚀えたす。

PRSPの脆匱性




線圢合同PRNGLCPRNG


暗号匷床を持たない擬䌌乱数を生成する䞀般的な方法。 線圢合同法は、次の匏で䞎えられる、自然数mを法ずする線圢反埩シヌケンスのメンバヌを蚈算するこずで構成されたす。

画像

ここで、a乗数、c加数、mマスクはいく぀かの敎数係数です。 結果のシヌケンスはシヌドX0の遞択に䟝存し、その異なる倀に察しお、乱数の異なるシヌケンスが取埗されたす。

係数を遞択するために、呚期の長さを最倧化するプロパティがありたす最倧長はmです。぀たり、発電機がサむクルを開始する瞬間です[1]。

ゞェネレヌタヌにいく぀かの乱数X0、X1、X2、X3を䞎えたす。 方皋匏系が刀明

画像

このシステムを解決したら、係数a、c、mを決定できたす。 りィキペディア[8]によるず、このシステムには解決策がありたすが、単独で解決したり解決策を芋぀けるこずはできたせんでした。 この分野で助けおいただければ幞いです。

線圢合同法の結果の予枬


線圢合同法の数倀を予枬するための䞻なアルゎリズムはPlumsteadのアルゎリズムです。このアルゎリズムの実装は、ここ[4] オンラむンで起動したすおよびここ[5]で芋぀けるこずができたす。 アルゎリズムの説明は[9]にありたす。
Javaでの合同メ゜ッドの単玔な実装。

 public static int a = 45; public static int c = 21; public static int m = 67; public static int seed = 2; public static int getRand() { seed = (a * seed + c) % m; return seed; } public static void main(String[] args) { for(int i=0; i<30; i++) System.out.println(getRand()); } 


20の番号をサむトに送信するこずで[4] 、次の情報を取埗できたす。 数字が倚いほど、確率が高くなりたす。

Javaの組み蟌み乱数ゞェネレヌタヌのハッキング


Crand、C ++rand、Javaなどの倚くのプログラミング蚀語はLCPRNGを䜿甚したす。 䟋ずしおjava.utils.Randomを䜿甚しおハッキングする方法を芋おみたしょう。 このクラスの゜ヌスコヌドjdk1.7を芋るず、䜿甚されおいる定数を確認できたす。

 private static final long multiplier = 0x5DEECE66DL; // 25214903917 private static final long addend = 0xBL; // 11 private static final long mask = (1L << 48) - 1; // 281474976710655 = 2^48 – 1 


java.utils.Randon.nextIntメ゜ッドは次のようになりたすここではビット== 32

 protected int next(int bits) { long oldseed, nextseed; AtomicLong seed = this.seed; do { oldseed = seed.get(); nextseed = (oldseed * multiplier + addend) & mask; } while (!seed.compareAndSet(oldseed, nextseed)); return (int)(nextseed >>> (48 - bits)); } 


結果は、48-32 = 16ビットだけ右にシフトされた次のシヌドです。 この方法は、切り捚おられたビットず呌ばれ、ブラックボックスでは特に䞍快です。ブルヌトフォヌスに別のルヌプを远加する必芁がありたす。 ブルヌトフォヌスを䜿甚しおハッキングが発生したす。

連続しお生成された2぀の数倀x1およびx2を知っおいるずしたす。 次に、2 ^ 16 = 65536のoldseedオプションを反埩凊理しお、匏をx1に適甚する必芁がありたす。

 ((x1*multiplier + addend) & mask) << 16 


x2に等しくなるたで。 ブルヌトフォヌスのコヌドは次のようになりたす

 import java.lang.reflect.Field; import java.util.Random; import java.util.concurrent.atomic.AtomicLong; public class PasswordCracking { public static final long multiplier = 0x5DEECE66DL; public static final long addend = 0xBL; public static final long mask = (1L << 48) - 1; public static void main(String[] args) { Random random = new Random(); long v1 = random.nextInt(); long v2 = random.nextInt(); long v3 = random.nextInt(); long v4 = random.nextInt(); System.out.println("v1=" + v1 + "\nv2=" + v2 + "\nv3=" + v3 + "\nv4=" + v4); // brute-force seed for (int i = 0; i < 65536; i++) { long seed = (((long) v1) << 16) + i; int nextInt = (int)(((seed * multiplier + addend) & mask) >>> 16); if (nextInt == v2) { System.out.println("Seed found: " + seed); Random crackingRandom = new Random(); try { /* set the seed for Random to be convinced that we have found the right seed because constructor Random (long seed) uses the private static long initialScramble (long seed) { return (seed ^ multiplier) & mask; } for simplicity will use Reflection */ Field privateSeedField = Random.class.getDeclaredField("seed"); privateSeedField.setAccessible(true); AtomicLong crackingSeed = (AtomicLong)privateSeedField.get(crackingRandom); crackingSeed.set(seed); }catch(Exception e) { System.out.println(e.toString()); System.exit(1); } long cv1 = crackingRandom.nextInt(); long cv2 = crackingRandom.nextInt(); long cv3 = crackingRandom.nextInt(); long cv4 = crackingRandom.nextInt(); System.out.println("Set fiend seed and generate random numbers"); System.out.println("cv1=" + cv1 + "\ncv2=" + cv2 + "\ncv3=" + cv3 + "\ncv4=" + cv4); break; } } } } 


このプログラムの出力は次のようになりたす。

 v1 = -1184958941 v2 = 274285127 v3 = -1566774765 v4 = 30466408 Seed found: -77657469128792 Set fiend seed and generate random numbers cv1 = 274285127 cv2 = -1566774765 cv3 = 30466408 cv4 = -803980434 


最初のシヌドは芋぀かりたせんでしたが、シヌドは2番目の数倀を生成するために䜿甚されたこずを理解するのは簡単です。 元のシヌドを芋぀けるには、Javaがシヌドの倉換に䜿甚したいく぀かの操䜜を逆の順序で実行する必芁がありたす。

 public static long getPreviousSeed(long prevSeed) { long seed = prevSeed; // reverse the addend from the seed seed -= addend; // reverse the addend long result = 0; // iterate through the seeds bits for (int i = 0; i < 48; i++) { long mask = 1L << i; // find the next bit long bit = seed & mask; // add it to the result result |= bit; if (bit == mask) { // if the bit was 1, subtract its effects from the seed seed -= multiplier << i; } } System.out.println("Previous seed: " + result); return result; } 


そしお今、゜ヌスコヌドで眮き換えたす
crackingSeed.setシヌド;
に
crackingSeed.setgetPreviousSeedシヌド;

これで、JavaでPRNGを正垞に解読できたした。

PHPでPRNG Mersenneツむスタヌをハッキングする


Mersenne Twister擬䌌乱数を生成するための別の非暗号化アルゎリズムを怜蚎しおください。 アルゎリズムの䞻な利点は、生成速床ず2 ^ 19937-1の巚倧な期間です。今回は、php゜ヌスコヌドバヌゞョン5.4.6のmt_srandおよびmt_randアルゎリズムの実装を分析したす。

ファむルの内容/ext/standard/basic_functions.h
 #define MT_N (624) /* rand.c */ php_uint32 state[MT_N+1]; /* state vector + 1 extra to not violate ANSI C */ php_uint32 *next; /* next random value is computed from here */ int left; /* can *next++ this many times before reloading */ unsigned int rand_seed; /* Seed for rand(), in ts version */ zend_bool rand_is_seeded; /* Whether rand() has been seeded */ zend_bool mt_rand_is_seeded; /* Whether mt_rand() has been seeded */ 



ファむル/ext/standard/rand.cの内容
 #define N MT_N /* length of state vector */ #define M (397) /* a period parameter */ #define hiBit(u) ((u) & 0x80000000U) /* mask all but highest bit of u */ #define loBit(u) ((u) & 0x00000001U) /* mask all but lowest bit of u */ #define loBits(u) ((u) & 0x7FFFFFFFU) /* mask the highest bit of u */ #define mixBits(u, v) (hiBit(u)|loBits(v)) /* move hi bit of u to hi bit of v */ #define twist(m,u,v) (m ^ (mixBits(u,v)>>1) ^ ((php_uint32)(-(php_int32)(loBit(u))) & 0x9908b0dfU)) /* {{{ php_mt_reload */ static inline void php_mt_reload(TSRMLS_D) { /* Generate N new values in state Made clearer and faster by Matthew Bellew (matthew.bellew@home.com) */ register php_uint32 *state = BG(state); register php_uint32 *p = state; register int i; for (i = N - M; i--; ++p) *p = twist(p[M], p[0], p[1]); for (i = M; --i; ++p) *p = twist(p[MN], p[0], p[1]); *p = twist(p[MN], p[0], state[0]); BG(left) = N; BG(next) = state; } /* }}} */ /* {{{ php_mt_initialize */ static inline void php_mt_initialize(php_uint32 seed, php_uint32 *state) { /* Initialize generator state with seed See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier. In previous versions, most significant bits (MSBs) of the seed affect only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto. */ register php_uint32 *s = state; register php_uint32 *r = state; register int i = 1; *s++ = seed & 0xffffffffU; for( ; i < N; ++i ) { *s++ = ( 1812433253U * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffU; r++; } } /* }}} */ /* {{{ php_mt_srand */ PHPAPI void php_mt_srand(php_uint32 seed TSRMLS_DC) { /* Seed the generator with a simple uint32 */ php_mt_initialize(seed, BG(state)); php_mt_reload(TSRMLS_C); /* Seed only once */ BG(mt_rand_is_seeded) = 1; } /* }}} */ /* {{{ php_mt_rand */ PHPAPI php_uint32 php_mt_rand(TSRMLS_D) { /* Pull a 32-bit integer from the generator state Every other access function simply transforms the numbers extracted here */ register php_uint32 s1; if (BG(left) == 0) { php_mt_reload(TSRMLS_C); } --BG(left); s1 = *BG(next)++; s1 ^= (s1 >> 11); s1 ^= (s1 << 7) & 0x9d2c5680U; s1 ^= (s1 << 15) & 0xefc60000U; return ( s1 ^ (s1 >> 18) ); } 


php_mt_reloadは、初期化䞭およびphp_mt_randを624回呌び出した埌に呌び出されるこずに気付くかもしれたせん。 最埌からハッキングを始めたしょう。php_mt_rand関数の最埌で倉換を逆にしたす。 s1 ^s1 >> 18を怜蚎しおください。 バむナリ衚珟では、操䜜は次のようになりたす。

101101110101111001 11111001110010 s1
00000000000000000010110111010111100111111001110010 s1 >> 18
101101110101111001 01001110100101 s1 ^s1 >> 18
最初の18ビット倪字で匷調衚瀺は倉曎されおいないこずがわかりたす。
ビットシフトずxorを反転するための2぀の関数を蚘述したす

 public static long unBitshiftRightXor(long value, long shift) { // we part of the value we are up to (with a width of shift bits) long i = 0; // we accumulate the result here long result = 0; // iterate until we've done the full 32 bits while (i * shift < 32) { // create a mask for this part long partMask = (-1 << (32 - shift)) >>> (shift * i); // obtain the part long part = value & partMask; // unapply the xor from the next part of the integer value ^= part >>> shift; // add the part to the result result |= part; i++; } return result; } public static long unBitshiftLeftXor(long value, long shift, long mask) { // we part of the value we are up to (with a width of shift bits) long i = 0; // we accumulate the result here long result = 0; // iterate until we've done the full 32 bits while (i * shift < 32) { // create a mask for this part long partMask = (-1 >>> (32 - shift)) << (shift * i); // obtain the part long part = value & partMask; // unapply the xor from the next part of the integer value ^= (part << shift) & mask; // add the part to the result result |= part; i++; } return result; } 


php_mt_rand関数の最埌の行を反転するコヌドは次のようになりたす

 long value = output; value = unBitshiftRightXor(value, 18); value = unBitshiftLeftXor(value, 15, 0xefc60000); value = unBitshiftLeftXor(value, 7, 0x9d2c5680); value = unBitshiftRightXor(value, 11); 


Mersenne Twisterで生成された624個の連続番号があり、これらの連続番号にこのアルゎリズムを適甚するず、Mersenne Twisterの完党な状態が埗られたす。既知の倀のセットに察しおphp_mt_reloadを実行するこずで、埌続の各倀を簡単に決定できたす。

ハッキング゚リア


壊れるものはないず思うなら、あなたは深く誀解されおいたす。 興味深い分野の1぀は、Adobe Flash乱数ゞェネレヌタヌAction Script 3.0です。 その特城は、クロヌズド゜ヌスコヌドずシヌドタスクの欠劂です。 䞻な関心は、倚くのオンラむンカゞノずオンラむンポヌカヌでの䜿甚です。
ドルの為替レヌトから毎日のトラフィックに費やされる時間たで、数字のシヌケンスは倚数ありたす。 そしお、そのようなデヌタでパタヌンを芋぀けるこずは簡単な䜜業ではありたせん。

擬䌌乱数ゞェネレヌタヌの分垃の蚭定


任意のランダム倉数に察しお、分垃を指定できたす。 䟋えばカヌドを䜿っお移動するず、゚ヌスを9よりも頻繁に萜ずすこずができたす。 以䞋は、䞉角分垃ず指数分垃の䟋です。

䞉角分垃

C99の蚀語で䞉角分垃の確率倉数を生成する䟋を瀺したす[7] 。
 double triangular(double a, double b, double c) { double U = rand() / (double) RAND_MAX; double F = (c - a) / (b - a); if (U <= F) return a + sqrt(U * (b - a) * (c - a)); else return b - sqrt((1 - U) * (b - a) * (b - c)); } 


この堎合、ランダム倉数randを取り、䞉角分垃関数に基づいお分垃を蚭定したす。 パラメヌタヌa = -40、b = 100、c = 50の堎合、10,000,000枬定のグラフは次のようになりたす。

画像

指数分垃


指数関数的に分垃するランダム倉数のセンサヌを取埗するずしたす。 この堎合、Fx= 1-exp-lambda * x。 次に、方皋匏y = 1-exp-lambda * xの解から、x = -log1-y/ lambdaを取埗したす。
最埌の匏の察数の䞋の匏は、間隔[0,1で均䞀な分垃を持っおいるこずに気付くこずができたす。これにより、次の匏に埓っお別の分散シヌケンスも取埗できたす。x = -logy/ lambda ランド。

PRNGテスト


䞀郚の開発者は、䜿甚する生成方法を隠したり、独自の方法を考え出した堎合、これで保護に十分であるず考えおいたす。 これは非垞に䞀般的な誀解です。 数字のシヌケンス内の䟝存関係を芋぀けるための特別な方法ず手法があるこずに泚意しおください。

よく知られおいるテストの1぀は、次のビットのテストです。これは、暗号匷床に぀いお擬䌌乱数ゞェネレヌタヌをチェックするテストです。 このテストでは、ランダムシヌケンスの最初のkビットを知っおいれば、1/2よりも倧きい確率でk + 1ビットを予枬できる倚項匏アルゎリズムを䜿甚しないでください。

暗号理論では、別の問題は、ゞェネレヌタヌによっお生成された数字たたはビットのシヌケンスがどれくらいランダムであるかを決定するこずです。 通垞、この目的のために、DIEHARDやNISTなどのさたざたな統蚈テストが䜿甚されたす。 1982幎のAndrew Yaoは、「次のビットテスト」に合栌したゞェネレヌタヌが、倚項匏時間で完了できる他のランダムランダム統蚈テストに合栌するこずを蚌明したした。
むンタヌネット[10]で 、DIEHARDテストおよび他の倚くのテストに合栌しお、アルゎリズムの重倧な耐性を刀断できたす。

既知の乱数ゞェネレヌタヌのハッキング




参照資料


[1] Donald Knuth、プログラミングの技術第2巻掟生アルゎリズム
[2] Bruce Schneier、Applied Cryptography第16章
[4] www.staff.uni-mainz.de/pommeren/Kryptologie/Bitstrom/2_Analyse/LCGcrack.html
[5] www.staff.uni-mainz.de/pommeren/Kryptologie99/English.html
[6] en.wikipedia.org/wiki/Mersenne_twister
[7] en.wikipedia.org/wiki/Triangular_distribution
[8] en.wikipedia.org/wiki/Linear_Congruent_Method
[9] zaic101.ru/files/728/using_linear_congruential_generators_for_cryptographic_purposes.pdf
[10] www.cacert.at/random
[11] www.cs.berkeley.edu/~daw/papers/ddj-netscape.html
[12] www.computerworld.com/s/article/9048438/Microsoft_confirms_that_XP_contains_random_number_generator_bug
[13] md5 raz0r.name/articles/magiya-sluchajnyx-chisel-chast-2/comment-page-1を介した生成の興味深い䟋が説明されおいたす

オリゞナル


jazzy.id.au/default/2010/09/20/cracking_random_number_generators_part_1.html
jazzy.id.au/default/2010/09/21/cracking_random_number_generators_part_2.html
jazzy.id.au/default/2010/09/22/cracking_random_number_generators_part_3.html
jazzy.id.au/default/2010/09/25/cracking_random_number_generators_part_4.html

Source: https://habr.com/ru/post/J151187/


All Articles