首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >BouncyCastle Diffie Hellman

BouncyCastle Diffie Hellman
EN

Code Review用户
提问于 2015-11-16 21:06:29
回答 2查看 4.1K关注 0票数 6

我想要写一个完整的diffie示例,用于弹跳城堡,包括密钥生成、密钥交换、加密和解密。我还想验证一下,如果Alice正在与Bob建立连接,那么她应该发送她的公钥、参数P和参数G。

也是一个很好的参考。

命名空间:

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Agreement;
using Org.BouncyCastle.Crypto.Agreement.Kdf;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Asn1.X509;
using System.Diagnostics;
using Org.BouncyCastle.OpenSsl;

此测试用例的一些常量:

代码语言:javascript
复制
const string Algorithm = "ECDH"; //What do you think about the other algorithms?
const int KeyBitSize = 256;
const int NonceBitSize = 128;
const int MacBitSize = 128;
const int DefaultPrimeProbability = 30;

启动配对并处理验证加密的Main方法:

代码语言:javascript
复制
public static void TestMethod() {
    //BEGIN SETUP ALICE
    IAsymmetricCipherKeyPairGenerator aliceKeyGen = GeneratorUtilities.GetKeyPairGenerator (Algorithm);
    DHParametersGenerator aliceGenerator = new DHParametersGenerator ();
    aliceGenerator.Init (KeyBitSize, DefaultPrimeProbability, new SecureRandom ());
    DHParameters aliceParameters = aliceGenerator.GenerateParameters ();

    KeyGenerationParameters aliceKGP = new DHKeyGenerationParameters (new SecureRandom (), aliceParameters);
    aliceKeyGen.Init (aliceKGP);

    AsymmetricCipherKeyPair aliceKeyPair = aliceKeyGen.GenerateKeyPair ();
    IBasicAgreement aliceKeyAgree = AgreementUtilities.GetBasicAgreement (Algorithm);
    aliceKeyAgree.Init (aliceKeyPair.Private);

    //END SETUP ALICE

    /////AT THIS POINT, Alice's Public Key, Alice's Parameter P and Alice's Parameter G are sent unsecure to BOB

    //BEGIN SETUP BOB
    IAsymmetricCipherKeyPairGenerator bobKeyGen = GeneratorUtilities.GetKeyPairGenerator (Algorithm);
    DHParameters bobParameters = new DHParameters( aliceParameters.P, aliceParameters.G );

    KeyGenerationParameters bobKGP = new DHKeyGenerationParameters (new SecureRandom (), bobParameters);
    bobKeyGen.Init (bobKGP);

    AsymmetricCipherKeyPair bobKeyPair = bobKeyGen.GenerateKeyPair ();
    IBasicAgreement bobKeyAgree = AgreementUtilities.GetBasicAgreement (Algorithm);
    bobKeyAgree.Init (bobKeyPair.Private);
    //END SETUP BOB

    BigInteger aliceAgree = aliceKeyAgree.CalculateAgreement (bobKeyPair.Public);
    BigInteger bobAgree = bobKeyAgree.CalculateAgreement (aliceKeyPair.Public);

    if (!aliceAgree.Equals (bobAgree)) {
        throw new Exception ("Keys do not match.");
    }

    byte[] nonSecretMessage = GetBytes ("HeaderMessageForASDF");
    byte[] secretMessage = GetBytes ("Secret message contents");
    byte[] decNonSecretBytes;

    KeyParameter sharedKey = new KeyParameter (aliceAgree.ToByteArrayUnsigned ());

    var encMessage = EncryptMessage( sharedKey, nonSecretMessage, secretMessage );
    var decMessage = DecryptMessage( sharedKey, encMessage, out decNonSecretBytes );

    var decNonSecretMessage = GetString( decNonSecretBytes );
    var decSecretMessage = GetString( decMessage );

    Debug.WriteLine( decNonSecretMessage + " - " + decSecretMessage );

    return;
}

用给定数据加密消息的包装方法:

代码语言:javascript
复制
public static byte[] EncryptMessage (string sharedKey, string nonSecretMessage, string secretMessage)
{
    return EncryptMessage( new KeyParameter( Convert.FromBase64String( sharedKey ) ), GetBytes( nonSecretMessage ), GetBytes( secretMessage ) );
}

使用给定数据加密消息的助手方法

代码语言:javascript
复制
public static byte[] EncryptMessage( KeyParameter sharedKey, byte[] nonSecretMessage, byte[] secretMessage ) {
    if( nonSecretMessage != null && nonSecretMessage.Length > 255 ) throw new Exception( "Non Secret Message Too Long!" );
    byte nonSecretLength = nonSecretMessage == null ? (byte)0 : (byte)nonSecretMessage.Length;

    var nonce = new byte[NonceBitSize / 8];
    var rand = new SecureRandom();
    rand.NextBytes(nonce, 0, nonce.Length);

    var cipher = new GcmBlockCipher(new AesFastEngine());
    var aeadParameters = new AeadParameters(sharedKey, MacBitSize, nonce, nonSecretMessage );
    cipher.Init(true, aeadParameters);

    //Generate Cipher Text With Auth Tag
    var cipherText = new byte[cipher.GetOutputSize(secretMessage.Length)];
    var len = cipher.ProcessBytes(secretMessage, 0, secretMessage.Length, cipherText, 0);
    cipher.DoFinal(cipherText, len);

    using (var combinedStream = new MemoryStream())
    {
        using (var binaryWriter = new BinaryWriter(combinedStream))
        {
            //Prepend Authenticated Payload
            binaryWriter.Write(nonSecretLength);
            binaryWriter.Write(nonSecretMessage);

            //Prepend Nonce
            binaryWriter.Write(nonce);
            //Write Cipher Text
            binaryWriter.Write(cipherText);
        }
        return combinedStream.ToArray();
    }
}        

用于解密消息的包装器方法

代码语言:javascript
复制
public static string DecryptMessage (string sharedKey, byte[] encryptedMessage, out string nonSecretPayload)
{
    byte[] nonSecretPayloadBytes;
    byte[] payload = DecryptMessage( new KeyParameter( Convert.FromBase64String( sharedKey ) ), encryptedMessage, out nonSecretPayloadBytes );

    nonSecretPayload = GetString( nonSecretPayloadBytes );
    return GetString( payload );
}

帮助方法解密消息。

代码语言:javascript
复制
public static byte[] DecryptMessage( KeyParameter sharedKey, byte[] encryptedMessage, out byte[] nonSecretPayloadBytes )
{
    using (var cipherStream = new MemoryStream(encryptedMessage))
    using (var cipherReader = new BinaryReader(cipherStream))
    {
        //Grab Payload
        int nonSecretLength = (int)cipherReader.ReadByte();
        nonSecretPayloadBytes = cipherReader.ReadBytes(nonSecretLength);

        //Grab Nonce
        var nonce = cipherReader.ReadBytes(NonceBitSize / 8);

        var cipher = new GcmBlockCipher(new AesFastEngine());
        var parameters = new AeadParameters(sharedKey, MacBitSize, nonce, nonSecretPayloadBytes);
        cipher.Init(false, parameters);

        //Decrypt Cipher Text
        var cipherText = cipherReader.ReadBytes(encryptedMessage.Length - nonSecretLength - nonce.Length);
        var plainText = new byte[cipher.GetOutputSize(cipherText.Length)];  

        try
        {
            var len = cipher.ProcessBytes(cipherText, 0, cipherText.Length, plainText, 0);
            cipher.DoFinal(plainText, len);
        }
        catch (InvalidCipherTextException)
        {
            //Return null if it doesn't authenticate
            return null;
        }

        return plainText;
    }
}

返回给定字符串的字节数据:

代码语言:javascript
复制
static byte[] GetBytes(string str)
{
    if( str == null ) return null;
    return System.Text.Encoding.Unicode.GetBytes( str );
}

返回给定字节数据的字符串:

代码语言:javascript
复制
static string GetString(byte[] bytes)
{
    if( bytes == null ) return null;
    return System.Text.Encoding.Unicode.GetString( bytes, 0, bytes.Length );
}
EN

回答 2

Code Review用户

发布于 2015-11-17 10:33:25

这只是一个小小的回顾,因为赫斯拉赫已经涵盖了我想要表达的大部分观点,但我对你对var的使用持异议。

正如赫斯拉赫所言,您在这里使用var是错误的:

代码语言:javascript
复制
var len = cipher.ProcessBytes(secretMessage, 0, secretMessage.Length, cipherText, 0);

因为

任务的右侧返回的内容并不明显。

但是,在这里您也忽略了var的有用用途:

代码语言:javascript
复制
int nonSecretLength = (int)cipherReader.ReadByte();

也在这里:

代码语言:javascript
复制
DHParametersGenerator aliceGenerator = new DHParametersGenerator ();

还有很多其他的案例。

使用var的关键规则是在变量声明的右侧使其类型明显时使用var

票数 2
EN

Code Review用户

发布于 2020-02-27 17:53:30

我总是鼓励对页面顶部的用法进行清理,所以当我查看代码时,我大致知道我将要进入什么。

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/110952

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档