web-dev-qa-db-ja.com

Diffie Hellman C#の実装

こんにちは

テストプロジェクトでは、安全なキー交換のために(有名な)Diffie Hellmanアルゴリズムを実装しようとしました。

今私はこれをC#で書いています:

using System;
using System.Collections;
using System.Collections.Generic;

namespace DiffieHellman.Cryptology
{
    public static class CentralAuthority
    {
        private static readonly List<Int32> _primes = new List<Int32>();

        public static void CreatePrimeTable()
        {
            const Int32 topNumber = Int32.MaxValue / 2;
            BitArray numbers = new BitArray(topNumber, true);

            for (Int32 i = 2; i < topNumber; i++)
            {
                if (!numbers[i])
                    continue;

                for (Int32 j = i * 2; j < topNumber; j += i)
                    numbers[j] = false;
            }

            for (Int32 i = 1; i < topNumber; i++)
            {
                if (numbers[i])
                    _primes.Add(i);
            }
        }

        /// <summary>
        /// Generate a random Prime Number.
        /// </summary>
        public static Int32 GeneratePrime()
        {
            Int32 p = Randomizer.GetRandom(1, _primes.Count);
            return _primes[p];
        }

        /// <summary>
        /// Generate a random base integer (g) less than the prime
        /// </summary>
        public static Int32 GenerateBase(
            Int32 prime)
        {
            return Randomizer.GetRandom(1, prime - 1);
        }
    }
}




using System;

namespace DiffieHellman.Cryptology
{
    public class CaDiffieHellman
    {
        public Int64 Key { get; private set; }
        public Int32 Prime { get; private set; }
        public Int32 Generator { get; private set; }
        public Int64 ExponentiationY { get; private set; }
        private Int32 _privateX;

        public void GenerateParameters(
            Int32 prime = 0,
            Int32 generator = 0)
        {
            if (prime < 1 && generator < 1)
            {
                prime = CentralAuthority.GeneratePrime();
                generator = CentralAuthority.GenerateBase(prime);
            }

            if (prime <= generator - 1)
                return;

            Prime = prime;
            Generator = generator;
            _privateX = Randomizer.GetRandom(1, Prime - 1);

            Int64 xor = Generator ^ _privateX;
            while (xor > Prime - 1
                || xor == _privateX)
            {
                _privateX = Randomizer.GetRandom(1, Prime - 1);
                xor = Generator ^ _privateX;
            }

            ExponentiationY = (xor) % Prime;
        }

        public void GenerateKey(
            Int64 exponentiationYOther)
        {
            Key = (exponentiationYOther ^ _privateX) % Prime;
        }
    }
}



using System;
using System.Security.Cryptography;

namespace DiffieHellman.Cryptology
{
    public static class Randomizer
    {
        /// <summary>
        /// Real random generator
        /// Slower then Random().Next()!
        /// </summary>
        public static Int32 GetRandom(
            Int32 max)
        {
            return GetRandom(0, max);
        }

        /// <summary>
        /// Real random generator
        /// Slower than Random().Next()!
        /// </summary>
        public static Int32 GetRandom(
            Int32 min,
            Int32 max)
        {
            // Start a slower but more acurate randomizer service
            RNGCryptoServiceProvider rngCryptoServiceProvider = new RNGCryptoServiceProvider();
            Byte[] randomBytes = new Byte[4];
            rngCryptoServiceProvider.GetBytes(randomBytes);
            Int32 seed = BitConverter.ToInt32(randomBytes, 0);

            return new Random(seed).Next(min, max);
        }
    }
}


using System;
using System.Diagnostics;
using DiffieHellman.Cryptology;

namespace DiffieHellman
{
    public class Program
    {
        private static readonly CaDiffieHellman _caDiffieHellmanServer = new CaDiffieHellman();
        private static readonly CaDiffieHellman _caDiffieHellmanClient = new CaDiffieHellman();

        static void Main()
        {
            Stopwatch stopwatch = Stopwatch.StartNew();
            CentralAuthority.CreatePrimeTable();
            stopwatch.Stop();
            Console.WriteLine("Create Prime Table: {0}ms", stopwatch.ElapsedMilliseconds);

            stopwatch = Stopwatch.StartNew();
            for (Int32 i = 0; i < Int32.MaxValue; i++)
            {
                // Generate random prime and generator at server
                _caDiffieHellmanServer.GenerateParameters();

                // Send prime and generator to client
                _caDiffieHellmanClient.GenerateParameters(_caDiffieHellmanServer.Prime, _caDiffieHellmanServer.Generator);

                // Calculate the key
                _caDiffieHellmanServer.GenerateKey(_caDiffieHellmanClient.ExponentiationY);

                // Calculate the key
                _caDiffieHellmanClient.GenerateKey(_caDiffieHellmanServer.ExponentiationY);

                if (_caDiffieHellmanServer.Key != _caDiffieHellmanClient.Key)
                    Console.WriteLine("Error ({0}): wrong key", i);

                if (_caDiffieHellmanServer.Key == 0 || _caDiffieHellmanClient.Key == 0)
                    Console.WriteLine("Error ({0}): key 0", i);

                if (i % 10000 == 0)
                    Console.WriteLine("Progress: {0}, {1}ms, {2}", i, stopwatch.ElapsedMilliseconds, _caDiffieHellmanServer.Key);
            }
            stopwatch.Stop();
            Console.WriteLine("Loop: {0}ms", stopwatch.ElapsedMilliseconds);

            Console.ReadKey();
        }
    }
}

今の私の主な懸念は、標準の式を使用しなかったことです:g pow(a)mod p = Aが、g XOR a mod p。pow(a)が機能しない場合int64値の範囲外になります。

これは安全上の問題ですか?

この実装には1つのバグしかありません。両方のパーティが同じprivateXを生成すると失敗しますが、大量の基本数が生成されるため、これは約5,000万回に1回だけ発生します。

この方法の長所と潜在的な落とし穴についてお話したいと思います。

ありがとう!

5
Roger Far

あなたが実装したものはではなくDiffie-Hellmanであり、まったく力がありません。 '_^_'文字の使用と混同されています。

Cのようなプログラミング言語では、 '_^_'はビット単位の排他的論理和(「XOR」)の演算子です。

数学をASCIIで書く場合、慣習的に '_^_'文字で指数を表す-これはまったくXORではありません!この表記は、組版であるLaTeXに由来します。数学者の間で事実上の標準となっているシステムです。このメッセージでは、HTMLタグを使用して「ga 'は、「gto the powera "、しかし、もし私が平文で書くならASCII(例えばUsenet))、私は書く必要があります: 'g ^ a '。

さらに、Diffie-Hellmanは、大きな整数に対してmodular指数を使用します-一般的なサイズは1024ビット以上です。 32ビットまたは64ビットの整数では、あらゆる種類のセキュリティを実現するには不十分であり、いずれの場合でも、べき乗剰余はnotwhat pow()を実装します(代数的には、単純な整数や実数ではなく、有限体で作業したい)。 C#(.NET 4.0)では、 System.Numerics.BigInteger クラス、特にそのModPow()メソッドを使用します。しかし、最初に、それを実行したい場合は、最初に基礎となる数学を理解する必要があります。 ハンドブックの応用暗号化 の最初の3つの章を読むことから始めることができます(シュナイアーの「応用暗号化」とはまったく関係がありません。私の見解では、「ハンドブック」ははるかに有用な本です)。 。少し厳しいように見えるかもしれませんが、最初の3つの章で説明されている数学を習得しない限り、Diffie-Hellmanを適切に実装することはできません。

(そしてもちろん、暗号化アルゴリズムの実装にはサイドチャネルリークに関連する他の落とし穴があります。そのため、数学的に何が起こるかをdo理解しても、独自の実装は必ずしも良い考えではありません。)

10
Thomas Pornin

Diffie-Hellmanはモジュラー指数に基づいているため、このコードで別の関数を使用することで、Diffie-Hellmanをまったく実装していません。

また、使用している63/64ビットの数値は、いずれの場合も小さすぎます。

暗号化に関する基本的なテキストを読む必要があります。シュナイアーの応用暗号。

4
frankodwyer