Diffie Hellman c# 实现

信息安全 密码学 。网 密钥交换
2021-09-11 10:49:31

对于一个测试项目,我尝试实现(著名的)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 值,则它不起作用。

这是一个安全问题吗?

这个实现只有一个错误:当双方生成相同的 privateX 时,它会失败,但是由于生成了大量的基数,这种情况只会在大约 5000 万次中发生一次。

我想讨论这种方法的强度和潜在的陷阱!

谢谢!

2个回答

你实现的不是Diffie-Hellman,完全没有实力。^您对“ ”字符的使用感到困惑。

在类 C 编程语言中,' ^' 是按位异或(“XOR”)的运算符。

用 ASCII 写数学时,习惯上用 ' ^' 字符表示求幂 - 它根本不是 XOR!这个符号来自 LaTeX,这是一种排版系统,是数学家中事实上的标准。在此消息中,我可以使用 HTML 标记并写“ g a ”来表示“ g的a次方”,但如果我要使用纯 ASCII 写(例如在 Usenet 上),我将不得不写:' g^a '。

此外,Diffie-Hellman对大整数使用模幂——典型大小为 1024 位或更多。32 位或 64 位整数不足以实现任何类型的安全性,并且在任何情况下,模幂都不pow()实现的(在代数术语中,您希望在有限域上工作,而不是纯整数或实数数)。在 C# (.NET 4.0) 中,您可能希望使用System.Numerics.BigInteger类,尤其是它的ModPow()方法。但首先,如果你想这样做,你首先必须了解基础数学。您可以从阅读应用密码学手册的前三章开始(与 Schneier 的“应用密码学”没有任何关系,而且在我看来,“手册”是一本更有用的书)。这可能看起来有点苛刻,但除非你掌握了前三章中描述的数学,否则你不能希望正确地实现 Diffie-Hellman。

(当然,实现加密算法还有其他陷阱,与侧信道泄漏有关,所以即使你确实了解数学上发生的事情,自己实现也不一定是个好主意。)

Diffie-Hellman 基于模幂运算,因此通过在此代码中使用不同的函数,您根本没有实现 Diffie-Hellman,而是实现了其他东西。

此外,您使用的 63/64 位数字在任何情况下都太小了。

您应该阅读有关密码学的基本文本,例如 Schneier 的应用密码学。