在我的MemoryStream中寻找会产生不希望的结果

时间:2016-05-04 03:37:40

标签: c# bytearray memorystream binaryreader binarywriter

我正在努力将我们的加密类重写为符合FIPS标准,并且这样做必须重新处理我们如何处理非秘密有效载荷数据。此刻,我正在写出我的非秘密有效载荷的大小,然后写出我的IV的大小。我通过编写非秘密有效载荷和IV来跟进,所有这些写入共享BinaryWriter。最后,我然后共享相同的MemoryStream并将需要加密的数据写入CryptoStream

这是班级目前的样子:

public class Encryption
{
    private const int SaltBlockSize = 8;
    private const int SaltBitSize = 64;
    private const int KeyBitSize = 256;
    private const int SaltIterations = 10000;

    private const int nonSecretPayloadOffsetInPayload = 0;
    private const int ivOffsetInPayload = 1;

    public byte[] GetNonSecretPayload(byte[] completePayload)
    {
        byte[] nonSecretPayload;
        using (var memoryStream = new MemoryStream(completePayload))
        {
            using (var binaryReader = new BinaryReader(memoryStream))
            {
                int nonSecretPayloadLength = binaryReader.ReadInt32();
                binaryReader.BaseStream.Position = 3;
                nonSecretPayload = binaryReader.ReadBytes(nonSecretPayloadLength);
            }
        }

        return nonSecretPayload;
    }

    public byte[] EncryptMessageWithPassword(byte[] secretMessage, string password, byte[] nonSecretPayload = null)
    {
        if (string.IsNullOrEmpty(password))
        {
            throw new InvalidOperationException("You can not provide an empty password, you must give a string that is at least 12 characters in size. If you just want to obfuscate the message without any protection, an alternative way is to use a Base64 String");
        }
        else if (password.Length < 12)
        {
            throw new InvalidOperationException("The minimum size your password can be is 12 characters.");
        }

        byte[] saltHash;
        byte[] saltKey = this.CreateSaltKeysFromPassword(password, 0, out saltHash);

        byte[] encryptedValue = null;

        using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider())
        {
            aesProvider.Key = saltKey;
            aesProvider.Mode = CipherMode.CBC;
            aesProvider.Padding = PaddingMode.PKCS7;
            aesProvider.GenerateIV();
            using (MemoryStream memoryStream = new MemoryStream())
            {
                // Write our IV out first so we can pull the IV off later during decryption.
                // The IV does not need to be encrypted, it is safe to store as as unencrypted buffer in the encrypted byte array.
                using (BinaryWriter ivWriter = new BinaryWriter(memoryStream, Encoding.UTF8, true))
                {
                    // The first two writes to the stream should be the size of the non-secret payload
                    // and the size of the IV. If no payload exists, then we write 0.
                    if (nonSecretPayload == null || nonSecretPayload.Length == 0)
                    {
                        ivWriter.Write(0);
                    }
                    else
                    {
                        ivWriter.Write(nonSecretPayload.Length);
                    }
                    ivWriter.Write(aesProvider.IV.Length);

                    // If we have a payload, write it out.
                    if (nonSecretPayload != null && nonSecretPayload.Length > 0)
                    {
                        ivWriter.Write(nonSecretPayload);
                    }

                    // Write the Initialization Vector.
                    ivWriter.Write(aesProvider.IV);
                }

                // Create our encryptor and write the secret message to the encryptor stream.
                var encryptor = aesProvider.CreateEncryptor(saltKey, aesProvider.IV);
                using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(secretMessage, 0, secretMessage.Length);
                    cryptoStream.FlushFinalBlock();
                }

                // Get the non-secret payload, IV, payload and IV lengths and encrypted data back as an array of bytes.
                encryptedValue = memoryStream.ToArray();
            }
        }

        return encryptedValue;
    }

    public string EncryptMessageWithPassword(string secretMessage, string password, byte[] nonSecretPayLoad = null)
    {
        byte[] secreteMessageBytes = Encoding.UTF8.GetBytes(secretMessage);
        byte[] encryptedMessage = this.EncryptMessageWithPassword(secreteMessageBytes, password, nonSecretPayLoad);
        return Convert.ToBase64String(encryptedMessage);
    }

    private byte[] CreateSaltKeysFromPassword(string password, int nonSecretPayloadSize, out byte[] saltHash)
    {
        byte[] saltKey;

        //Use Random Salt to prevent pre-generated weak password attacks.
        using (var generator = new Rfc2898DeriveBytes(password, SaltBitSize / SaltBlockSize, SaltIterations))
        {
            // Get a generated salt derived from the user password, hashed n-times where n = SaltIterations
            saltHash = generator.Salt;

            //Generate Keys
            saltKey = generator.GetBytes(KeyBitSize / SaltBlockSize);
        }

        return saltKey;
    }
}

我希望在我的GetNonSecretPayload(byte[] payload);中通过设置位置,或使用binaryReader.BaseStream.Seek(2);跳过IV长度项,我会跳过byte []数组中的IV大小条目并且能够读取与实际非机密数据相关的字节。但这并不起作用,大概是因为这不是封面下面的数组,我可以移动到数组中的下一个元素,跳过最初写出的IV长度。

我有以下单元测试。

[TestClass]
public class EncryptionTests
{
    private const string _ContentToEncrypt = "This is a test to make sure the encryption Type actually encrypts the data right.";

    private const string _Password = "EncryptedPassword1";

    [TestMethod]
    public void Extract_non_secret_payload_content_from_encrypted_string()
    {
        // Arrange
        var encryption = new Encryption();
        string nonSecretData = "My payload is not considered secret and can be pulled out of the payload without decrypting";

        // Convert the secret and non-secret data into a byte array
        byte[] payload = Encoding.UTF8.GetBytes(nonSecretData);
        byte[] encodedBytes = Encoding.UTF8.GetBytes(_ContentToEncrypt);

        // Encrypt the secret data while injecting the nonsecret payload into the encrypted stream.
        byte[] encryptedValue = encryption.EncryptMessageWithPassword(encodedBytes, _Password, payload);

        // Act
        // Pull the non-secret payload out of the encrypted message - without having to decrypt it.
        byte[] UnencryptedPayloadWithinEncryptedArray = encryption.GetNonSecretPayload(encryptedValue);
        string payloadContent = Encoding.UTF8.GetString(UnencryptedPayloadWithinEncryptedArray);

        // Assert
        Assert.AreEqual(nonSecretData, payloadContent);
    }
}

我当前binaryReader.BaseStream.Position = 3获得的是

  

&#34; \ 0 \ u0010 \ 0 \ 0 \ 0我的有效载荷不被视为机密,可以在没有解密的情况下从有效载荷中拉出来#34;

我过去使用BinaryWriter读取和写入这样的数据,但我从来没有必要通过它来跳过数据。我在这里做错了什么?

0 个答案:

没有答案