问题 .NET中的最小邮件大小公钥加密


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

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

我在维基百科中阅读了一些关于椭圆曲线加密的内容,并且文本似乎表明其中的密钥大小通常比RSA密钥短得多。

这是否也转换为短信息?可以.NET ECDiffieHellmanCng class用于解密消息?它似乎具有不同的类结构,比如RSA或对称密码。


6208
2017-07-07 15:31


起源

公钥加密取决于大密钥大小,因为今天的快速计算机可以在几个小时内打破256位密钥。如果安全性需求很高,那么你不应该使用小密钥。 OW只使用对称密钥。 - apoorv020
@ apoorv020;应用于椭圆曲线公钥加密时,您的语句不正确。 - James K Polk


答案:


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

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

静态短暂有点不同:这里加密器生成临时(短暂的)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));

11
2017-07-07 20:24



只发送短暂公钥的x坐标可以节省32个字节。 - James K Polk
谢谢!静态静态ECDH似乎就是我想要的。您是否知道我是否以及如何使用.NET ECDH类来加密消息?正如萨尼指出的那样,这似乎不是他们的主要功能。 - Jens
@Jens:我添加了一个小例子 - Rasmus Faber
非常感谢!这会有所帮助! - Jens
我认为你是对的,你必须添加很多自己的代码来计算y坐标。有些系统支持“压缩”形式;也许.NET以一种未经证实的方式做了。 .NET文档不是很好恕我直言。 - James K Polk


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

这里 是有关ECDiffieHellmanCNG及其目的的一些信息。


0
2017-07-07 15:47



感谢您的投入!我希望我能以某种方式滥用本课程中使用的算法来实现我的目的。 =) - Jens