Joh*_*don 3 c# random hash cryptography sha
我研究了可证明公平的随机数,并发现了这个网站: https: //dicesites.com/provively-fair
首先,服务器端哈希应该使用什么类?有很多哈希算法,如 SHA512、SHA256 或 SHA384Cng,我不明白它们之间的区别。
其次,将使用什么方法从未散列的种子转换为散列的种子,以及在散列创建过程中将使用什么方法将用户提供的种子字符串考虑在内。另外,随机数是否只是简单地添加在用户提供的字符串末尾以防止重复哈希?
第三,我不明白为什么散列服务器种子最初是 SHA256 散列,但后来用于计算 HMAC SHA512 散列。
最后,如何将最终生成的哈希值的前 5 个字符转换为卷号?
我没有运气找到任何使用服务器种子和客户端种子的随机数生成器的示例,只有诸如System.Security.Cryptography.RandomNumberGenerator.
您链接到的页面描述了该过程,但我将尝试更详细地介绍并提供 C# 示例。
首先发生了两次散列。一个通用散列,用于证明服务器在您赌博时没有更改服务器密钥,该散列不是秘密的,而是在游戏开始时提供给玩家的。还有一个密钥散列(称为 HMAC)来实际生成骰子,并使用服务器密钥、用户提供的数据和累加数字的组合。
这是发生的过程:
int,然后检查 是否int大于 999999,如果是,则不断重复,直到找到不超过 999999 的数字。number%(10000)/100.0对其进行处理以获得浮点数。用户从第 10 步获得密钥后,可以使用 SHA256 对其进行哈希处理,并检查他获得的哈希值是否与游戏会话开始时告知的哈希值相同。然后,既然他有了密钥,他就可以重新执行服务器执行的所有步骤,并验证服务器没有伪造任何骰子。
如何在代码中执行此操作:
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace SandboxConsole
{
public class Result
{
public Result(string hmacMessage, float roll)
{
HmacMessage = hmacMessage;
Roll = roll;
}
public string HmacMessage { get; }
public float Roll { get; }
}
class FairDiceRollServer
{
private byte[] _serverKey;
private ulong _nonce;
public byte[] StartSession()
{
if (_serverKey != null)
throw new InvalidOperationException("You must call EndSession before starting a new session");
//Generate a new server key.
using (var rng = RandomNumberGenerator.Create())
{
_serverKey = new byte[128];
rng.GetBytes(_serverKey);
}
_nonce = 0;
//Hash the server key and return it to the player.
using (var sha = SHA256.Create())
{
return sha.ComputeHash(_serverKey);
}
}
public Result RollDice(string userKey)
{
if(_serverKey == null)
throw new InvalidOperationException("You must call StartSession first");
if(_nonce == ulong.MaxValue)
throw new InvalidOperationException("Ran out of Nonce values, you must start a new session.");
using (var hmac = new HMACSHA256(_serverKey))
{
float? roll = null;
string message = null;
while (roll == null)
{
message = userKey + "-" + _nonce;
_nonce++;
var data = Encoding.UTF8.GetBytes(message);
var hash = hmac.ComputeHash(data);
roll = GetNumberFromByteArray(hash);
}
return new Result(message, roll.Value);
}
}
private float? GetNumberFromByteArray(byte[] hash)
{
var hashString = string.Join("", hash.Select(x => x.ToString("X2")));
const int chars = 5;
for (int i = 0; i <= hashString.Length - chars; i += chars)
{
var substring = hashString.Substring(i, chars);
var number = int.Parse(substring, System.Globalization.NumberStyles.HexNumber);
if(number > 999999)
continue;
return (number % 10000) / 100.0f;
}
return null;
}
public byte[] EndSession()
{
var key = _serverKey;
_serverKey = null;
return key;
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用中的示例
using System;
using System.Linq;
namespace SandboxConsole
{
class Program
{
private int _test;
static void Main(string[] args)
{
var server = new FairDiceRollServer();
var hash = server.StartSession();
Console.WriteLine(string.Join("", hash.Select(x => x.ToString("X2"))));
for (int i = 0; i < 10; i++)
{
var roll = server.RollDice("My Key");
Console.WriteLine("Message: {0} Result: {1}", roll.HmacMessage, roll.Roll);
}
var key= server.EndSession();
Console.WriteLine(string.Join("", key.Select(x => x.ToString("X2"))));
Console.ReadLine();
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用有关所使用的算法的已发布信息,返回的信息RollDice以及从用户返回给用户的密钥EndSession可以重新创建所有骰子掷骰并证明服务器确实进行了随机生成(感谢用户在掷骰子中提供的数据)服务器不允许选择),而不是一些伪造的预选密钥,这肯定会导致损失。