3

バウチャーなどの引き換えコードとして使用される数値コードを生成する必要があります。要件は、コードが数値であり、レジ オペレーターのデータ入力速度が比較的短いことです。約 6 文字の長さの数字。数が少ないことはわかっているため、コードの有効期限が切れて再利用できるようにするためのプロセスが用意されています。

一意のコードを生成するという点でうまく機能している順次整数ジェネレーターを使用することから始めました。これに関する問題は、生成されたコードがシーケンシャルであるため予測可能であることです。つまり、顧客は私たちが生成したコードを推測し、意図されていないバウチャーを引き換えることができます.

Format Preserving Encryptionについて読んでいますが、これはうまくいくようです。コード自体は任意であるため、いつでもコードを解読する必要はありません。(日常の人々が) 予測できないことを確認する必要があるだけです。正直な人々を正直に保つことは、セキュリティにとって重要ではありません。

ウィキペディアの記事で参照されているさまざまな暗号がありますが、私は非常に基本的な暗号化および数学のスキルを持っており、暗号に基づいてこれを達成するための独自のコードを作成することはできません。

私の質問は、整数を別の整数に暗号化し、同じ長さを維持するこれの ac# 実装を知っている人はいますか?

FPE は、16 桁のクレジット カード番号を別の 16 桁の番号に暗号化するためによく使用されるようです。同じ種類のものが必要ですが、必ずしも長さに固定されているわけではありませんが、プレーンな値の長​​さが暗号化された値の長さと一致する限りです。

したがって、次の 4 つの整数が暗号化されます。

123456 から 123457 123458 123459

このようなノンシーケンシャルなものに

521482 265012 961450 346582

この FPE を実現するための他の提案を受け入れるのは、良い選択肢のように思えたからです。

編集

一意のコードを生成して保存し、重複をチェックするだけの提案をありがとう。生成時にストレージをチェックする必要がないため、現時点ではこれを避けています。これが、コードが一意かどうかを確認する必要がないように、順次整数ジェネレーターを使用する理由です。これについては再調査しますが、今のところ、コードを生成するたびにストレージに移動する必要がないようにする方法を探しています。

4

3 に答える 3

1

I wonder if this will not be off base also, but let me give it a try. This solution will require no storage but will require processing power (a tiny amount, but it would not be pencil-and-paper easy). It is essentially a homemade PRNG but may have characteristics more suitable to what you want to do than the built-in ones do.

To make your number generator, make a polynomial with prime coefficients and a prime modulus. For example, let X represent the Nth voucher you issed. Then:

Voucher Number = (23x^4+19x^3+5x^2+29x+3)%65537. This is of course just an example; you could use any number of terms, any primes you want for the coefficients, and you can make the modulus as large as you like. In fact, the modulus does not need to be prime at all. It only sets the maximum voucher number. Having the coefficients be prime helps cut down on collisions.

In this case, vouchers #100, 101, and 102 would have numbers 26158, 12076, and 6949, respectively. Consider it a sort of toy encryption where the coefficients are your key. Not super secure, but nothing with an output space as small as you are asking for would be secure against a strong adversary. But this should stop the everyday fraudster.

To confirm a valid voucher would take the computer (but calculation only, not storage). It would iterate through a few thousand or tens of thousands of input X looking for the output Y that matches the voucher presented to you. When it found the match, it could signal a valid voucher.

Alternatively, you could issue the vouchers with the serial number and the calculation concatenated together, like a value and checksum. Then you could run the calculation on the value by hand using your secret coefficients to confirm validity.

As long as you do not reveal the coefficients to anyone, it is very hard to identify a pattern in the outputs. I am not sure if this is even close to as secure as what you were looking for, but posting the idea just in case.

I miscalculated the output for 100 (did it by hand and failed). Corrected it just now. Let me add some code to illustrate how I'd check for a valid voucher:

using System;
using System.Numerics;

namespace Vouchers
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Enter voucher number: ");
            BigInteger input = BigInteger.Parse(Console.ReadLine());
            for (BigInteger i = 0;i<10000000;i++)
            {
                BigInteger testValue = (23 * i * i * i * i + 19 * i * i * i + 5 * i * i + 29 * i + 3) % 65537;
                if(testValue==input)
                {
                    Console.WriteLine("That is voucher # " + i.ToString());
                    break;
                }
                if (i == 100) Console.WriteLine(testValue);
            }
            Console.ReadKey();
        }
    }
}
于 2015-09-08T03:28:33.830 に答える
0

1 つのオプションは、数値のインプレース ランダム順列を構築することです。次のコードを検討してください。

private static readonly Random random = new Random((int)DateTime.UtcNow.Ticks);

private static int GetRandomPermutation(int input)
{
    char[] chars = input.ToString().ToCharArray();
    for (int i = 0; i < chars.Length; i++ )
    {
        int j = random.Next(chars.Length);
        if (j != i)
        {
            char temp = chars[i];
            chars[i] = chars[j];
            chars[j] = temp;
        }
    }
    return int.Parse(new string(chars));
}

あなたは、他のいくつかの手法でパフォーマンスの問題に遭遇したと述べました。この方法は多くの作業を行うため、パフォーマンス要件を満たさない場合があります。とにかく、きちんとしたアカデミックな練習です。

于 2015-09-08T02:39:48.527 に答える
0

Blogbeardlcからの、これに関する私の元の投稿へのコメントからの助けに感謝します。とにかくコードを生成するときにストレージをヒットする必要があることが判明したため、暗号化をいじるよりも PRNG を実装する方が適切なオプションでした。

これが私たちがやったことです

  1. 引き続きシーケンシャル ナンバー ジェネレーターを使用して整数を生成します
  2. シーケンシャル番号をシードとして使用して、C# Random クラス (PRNG) のインスタンスを作成します。
  3. 必要な最小数と最大数の範囲内で乱数を生成します。
  4. 重複をチェックし、一意のものが見つかるまで再生成します

シーケンシャル番号を各世代のシードとして使用すると、シードで c# random を使用すると、実際には乱数がかなり予測可能になります。

たとえば、シーケンシャル シードを使用して 1 ~ 999999 の範囲でテストしたところ、衝突が 1 回も発生せずに 500000 個の値が生成されました。

于 2015-09-14T23:21:37.560 に答える