Я хотел бы зашифровать очень небольшие данные (15 байтов, чтобы быть точным) в максимально короткий (оптимально, не более, чем 16 байтов) сообщение с помощью системы шифрования с открытым ключом.
Стандартная система с открытым ключом, RSA, к сожалению, создает сообщения, столь же большие как его ключи, который составляет приблизительно 100 байтов, в зависимости от размера ключа. Для создания вещей более трудными я могу только пользоваться библиотеками платформы.NET, т.е. никаким третьим лицом.
Я читал немного о шифровании в эллиптических кривых в Википедии, и текст там, кажется, предполагает что размеры ключа, там обычно намного короче, чем ключи RSA.
Это переводит в короткие сообщения также? Может.NET ECDiffieHellmanCng
класс привыкнуть к сообщениям de/encrypt? Это, кажется, показывает другую структуру класса затем, скажем, RSA или симметричные шифры.
Вы можете использовать ECDiffieHellman для шифрования сообщений. У вас есть два варианта: статический-статический ECDH и статический-эфемерный ECDH:
Для статического ECDH получателю необходимо знать открытый ключ отправителя (это может быть или не быть опцией в вашем приложении). У вас также должны быть некоторые данные, уникальные для этого сообщения (это может быть серийный номер, который вы получаете откуда-то из другого места в протоколе или из строки базы данных, или что-то еще, или это может быть nonce). Затем вы используете ECDH для генерации секретного ключа и используете его для шифрования ваших данных. Это даст вам желаемую длину зашифрованных данных в 16 байт, но это не полностью асимметрично: шифровальщик также может расшифровывать сообщения (опять же: это может быть или не быть проблемой в вашем приложении).
Статический-эфемерный немного отличается: здесь шифровальщик генерирует временную (эфемерную) пару ключей EC. Затем он использует эту пару ключей вместе с открытым ключом получателя для создания секретного ключа, который может быть использован для шифрования данных. Наконец, он отправляет открытый ключ эфемерной пары ключей получателю вместе с зашифрованными данными. Это может лучше подойти для вашего приложения, но полные зашифрованные данные теперь будут 2*32+16=80 байт при использовании ECDH-256 и AES (как отмечает GregS, вы можете сэкономить 32 байта, отправив только x-координату открытого ключа, но я не верю, что .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));
ECDiffieHellmanCNG - это производная от оригинального протокола обмена ключами Диффи-Хеллмана.
Он не предназначен для шифрования сообщений, а скорее для вычисления одного и того же секретного значения на обоих концах.
Здесь приведена некоторая информация о ECDiffieHellmanCNG и его назначении.