伪随机数的预测--1

伪随机数的预测–1

1 简介

关于伪随机数生成器的相关知识,参考解密随机数生成器

Java.util.Random采用的是线性同余法生成伪随机数,种子是48位的,而Random.nextInt返回的是32位数字:next(32)。如下代码,直接是nextSeed右移16位的结果。

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));
}

因此,只要知道两个连续的nextInt值,便可以通过暴力猜解丢失的前18位来获得种子。

2 具体实现

参考cracking random number generators的实现:

;; 常数定义和算法都取自java.util.Random类
(def multiplier 0x5DEECE66D)
(def addend 0xB)
(def mask (dec (bit-shift-left 1 48)))

(defn next-seed
  [seed]
  (bit-and
   (+ (unchecked-multiply seed multiplier)
      addend)
   mask))

(defn next-int
  [seed]
  (-> (next-seed seed)
      (unsigned-bit-shift-right 16)
      unchecked-int))

(defn brute-seed
  "只要有两个连续的randInt值就可以非常快的爆破出种子"
  [v1 v2]
  (loop [i 0]
    (when (< i 65536)
      (let [seed (+ i
                    (* v1 65536))
            test-v (next-int seed)]
        (if (= test-v v2)
          seed
          (recur (inc i)))))))

;;; 以下为测试代码
(def rnd (java.util.Random.))
(def rnd-v1 (.nextInt rnd))
(def rnd-v2 (.nextInt rnd))

rnd-v1
;; => -1680039525
rnd-v2
;; => -1809533376

(def seed (brute-seed rnd-v1 rnd-v2))
seed
;; => -110103070270234

;; 获得下一个随机值
(-> (next-seed seed)
    next-int)
;; => 796622690

;; 与生成的随机值比较,可以看到正确的获取到了下一个Int值
(.nextInt rnd)
;; => 796622690

;; 再测试下下个
(-> (next-seed seed)
    next-seed
    next-int)
;; => -52712848

(.nextInt rnd)
;; => -52712848

3 结尾

猜测216还是很快的.

但对于nextInt(int bound)的调用,由于信息损失较多,就不大可能直接猜解出来,要爆破248速度还没那么快。下一篇是关于php mt_rand的讲解。

作者: ntestoc

Created: 2019-03-15 周五 10:27

猜你喜欢

转载自www.cnblogs.com/ntestoc/p/10535267.html