我使用RSA加密并正确签名吗?

时间:2013-07-27 14:45:50

标签: encryption .net rsa

我想确保在我的应用中获得加密部分。我打算开源这段代码。您可以在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;
}

1 个答案:

答案 0 :(得分:0)

固定IV肯定是不对的。

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

mac对于避免选择的密文攻击非常重要,你正在阅读和编写自己的格式,你必须担心操纵你的密文才能暴露某些东西,你的aes代码可能会抛出一个填充异常,可以用来通过将修改后的密文发送给接收方来恢复明文。

你的代码是开源的,开放分析和补丁是件好事,但是你应该知道applying cryptography correctly is difficult并且容易出错。

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