2016-03-16 60 views
1

我有下面的测试程序,我试图使用种子随机数使用电话号码加上当前时间。它看起来像下面是产生重复。有任何想法吗?随机代码种子生产重复

数= 100000 大小= 683

import java.security.SecureRandom; 
import java.util.HashSet; 
import java.util.Random; 
import java.util.Set; 

public class Test { 
    static int LENGTH = 8; 
    static String VAULES = ""; 
    static int cnt = 0; 

    public static void main(String[] args) { 
     Set<Long> codes = new HashSet<Long>(); 
     for(int i = 0; i < 100000; i++){ 
      Long seed = Long.valueOf(PHONE_VAULES) * 1000 + System.currentTimeMillis() % 1000L; 

      codes.add(seed); 
      System.out.println(generateRandomPassword(seed)); 
      cnt = cnt + 1; 
     } 
     System.out.println("count="+ cnt); 
     System.out.println("size="+ codes.size()); 
    } 

    public static String generateRandomPassword(long seed) { 
     Random random = new SecureRandom(); 
     random.setSeed(seed); 
     return Long.toString(random.nextLong()).substring(1, CODE_LENGTH + 1); 
    } 

} 
+3

不要像那样重置种子。你正在使用'SecureRandom',根本不要设置种子。你为什么设置**种子**? *使用电话号码加当前时间*是什么意思? –

+0

@ElliottFrisch我想根据用户的电话号码和时间戳产生一个随机数,以确保它是一个随机数,但它们是唯一的。 – c12

+2

[Pigeonhole原理](https://en.wikipedia.org/wiki/Pigeonhole_principle)表示不能保证。要么使用顺序号码生成器(1,2,3),要么计划重复项目(不管怎样,不要种下“SecureRandom” - 它是自我播种)。并且不要在每次调用'random'时更新'seed';你几乎保证不会得到一个随机的结果。 –

回答

1

嗯,这是因为你使用System.currentTimeMillis(),这意味着一毫秒,这个值不会改变,所以你做的种子重复yeilding。并且你在1毫秒内多次遍历你的循环

我不认为有一种方法可以在纳秒内获得时间。您应该至少等待一毫秒(如果您的应用程序可能)

0

您生成的不同种子的数量直接与生成所有种子所花费的毫秒数相关联。使用System.currentTimeMillis()测量循环所需的时间然后打印它,我总是有time = size-1

解决方法:改为使用System.nanoTime()

做这个改变,你会一直有size=1000。这是因为%1000L,它将给定电话号码的可能输出数量最大为1000。如果可以,请将其移除。

编辑:从https://docs.oracle.com/javase/7/docs/api/java/security/SecureRandom.html

公共无效过setSeed(长种子)

重新种植该随机对象,使用包含在给定长的种子八个字节。给定的种子补充而不是替代现有的种子。因此,保证重复呼叫绝不会降低随机性。

虽然什么OP是做可能没有必要,它不应该是一个安全隐患,因为setSeed没有了SecureRandom对象复位到一个可预测的状态。

而且,在生产相同的种子和过是不是真的,因为同一事实的一个问题:到底的安全性依赖于SecureRandom的内部工作,而不是在种子生成...