【问题标题】:Minimal message size public key encryption in .NET.NET 中最小消息大小的公钥加密
【发布时间】:2010-07-07 15:31:32
【问题描述】:

我想使用公钥加密系统将非常少的数据(确切地说是 15 个字节)加密为尽可能短(最好不超过 16 个字节)的消息。

不幸的是,标准公钥系统 RSA 生成的消息与其密钥一样大,大约 100 字节,具体取决于密钥大小。 为了让事情变得更加困难,我只能使用.NET框架库,即没有第三方。

我在维基百科中读过一些关于椭圆曲线密码学的内容,那里的文字似乎表明那里的密钥大小通常比 RSA 密钥短得多。

这是否也转化为短消息? .NET ECDiffieHellmanCng 类可以用来解密/加密消息吗?它似乎具有不同的类结构,例如 RSA 或对称密码。

【问题讨论】:

  • 公钥加密依赖于较大的密钥大小,因为今天的快速计算机可以在几个小时内破解 256 位密钥。如果安全需求很高,那么您不应该使用小密钥。 OW 只使用对称密钥。
  • @apoorv020;当应用于椭圆曲线公钥密码学时,您的陈述不正确。

标签: c# .net cryptography


【解决方案1】:

您可以使用 ECDiffieHellman 来加密消息。您有两个选择:静态静态 ECDH 和静态临时 ECDH:

对于静态 ECDH,接收者需要知道发送者的公钥(这可能是您的应用程序中的一个选项,也可能不是)。您还应该有一些对于此消息是唯一的数据(它可能是您从协议或数据库行中的其他位置获得的序列号,或者它可能是随机数)。然后,您使用 ECDH 生成密钥并使用它来加密您的数据。这将为您提供所需的 16 字节的加密数据长度,但它并非完全不对称:加密器还能够解密消息(同样:这可能是您的应用程序中的问题,也可能不是问题)。

Static-ephemeral 有点不同:这里加密器生成一个临时(临时)EC 密钥对。然后他使用这个密钥对和接收者的公钥来生成一个可以用来加密数据的密钥。最后,他将临时密钥对的公钥与加密数据一起发送给接收方。这可能更适合您的应用程序,但是使用 ECDH-256 和 AES 的完整加密数据现在将是 2*32+16=80 字节(正如 GregS 指出的那样,您可以通过仅发送公共的 x 坐标来节省 32 个字节-键,但我不相信 .NET 公开了重新计算 y 坐标的功能。

这是一个小类,将做静态-静态 ECDH:

public static class StaticStaticDiffieHellman
{
  private static Aes DeriveKeyAndIv(ECDiffieHellmanCng privateKey, ECDiffieHellmanPublicKey publicKey, byte[] nonce)
  {
    privateKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
    privateKey.HashAlgorithm = CngAlgorithm.Sha256;
    privateKey.SecretAppend = nonce;
    byte[] keyAndIv = privateKey.DeriveKeyMaterial(publicKey);
    byte[] key = new byte[16];
    Array.Copy(keyAndIv, 0, key, 0, 16);
    byte[] iv = new byte[16];
    Array.Copy(keyAndIv, 16, iv, 0, 16);

    Aes aes = new AesManaged();
    aes.Key = key;
    aes.IV = iv;
    aes.Mode = CipherMode.CBC;
    aes.Padding = PaddingMode.PKCS7;

    return aes;
  }

  public static byte[] Encrypt(ECDiffieHellmanCng privateKey, ECDiffieHellmanPublicKey publicKey, byte[] nonce, byte[] data){
    Aes aes = DeriveKeyAndIv(privateKey, publicKey, nonce);
    return aes.CreateEncryptor().TransformFinalBlock(data, 0, data.Length);
  }

  public static byte[] Decrypt(ECDiffieHellmanCng privateKey, ECDiffieHellmanPublicKey publicKey, byte[] nonce, byte[] encryptedData){
    Aes aes = DeriveKeyAndIv(privateKey, publicKey, nonce);
    return aes.CreateDecryptor().TransformFinalBlock(encryptedData,0, encryptedData.Length);
  }
}

// Usage:

ECDiffieHellmanCng key1 = new ECDiffieHellmanCng();    
ECDiffieHellmanCng key2 = new ECDiffieHellmanCng();

byte[] data = Encoding.UTF8.GetBytes("TestTestTestTes");
byte[] nonce = Encoding.UTF8.GetBytes("whatever");

byte[] encryptedData = StaticStaticDiffieHellman.Encrypt(key1, key2.PublicKey, nonce, data);

Console.WriteLine(encryptedData.Length); // 16

byte[] decryptedData = StaticStaticDiffieHellman.Decrypt(key2, key1.PublicKey, nonce, encryptedData);

Console.WriteLine(Encoding.UTF8.GetString(decryptedData));

【讨论】:

  • 只发送临时公钥的x坐标就可以节省32个字节。
  • 谢谢!静态静态 ECDH 似乎是我想要的。您是否知道我是否以及如何使用 .NET ECDH 类来加密消息?正如 Sani 所指出的,这似乎不是它们的主要功能。
  • @Jens:我加了一个小例子
  • 非常感谢!这会很有帮助!
  • 我认为你是对的,你必须添加很多自己的代码来计算 y 坐标。一些系统支持“压缩”形式;也许 .NET 也以某种未经宣传的方式做到了。 .NET 文档不是很好恕我直言。
【解决方案2】:

ECDiffieHellmanCNG 是原始 Diffie-Hellman 密钥交换协议的衍生版本。
它不是用于加密消息,而是在两端计算相同的秘密值。

Here 是有关 ECDiffieHellmanCNG 及其用途的一些信息。

【讨论】:

  • 感谢您的意见!我希望我能以某种方式滥用本课程中使用的算法来达到我的目的。 =)
猜你喜欢
  • 1970-01-01
  • 2012-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-29
  • 2014-02-21
  • 2018-07-29
  • 2012-06-26
相关资源
最近更新 更多