vb.net中的加密/解密并不总是返回相同的值 [英] Encrypting / Decrypting in vb.net does not always return the same value

查看:165
本文介绍了vb.net中的加密/解密并不总是返回相同的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个程序,我在其中编写和读取配置文件。当我写的时候,我使用vb.net中的RijndaelManaged对象来加密整个文件,当我使用与key和init vector相同的值读取I decrypt时。



我的开发机器和其他许多工具都可以正常工作。但是,有些PC无法使用相同的程序对文件进行加密/解密。



此加密对象中有什么可以阻止它,您会建议使用什么? / p>

谢谢



编辑:这里是我用来加密和解密的代码:从我可以看到,如果我从我的主机加密字节,我可以从任何一台电脑中剔除它。但是,如果我从其他PC加密字节,我无法从任何PC解密。此外,当我查看文件的内容时,它们看起来不一样。请注意,我通常的方式是从文件(通常是XML)创建一个memorystream,并加密/解密。

 公共共享函数EncryptBytes(ByVal strContenu()As Byte,ByVal initVectorBytes()As Byte,ByVal saltValueBytes()As Byte)As Byte()

'将我们的明文转换为字节数组。
'让我们假设明文包含UTF8编码的字符。
Dim plainTextBytes As Byte()= strContenu
'plainTextBytes = System.Text.Encoding.Unicode.GetBytes(strMessage)

Dim strPassPhrase As String =d%6& 76dhd8?532LDhds8!7?&?8&?dhcv77

Dim strHashAlgorithm As String =SHA1

Dim intPswdIterations As Integer = 2

'首先,我们必须创建一个密码,从中导出密钥。
'该密码将从指定的密码和
'salt值生成。将使用指定的哈希
'算法创建密码。密码创建可以在几次迭代中完成。
Dim password As PasswordDeriveBytes
password = New PasswordDeriveBytes(strPassPhrase,_
saltValueBytes,_
strHashAlgorithm,_
intPswdIterations)

'使用为加密
'键生成伪随机字节的密码。指定密钥的大小(以字节为单位)。
Dim keyBytes As Byte()
keyBytes = password.GetBytes(32)

'创建未初始化的Rijndael加密对象。
Dim symmetricKey As RijndaelManaged
symmetricKey = New RijndaelManaged()

'将加密模式设置为密码块链接
'(CBC)是合理的。对其他对称密钥参数使用默认选项。
symmetricKey.Mode = CipherMode.CBC

'从现有密钥字节和初始化
'向量生成加密器。密钥大小将根据密钥
'字节的数量进行定义。
Dim加密器作为ICryptoTransform
encryptor = symmetricKey.CreateEncryptor(keyBytes,initVectorBytes)

'定义将用于保存加密数据的内存流。
Dim memoryStream As System.IO.MemoryStream
memoryStream = New System.IO.MemoryStream()

'定义加密流(始终使用写入模式进行加密)。
Dim cryptoStream As CryptoStream
cryptoStream =新的CryptoStream(memoryStream,_
encryptor,_
CryptoStreamMode.Write)
'开始加密。
cryptoStream.Write(plainTextBytes,0,plainTextBytes.Length)

'完成加密。
cryptoStream.FlushFinalBlock()

'将加密数据从内存流转换为字节数组。
Dim cipherTextBytes As Byte()
cipherTextBytes = memoryStream.ToArray()

'关闭这两个流。
memoryStream.Close()
cryptoStream.Close()

'将加密数据转换为base64编码的字符串。
'Dim cipherText As String
'cipherText =
返回cipherTextBytes

'返回加密的字符串。
'返回cipherText

公共共享函数DecryptBytes )By Byte()

'将将加密密钥特征定义为字节
'数组的字符串。我们假设字符串只包含ASCII码。
'如果字符串包含Unicode字符,请使用Unicode,UTF7或UTF8
'编码。

'将我们的密文转换为字节数组。
Dim cipherTextBytes As Byte()= strContenuEncrypte

Dim strPassPhrase As String =d%6&?76dhd8DSDhds8!7?&?8&?dhcv77

Dim strHashAlgorithm As String =SHA1

Dim intPswdIterations As Integer = 2

'首先,我们必须创建一个密码,从中键
派生。该密码将从指定的
'密码和盐值生成。将使用
'指定的哈希算法创建密码。密码创建可以在
'几次迭代中完成。
Dim password As PasswordDeriveBytes
password = New PasswordDeriveBytes(strPassPhrase,_
saltValueBytes,_
strHashAlgorithm,_
intPswdIterations)

'使用为加密
'键生成伪随机字节的密码。指定密钥的大小(以字节为单位)。
Dim keyBytes As Byte()
keyBytes = password.GetBytes(32)

'创建未初始化的Rijndael加密对象。
Dim symmetricKey As RijndaelManaged
symmetricKey = New RijndaelManaged()

'将加密模式设置为密码块链接
'(CBC)是合理的。对其他对称密钥参数使用默认选项。
symmetricKey.Mode = CipherMode.CBC

'从现有密钥字节生成解密器,并初始化
'向量。密钥大小将根据密钥
'字节的数量进行定义。
Dim解密器作为ICryptoTransform
decryptor = symmetricKey.CreateDecryptor(keyBytes,initVectorBytes)

'定义将用于保存加密数据的内存流。
Dim memoryStream As System.IO.MemoryStream
memoryStream = New System.IO.MemoryStream(cipherTextBytes)

'定义将用于保存加密数据的内存流。
Dim cryptoStream As CryptoStream
cryptoStream = New CryptoStream(memoryStream,_
decryptor,_
CryptoStreamMode.Read)

'既然这时我们不知道解密数据
'的大小是什么,分配缓冲区足够长的时间来保存密文;
'plaintext永远不会超过密文。
Dim plainTextBytes As Byte()
ReDim plainTextBytes(cipherTextBytes.Length)

'开始解密。
Dim decryptptedByteCount As Integer
decryptptedByteCount = cryptoStream.Read(plainTextBytes,_
0,_
plainTextBytes.Length)

'关闭两个流。
memoryStream.Close()
cryptoStream.Close()

'将解密的数据转换为字符串。
'让我们假设原始明文字符串是UTF8编码的。
Dim plainText As String
plainText = System.Text.Encoding.Unicode.GetString(plainTextBytes,_
0,_
decryptptedByteCount)

'返回解密字符串。
返回plainTextBytes


结束函数


解决方案

如果您使用Mono而不是正常的.NET作为运行时,那么对于高于20的任何输出, PasswordDeriveBytes 将失败。 PasswordDeriveBytes 使用一个未知的,专有的,非确定性的,破坏的,加密的不安全的方法,当请求的输出比散列输出可以在 PasswordDeriveBytes Mono开发人员已将其标记为不修复。



最好的做法是升级到 Rfc2898DeriveBytes ,它实现PBKDF2而不是PBKDF1。 PBKDF2定义了如何扩展输出量,以便所有实现都应该按照指定的方式运行。



如果您需要比哈希函数提供更多的输出,那么它更安全使用KBKDF(如HKDF)对PBKDF2的输出。 PKBDF2需要另外一整套轮来创建更多的数据,这可能有利于攻击者而不是普通用户,并且会根据请求多少字节将CPU负载加倍或三倍。





另请注意, PasswordDeriveBytes 采用密码字符串不指定要使用的字符编码,所以您最好在将其转换为字节之前将其转换为构造函数。



根据大多数观察,两者似乎都使用UTF-8,但请注意,其他运行时(如Java)可能在这方面有所不同。


I have a program in which I write and read configuration files. When I write, I encrypt the whole file using the RijndaelManaged object in vb.net, and when I read I decrypt using the same value for the key and init vector.

It all work fine on my development machine and on many others. However, some PC can't encrypt/decrypt files using the same program.

is there anything in this encryption object that prevent it and what would you recommend using instead ?

Thanks

Edit : here is the code I use to encrypt and decrypt : From what I can see, if I encrypt bytes from my main machine, I can decypt it from any PC. However, if I encrypt bytes from my other PC, I cannot decrypt it from any PC. Also, when I looked at the content of the files, they don't look the same at all. Note that the usual way I go around is I create a memorystream from the file (which is usually XML) and I encrypt/decrypt.

Public Shared Function EncryptBytes(ByVal strContenu() As Byte, ByVal initVectorBytes() As Byte, ByVal saltValueBytes() As Byte) As Byte()

    ' Convert our plaintext into a byte array.
    ' Let us assume that plaintext contains UTF8-encoded characters.
    Dim plainTextBytes As Byte() = strContenu
    'plainTextBytes = System.Text.Encoding.Unicode.GetBytes(strMessage)

    Dim strPassPhrase As String = "d%6&?76dhd8?532LDhds8!7?&?8&?dhcv77"

    Dim strHashAlgorithm As String = "SHA1"

    Dim intPswdIterations As Integer = 2

    ' First, we must create a password, from which the key will be derived.
    ' This password will be generated from the specified passphrase and 
    ' salt value. The password will be created using the specified hash 
    ' algorithm. Password creation can be done in several iterations.
    Dim password As PasswordDeriveBytes
    password = New PasswordDeriveBytes(strPassPhrase, _
                                       saltValueBytes, _
                                       strHashAlgorithm, _
                                       intPswdIterations)

    ' Use the password to generate pseudo-random bytes for the encryption
    ' key. Specify the size of the key in bytes (instead of bits).
    Dim keyBytes As Byte()
    keyBytes = password.GetBytes(32)

    ' Create uninitialized Rijndael encryption object.
    Dim symmetricKey As RijndaelManaged
    symmetricKey = New RijndaelManaged()

    ' It is reasonable to set encryption mode to Cipher Block Chaining
    ' (CBC). Use default options for other symmetric key parameters.
    symmetricKey.Mode = CipherMode.CBC

    ' Generate encryptor from the existing key bytes and initialization 
    ' vector. Key size will be defined based on the number of the key 
    ' bytes.
    Dim encryptor As ICryptoTransform
    encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes)

    ' Define memory stream which will be used to hold encrypted data.
    Dim memoryStream As System.IO.MemoryStream
    memoryStream = New System.IO.MemoryStream()

    ' Define cryptographic stream (always use Write mode for encryption).
    Dim cryptoStream As CryptoStream
    cryptoStream = New CryptoStream(memoryStream, _
                                    encryptor, _
                                    CryptoStreamMode.Write)
    ' Start encrypting.
    cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length)

    ' Finish encrypting.
    cryptoStream.FlushFinalBlock()

    ' Convert our encrypted data from a memory stream into a byte array.
    Dim cipherTextBytes As Byte()
    cipherTextBytes = memoryStream.ToArray()

    ' Close both streams.
    memoryStream.Close()
    cryptoStream.Close()

    ' Convert encrypted data into a base64-encoded string.
    'Dim cipherText As String
    'cipherText = 
    Return cipherTextBytes

    ' Return encrypted string.
    'Return cipherText

End Function

Public Shared Function DecryptBytes(ByVal strContenuEncrypte() As Byte, ByVal initVectorBytes() As Byte, ByVal saltValueBytes() As Byte) As Byte()

    ' Convert strings defining encryption key characteristics into byte
    ' arrays. Let us assume that strings only contain ASCII codes.
    ' If strings include Unicode characters, use Unicode, UTF7, or UTF8
    ' encoding.

    ' Convert our ciphertext into a byte array.
    Dim cipherTextBytes As Byte() = strContenuEncrypte

    Dim strPassPhrase As String = "d%6&?76dhd8DSDhds8!7?&?8&?dhcv77"

    Dim strHashAlgorithm As String = "SHA1"

    Dim intPswdIterations As Integer = 2

    ' First, we must create a password, from which the key will be 
    ' derived. This password will be generated from the specified 
    ' passphrase and salt value. The password will be created using
    ' the specified hash algorithm. Password creation can be done in
    ' several iterations.
    Dim password As PasswordDeriveBytes
    password = New PasswordDeriveBytes(strPassPhrase, _
                                       saltValueBytes, _
                                       strHashAlgorithm, _
                                       intPswdIterations)

    ' Use the password to generate pseudo-random bytes for the encryption
    ' key. Specify the size of the key in bytes (instead of bits).
    Dim keyBytes As Byte()
    keyBytes = password.GetBytes(32)

    ' Create uninitialized Rijndael encryption object.
    Dim symmetricKey As RijndaelManaged
    symmetricKey = New RijndaelManaged()

    ' It is reasonable to set encryption mode to Cipher Block Chaining
    ' (CBC). Use default options for other symmetric key parameters.
    symmetricKey.Mode = CipherMode.CBC

    ' Generate decryptor from the existing key bytes and initialization 
    ' vector. Key size will be defined based on the number of the key 
    ' bytes.
    Dim decryptor As ICryptoTransform
    decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes)

    ' Define memory stream which will be used to hold encrypted data.
    Dim memoryStream As System.IO.MemoryStream
    memoryStream = New System.IO.MemoryStream(cipherTextBytes)

    ' Define memory stream which will be used to hold encrypted data.
    Dim cryptoStream As CryptoStream
    cryptoStream = New CryptoStream(memoryStream, _
                                    decryptor, _
                                    CryptoStreamMode.Read)

    ' Since at this point we don't know what the size of decrypted data
    ' will be, allocate the buffer long enough to hold ciphertext;
    ' plaintext is never longer than ciphertext.
    Dim plainTextBytes As Byte()
    ReDim plainTextBytes(cipherTextBytes.Length)

    ' Start decrypting.
    Dim decryptedByteCount As Integer
    decryptedByteCount = cryptoStream.Read(plainTextBytes, _
                                           0, _
                                           plainTextBytes.Length)

    ' Close both streams.
    memoryStream.Close()
    cryptoStream.Close()

    ' Convert decrypted data into a string. 
    ' Let us assume that the original plaintext string was UTF8-encoded.
    Dim plainText As String
    plainText = System.Text.Encoding.Unicode.GetString(plainTextBytes, _
                                        0, _
                                        decryptedByteCount)

    ' Return decrypted string.
    Return plainTextBytes


End Function

解决方案

If you are using Mono instead of the normal .NET as runtime, then PasswordDeriveBytes will fail for any output higher than 20. PasswordDeriveBytes uses an unknown, proprietary, non-deterministic, broken, cryptographically insecure method when more output is requested than the hash output can provide within PasswordDeriveBytes. This has been marked as no-fix by the Mono developers..

The best thing to do is to upgrade to Rfc2898DeriveBytes, which implements PBKDF2 instead of PBKDF1. The PBKDF2 defines how to extend the amount of output so all implementations should behave as specified.

If you require more output than that the hash function provides then it is however more secure to use a KBKDF such as HKDF over the output of PBKDF2. PKBDF2 requires another full set of rounds to create more data, and this may favor the attacker instead of the normal user and will double or triple the CPU load depending on how much bytes are requested.

[EDIT]

Also note that the constructor of PasswordDeriveBytes that takes a password string does not specify the character encoding that is to be used, so you are better off converting it into bytes before feeding it to the constructor.

According to most observations both seem to use UTF-8 though - beware that other runtimes (such as Java) may differ in this regard.

这篇关于vb.net中的加密/解密并不总是返回相同的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆