1

ランダムな一時パスワードを生成するビジネス要件があります。ユースケースによると、そのような通話の量は非常に少ないと予想されます (〜 400 通話/日)。java.security.SecureRandomインターネット上のさまざまな推奨事項に従って、SO に関する多くの同様の投稿を読んだ後、暗号的に強力なランダム化を実現するために使用することにしました。

これで、単純なランダマイザー (内部で を使用) が作成されました。これは、Web アプリケーション内でSecureRandomとして使用されることになっています。singletonただし、SO の推奨事項に従って、定期的に再シードすることも必要です。そのために、以下は同じことを実現するサンプル コードです。誰かがそれを見直して、これが適切で合理的に効率的なアプローチであるかどうかをお知らせください。synchronizationまた、スレッドの安全性を維持しながら、コード内でを回避する方法はありますか?:

import java.security.*;
public final class Randomizer {
    private static final Randomizer INSTANCE = new Randomizer();

    private static final String DEFAULT_CSPRNG_ALGO = "SHA1PRNG";

    private volatile SecureRandom sr;
    private volatile long lastSeedTime;

    public static final Randomizer getInstance() throws Exception {
        return INSTANCE;
    }

    public int nextInt(int len) throws RuntimeException {
        reseedRandomAsNeeded();
        return sr.nextInt(len);
    }

    private Randomizer() throws RuntimeException {
        try {
                System.out.printf("%s Constructing Randomizer...%n", Thread.currentThread());
                recreateSecureRandomInstance();
                lastSeedTime = System.nanoTime();
        } catch (NoSuchAlgorithmException e) {
                throw new RuntimeException(e);
        }
    }

    /**
     * TODO Is there a way to avoid the synchronization overhead here? We really
     * only need to synchronize when the reseed happens.
     * 
     * @throws RuntimeException
     */
    private synchronized void reseedRandomAsNeeded() throws RuntimeException {
        if (isItTimeToReseed()) {
                // TODO Need to do a reseed. Just get a new SecureRandom for now.
                try {
                        recreateSecureRandomInstance();
                } catch (NoSuchAlgorithmException e) {
                        throw new RuntimeException(e);
                }
        }
    }

    private boolean isItTimeToReseed() {
        boolean reseed = false;
        long currentTime = System.nanoTime();
        long difference = ((currentTime - this.lastSeedTime) / (1000 * 1000 * 1000)/* *60 * 60 * 24*/);
        // System.out.printf("%s Current time: %d, Last Reseed Time: %d, difference: %d%n",
        // Thread.currentThread(), currentTime, lastSeedTime, difference);

        // TODO For testing, test for just a 3 seconds difference.
        if (difference > 3) {
                reseed = true;
                this.lastSeedTime = currentTime;
        }

        return reseed;
    }

    private void recreateSecureRandomInstance() throws NoSuchAlgorithmException {
        sr = SecureRandom.getInstance(DEFAULT_CSPRNG_ALGO);
        System.out.printf("%s Created a new SecureRandom instance: %s%n", Thread.currentThread(), sr);
    }

}
4

1 に答える 1