Ehs*_*n88 10 c# sql integer numbers data-structures
我想在我的应用中为客户打印发票.每张发票都有一个发票ID.我希望ID为:
我自己的想法:自特定日期和时间以来 的秒数(例如1/1/2010 00 AM).
任何其他想法如何生成这些数字?
Vad*_*dim 10
我不喜欢使用时间的想法.您可以遇到各种各样的问题 - 时间差异,一秒钟内发生的几个事件等等.
如果你想要一些顺序且不容易追踪的东西,那么如何为每个新Id生成1和任何你想要的随机数(例如100).每个新Id都是先前的Id +随机数.
您还可以为ID添加常量,使其看起来更令人印象深刻.例如,您可以为所有ID添加44323,并将ID 15,23和27转换为44338,44346和44350.
你的问题有两个问题.一个是可解决的,一个不是(有你给出的约束).
第一个很简单:当客户有权访问一组有效的发票号时,客户很难猜出有效的发票号(或下一个有效的发票号).
您可以使用约束来解决此问题:
将发票编号分为两部分:
有了这些计划,有100万有效发票号码.您可以预先计算它们并将它们存储在数据库中.显示发票号时,请检查它是否在您的数据库中.如果不是,则无效.
使用SQL序列分发数字.发出新的(即未使用的)发票号时,增加seuqnce并从预先计算的列表中发出第n个数字(按值排序).
如果您想要阻止拥有多个有效发票号的客户猜测您已发出多少发票号(以及您拥有多少客户):这是不可能的.
你有一个所谓的" 德国坦克问题 " 的变种.在第二次世界大战中,盟国使用印在德国坦克齿轮箱上的序列号来猜测德国制造了多少坦克.这很有效,因为序列号没有间隙地增加.
但即使你增加了数量,但德国坦克问题的解决方案仍然有效.这很容易:
现在您可以很好地猜测发票数量的数量级(200,15000,50万等).
只要在理论上存在两个连续发票号的平均值,这就可以正常工作.即使使用随机数发生器,通常也是如此,因为大多数随机数发生器被设计成具有这样的平均值.
有一个对策:您必须确保两个连续数字的间隙不存在平均值.具有此属性的随机数生成器可以非常容易地构造.
例:
虽然这在理论上有效,但很快就会耗尽32位整数.
我不认为这个问题有实际的解决方案.两个连续数字之间的间隙具有平均值(方差很小),您可以轻松猜出已发布数字的数量.或者你将很快耗尽32位数.
不要使用任何基于时间的解决方案.时间戳通常很容易猜到(可能会在发票上的某处打印一个大致正确的时间戳).使用时间戳通常会使攻击者更容易,而不是更难.
不要使用不安全的随机数.大多数随机数生成器不具有加密安全性.它们通常具有对统计有利但对您的安全性有害的数学属性(例如可预测的分布,稳定的平均值等)
一种解决方案可能涉及异或(XOR)二进制位图.结果函数是可逆的,可以生成非连续数字(如果最低有效字节的第一位设置为1),并且非常容易实现.而且,只要您使用可靠的序列生成器(例如,您的数据库),就不需要线程安全问题.
根据MSDN,'当或仅当其操作数中的一个为真时,[异或运算]的结果才为真.反向逻辑表明,相等的操作数总是会导致错误.
例如,我刚在Random.org上生成了一个32位序列.就是这个:
11010101111000100101101100111101
Run Code Online (Sandbox Code Playgroud)
这个二进制数转换为3588381501十进制,0xD5E25B3D十六进制.我们称之为你的基础密钥.
现在,让我们使用([基本键] XOR [ID])公式生成一些值.在C#中,这就是你的加密函数的样子:
public static long FlipMask(long baseKey, long ID)
{
return baseKey ^ ID;
}
Run Code Online (Sandbox Code Playgroud)
以下列表包含一些生成的内容.其栏目如下:
最后,'加密'十进制值
0 | 000 | 11010101111000100101101100111101 | 3588381501
1 | 001 | 11010101111000100101101100111100 | 3588381500
2 | 010 | 11010101111000100101101100111111 | 3588381503
3 | 011 | 11010101111000100101101100111110 | 3588381502
4 | 100 | 11010101111000100101101100111001 | 3588381497
Run Code Online (Sandbox Code Playgroud)为了反转生成的密钥并确定原始值,您只需使用相同的基本密钥执行相同的XOR操作.假设我们想获得第二行的原始值:
11010101111000100101101100111101 XOR
11010101111000100101101100111100 =
00000000000000000000000000000001
Run Code Online (Sandbox Code Playgroud)
这确实是你原来的价值.
现在,斯特凡提出了非常好的观点,第一个话题至关重要.
为了掩盖他的顾虑,你可以保留最后一个,比方说8个字节是纯随机垃圾(我相信这被称为nonce),你在加密原始ID时会产生,而在反转它时会忽略.这将大大增加您的安全性,代价是32位的所有可能正整数的大片(16,777,216而不是4,294,967,296,或1/256).
这样做的类看起来像这样:
public static class int32crypto
{
// C# follows ECMA 334v4, so Integer Literals have only two possible forms -
// decimal and hexadecimal.
// Original key: 0b11010101111000100101101100111101
public static long baseKey = 0xD5E25B3D;
public static long encrypt(long value)
{
// First we will extract from our baseKey the bits we'll actually use.
// We do this with an AND mask, indicating the bits to extract.
// Remember, we'll ignore the first 8. So the mask must look like this:
// Significance mask: 0b00000000111111111111111111111111
long _sigMask = 0x00FFFFFF;
// sigKey is our baseKey with only the indicated bits still true.
long _sigKey = _sigMask & baseKey;
// nonce generation. First security issue, since Random()
// is time-based on its first iteration. But that's OK for the sake
// of explanation, and safe for most circunstances.
// The bits it will occupy are the first eight, like this:
// OriginalNonce: 0b000000000000000000000000NNNNNNNN
long _tempNonce = new Random().Next(255);
// We now shift them to the last byte, like this:
// finalNonce: 0bNNNNNNNN000000000000000000000000
_tempNonce = _tempNonce << 0x18;
// And now we mix both Nonce and sigKey, 'poisoning' the original
// key, like this:
long _finalKey = _tempNonce | _sigKey;
// Phew! Now we apply the final key to the value, and return
// the encrypted value.
return _finalKey ^ value;
}
public static long decrypt(long value)
{
// This is easier than encrypting. We will just ignore the bits
// we know are used by our nonce.
long _sigMask = 0x00FFFFFF;
long _sigKey = _sigMask & baseKey;
// We will do the same to the informed value:
long _trueValue = _sigMask & value;
// Now we decode and return the value:
return _sigKey ^ _trueValue;
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1970 次 |
最近记录: |