Decrypting a .Net Encrypted string in VB6

  • Thread starter Thread starter KRoy
  • Start date Start date
K

KRoy

I have a password stored in the Registry encrypted using
System.Security.Cryptography DES Algorithm. I supplied it
a password and a Initialization Vector.

I am trying to decrypt it using the CryptoAPI in VB6. I
am using the CryptDeriveKey to generate a session key from
a password. But it is not working and I am sure the
password is correct.

In .net I supplied an IV, when and how do I do that using
the CryptoAPI? In VB6, I must create a hash object to
hash the password into, what hashing algorithm should be
used? Any other pointers would be helpful!!!
 
Hi, I'm not entirely sure I understand... Are you encrypting a password with
the DES algorithm, using VB.NET, then storing it in the registry, and now
trying to Decrypt it with VB6 and the CryptoAPI?

Also, As for a hashing algorithm... It depends on how secure and legal you
want it to be.

--
HTH,
-- Tom Spink, Über Geek

Woe be the day VBC.EXE says, "OrElse what?"

Please respond to the newsgroup,
so all can benefit
 
KRoy said:
I have a password stored in the Registry encrypted using
System.Security.Cryptography DES Algorithm. I supplied it
a password and a Initialization Vector.

By "password", you mean "Key", right? If not, how did you translate the
"password" into a "key"? Also, there are several methods you can use to
encrypt using this class, and several options as well, and each will affect
the output slightly. Might be worth posting your code so we can tell how
it's being performed.
Another issue is that you appear to be calling the base DES implementation,
which can swap out the actual cipher Provider class based on config
settings.
I am trying to decrypt it using the CryptoAPI in VB6. I
am using the CryptDeriveKey to generate a session key from
a password. But it is not working and I am sure the
password is correct.

Depending on how you encrypted the value in the first place (see my first
comment above), you may or may not be able to use the CryptAPI.
One thing is that in this case, you seem to be derriving a key from a
password, yet you did not state what you are doing with this "password" in
the first paragraph to encrypt the value.
In .net I supplied an IV, when and how do I do that using
the CryptoAPI? In VB6, I must create a hash object to
hash the password into, what hashing algorithm should be
used? Any other pointers would be helpful!!!

The IV is used for FeedBack modes. Straight DES encryption is rather weak
(note that it is no longer used by the government for this reason). All
block cipher algorithms work by transforming your plain text one block at a
time, and the results for each block will always be the same for plain text.
So, if you have a lot of repeating values, you'll get a lot of repeating
encrypted blocks, which attackers can use to analyze and possibly reverse
the encryption key. Therefore, most block cipher implementations also allow
different FeedBack modes. These modes introduce derrived bits from the
previous block into subsequent blocks, so that even repeating blocks will
get different resulting values. However, the first block has no previous
data to feed into it, and that's what the IV is for. If you look up the
CryptDeriveKey function call in the MSDN, you will see this line:

"When keys are generated for symmetric block ciphers, the key by default is
set up in cipher block chaining (CBC) mode with an initialization vector of
zero."

Notice the IV (initialization vector) is automatically set to an all-zero
string.

Honestly, I think the best (or at least easiest) thing is to *NOT* mix .NET
crypto functions and the native CryptoAPI functions.
You can achieve this by creating a COM object in .NET that exposes Encrypt
and Decrypt functions (using the .NET crypto classes internally). Once you
install the .NET assembly and register it, VB6 applications will be able to
interface with it through COM.

-Rob Teixeira [MVP]
 
Yes, you are correct.
-----Original Message-----
Hi, I'm not entirely sure I understand... Are you encrypting a password with
the DES algorithm, using VB.NET, then storing it in the registry, and now
trying to Decrypt it with VB6 and the CryptoAPI?

Also, As for a hashing algorithm... It depends on how secure and legal you
want it to be.

--
HTH,
-- Tom Spink, Über Geek

Woe be the day VBC.EXE says, "OrElse what?"

Please respond to the newsgroup,
so all can benefit




.
 
I have decided to P/Invoke the CryptoAPI into my .net
application. However, this seems to be throwing me a new
curve with how to send my plainText (vb string) to the
CryptEncrypt function as pbData. My code is as follows:

<DllImport(CryptDll)> _
Public Shared Function CryptEncrypt _
(ByVal hKey As Integer, _
ByVal hHash As Integer, _
ByVal Final As Boolean, _
ByVal dwFlags As Integer, _
ByRef pdData As String, _
ByRef pdwDataLen As Integer, _
ByVal dwBufLen As Integer) As Boolean
End Function

Public Function Encrypt(dataString as String) as String
..
.... Got hKey (vb Integer) from CryptDeriveKey
..
lResult = CryptEncryptNULL(hKey, 0, True, 0, Nothing,
dataLength, bufLength)
If Not lResult Then
msgResult = MsgBox("Failed")
Else
' Create buffer string to correct size and fill it
with dataString
Dim codedString As Byte() =
System.Text.Encoding.ASCII.GetBytes(dataString)
Dim codedBuffer As Byte() =
System.Text.Encoding.ASCII.GetBytes(Space(dataLength))
System.Buffer.BlockCopy(codedString, 0, codedBuffer,
0, codedString.Length)
Dim bufferString As String =
System.Text.Encoding.ASCII.GetString(codedBuffer)
' Now we have string the size of the buffer
dataLength = dataString.Length
bufLength = bufferString.Length
lResult = WinApi.CryptEncrypt(hKey, 0, True, 0,
bufferString, dataLength, bufLength)

On this last line, I get the following error:
"An unhandled exception of
type 'System.NullReferenceException' occurred in
pedge.security.dll

Additional information: Object reference not set to an
instance of an object."

I think this has to do with the function trying to return
the value "ByRef" back into bufferString. In VB6, we
could pass bufferString ByVal to pass the pointer, this
can't be done in vb.net. How can I pass the pointer of
bufferString???
 
pdData is an [in/out] parameter. Never pass a .NET String variable to an
unmanaged function that will modify it. .NET strings must remain immutable
(can't be changed). Also, the "real" function prototype defines pdData as a
pointer to a byte array. I suggest you actually define it that way as well -
after all, you already have the byte array buffer, no need to create a
seperate string copy. Also note that DES is a block cipher. That being said,
block ciphers don't return data that is exactly the size of the input (plain
text). For example, if the block is 16 bits (which off the top of my head, i
believe is what DES uses), it will always return data with a size in a
multiple of 16 bits. If the input data length is exactly a multiple of 16
bits, then you'll have no problem, but if it is not, then the returned data
will require a length to the nearest 16-bit block size, plus an additional
full block (which will be padded by the cipher algorithm).

-Rob Teixeira [MVP]
 
Thanks! That was a good expaination, however I seem to be
still getting that error with the byte array. Code as
follows:

<DllImport(CryptDll)> _
Public Shared Function CryptEncrypt _
(ByVal hKey As Integer, _
ByVal hHash As Integer, _
ByVal Final As Boolean, _
ByVal dwFlags As Integer, _
ByRef pdData() As Byte, _
ByRef pdwDataLen As Integer, _
ByVal dwBufLen As Integer) As Boolean
End Function

Public Function Encrypt(dataString as String) as String
...
..... Got hKey (vb Integer) from CryptDeriveKey
...
lResult = CryptEncryptNULL(hKey, 0, True, 0, Nothing,
dataLength, bufLength)
If Not lResult Then
msgResult = MsgBox("Failed")
Else
' Create codedBuffer to correct size and fill it
with codedData
Dim codedString As Byte() =
System.Text.Encoding.ASCII.GetBytes(dataString)
Dim codedBuffer As Byte() = New Byte(dataLength - 1)
{}
System.Buffer.BlockCopy(codedString, 0, codedBuffer,
0, codedString.Length)
' Now codedBuffer is sized correctly
dataLength = codedString.Length
bufLength = codedBuffer.Length
lResult = WinApi.CryptEncrypt(hKey, 0, True, 0,
codedBuffer, dataLength, bufLength)

On this last line, I'm still getting the following error:
"An unhandled exception of
type 'System.NullReferenceException' occurred in
pedge.security.dll

Additional information: Object reference not set to an
instance of an object."

-----Original Message-----
pdData is an [in/out] parameter. Never pass a .NET String variable to an
unmanaged function that will modify it. .NET strings must remain immutable
(can't be changed). Also, the "real" function prototype defines pdData as a
pointer to a byte array. I suggest you actually define it that way as well -
after all, you already have the byte array buffer, no need to create a
seperate string copy. Also note that DES is a block cipher. That being said,
block ciphers don't return data that is exactly the size of the input (plain
text). For example, if the block is 16 bits (which off the top of my head, i
believe is what DES uses), it will always return data with a size in a
multiple of 16 bits. If the input data length is exactly a multiple of 16
bits, then you'll have no problem, but if it is not, then the returned data
will require a length to the nearest 16-bit block size, plus an additional
full block (which will be padded by the cipher algorithm).

-Rob Teixeira [MVP]


I have decided to P/Invoke the CryptoAPI into my .net
application. However, this seems to be throwing me a new
curve with how to send my plainText (vb string) to the
CryptEncrypt function as pbData. My code is as follows:

<DllImport(CryptDll)> _
Public Shared Function CryptEncrypt _
(ByVal hKey As Integer, _
ByVal hHash As Integer, _
ByVal Final As Boolean, _
ByVal dwFlags As Integer, _
ByRef pdData As String, _
ByRef pdwDataLen As Integer, _
ByVal dwBufLen As Integer) As Boolean
End Function

Public Function Encrypt(dataString as String) as String
.
... Got hKey (vb Integer) from CryptDeriveKey
.
lResult = CryptEncryptNULL(hKey, 0, True, 0, Nothing,
dataLength, bufLength)
If Not lResult Then
msgResult = MsgBox("Failed")
Else
' Create buffer string to correct size and fill it
with dataString
Dim codedString As Byte() =
System.Text.Encoding.ASCII.GetBytes(dataString)
Dim codedBuffer As Byte() =
System.Text.Encoding.ASCII.GetBytes(Space(dataLength))
System.Buffer.BlockCopy(codedString, 0, codedBuffer,
0, codedString.Length)
Dim bufferString As String =
System.Text.Encoding.ASCII.GetString(codedBuffer)
' Now we have string the size of the buffer
dataLength = dataString.Length
bufLength = bufferString.Length
lResult = WinApi.CryptEncrypt(hKey, 0, True, 0,
bufferString, dataLength, bufLength)

On this last line, I get the following error:
"An unhandled exception of
type 'System.NullReferenceException' occurred in
pedge.security.dll

Additional information: Object reference not set to an
instance of an object."

I think this has to do with the function trying to return
the value "ByRef" back into bufferString. In VB6, we
could pass bufferString ByVal to pass the pointer, this
can't be done in vb.net. How can I pass the pointer of
bufferString???


.
 
Change pdData to ByVal. Like a String, Arrays are references. ByRef will
give you a pointer to a pointer, which is not what you want in this case.

-Rob Teixeira [MVP]
 
Back
Top