How to decrypt a string?

R

Ralph Moritz

Hi group,

I'm trying to encrypt & then decrypt a string using symmetric
encryption. The encryption seems to work fine, but when trying to
decrypt, I get a System.IndexOutOfRangeException. Please would someone
be kind enough to point out my mistake? Please see my code (C++/CLI)
below.

TIA,
Ralph


System::String^ Quantum::Util::EncryptString(System::String^ str)
{
using namespace System::IO;
using namespace System::Security::Cryptography;

MemoryStream^ ms = gcnew MemoryStream;
RijndaelManaged^ rm = gcnew RijndaelManaged;
CryptoStream^ cs = gcnew CryptoStream(ms, rm->CreateEncryptor(m_key, m_iv),
CryptoStreamMode::Write);
StreamWriter^ sw = gcnew StreamWriter(cs);

try {
sw->Write(str);
} finally {
sw->Close();
cs->Close();
ms->Close();
}

return System::Convert::ToBase64String(ms->ToArray());
}

System::String^ Quantum::Util::DecryptString(System::String^ str)
{
using namespace System::IO;
using namespace System::Security::Cryptography;

MemoryStream^ ms = gcnew MemoryStream;
RijndaelManaged^ rm = gcnew RijndaelManaged;
CryptoStream^ cs = gcnew CryptoStream(ms, rm->CreateDecryptor(m_key, m_iv),
CryptoStreamMode::Read);
StreamWriter^ sw = gcnew StreamWriter(ms);
StreamReader^ sr = gcnew StreamReader(cs);

System::String^ cleartext;
try {
array<System::Byte>^ bytes = System::Convert::FromBase64String(str);
sw->Write(bytes);
cleartext = sr->ReadToEnd();
} finally {
sw->Close();
sr->Close();
cs->Close();
ms->Close();
}

return cleartext;
}
 
K

Kevin Spencer

To use the CryptoStream class, you create an instance of the class from a
stream, as you have done. Then you use a StreamWriter to write your input to
the CryptoStream, which you have also done. This writes the encrypted string
to the stream you initialized the CryptoStream with. At this point, your
MemoryStream contains a string; it is a stream of text. So, rather than
using the Convert.ToBase64String method, just create a StreamReader to read
the string from your MemoryStream.

--
HTH,

Kevin Spencer
Microsoft MVP
Software Composer
http://unclechutney.blogspot.com

The shortest distance between 2 points is a curve.
 
R

Ralph Moritz

Kevin Spencer said:
To use the CryptoStream class, you create an instance of the class from a
stream, as you have done. Then you use a StreamWriter to write your input to
the CryptoStream, which you have also done. This writes the encrypted string
to the stream you initialized the CryptoStream with. At this point, your
MemoryStream contains a string; it is a stream of text. So, rather than
using the Convert.ToBase64String method, just create a StreamReader to read
the string from your MemoryStream.

That won't work, I'm afraid. My program needs to encrypt a string and
write it to a config file. When the program starts up, it checks for
the existence of a config file, and tries to read the encrypted
connection string from the file. The problem I discovered early on is
that mixing text and binary data is a BAD IDEA, so I have to Base64
encode the string before writing it to the config file. Logically
then, it follows that I need to Base64 decode the string before
attempting to decrypt it.
 
K

Kevin Spencer

Not at all. The MemoryStream already contains a string. In essence, you are
converting a string to another string.

--
HTH,

Kevin Spencer
Microsoft MVP
Software Composer
http://unclechutney.blogspot.com

The shortest distance between 2 points is a curve.
 
J

Jon Skeet [C# MVP]

Kevin Spencer said:
Not at all. The MemoryStream already contains a string. In essence, you are
converting a string to another string.

No. Encryption works on binary data, and it's not safe to treat
arbitrary binary data as if it were valid text data.

The OP is quite right to convert the encrypted bytes into a string
using Base64 and then convert the Base64 data back into bytes before
decryption.

What he's doing wrong is using StreamWriter.Write(bytes) instead of
just writing the converted data directly into the MemoryStream.

The encryption is:
Plaintext String -> Encrypted bytes -> Base64

The decrypion should thus be:
Base64 -> Encrypted bytes -> Plaintext String

Currently it's

Base64 -> Encrypted bytes -> ToString() -> Plaintext String

The call to ToString() is in the StreamWriter.Write(object) call.
 
K

Kevin Spencer

Hi Jon,

In this case, it's not arbitrary data. It's a string. The methods are
strongly-typed to encrypt and decrypt string data.

--
HTH,

Kevin Spencer
Microsoft MVP
Software Composer
http://unclechutney.blogspot.com

The shortest distance between 2 points is a curve.
 
J

Jon Skeet [C# MVP]

In this case, it's not arbitrary data. It's a string. The methods are
strongly-typed to encrypt and decrypt string data.

It starts off as a string, but encryption will turn it into arbitrary
binary data. An encrypted version of a UTF-8 string isn't necessarily
(and often won't be) a valid UTF-8 encoded string. Converting
encrypted data into a string just using Encoding.UTF8 (or the like) is
very, very likely to lose data. It's like trying to load up the
contents of a jpeg file as a string, pass that to someone else to
write out, and then expecting it to still load. It just won't work (in
the general case).

Base64 is absolutely the way to go here.

Jon
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top