アプリで暗号化部分を正しく取得したことを確認するのが好きです。このコードをオープンソース化する予定です。2 つの関連ファイルはhttps://gist.github.com/lameguy7quick/1e998aad673354d2661bで取得できます。
私は間違いを犯しましたか?執筆時点では HMAC を理解していませんでした。
考え方は単純です。受信者の公開鍵を読み込みます。ランダムに作成された AES キーを暗号化します。上記の AES でメッセージをエンコードし、それを tcp 接続に詰め込みます。正しく動作しているように見えますが、何か見落としていませんか? aes にはランダムに作成された IV が必要なのかもしれませんが、キー自体はランダムに生成されるので、必要ないのではないでしょうか?
SHA1CryptoServiceProvider も使用していますが、SHA512CryptoServiceProvider を使用する必要があると思います。
私は正しく署名しましたか?署名されていると表示されていますが、攻撃があるかどうかはわかりません
public byte[] SendMessage(byte[] recipient_pubkey, byte[] replyTo, string txt, byte[] prvkey, byte[] pubkey)
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
var msgid = new byte[16];
rng.GetBytes(msgid);
using (var aes = new RijndaelManaged())
{
byte[] rsa_aes_key;
RSAParameters recipient_rsap;
Shared.LoadKey2(Shared.pubToPem(recipient_pubkey), null, out recipient_rsap);
using (var rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(recipient_rsap);
rsa_aes_key = rsa.Encrypt(aes.Key, false);
}
var aesmsg = EncodeMessage(recipient_pubkey, msgid, replyTo, txt, prvkey, pubkey, aes.Key, Shared.FixedIV_16bytes);
if (rsa_aes_key.Length + aesmsg.Length > 1024 * 15) throw new Exception();
sw.WriteByte((byte)ClientServerCmd.SendMessage);
sw.WriteShort((short)recipient_pubkey.Length);
sw.Write(recipient_pubkey, 0, recipient_pubkey.Length);
sw.WriteShort(rsa_aes_key.Length + aesmsg.Length);
sw.Write(rsa_aes_key, 0, rsa_aes_key.Length);
sw.Write(aesmsg, 0, aesmsg.Length);
sw.Flush();
var resp = sr.ReadByte();
if (resp != (byte)ClientServerCmd.KeyLenOk)
throw new Exception();
resp = sr.ReadByte();
if (resp == (byte)ClientServerCmd.NotRegistered)
throw new MyException("User you're writing to does not exist");
if (resp != (byte)ClientServerCmd.Success)
throw new Exception();
}
return msgid;
}
byte[] EncodeMessage(byte[] recipient_pubkey, byte[]msgid, byte[] replyTo, string txt, byte[] prvkey, byte[] pubkey, byte[] aes_key, byte[] aes_iv)
{
if (replyTo == null)
{
replyTo = new byte[16];
}
var txtbuf = Encoding.UTF8.GetBytes(txt);
var SignMessage = prvkey != null;
byte[] hash = null;
if (SignMessage)
{
using (var rsa = new RSACryptoServiceProvider())
{
RSAParameters rsap;
Shared.LoadKey2(Shared.prvToPem(prvkey), null, out rsap);
rsa.ImportParameters(rsap);
using (var ms = new MemoryStream()) //sign
{
ms.Write(msgid, 0, msgid.Length);
ms.Write(replyTo, 0, replyTo.Length);
ms.WriteShort((short)txtbuf.Length);
ms.Write(txtbuf, 0, txtbuf.Length);
ms.WriteShort((short)pubkey.Length);
ms.Write(pubkey, 0, pubkey.Length);
ms.WriteShort((short)recipient_pubkey.Length);
ms.Write(recipient_pubkey, 0, recipient_pubkey.Length);
ms.Position = 0;
hash = rsa.SignData(ms, new SHA1CryptoServiceProvider());
}
}
}
byte[] c1;
using (var ms1 = new MemoryStream())
using (var ms = new BZip2OutputStream(ms1))
{
ms.Write(txtbuf, 0, txtbuf.Length);
ms.Close();
c1 = ms1.ToArray();
}
var compressText = c1.Length < txtbuf.Length;
byte[] aesmsg;
byte[] aeskey;
using (var aes = new RijndaelManaged())
{
aeskey = aes.Key;
aes.IV = Shared.FixedIV_16bytes;
using (MemoryStream msEncrypt = new MemoryStream())
{
using (var encryptor = aes.CreateEncryptor(aes_key, aes_iv))
using (CryptoStream sw2 = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
sw2.WriteByte((Byte)((compressText ? 1 : 0) | (SignMessage ? 2 : 0)));
sw2.Write(msgid, 0, msgid.Length);
sw2.Write(replyTo, 0, replyTo.Length);
if (compressText)
{
sw2.WriteShort((short)c1.Length);
sw2.Write(c1, 0, c1.Length);
}
else
{
sw2.WriteShort((short)txtbuf.Length);
sw2.Write(txtbuf, 0, txtbuf.Length);
}
if (SignMessage)
{
sw2.WriteShort((short)pubkey.Length);
sw2.Write(pubkey, 0, pubkey.Length);
sw2.WriteShort((short)hash.Length);
sw2.Write(hash, 0, hash.Length);
}
}
msEncrypt.Flush();
aesmsg = msEncrypt.ToArray();
}
}
return aesmsg;
}