blueDroid
blueDroid

Reputation: 231

The input data is not a complete block

enter image description hereenter image description hereScenario: One symmetric key, each user has his own IV, the documents are stored in a NVARCHAR(MAX) field. When I try to to decrypt the file, I get:
The input data is not a complete block.

// Create symmetric key
public static byte[] CreateKey()
{
    AesCryptoServiceProvider aesCrypto = (AesCryptoServiceProvider)AesCryptoServiceProvider.Create();
    byte[] key = aesCrypto.Key;
    return key;
}

//Get key (stored in a database)
public static Byte[] GetAppKey()
{
    return db.Encryptors.Where(x => x.EncryptorID == 1).Single().EncryptionKey.ToArray();
}

// Get application IV (stored in database)
public static Byte[] GetAppIV()
{
    return db.Encryptors.Where(x => x.EncryptorID == 1).Single().IV.ToArray();
}

// Encrypt document (this will be stored in a VARBINARY(MAX) field
public static byte[] EncryptBinaryToBytes(Binary document, byte[] iv)
{
    byte[] key = GetAppKey();
    byte[] encrypted;

    using (AesCryptoServiceProvider aesCsp = new AesCryptoServiceProvider())
    {
        aesCsp.Key = key;
        aesCsp.IV = iv;

        ICryptoTransform encryptor = aesCsp.CreateEncryptor(aesCsp.Key, aesCsp.IV);

        using (MemoryStream msEncrypt = new MemoryStream())
        {
            using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
            {
                using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                {
                    swEncrypt.Write(document);
                }
                encrypted = msEncrypt.ToArray();
            }
        }
    }
    // return the encrypted document
    return encrypted;
}

// Decrypt document
public static byte[] DecryptBytesToBytes(byte[] document, byte[] iv) 
{
    byte[] key = GetAppKey();

    using (AesCryptoServiceProvider aesCsp = new AesCryptoServiceProvider())
    {
        aesCsp.Key = key;
        aesCsp.IV = iv;

        ICryptoTransform decryptor = aesCsp.CreateDecryptor(aesCsp.Key, aesCsp.IV);

        using (MemoryStream msDecrypt = new MemoryStream())
        {
            using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write))
            {
                using (StreamWriter swDecrypt = new StreamWriter(csDecrypt))
                {
                    swDecrypt.Write(document);
                }
                byte[] decrypted = msDecrypt.ToArray();
                // return the unencrypted document
                return decrypted;
            }
        }
    }
}

Thanks in advance.

To store the document

    byte[] fileByte = fluUploadFile.FileBytes;
    Binary document = new Binary(fileByte);

    byte[] appIv = AES.GetAppIV();
    byte[] encryptedDocument = AES.EncryptBinaryToBytes(document, appIv);
    byte[] decryptedDocument = AES.DecryptBytesToBytes(encryptedDocument, appIv);
    Document d = new Document()
    {
        OriginalName = originalName,
        DocSize = fileSize,
        BinaryDocument = encryptedDocument,
        UploadedName = uploadedFileName,
        MimeType = MIMEType,
        DocExtension = extension
    };
    db.Documents.InsertOnSubmit(d);
    db.SubmitChanges();

Upvotes: 0

Views: 6794

Answers (1)

Xint0
Xint0

Reputation: 5399

It's really important that you change the data type of the database field to VARBINARY(MAX), that way you avoid issues with character encodings and byte combinations that cannot be interpreted as legal characters.

Also, I think the problem is that you are not closing the streams before calling ToArray() method on the MemoryStream in both encrypt and decrypt routines. It's very important to call Close() in the CryptoStream so that FlushFinalBlock() is called and the encryption process writes the final block to the stream.

Try moving the call to MemoryStream.ToArray() to the outer using block, that is, outside the using block of CryptoStream, so that Dispose() is called on the CryptoStream and call MemoryStream.Close() before that.

Another problem with your code is that you are wrapping the CryptoStream with a StreamWriter, which writes the text representation of the object you pass into the Write method. You should instead write directly to the CryptoStream to avoid any byte to string conversions.

Upvotes: 2

Related Questions