0

我想确保我的应用程序中的加密部分是正确的。我打算开源这个代码。您可以在以下位置获取两个相关文件: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;
}
4

1 回答 1

0

固定IV肯定是不对的。

AES CBC 的 IV 不应该是可预测的。通常,您将其随机化并将其包含在密文中。

mac对于避免选择的密文攻击很重要,您正在阅读和编写自己的格式,您必须担心密文的操作会导致某些内容被暴露,您的aes代码可能会引发可用于恢复明文的填充异常通过将修改后的密文发送给您的接收者。

您的代码将是开源的,可以对其进行分析和修补,这很好,但是您应该意识到正确应用密码学是困难的,而且很容易出错。

如果您可以适应高级库,例如Keyczar(我将其移植到 c#),您将处于更好的状态,尽管没有什么是完美的。

于 2013-07-27T23:04:41.630 回答