我想使用公共密钥加密系统将很少的数据(15个字节精确地)加密到尽可能短的位置(最佳不超过16个字节)的消息.
标准的公共密钥系统RSA不幸地生成与其密钥一样大的消息,大约是100字节,这取决于密钥大小.
为了使事情更加困难,我只能使用.NET框架库,即没有第三方.
我已经在维基百科上看过一些关于椭圆曲线密码术的文章,并且文本似乎表明,键的大小通常比RSA密钥短得多.
这是否也转化为短信?可以使用.NET ECDiffieHellmanCng类来消息/加密吗?它似乎具有不同的类结构,然后就是说,RSA或对称密码.
解决方法
您可以使用ECDiffieHellman加密消息.您有两个选项:静态ECDH和静态临时ECDH:
对于静态ECDH,接收方将需要知道发送者的公钥(这可能是或可能不是应用程序中的一个选项).你也应该有一些这个消息是唯一的数据(它可能是你从协议或数据库行中的其他地方获得的序列号,或者它或者是一个随机数).然后,您可以使用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,key,16); byte[] iv = new byte[16]; Array.Copy(keyAndIv,16,iv,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,byte[] nonce,byte[] data){ Aes aes = DeriveKeyAndIv(privateKey,publicKey,nonce); return aes.CreateEncryptor().TransformFinalBlock(data,data.Length); } public static byte[] Decrypt(ECDiffieHellmanCng privateKey,byte[] encryptedData){ Aes aes = DeriveKeyAndIv(privateKey,nonce); return aes.CreateDecryptor().TransformFinalBlock(encryptedData,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,encryptedData); Console.WriteLine(Encoding.UTF8.GetString(decryptedData));