private BCryptGenRandom ( |
||
hAlgorithm | ||
pbBuffer | [ | |
cbBuffer | int | |
dwFlags | int | |
return | NTSTATUS |
}//NextBytes() void NextBytesInternal(ArraySegment<byte> bufferSegment) { BCrypt.NTSTATUS status; var buffer = bufferSegment.Array; var offset = bufferSegment.Offset; var count = bufferSegment.Count; if (count > CACHE_THRESHOLD) { status = (offset == 0) ? BCrypt.BCryptGenRandom(buffer, count) : BCrypt.BCryptGenRandom_PinnedBuffer(buffer, offset, count); if (status == BCrypt.NTSTATUS.STATUS_SUCCESS) return; throw new CryptographicException((int)status); } lock (_byteCache) { if (_byteCachePosition + count <= BYTE_CACHE_SIZE) { Utils.BlockCopy(_byteCache, _byteCachePosition, buffer, offset, count); _byteCachePosition += count; return; } status = BCrypt.BCryptGenRandom(_byteCache, BYTE_CACHE_SIZE); if (status == BCrypt.NTSTATUS.STATUS_SUCCESS) { _byteCachePosition = count; Utils.BlockCopy(_byteCache, 0, buffer, offset, count); return; } throw new CryptographicException((int)status); }// lock }//NextBytesInternal()
}//NextBytes() void NextBytesInternal(byte[] buffer, int offset, int count) { BCrypt.NTSTATUS status; if (count > CACHE_THRESHOLD) { status = (offset == 0) ? BCrypt.BCryptGenRandom(buffer, count) : BCrypt.BCryptGenRandom_WithOffset(buffer, offset, count); if (status == BCrypt.NTSTATUS.STATUS_SUCCESS) return; ThrowNewCryptographicException((int)status); } lock (_byteCache) { if (_byteCachePosition + count <= BYTE_CACHE_SIZE) { Utils.BlockCopy(_byteCache, _byteCachePosition, buffer, offset, count); _byteCachePosition += count; return; } status = BCrypt.BCryptGenRandom(_byteCache, BYTE_CACHE_SIZE); if (status == BCrypt.NTSTATUS.STATUS_SUCCESS) { _byteCachePosition = count; Utils.BlockCopy(_byteCache, 0, buffer, offset, count); return; } ThrowNewCryptographicException((int)status); }// lock }//NextBytesInternal()
}//GetRandomUInt() /// <summary> /// Gets one random unsigned 64bit integer in a thread safe manner. /// </summary> ulong GetRandomULong() { BCrypt.NTSTATUS status; while (true) { int currentByteCachePosition = Interlocked.Add(ref _byteCachePosition, sizeof(ulong)); if (currentByteCachePosition <= BYTE_CACHE_SIZE && currentByteCachePosition > 0) return BitConverter.ToUInt64(_byteCache, currentByteCachePosition - sizeof(ulong)); lock (_byteCache) { currentByteCachePosition = _byteCachePosition; // atomic read if (currentByteCachePosition > (BYTE_CACHE_SIZE - sizeof(ulong)) || currentByteCachePosition <= 0) { status = BCrypt.BCryptGenRandom(_byteCache, BYTE_CACHE_SIZE); if (status == BCrypt.NTSTATUS.STATUS_SUCCESS) { _byteCachePosition = sizeof(ulong); // atomic write return BitConverter.ToUInt64(_byteCache, 0); } // defensive logic to prevent _byteCachePosition from wrapping into valid range due to BCryptGenRandom failures if (currentByteCachePosition > BYTE_CACHE_SIZE || currentByteCachePosition < 0) _byteCachePosition = BYTE_CACHE_SIZE; throw new CryptographicException((int)status); }// if outside the valid range }// lock }// while(true) }//GetRandomULong()
}//NextBytesInternal() #if (NETCOREAPP2_1 || NETSTANDARD2_1) void NextBytesInternal_Span(Span<byte> buffer, int count) { BCrypt.NTSTATUS status; if (count > CACHE_THRESHOLD) { status = BCrypt.BCryptGenRandom_Span(buffer); if (status == BCrypt.NTSTATUS.STATUS_SUCCESS) return; ThrowNewCryptographicException((int)status); } lock (_byteCache) { if (_byteCachePosition + count <= BYTE_CACHE_SIZE) { new Span<byte>(_byteCache, _byteCachePosition, count).CopyTo(buffer); _byteCachePosition += count; return; } status = BCrypt.BCryptGenRandom(_byteCache, BYTE_CACHE_SIZE); if (status == BCrypt.NTSTATUS.STATUS_SUCCESS) { _byteCachePosition = count; new Span<byte>(_byteCache, 0, count).CopyTo(buffer); return; } ThrowNewCryptographicException((int)status); }// lock }//NextBytesInternal_Span()
}// ctor static void SanityCheck() { var testBuffer = new byte[BYTE_CACHE_SIZE / 2]; int status, i, j; const int COLLISION_FREE_BLOCK_SIZE = 16; status = (int)BCrypt.BCryptGenRandom(testBuffer, testBuffer.Length); if (status != (int)BCrypt.NTSTATUS.STATUS_SUCCESS) throw new CryptographicException(status); if (testBuffer.Length < COLLISION_FREE_BLOCK_SIZE * 2) return; // should be compiled away for (i = 0; i < testBuffer.Length - COLLISION_FREE_BLOCK_SIZE; i += COLLISION_FREE_BLOCK_SIZE) { for (j = 0, status = 0; j < COLLISION_FREE_BLOCK_SIZE; ++j) status |= testBuffer[i + j] ^ testBuffer[i + j + COLLISION_FREE_BLOCK_SIZE]; if (status == 0) throw new CryptographicException("CryptoRandom failed sanity check #2."); } }// SanityCheck()
void NextBytesInternal(ArraySegment<byte> bufferSegment) { BCrypt.NTSTATUS status; var buffer = bufferSegment.Array; var offset = bufferSegment.Offset; var count = bufferSegment.Count; if (count > CACHE_THRESHOLD) { status = (offset == 0) ? BCrypt.BCryptGenRandom(buffer, count) : BCrypt.BCryptGenRandom_PinnedBuffer(buffer, offset, count); if (status == BCrypt.NTSTATUS.STATUS_SUCCESS) return; throw new CryptographicException((int)status); } while (true) { int currentByteCachePosition = Interlocked.Add(ref _byteCachePosition, count); if (currentByteCachePosition <= BYTE_CACHE_SIZE && currentByteCachePosition > 0) { Utils.BlockCopy(_byteCache, currentByteCachePosition - count, buffer, 0, count); return; } lock (_byteCache) { currentByteCachePosition = _byteCachePosition; // atomic read if (currentByteCachePosition > (BYTE_CACHE_SIZE - count) || currentByteCachePosition <= 0) { status = BCrypt.BCryptGenRandom(_byteCache, BYTE_CACHE_SIZE); if (status == BCrypt.NTSTATUS.STATUS_SUCCESS) { _byteCachePosition = count; // atomic write Utils.BlockCopy(_byteCache, 0, buffer, 0, count); return; } // defensive logic to prevent _byteCachePosition from wrapping into valid range due to BCryptGenRandom failures if (currentByteCachePosition > BYTE_CACHE_SIZE || currentByteCachePosition < 0) _byteCachePosition = BYTE_CACHE_SIZE; throw new CryptographicException((int)status); }// if outside the valid range }// lock }// while(true) }//NextBytes()
internal static NTSTATUS BCryptGenRandom_PinnedBuffer(byte[] pbBuffer, int obBuffer, int cbBuffer) { Debug.Assert(pbBuffer != null); Debug.Assert(cbBuffer >= 0 && obBuffer >= 0 && (obBuffer + cbBuffer) <= pbBuffer.Length); GCHandle pinnedBufferHandle = default; NTSTATUS status; try { pinnedBufferHandle = GCHandle.Alloc(pbBuffer, GCHandleType.Pinned); status = BCrypt.BCryptGenRandom(IntPtr.Zero, pinnedBufferHandle.AddrOfPinnedObject() + obBuffer, cbBuffer, BCRYPT_USE_SYSTEM_PREFERRED_RNG); } finally { if (pinnedBufferHandle.IsAllocated) pinnedBufferHandle.Free(); } return status; }// BCryptGenRandom()
}//GetRandomInt() /// <summary> /// Gets one random signed 64bit integer in a thread safe manner. /// </summary> long GetRandomLong() { lock (_byteCache) { if (_byteCachePosition + sizeof(long) <= BYTE_CACHE_SIZE) { var result = BitConverter.ToInt64(_byteCache, _byteCachePosition); _byteCachePosition += sizeof(long); return result; } BCrypt.NTSTATUS status = BCrypt.BCryptGenRandom(_byteCache, BYTE_CACHE_SIZE); if (status == BCrypt.NTSTATUS.STATUS_SUCCESS) { _byteCachePosition = sizeof(long); return BitConverter.ToInt64(_byteCache, 0); } throw new CryptographicException((int)status); }// lock }//GetRandomLong()
}//NextBytesInternal() /// <summary> /// Gets one random signed 32bit integer in a thread safe manner. /// </summary> int GetRandomInt() { lock (_byteCache) { if (_byteCachePosition + sizeof(int) <= BYTE_CACHE_SIZE) { var result = Unsafe.As<byte, int>(ref _byteCache[_byteCachePosition]);//BitConverter.ToInt32(_byteCache, _byteCachePosition); _byteCachePosition += sizeof(int); return result; } BCrypt.NTSTATUS status = BCrypt.BCryptGenRandom(_byteCache, BYTE_CACHE_SIZE); if (status == BCrypt.NTSTATUS.STATUS_SUCCESS) { _byteCachePosition = sizeof(int); return Unsafe.As<byte, int>(ref _byteCache[0]);//BitConverter.ToInt32(_byteCache, 0); } return ThrowNewCryptographicException((int)status); }// lock }//GetRandomInt()