1. 程式人生 > >如何在各種程式語言中生成安全的隨機數?

如何在各種程式語言中生成安全的隨機數?

轉自:如何在各種程式語言中生成安全的隨機數? 
安全隨機數圖 
生成安全的隨機資料指什麼?為什麼要生成安全的隨機資料?之前一些文獻中這並沒有很好得說明如何生成“安全”的隨機數。所以,這裡將介紹如何在下面的程式語言中安全地生成隨機數。

  • C/C++

  • Java

  • .NET

  • Node.js

  • PHP

  • Python

  • Ruby

需要包含的一般條件

這篇文章的所有方案都必須只從核心的CSPRNG(Cryptographically Secure Pseudo-Random Number Generator,密碼安全的偽隨機數生成器)中讀取,並且失敗後立即關閉。使用者空間的RNG以及回退到不安全的RNG都是不允許的。所以,根據平臺的不同,使用下面的熵源:

  • Windows: 
    RtlGenRandom

  • Linux: 
    getrandom (如何可用的話) 
    它的方法是正確的,在播種之前會阻塞,之後不再播種。 
    /dev/urandom (老的Linux核心) 
    對於在Linux啟動時執行的軟體,查詢/dev/random,直到它可用。 
    不要從/dev/random中讀取。

  • OpenBSD: 
    getentropy() 
    arc4random_buf() 使用ChaCha20加密演算法 (不是RC4)

  • 其它類Unix系統 (包括OS X): 
    /dev/urandom

這裡不考慮依賴於haveged,egd等程式的解決方案。

C/C++中的密碼安全隨機

最簡單和安全的方法是,把libsodium庫新增到工程的依賴庫中,使用randombytes_buf()函式。

這裡檢視libsodium是怎樣實現這些函式的。PHP團隊在其內部的random_bytes函式實現中採用了與此類似的方法。

#include "sodium.h"

int foo() {

    char myString[32];
    int myInt;

    /* myString will be a string of 32 random bytes */
    randombytes_buf(myString, 32);

    /* myInt will be a random number between 0 and 9 */
    myInt = randombytes_uniform(10);
}

如果可以的話就使用libsodium,下面的其它語言也是如此。

Java中的密碼安全隨機

除了使用libsodium(推薦),也可以直接使用Java的SecureRandom類:

SecureRandom csprng = new SecureRandom();

byte[] randomBytes = new byte[32];

csprng.nextBytes(randomBytes);

備註:SecureRandom類,此類提供加密的強隨機數生成器 (RNG)。 
檔案頭要加入該句import java.security.SecureRandom; 
注意:不要在Linux上使用SecureRandom.getInstanceStrong(),不要被名稱誤導,它等同於讀取/dev/random,這個是不安全的。Java8中new SecureRandom()預設讀取/dev/urandom,這才是你需要的。

.NET(C#)中的密碼安全隨機

普遍採用的方案是使用System.Security.Cryptography.RNGCryptoServiceProvider,比如:

RandomNumberGenerator csprng = new RNGCryptoServiceProvider();

byte[] rawByteArray = new byte[32];

csprng.getBytes(rawByteArray);

如果你需要生成密碼上安全的整數,檢視Inferno(一個Stan Drapkin寫的.NET密碼庫)中的CryptoRandom類的實現方法。

Node.js中的密碼安全隨機

不要使用crypto.randomBytes()

在openssl抹掉crypto.randomBytes之前,你最好的選擇是使用node-sodium(來替代這個函式)

var csprng = require("sodium").Random;

var bytes = csprng.randombytes_buf(32);

PHP中的密碼安全隨機

如果你執行的是PHP 7,有一個內建的函式:

$string = random_bytes(32);

$integer = random_int(0, PHP_INT_MAX);

如何你用的還是PHP 5, 獲取random_compat,然後同PHP 7一樣使用相同的API。

composer require paragonie/random_compat:^2

請使用版本2。版本1會回退到OpenSSL,如果沒有其它可用的熵源,它會導致安全問題。然而,一些人為了相容性,會明確地使用版本1。

如果你在寫一個供別人在他們的工程中使用的PHP 5庫,將你的composer.json條件字串設定為^1|^2。相反,如果你在寫一個應用程式,將條件字串設定為^2。

Python中的密碼安全隨機

如果你沒有使用libsodium:

如果你需要隨機位元組,使用os.urandom().

如果你需要其它格式的隨機資料,你需要使用random.SystemRandom(),而不是random。

import sys

import random

# Random bytes

bytes = os.urandom(32)

csprng = random.SystemRandom()

# Random (probably large) integer

int = csprng.randint(0, sys.maxint)

Ruby中的密碼安全隨機

不要使用Ruby的SecureRandom!

與名稱無關,它不是最好的CSPRNG。幸運的是,Tony Arcieri(密碼專家,Cryptosphere 的設計者,全面的密碼應用工程師)給Ruby community提供了一個安全的選擇,將libsodium的sysrandom介面移植到了Ruby gem中。

建議:使用Sysrandom代理SecureRandom。

安裝sysrandom:

gem install sysrandom
  • 1

Sysrandom與SecureRandom API相容。可以通過打補丁來代替SecureRandom。

*本文譯者:felix,翻譯自:https://paragonie.com/blog/2016/05/how-generate-secure-random-numbers-in-various-programming-languages,轉載須註明來自FreeBuf黑客與極客(FreeBuf.COM)