2012-09-03 25 views
10

Đoạn mã này có an toàn không?Hạt an toàn SecureRandom trong Java

SecureRandom randomizer = new SecureRandom(String.valueOf(new Date().getTime()).getBytes()); 

Đây có phải là cách thích hợp để thể hiện hạt giống ngẫu nhiên an toàn không?

Trả lời

23

Không, bạn nên tránh hàm tạo SecureRandom(byte[]). Nó là cả hai không an toàn và không di động.

Đó là không cầm tay vì nó thường chạy khác trên Windows vs hệ điều hành khác.

Trên hầu hết các hệ điều hành, thuật toán mặc định là "NativePRNG", lấy dữ liệu ngẫu nhiên từ hệ điều hành (thường là "/dev/random") và bỏ qua hạt giống bạn cung cấp.

Trên Windows, thuật toán mặc định là "SHA1PRNG", trong đó kết hợp hạt giống của bạn với một bộ đếm và tính toán một hash của kết quả.

Đây là tin xấu trong ví dụ của bạn, vì đầu vào (thời gian UTC hiện tại tính bằng mili giây) có phạm vi giá trị tương đối nhỏ. Ví dụ, nếu một kẻ tấn công biết rằng RNG được gieo mầm trong vòng 48 giờ qua, họ có thể thu hẹp hạt xuống đến dưới 2 giá trị có thể, ví dụ: bạn chỉ có 27 bit entropy.

Nếu mặt khác, bạn đã sử dụng hàm tạo mặc định SecureRandom() trên Windows, nó sẽ được gọi là hàm gốc CryptoGenRandom để nhận hạt giống 128 bit. Vì vậy, bằng cách xác định hạt giống của riêng bạn, bạn đã làm suy yếu an ninh.

Nếu bạn thực sự muốn ghi đè lên các hạt giống mặc định (ví dụ cho đơn vị thử nghiệm) bạn cũng nên xác định các thuật toán. Ví dụ.

SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); 
sr.setSeed("abcdefghijklmnop".getBytes("us-ascii")); 

Xem thêm How to solve performance problem with Java SecureRandom?
và bài viết trên blog này: http://www.cigital.com/justice-league-blog/2009/08/14/proper-use-of-javas-securerandom/

+1

Lưu ý rằng mã bạn cung cấp không khởi tạo trình tạo ngẫu nhiên giả chỉ với chuỗi được mã hóa làm đầu vào. Vì vậy, nó sẽ tạo ra cùng một ngẫu nhiên mỗi lần.Tôi nghĩ rằng bạn có nghĩa là để hiển thị chính xác điều này, nhưng bạn có thể muốn làm cho rõ ràng hơn trong câu trả lời (vì nó chắc chắn là không an toàn). Nó cũng có thể khác nếu bất kỳ nhà cung cấp nào khác cung cấp '" SHA1PRNG "', vì vậy trong vấn đề đó nó có một chút nguy hiểm. –

+0

Đây là câu trả lời tôi mong đợi, cảm ơn! –

+0

@MaartenBodewes Tại sao bạn cho rằng hạt giống bị bỏ qua khi sử dụng "NativePRNG"? –

1

Mã này là an toàn hợp lý bởi vì nó không chỉ cần sử dụng hạt giống được gieo mầm Randomizer.

Nó không nhiều ngẫu nhiên hơn chỉ sử dụng.

SecureRandom randomizer = new SecureRandom(); 
+2

Đúng, có thể sử dụng mặc định là tốt hơn - giả sử rằng các nhà thiết kế của thuật toán sẽ chọn một lược đồ giống tốt. Đề án trên có thể làm suy yếu hạt giống một chút bằng cách chuyển đổi thành biểu diễn ký tự. –

+4

Nó là đáng kể * ít * ngẫu nhiên hơn bằng cách sử dụng hàm tạo mặc định. – EJP

+0

@PeterLawrey Ở đây bạn khuyên bạn nên sử dụng 'SecureRandom mới()' nhưng tại [this] (http://stackoverflow.com/a/8572501/1317865) bạn nói để sử dụng 'System.nanoTime'. Trong trường hợp này, tôi nên sử dụng 'SecureRandom()' hoặc 'System.nanoTime' mới. Cảm ơn trước – Favolas

2

Tôi nghĩ rằng cách tốt nhất là để cho các hạt giống SecureRandom riêng của mình. Điều này được thực hiện bằng cách gọi nextBytes ngay sau khi tạo ra nó (gọi setSeed sẽ ngăn chặn điều này).

final byte[] dummy = new byte[512]; 
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); 
sr.nextBytes(dummy); 

Bạn muốn sử dụng SHA1PRNG vì nó đảm bảo triển khai không chặn nhanh ngay cả trên Linux, nơi không mặc định.

+2

Nếu cuộc gọi 'nextBytes()' chỉ dành cho việc khởi động hạt giống, tôi sẽ không sử dụng 512 byes nhưng chỉ 1 cho các lý do hiệu quả. – eckes

Các vấn đề liên quan