Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/security/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 安全地生成一致随机BigInteger_.net_Security_Random_Cryptography_Biginteger - Fatal编程技术网

.net 安全地生成一致随机BigInteger

.net 安全地生成一致随机BigInteger,.net,security,random,cryptography,biginteger,.net,Security,Random,Cryptography,Biginteger,我想在[0,N]范围内安全地生成一个随机数,其中N是一个参数。但是,System.Security.Cryptography.RandomNumberGenerator仅提供一个GetBytes()方法来用随机值填充数组 (我需要在稍微修改过的SRP版本中使用的nonce的随机整数。“稍微修改过的”部分超出了我的控制,这也是我接触加密内容的唯一原因。) 我已经写了一个方法来做到这一点,但我正在寻找一个更好的方法,或者至少确认我做得对 using System.Numerics ///<s

我想在[0,N]范围内安全地生成一个随机数,其中N是一个参数。但是,System.Security.Cryptography.RandomNumberGenerator仅提供一个GetBytes()方法来用随机值填充数组

(我需要在稍微修改过的SRP版本中使用的nonce的随机整数。“稍微修改过的”部分超出了我的控制,这也是我接触加密内容的唯一原因。)

我已经写了一个方法来做到这一点,但我正在寻找一个更好的方法,或者至少确认我做得对

using System.Numerics

///<summary>Generates a uniformly random integer in the range [0, bound).</summary>
public static BigInteger RandomIntegerBelow(this System.Security.Cryptography.RandomNumberGenerator source, BigInteger bound) {
    Contract.Requires<ArgumentException>(source != null);
    Contract.Requires<ArgumentException>(bound > 0);
    Contract.Ensures(Contract.Result<BigInteger>() >= 0);
    Contract.Ensures(Contract.Result<BigInteger>() < bound);

    //Get a byte buffer capable of holding any value below the bound
    var buffer = (bound << 16).ToByteArray(); // << 16 adds two bytes, which decrease the chance of a retry later on

    //Compute where the last partial fragment starts, in order to retry if we end up in it
    var generatedValueBound = BigInteger.One << (buffer.Length * 8 - 1); //-1 accounts for the sign bit
    Contract.Assert(generatedValueBound >= bound);
    var validityBound = generatedValueBound - generatedValueBound % bound;
    Contract.Assert(validityBound >= bound);

    while (true) {
        //generate a uniformly random value in [0, 2^(buffer.Length * 8 - 1))
        source.GetBytes(buffer);
        buffer[buffer.Length - 1] &= 0x7F; //force sign bit to positive
        var r = new BigInteger(buffer);

        //return unless in the partial fragment
        if (r >= validityBound) continue;
        return r % bound;
    }
}
使用系统数值
///生成范围为[0,界]的均匀随机整数。
public static BigInteger RandomInteger下面(此System.Security.Cryptography.RandomNumberGenerator源,BigInteger绑定){
Contract.Requires(source!=null);
合同要求(绑定>0);
Contract.Result(Contract.Result()>=0);
契约。确保(契约。结果()<绑定);
//获取一个字节缓冲区,该缓冲区能够保存低于界限的任何值
var buffer=(bound=validityBound)continue;
返回r%界;
}
}

该实现在生成范围内的无偏整数时看起来是正确的

另一种方法是将随机字节作为二进制分数
0.xxxxxx…
中的无限位,乘以
bound
,然后向下取整。实际上,它不需要无限位,只需要确定向下取整的结果是什么。我认为这更复杂

但是,对您的协议而言,生成全范围的数字可能是不必要的。第3.1节只需要256位专用指数。该数字来自哈希输出的位长度加倍,并且需要使用安全素数。RFC的早期草案参考了第4节第一段中的解释在那里


如果您喜欢更多的随机位,请将
范围
的位长度减去1。这就是OpenSSL(搜索
BN_rand
及其前面的行)。这更容易生成,并且比全范围短两倍,如果这有区别,您应该使用更大的素数。

您的代码看起来正确无偏。但是,如果您在追求性能,并且取决于您使用的随机源的速度,您可能需要对其进行一点更改。其目的是掩盖错误再多几位,使随机值
r
小于
2*bound
。如果bound的位长度为
x
(长度不包括符号位),则生成一个
n=((x+8)/8)
字节的缓冲区,并屏蔽上层
(n*8-x)
位。在C#中,这应该如下所示:

var x = BitLength(bound);
var n = ((x + 8) / 8);
var buffer = new Byte[n];
var mask = 0xFF >> (8 * n - x);
while (true) {
    source.GetBytes(buffer);
    buffer[n - 1] &= mask;
    var r = new BigInteger(buffer);
    if (r < bound)
        return r;
}

我使用的是
bound
编码的长度,以字节为单位,由
ToByteArray()返回
,正是我需要的
n
的值。

我也很惊讶没有一个位长度成员。我并不特别担心Mod操作的成本,因为我必须对结果值使用ModPow。
var buffer = bound.ToByteArray();
var n = buffer.length;
var msb = buffer[n - 1];
var mask = 0;
while (mask < msb)
    mask = (mask << 1) + 1;
while (true) {
    source.GetBytes(buffer);
    buffer[n - 1] &= mask;
    var r = new BigInteger(buffer);
    if (r < bound)
        return r;
}