I thought I would post this as I did not find an off-the-shelf solution for the AES encryption needed for the V3.00 upgrade.
The SagePay C# solution example for some reason did not have have an encryption/decryption code example in it as far as I could see.
I cobbled together the code from existing posts and the RijndaelManaged Class VB example (https://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged(v=vs.110).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1)....
Imports System.Security.Cryptography
Public Shared Function AESEncryption(ByVal strCrypt As String) As String
Dim keyAndIvBytes As [Byte]() = UTF8Encoding.UTF8.GetBytes(strEncryptionPassword)
' Create a new instance of the RijndaelManaged
' class. This generates a new key and initialization
' vector (IV).
Using AES As New RijndaelManaged()
' Set the mode, padding and block size for the key
AES.Padding = PaddingMode.PKCS7
AES.Mode = CipherMode.CBC
AES.KeySize = 128
AES.BlockSize = 128
' Encrypt the string to an array of bytes.
Dim encrypted As Byte() = EncryptStringToBytes(strCrypt, keyAndIvBytes, keyAndIvBytes)
AESEncryption = "#" & BitConverter.ToString(encrypted).Replace("-", "").ToUpper
End Using
End Function
Public Shared Function AESDecryption(ByVal strCrypt As String) As String
Dim keyAndIvBytes As [Byte]() = UTF8Encoding.UTF8.GetBytes(strEncryptionPassword)
' Create a new instance of the RijndaelManaged
' class. This generates a new key and initialization
' vector (IV).
Using AES As New RijndaelManaged()
' Set the mode, padding and block size for the key
AES.Padding = PaddingMode.PKCS7
AES.Mode = CipherMode.CBC
AES.KeySize = 128
AES.BlockSize = 128
Dim encryptedData As Byte() = StringToByteArray(strCrypt.Remove(0, 1))
Dim roundtrip As String = DecryptStringFromBytes(encryptedData, keyAndIvBytes, keyAndIvBytes)
AESDecryption = roundtrip
End Using
End Function
Shared Function byteArrayToHexString(ByVal ba As Byte()) As String
Return BitConverter.ToString(ba).Replace("-", "")
End Function
Shared Function StringToByteArray(ByVal hex As String) As Byte()
Return Enumerable.Range(0, hex.Length).Where(Function(x) x Mod 2 = 0).[Select](Function(x) Convert.ToByte(hex.Substring(x, 2), 16)).ToArray()
End Function
Shared Function EncryptStringToBytes(ByVal plainText As String, ByVal Key() As Byte, ByVal IV() As Byte) As Byte()
' Check arguments.
If plainText Is Nothing OrElse plainText.Length <= 0 Then
Throw New ArgumentNullException("plainText")
End If
If Key Is Nothing OrElse Key.Length <= 0 Then
Throw New ArgumentNullException("Key")
End If
If IV Is Nothing OrElse IV.Length <= 0 Then
Throw New ArgumentNullException("IV")
End If
Dim encrypted() As Byte
' Create an RijndaelManaged object
' with the specified key and IV.
Using AES As New RijndaelManaged()
AES.Padding = PaddingMode.PKCS7
AES.Mode = CipherMode.CBC
AES.KeySize = 128
AES.BlockSize = 128
AES.Key = Key
AES.IV = IV
' Create a decrytor to perform the stream transform.
Dim encryptor As ICryptoTransform = AES.CreateEncryptor(AES.Key, AES.IV)
' Create the streams used for encryption.
Using msEncrypt As New MemoryStream()
Using csEncrypt As New CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)
Using swEncrypt As New StreamWriter(csEncrypt)
'Write all data to the stream.
swEncrypt.Write(plainText)
End Using
encrypted = msEncrypt.ToArray()
End Using
End Using
End Using
' Return the encrypted bytes from the memory stream.
Return encrypted
End Function 'EncryptStringToBytes
Shared Function DecryptStringFromBytes(ByVal cipherText() As Byte, ByVal Key() As Byte, ByVal IV() As Byte) As String
' Check arguments.
If cipherText Is Nothing OrElse cipherText.Length <= 0 Then
Throw New ArgumentNullException("cipherText")
End If
If Key Is Nothing OrElse Key.Length <= 0 Then
Throw New ArgumentNullException("Key")
End If
If IV Is Nothing OrElse IV.Length <= 0 Then
Throw New ArgumentNullException("IV")
End If
' Declare the string used to hold
' the decrypted text.
Dim plaintext As String = Nothing
' Create an RijndaelManaged object
' with the specified key and IV.
Using AES As New RijndaelManaged
AES.Padding = PaddingMode.PKCS7
AES.Mode = CipherMode.CBC
AES.KeySize = 128
AES.BlockSize = 128
'AES.Key = Key
'AES.IV = IV
' Create a decrytor to perform the stream transform.
Dim decryptor As ICryptoTransform = AES.CreateDecryptor(Key, IV)
' Create the streams used for decryption.
Using msDecrypt As New MemoryStream(cipherText)
Using csDecrypt As New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)
Using srDecrypt As New StreamReader(csDecrypt)
' Read the decrypted bytes from the decrypting stream
' and place them in a string.
plaintext = srDecrypt.ReadToEnd()
End Using
End Using
End Using
End Using
Return plaintext
End Function
Hopefully this will be of use especially as there is only 6 weeks left to migrate to V3.00 and all the V2 options are switched off.
Maybe I'm being silly here but if you reference the SagePay.IntegrationKit.DotNet dll you should have access to their Crytography class.
At least thats what I've done; added the .dll as a reference, imported it as the top of the file then used Cryptography.DecodeAndDecrypt & Cryptography.EncryptAndEncode.
c# AES Decryption
Is a great thread for SagePay C# AES encryption needed for the V3.00 upgrade.
Related
I've been trying to encrypt the connection string so I don't write it anywhere.
Using ChatGPT I came across the Rijndael method.
Module:
Imports System.Security.Cryptography
Imports System.Text
Module DB
' Encrypt the connection string
Public Function EncryptConnectionString(connectionString As String, key As Byte(), iv As Byte()) As String
' Create a new Rijndael instance
Dim rijndael As New RijndaelManaged()
rijndael.Padding = PaddingMode.PKCS7
rijndael.Key = key
rijndael.IV = iv
' Convert the connection string to a byte array
Dim data As Byte() = Encoding.UTF8.GetBytes(connectionString)
' Encrypt the data using the Rijndael instance
Dim encryptedData As Byte() = rijndael.CreateEncryptor().TransformFinalBlock(data, 0, data.Length)
' Concatenate the key, the initialization vector, and the encrypted data
Dim encryptedConnectionString As Byte() = New Byte(rijndael.Key.Length + rijndael.IV.Length + encryptedData.Length - 1) {}
Array.Copy(rijndael.Key, encryptedConnectionString, rijndael.Key.Length)
Array.Copy(rijndael.IV, 0, encryptedConnectionString, rijndael.Key.Length, rijndael.IV.Length)
Array.Copy(encryptedData, 0, encryptedConnectionString, rijndael.Key.Length + rijndael.IV.Length, encryptedData.Length)
' Convert the encrypted connection string to a base64 string
Return Convert.ToBase64String(encryptedConnectionString)
End Function
' Decrypt the connection string
Public Function DecryptConnectionString(encryptedConnectionString As String, key As Byte(), iv As Byte()) As String
' Convert the encrypted connection string from a base64 string
Dim encryptedConnectionBytes As Byte() = Convert.FromBase64String(encryptedConnectionString)
' Extract the key and initialization vector from the encrypted connection string
Dim decryptedKey As Byte() = New Byte(key.Length - 1) {}
Dim decryptedIV As Byte() = New Byte(iv.Length - 1) {}
Array.Copy(encryptedConnectionBytes, decryptedKey, key.Length)
Array.Copy(encryptedConnectionBytes, key.Length, decryptedIV, 0, iv.Length)
'Create a New Rijndael instance
Dim rijndael As New RijndaelManaged()
rijndael.Padding = PaddingMode.PKCS7
rijndael.Key = decryptedKey
rijndael.IV = decryptedIV
' Extract the encrypted data from the encrypted connection string
Dim encryptedData As Byte() = New Byte(encryptedConnectionBytes.Length - key.Length - iv.Length - 1) {}
Array.Copy(encryptedConnectionBytes, key.Length + iv.Length, encryptedData, 0, encryptedData.Length)
' Decrypt the data using the Rijndael instance
Dim decryptedData As Byte() = rijndael.CreateDecryptor().TransformFinalBlock(encryptedData, 0, encryptedData.Length)
' Convert the decrypted data to a string and return it
Return Encoding.UTF8.GetString(decryptedData)
End Function
End Module`
Form to test:
Imports System.Security.Cryptography
Imports System.Text
Public Class Form1
Private Sub BtnEncrypt_Click(sender As Object, e As EventArgs) Handles btnEncrypt.Click
' Generate a new key and initialization vector
Dim key As Byte() = New Byte(31) {}
Dim iv As Byte() = New Byte(15) {}
Using rng As New RNGCryptoServiceProvider()
rng.GetBytes(key)
rng.GetBytes(iv)
End Using
' Encrypt the connection string
Dim connectionString As String = "Server=" & txtIP.Text & ";Database=" & txtDatabase.Text & ";User ID=" & txtUsername.Text & ";Password=" & txtPassword.Text & ";port=" & txtPort.Text & ";"
Dim rijndael As New RijndaelManaged()
rijndael.Padding = PaddingMode.PKCS7
rijndael.Key = key
rijndael.IV = iv
Dim data As Byte() = Encoding.UTF8.GetBytes(connectionString)
Dim encryptedData As Byte() = rijndael.CreateEncryptor().TransformFinalBlock(data, 0, data.Length)
Dim encryptedConnectionString As String = Convert.ToBase64String(encryptedData)
'Save the encrypted connection string And the key And IV to the settings
My.Settings.EncryptedConnectionString = encryptedConnectionString
My.Settings.Key = Convert.ToBase64String(key)
My.Settings.IV = Convert.ToBase64String(iv)
My.Settings.Save()
txtconnectionstring.Text = encryptedConnectionString
txtKey.Text = Convert.ToBase64String(key)
txtIV.Text = Convert.ToBase64String(iv)
End Sub
Private Sub btnDecrypt_Click(sender As Object, e As EventArgs) Handles btnDecrypt.Click
' Retrieve the encrypted connection string, key, and IV from your settings or configuration
Dim encryptedConnectionString As String = My.Settings.EncryptedConnectionString
Dim key As Byte() = Convert.FromBase64String(txtKey.Text)
Dim iv As Byte() = Convert.FromBase64String(txtIV.Text)
' Decrypt the connection string using the key and IV
Dim connectionString As String = DecryptConnectionString(encryptedConnectionString, key, iv)
txtconnectionstring.Clear()
txtconnectionstring.Text = connectionString
End Sub
End Class
So Encryption is working good but decrypt is giving me hell. Error is: Padding is invalid and cannot be removed.
System.Security.Cryptography.CryptographicException
HResult=0x80131430
Message=Padding is invalid and cannot be removed.
Source=mscorlib
StackTrace:
at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast)
at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
For a little bit more context because i've read that the IV or KEY neeed to be the same. I saved those keys manual on the settings or i've saved it on the text box. I've always got the same error while decrypting.
If anyone could help,
Fábio
Tried to encrypt my connection string and save it to the settings of the app. Now I was trying to decrypt it so it could be used to connection to the mysql server.
I am trying to upgrade sage pay version from 2.22 to 3.00 and I am using Form Intergration to submit the values to Sage. The codes written asp.net(VB). In 2.2, it was using "SimpleXor encryption algorithm", but that doesn't allowed in version 3.00 and as a result, I am getting the below error message:
This transaction attempt has failed. We are unable to redirect you back to the web store from which you were purchasing. The details of the failure are given below.
Status: INVALID
Status Detail: 5068 : The encryption method is not supported by this protocol version.
I found, version 3.00 allowed only AES encryption, And I have added the below code in class file for encryption:
Public Shared Function AESEncrypt(ByVal clearText As String) As String
Dim EncryptionKey As String = "MAKV2SPBNI99212"
Dim clearBytes As Byte() = Encoding.Unicode.GetBytes(clearText)
Using encryptor As Aes = Aes.Create()
Dim pdb As New Rfc2898DeriveBytes(EncryptionKey, New Byte() {&H49, &H76, &H61, &H6E, &H20, &H4D, _
&H65, &H64, &H76, &H65, &H64, &H65, _
&H76})
encryptor.Key = pdb.GetBytes(32)
encryptor.IV = pdb.GetBytes(16)
Using ms As New MemoryStream()
Using cs As New CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write)
cs.Write(clearBytes, 0, clearBytes.Length)
cs.Close()
End Using
clearText = Convert.ToBase64String(ms.ToArray())
End Using
End Using
Return clearText
End Function
And in main .vb file, I change below code:
Dim strXOR As String = simpleXor(strPost, strEncryptionPassword)
strCrypt = base64Encode(strXOR)
To
Dim aesEncrypt As String = AESEncrypt(strPost)
strCrypt = "#" & aesEncrypt
Sorry, I am begginer on this. Is there any mistakes I did in my class file Or in main vb file? Do I need to base64encode after aes encryption?
Thank you in advance.
OK. Compete answer rewrite.
Ditch the code you have - I found it on another site and it isn't going to work.
Instead, use the stuff below (which I've adapted very slightly from here) :
Public Shared Function AESEncryption(ByVal strCrypt As String, ByVal strEncryptionPassword As String) As String
Dim keyAndIvBytes As Byte() = UTF8Encoding.UTF8.GetBytes(strEncryptionPassword)
Using AES As New RijndaelManaged()
' Set the mode, padding and block size for the key
AES.Padding = PaddingMode.PKCS7
AES.Mode = CipherMode.CBC
AES.KeySize = 128
AES.BlockSize = 128
' Encrypt the string to an array of bytes.
Dim encrypted As Byte() = EncryptStringToBytes(strCrypt, keyAndIvBytes, keyAndIvBytes)
AESEncryption = "#" & BitConverter.ToString(encrypted).Replace("-", "").ToUpper
' System.Console.WriteLine(AESEncryption)
End Using
End Function
Public Shared Function AESDecryption(ByVal strCrypt As String, ByVal strEncryptionPassword As String) As String
Dim keyAndIvBytes As [Byte]() = UTF8Encoding.UTF8.GetBytes(strEncryptionPassword)
' Create a new instance of the RijndaelManaged
' class. This generates a new key and initialization
' vector (IV).
Using AES As New RijndaelManaged()
' Set the mode, padding and block size for the key
AES.Padding = PaddingMode.PKCS7
AES.Mode = CipherMode.CBC
AES.KeySize = 128
AES.BlockSize = 128
Dim encryptedData As Byte() = StringToByteArray(strCrypt.Remove(0, 1))
Dim roundtrip As String = DecryptStringFromBytes(encryptedData, keyAndIvBytes, keyAndIvBytes)
AESDecryption = roundtrip
End Using
End Function
Shared Function byteArrayToHexString(ByVal ba As Byte()) As String
Return BitConverter.ToString(ba).Replace("-", "")
End Function
Shared Function StringToByteArray(ByVal hex As String) As Byte()
Return Enumerable.Range(0, hex.Length).Where(Function(x) x Mod 2 = 0).[Select](Function(x) Convert.ToByte(hex.Substring(x, 2), 16)).ToArray()
End Function
Shared Function EncryptStringToBytes(ByVal plainText As String, ByVal Key() As Byte, ByVal IV() As Byte) As Byte()
' Check arguments.
If plainText Is Nothing OrElse plainText.Length <= 0 Then
Throw New ArgumentNullException("plainText")
End If
If Key Is Nothing OrElse Key.Length <= 0 Then
Throw New ArgumentNullException("Key")
End If
If IV Is Nothing OrElse IV.Length <= 0 Then
Throw New ArgumentNullException("IV")
End If
Dim encrypted() As Byte
' Create an RijndaelManaged object
' with the specified key and IV.
Using AES As New RijndaelManaged()
AES.Padding = PaddingMode.PKCS7
AES.Mode = CipherMode.CBC
AES.KeySize = 128
AES.BlockSize = 128
AES.Key = Key
AES.IV = IV
' Create a decrytor to perform the stream transform.
Dim encryptor As ICryptoTransform = AES.CreateEncryptor(AES.Key, AES.IV)
' Create the streams used for encryption.
Using msEncrypt As New MemoryStream()
Using csEncrypt As New CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)
Using swEncrypt As New StreamWriter(csEncrypt)
'Write all data to the stream.
swEncrypt.Write(plainText)
End Using
encrypted = msEncrypt.ToArray()
End Using
End Using
End Using
' Return the encrypted bytes from the memory stream.
Return encrypted
End Function 'EncryptStringToBytes
Shared Function DecryptStringFromBytes(ByVal cipherText() As Byte, ByVal Key() As Byte, ByVal IV() As Byte) As String
' Check arguments.
If cipherText Is Nothing OrElse cipherText.Length <= 0 Then
Throw New ArgumentNullException("cipherText")
End If
If Key Is Nothing OrElse Key.Length <= 0 Then
Throw New ArgumentNullException("Key")
End If
If IV Is Nothing OrElse IV.Length <= 0 Then
Throw New ArgumentNullException("IV")
End If
' Declare the string used to hold
' the decrypted text.
Dim plaintext As String = Nothing
' Create an RijndaelManaged object
' with the specified key and IV.
Using AES As New RijndaelManaged
AES.Padding = PaddingMode.PKCS7
AES.Mode = CipherMode.CBC
AES.KeySize = 128
AES.BlockSize = 128
'AES.Key = Key
'AES.IV = IV
' Create a decrytor to perform the stream transform.
Dim decryptor As ICryptoTransform = AES.CreateDecryptor(Key, IV)
' Create the streams used for decryption.
Using msDecrypt As New MemoryStream(cipherText)
Using csDecrypt As New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)
Using srDecrypt As New StreamReader(csDecrypt)
' Read the decrypted bytes from the decrypting stream
' and place them in a string.
plaintext = srDecrypt.ReadToEnd()
End Using
End Using
End Using
End Using
Return plaintext
End Function
And in your main.vb file change:
Dim strXOR As String = simpleXor(strPost, strEncryptionPassword)
strCrypt = base64Encode(strXOR)
To:
strCrypt=AESEncryption(strPost, strEncryptionPassword)
I have used the following function to encrypt my password:
HashPasswordForStoringInConfigFile(Password, "MD5")
Now I want to decrypt the password again.
Note I'm showing the encrypted password in a grid-view and I want to decrypt it when the particular row goes in edit mode.
The simple answer is "you can't"
The idea of hashing is to generate a "safe" code from the real password, where that code can be stored in clear text; in a database (or text file) somewhere where other users might be seeing it somehow.
When someone tries to login, your system would compute another hash from the new login and then compare with the existing hash from your existing database, if the hash matches, then you know it's the correct password and then you can allow them to login, otherwise, it's not the same password / login-failed.
The reason why you cannot reverse the hash is because a hash is computed by doing the following steps:
1) Taking the password into some algorithm to:
2) Generate a very large string, then:
3) Chop that string and:
4) Take a part of it as your "hash"
So you see, even if you are superman in decoding and can figure the algorithm out, and know the hash code, and managed to reverse it back into the original form, then you would still have parts of the password missing, hence unsuccessful.
This is why Hashes are secure.
I hope this explains it.
you can make encrypt and decrypt function like this to encrypt and decrypt your text , and further u can use as per your need to display the decrypt text
here is the function
Public Function Encrypt(ByVal plainText As String) As String
Dim passPhrase As String = "yourPassPhrase"
Dim saltValue As String = "mySaltValue"
Dim hashAlgorithm As String = "MD5"
Dim passwordIterations As Integer = 2
Dim initVector As String = "#1B2c3D4e5F6g7H8"
Dim keySize As Integer = 256
Dim initVectorBytes As Byte() = Encoding.ASCII.GetBytes(initVector)
Dim saltValueBytes As Byte() = Encoding.ASCII.GetBytes(saltValue)
Dim plainTextBytes As Byte() = Encoding.UTF8.GetBytes(plainText)
Dim password As New PasswordDeriveBytes(passPhrase, saltValueBytes, hashAlgorithm, passwordIterations)
Dim keyBytes As Byte() = password.GetBytes(keySize \ 8)
Dim symmetricKey As New RijndaelManaged()
symmetricKey.Mode = CipherMode.CBC
Dim encryptor As ICryptoTransform = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes)
Dim memoryStream As New MemoryStream()
Dim cryptoStream As New CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length)
cryptoStream.FlushFinalBlock()
Dim cipherTextBytes As Byte() = memoryStream.ToArray()
memoryStream.Close()
cryptoStream.Close()
Dim cipherText As String = Convert.ToBase64String(cipherTextBytes)
Return cipherText
End Function
and for decrypt use this
Public Function Decrypt(ByVal cipherText As String) As String
Dim passPhrase As String = "yourPassPhrase"
Dim saltValue As String = "mySaltValue"
Dim hashAlgorithm As String = "MD5"
Dim passwordIterations As Integer = 2
Dim initVector As String = "#1B2c3D4e5F6g7H8"
Dim keySize As Integer = 256
' 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.
Dim initVectorBytes As Byte() = Encoding.ASCII.GetBytes(initVector)
Dim saltValueBytes As Byte() = Encoding.ASCII.GetBytes(saltValue)
' Convert our ciphertext into a byte array.
Dim cipherTextBytes As Byte() = Convert.FromBase64String(cipherText)
' 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 New PasswordDeriveBytes(passPhrase, saltValueBytes, hashAlgorithm, passwordIterations)
' 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() = password.GetBytes(keySize \ 8)
' Create uninitialized Rijndael encryption object.
Dim symmetricKey As 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 = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes)
' Define memory stream which will be used to hold encrypted data.
Dim memoryStream As New MemoryStream(cipherTextBytes)
' Define cryptographic stream (always use Read mode for encryption).
Dim cryptoStream As 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() = New Byte(cipherTextBytes.Length - 1) {}
' Start decrypting.
Dim decryptedByteCount As Integer = 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 = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount)
' Return decrypted string.
Return plainText
End Function
and call the function you will get the result.
Is there a standard library to use for AES encryption for VB.NET? I want to encrypt a string with a static private key.
I googled and found a lot of variations. I don't really know how to determine which algorithms are secure or not.
The System.Security.Cryptography namespace contains all the classes you need to perform most standard encryption tasks. Unfortunately, since encryption is a rather complicated topic, the classes are somewhat difficult to work with--especially for beginners. It's sometimes difficult to find a simple working example to start with. But, since I'm nice, I'll provide you with a simple example that you can play with and improve upon :)
The class you probably want to use is called RijndaelManaged. That is the class that implements the typical AES encryption. Here's a sample class that uses that to convert between plain text strings and byte arrays:
Public Class Aes256Encrypter
Public Function Encrypt(ByVal plainText As String, ByVal secretKey As String) As Byte()
Dim encryptedPassword As Byte()
Using outputStream As MemoryStream = New MemoryStream()
Dim algorithm As RijndaelManaged = getAlgorithm(secretKey)
Using cryptoStream As CryptoStream = New CryptoStream(outputStream, algorithm.CreateEncryptor(), CryptoStreamMode.Write)
Dim inputBuffer() As Byte = Encoding.Unicode.GetBytes(plainText)
cryptoStream.Write(inputBuffer, 0, inputBuffer.Length)
cryptoStream.FlushFinalBlock()
encryptedPassword = outputStream.ToArray()
End Using
End Using
Return encryptedPassword
End Function
Public Function Decrypt(ByVal encryptedBytes As Byte(), ByVal secretKey As String) As String
Dim plainText As String = Nothing
Using inputStream As MemoryStream = New MemoryStream(encryptedBytes)
Dim algorithm As RijndaelManaged = getAlgorithm(secretKey)
Using cryptoStream As CryptoStream = New CryptoStream(inputStream, algorithm.CreateDecryptor(), CryptoStreamMode.Read)
Dim outputBuffer(0 To CType(inputStream.Length - 1, Integer)) As Byte
Dim readBytes As Integer = cryptoStream.Read(outputBuffer, 0, CType(inputStream.Length, Integer))
plainText = Encoding.Unicode.GetString(outputBuffer, 0, readBytes)
End Using
End Using
Return plainText
End Function
Private Function getAlgorithm(ByVal secretKey As String) As RijndaelManaged
Const salt As String = "put your salt here"
Const keySize As Integer = 256
Dim keyBuilder As Rfc2898DeriveBytes = New Rfc2898DeriveBytes(secretKey, Encoding.Unicode.GetBytes(salt))
Dim algorithm As RijndaelManaged = New RijndaelManaged()
algorithm.KeySize = keySize
algorithm.IV = keyBuilder.GetBytes(CType(algorithm.BlockSize / 8, Integer))
algorithm.Key = keyBuilder.GetBytes(CType(algorithm.KeySize / 8, Integer))
algorithm.Padding = PaddingMode.PKCS7
Return algorithm
End Function
End Class
You should change the salt constant to something else. Ideally, it wouldn't even be a constant, since, to make it as secure as possible, you should use a different salt each time you perform the encryption, but that's a whole other topic.
If you want to have the encrypted value returned as a string instead of as a byte array, you can use Base-64 encoding to convert the byte array to, and from, strings, like this:
Public Class Aes256Base64Encrypter
Public Function Encrypt(ByVal plainText As String, ByVal secretKey As String) As String
Dim encryptedPassword As String = Nothing
Using outputStream As MemoryStream = New MemoryStream()
Dim algorithm As RijndaelManaged = getAlgorithm(secretKey)
Using cryptoStream As CryptoStream = New CryptoStream(outputStream, algorithm.CreateEncryptor(), CryptoStreamMode.Write)
Dim inputBuffer() As Byte = Encoding.Unicode.GetBytes(plainText)
cryptoStream.Write(inputBuffer, 0, inputBuffer.Length)
cryptoStream.FlushFinalBlock()
encryptedPassword = Convert.ToBase64String(outputStream.ToArray())
End Using
End Using
Return encryptedPassword
End Function
Public Function Decrypt(ByVal encryptedBytes As String, ByVal secretKey As String) As String
Dim plainText As String = Nothing
Using inputStream As MemoryStream = New MemoryStream(Convert.FromBase64String(encryptedBytes))
Dim algorithm As RijndaelManaged = getAlgorithm(secretKey)
Using cryptoStream As CryptoStream = New CryptoStream(inputStream, algorithm.CreateDecryptor(), CryptoStreamMode.Read)
Dim outputBuffer(0 To CType(inputStream.Length - 1, Integer)) As Byte
Dim readBytes As Integer = cryptoStream.Read(outputBuffer, 0, CType(inputStream.Length, Integer))
plainText = Encoding.Unicode.GetString(outputBuffer, 0, readBytes)
End Using
End Using
Return plainText
End Function
Private Function getAlgorithm(ByVal secretKey As String) As RijndaelManaged
Const salt As String = "put your salt here"
Const keySize As Integer = 256
Dim keyBuilder As Rfc2898DeriveBytes = New Rfc2898DeriveBytes(secretKey, Encoding.Unicode.GetBytes(salt))
Dim algorithm As RijndaelManaged = New RijndaelManaged()
algorithm.KeySize = keySize
algorithm.IV = keyBuilder.GetBytes(CType(algorithm.BlockSize / 8, Integer))
algorithm.Key = keyBuilder.GetBytes(CType(algorithm.KeySize / 8, Integer))
algorithm.Padding = PaddingMode.PKCS7
Return algorithm
End Function
End Class
If you are storing the encrypted value in a text file, XML file, or even a database, it's often easier to just use Base-64, like that.
There exist high-level encryption libraries that handle the subtle details of encryption so you don't make those mistakes, Keyczar, Nacl, GPGME.
I ported Keyczar to .net and it uses AES for it's default symmetric encryption.
You use a command line program to create a key set with a random AES key.
:> KeyczarTool.exe create --location=path_to_key_set --purpose=crypt
:> KeyczarTool.exe addkey --location=path_to_key_set --status=primary
In your project to encrypt,
Using encrypter As New Encrypter("path_to_key_set")
Return encrypter.Encrypt(plaintext)
End Using
And then to decrypt
Using crypter As new Crypter("path_to_key_set")
Return crypter.Decrypt(ciphertext)
End Using
I'm trying to make rijndael work in CBC mode. I'm not exactly sure how should I do it. I think problem in my current code is that the stream is initialized every time in the beginning of encryption, so no avalanche effect occurs (same data is encrypted twice and the output of those two encryption is the same which it should not be).
I tried to initialize the cryptostream only once but then my coded crashed because the canwrite property of cryptostream goes to false after the first write to the cryptostream.
Here is the code what I have now:
Sub Main()
Dim rij As New RijndaelManaged
Dim iv(15) As Byte
Dim key(15) As Byte
Dim secret() As Byte = {59, 60, 61}
Dim cs As ICryptoTransform
Dim cstream As CryptoStream
Dim out() As Byte
Dim NewRandom As New RNGCryptoServiceProvider()
NewRandom.GetBytes(iv)
NewRandom.GetBytes(key)
rij = New RijndaelManaged()
rij.KeySize = 128
rij.Padding = PaddingMode.PKCS7
rij.Mode = CipherMode.CBC
rij.IV = iv
rij.Key = key
cs = rij.CreateEncryptor()
Dim ms_in As New MemoryStream
cstream = New CryptoStream(ms_in, cs, CryptoStreamMode.Write)
Using cstream
cstream.Write(secret, 0, 3)
End Using
out = ms_in.ToArray
Console.WriteLine(ArrayToString(out, out.Length))
Erase out
ms_in = New MemoryStream
cstream = New CryptoStream(ms_in, cs, CryptoStreamMode.Write)
Using cstream
cstream.Write(secret, 0, 3)
End Using
out = ms_in.ToArray
Console.WriteLine(ArrayToString(out, out.Length))
End Sub
and the conversion function to convert an array to string
Public Function ArrayToString(ByVal bytes() As Byte, ByVal length As Integer) As String
If bytes.Length = 0 Then Return String.Empty
Dim sb As New System.Text.StringBuilder(length)
Dim k As Integer = length - 1
Dim i As Integer
For i = 0 To k
sb.Append(Chr(bytes(i)))
Next
Return sb.ToString()
End Function
This is what I need:
cs = rij.CreateEncryptor()
Dim ms_in As New MemoryStream
cstream = New CryptoStream(ms_in, cs, CryptoStreamMode.Write)
Using cstream
cstream.Write(secret, 0, 3) 'encrypt
End Using
out = ms_in.ToArray
Console.WriteLine(ArrayToString(out, out.Length)) 'see the encrypted message
Erase out
Using cstream
cstream.Write(secret, 0, 3) 'encrypt, this will crash here and this is the problem I'm trying to solve
End Using
out = ms_in.ToArray
Console.WriteLine(ArrayToString(out, out.Length)) 'see the encrypted message this should not be the same as the first one
Try this:
Public Sub Run()
Dim key() As Byte = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}
Dim plaintext1 As Byte() = {59, 60, 61}
Dim plaintext2 As Byte() = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, _
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, _
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, _
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 _
}
Roundtrip(plaintext1, key)
System.Console.WriteLine()
Roundtrip(plaintext2, key)
End Sub
Public Sub Roundtrip(ByRef plaintext As Byte(), ByRef key As Byte())
Dim rij As New RijndaelManaged
Dim iv(15) As Byte
Dim encryptor As ICryptoTransform
Dim decryptor As ICryptoTransform
Dim out() As Byte
'Dim NewRandom As New RNGCryptoServiceProvider()
'NewRandom.GetBytes(iv)
'NewRandom.GetBytes(key)
Console.WriteLine("Original:")
Console.WriteLine(ArrayToString(plaintext))
System.Console.WriteLine()
rij = New RijndaelManaged()
rij.KeySize = key.Length * 8 ' 16 byte key == 128 bits
rij.Padding = PaddingMode.PKCS7
rij.Mode = CipherMode.CBC
rij.IV = iv
rij.Key = key
encryptor = rij.CreateEncryptor()
Using msIn = New MemoryStream
Using cstream = New CryptoStream(msIn, encryptor, CryptoStreamMode.Write)
cstream.Write(plaintext, 0, plaintext.Length)
End Using
out = msIn.ToArray
Console.WriteLine("Encrypted:")
Console.WriteLine("{0}", ArrayToString(out))
System.Console.WriteLine()
End Using
decryptor = rij.CreateDecryptor()
Using msIn = New MemoryStream
Using cstream = New CryptoStream(msIn, decryptor, CryptoStreamMode.Write)
cstream.Write(out, 0, out.Length)
End Using
out = msIn.ToArray
Console.WriteLine("Decrypted: ")
Console.WriteLine("{0}", ArrayToString(out))
System.Console.WriteLine()
End Using
End Sub
Public Shared Function ArrayToString(ByVal bytes As Byte()) As String
Dim sb As New System.Text.StringBuilder()
Dim i As Integer
For i = 0 To bytes.Length-1
if (i <> 0 AND i mod 16 = 0) Then
sb.Append(Environment.NewLine)
End If
sb.Append(System.String.Format("{0:X2} ", bytes(i)))
Next
Return sb.ToString().Trim()
End Function
I made these basic changes to get it to work:
create a Decryptor
properly manage buffers and streams (see the Using clauses I added)
I also re-organized a little, and modified your code slightly to use a constant IV (all zeros) and use a constant key. This is so that you can get repeatable results from one run to the next. In a real app you would use a randomized IV and use a password-derived key. (See Rfc2898DeriveBytes)
ok, that allows the code to compile. I think you want to see the effect of chaining. That is not so easy, but maybe something like this will show you what you want to see:
For i As Integer = 1 To 2
Using ms = New MemoryStream
Using cstream = New CryptoStream(ms, encryptor, CryptoStreamMode.Write)
For j As Integer = 1 To i
cstream.Write(plaintext, 0, plaintext.Length)
Next j
End Using
out = ms.ToArray
Console.WriteLine("Encrypted (cycle {0}):", i)
Console.WriteLine("{0}", ArrayToString(out))
System.Console.WriteLine()
End Using
Next i