I need to pass a URL as a parameter into my querystring, since the URLs can be long I need to shorten the URL while passing and then be able to decrypt them on server side.
The URL that I am trying to pass does not contain sensitive information so string encryption techniques are not required, I am just looking to convert a long string to a short string and be able to reconstruct it back to a string.
I have tried AES encryption and it works but the resulting string is sometimes longer than the URL value itself.
Example of what I've tried so far :
private static byte[] key = { 252, 217, 19, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 112, 222, 209, 241, 24, 175, 144, 173, 53, 196, 29, 24, 26, 17, 218, 131, 236, 53, 209 };
private static byte[] vector = { 152, 64, 191, 111, 23, 3, 113, 119, 231, 121, 221, 112, 79, 32, 114, 156 };
private ICryptoTransform encryptor, decryptor;
private UTF8Encoding encoder;
public SimpleAES()
{
RijndaelManaged rm = new RijndaelManaged();
encryptor = rm.CreateEncryptor(key, vector);
decryptor = rm.CreateDecryptor(key, vector);
encoder = new UTF8Encoding();
}
public string Encrypt(string unencrypted)
{
return Convert.ToBase64String(Encrypt(encoder.GetBytes(unencrypted)));
}
public string Decrypt(string encrypted)
{
return encoder.GetString(Decrypt(Convert.FromBase64String(encrypted)));
}
public string EncryptToUrl(string unencrypted)
{
return HttpUtility.UrlEncode(Encrypt(unencrypted));
}
public string DecryptFromUrl(string encrypted)
{
return Decrypt(HttpUtility.UrlDecode(encrypted));
}
public byte[] Encrypt(byte[] buffer)
{
return Transform(buffer, encryptor);
}
public byte[] Decrypt(byte[] buffer)
{
return Transform(buffer, decryptor);
}
protected byte[] Transform(byte[] buffer, ICryptoTransform transform)
{
MemoryStream stream = new MemoryStream();
using (CryptoStream cs = new CryptoStream(stream, transform, CryptoStreamMode.Write))
{
cs.Write(buffer, 0, buffer.Length);
}
return stream.ToArray();
}
Example TEST :
string unencrypted = "/exampleurl/this_is_a_long_string_the_length_of_this_url_is_112_charachters_/this_string_needs_to_be-shortened/";
var result = EncryptToUrl(unencrypted);
"MHMyQdwbJpw8ah%2fbhAr2eJwTFa%2fyupemjuOVcBJmxTIdzcR0PZKCNSa5Fvi7kNrY3Kxlk5KWqAAEspWVtJfNjwwPs%2bCDGpC9Fn8CeGezWhXEbLT6CST2v%2fKpvptHVi3fBYSk1w3q1FYMx3C5DdKueQ%3d%3d"
The actual string is 112 charachters long and the result is 165 charahcters long.
The following code is taken verbatim from here. I duplicated this because the question is not a duplicate but the answer solves the problem this question poses. When you call Zip you will need to base64 encode the result to make it friendly for a browser if you plan to include it in a URL or something.
public static void CopyTo(Stream src, Stream dest) {
byte[] bytes = new byte[4096];
int cnt;
while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0) {
dest.Write(bytes, 0, cnt);
}
}
public static byte[] Zip(string str) {
var bytes = Encoding.UTF8.GetBytes(str);
using (var msi = new MemoryStream(bytes))
using (var mso = new MemoryStream()) {
using (var gs = new GZipStream(mso, CompressionMode.Compress)) {
//msi.CopyTo(gs);
CopyTo(msi, gs);
}
return mso.ToArray();
}
}
public static string Unzip(byte[] bytes) {
using (var msi = new MemoryStream(bytes))
using (var mso = new MemoryStream()) {
using (var gs = new GZipStream(msi, CompressionMode.Decompress)) {
//gs.CopyTo(mso);
CopyTo(gs, mso);
}
return Encoding.UTF8.GetString(mso.ToArray());
}
}
static void Main(string[] args) {
byte[] r1 = Zip("StringStringStringStringStringStringStringStringStringStringStringStringStringString");
string r2 = Unzip(r1);
}
This might sound strange, but can you store the querystring in a database and reference it by some primary key? That might be similar to using some third party URL shortening service.
Related
I need to decrypt (or encrypt original in the same way, whatever is easiest) passwords encrypted in C# by a user defined function in Coldfusion. Below is the c# function used
private static byte[] key = { };
private static byte[] IV = { 38, 55, 206, 48, 28, 64, 20, 16 };
private static string stringKey = "xxxxxxxxxxxxxxxxxxxxxxxx";
public static string Md5Encrypt(string password)
{
string empty = string.Empty;
string str;
try
{
Helpers.key = Encoding.UTF8.GetBytes(Helpers.stringKey.Substring(0, 8));
DESCryptoServiceProvider cryptoServiceProvider = new DESCryptoServiceProvider();
byte[] bytes = Encoding.UTF8.GetBytes(password.ToString());
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream((Stream) memoryStream, cryptoServiceProvider.CreateEncryptor(Helpers.key, Helpers.IV), CryptoStreamMode.Write);
cryptoStream.Write(bytes, 0, bytes.Length);
cryptoStream.FlushFinalBlock();
str = Convert.ToBase64String(memoryStream.ToArray()).Replace("+", "-").Replace("/", "_");
}
catch (Exception ex)
{
return "";
}
return str;
}
I just started with Cryptography in C# an tried to first encrypt and then decrypt a file. But during the decryption, in the function
private static byte[] Decrypt(byte[] inputBuffer)
, at
byte[] outputBuffer = transform.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
I am getting the following Exception:
System.Security.Cryptography.CryptographicException: "Invalid data".
But why is that?
This is the function to read the file:
private static void DecryptFile()
{
byte[] buffer = new byte[4096];
byte[] decryptionBuffer = new byte[4096];
int bytesRead = 0;
using (FileStream inputStream = File.OpenRead(Environment.CurrentDirectory + "\\Encrypted.txt"))
{
using (FileStream outputStream = File.Create(Environment.CurrentDirectory + "\\Decrypt.mp3"))
{
while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
{
decryptionBuffer = Decrypt(buffer);
outputStream .Write(decryptionBuffer, 0, decryptionBuffer.Length);
}
}
Console.WriteLine("Done.");
}
}
This is the function to decrypt the file, the key and the initialization vector:
private static byte[] key = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] iv = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] Decrypt(byte[] inputBuffer)
{
SymmetricAlgorithm algorithm = DES.Create();
ICryptoTransform transform = algorithm.CreateDecryptor(key, iv);
//here the exception is triggered
byte[] outputBuffer = transform.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
return outputBuffer;
}
this is how the file was encrypted:
private static void EncryptFile()
{
byte[] buffer = new byte[4096];
byte[] enryptionBuffer = new byte[4096];
int bytesRead = 0;
using (FileStream inputStream = File.OpenRead(Environment.CurrentDirectory + "\\Test.txt"))
{
using (FileStream outputStream = File.Create(Environment.CurrentDirectory + "\\Encrypted.txt"))
{
while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
{
encryptionBuffer = Encrypt(buffer);
outputStream .Write(encryptionBuffer, 0, encryptionBuffer.Length);
}
}
Console.WriteLine("Done.");
}
}
//Key and initialization vector are the same
private static byte[] key = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] iv = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] Encrypt(byte[] inputBuffer)
{
SymmetricAlgorithm algorithm = DES.Create();
ICryptoTransform transform = algorithm.CreateEncryptor(key, iv);
byte[] outputBuffer = transform.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
return outputBuffer;
}
Your encryption code produces larger output buffers than your input buffers. If you independently encrypt 4096 bytes at a time, it produces 4104 bytes of output1. If you wish to continue to independently encrypt each block of your file, you need to change your decryption code to use 4104 byte buffers when it's working in chunks.
Ideally though, this "encrypt each block separately" isn't a requirement. If that's the case, create your transform object once, not once each time through your loop. And use Transform rather than TransformFinalBlock up until you know you've reached the end of the file (pay attention that they return very different things however).
You're also ignoring bytesRead which tells you how much of your buffer is filled with useful data. You need to use that as well and don't make your final encryption round be x many bytes which are the last bytes of the file and bufferSize - x bytes of the previous block of data from the file.
I would probably look to instead create a CryptoStream that wraps one of your FileStream objects and then use Stream.CopyTo or moral equivalents to do this work. Let libraries worry about managing buffers, loops, etc.
And finally, ideally, you recognize that it's 2019 and so very far from appropriate to be writing new code that uses DES for encryption2
1This program, if you set a breakpoint on the Console.ReadLine line, has c containing 4104 bytes:
using System;
using System.Security.Cryptography;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var b = new byte[4096];
var c = Encrypt(b);
Console.ReadLine();
}
private static byte[] key = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] iv = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] Encrypt(byte[] inputBuffer)
{
SymmetricAlgorithm algorithm = DES.Create();
ICryptoTransform transform = algorithm.CreateEncryptor(key, iv);
byte[] outputBuffer = transform.TransformFinalBlock(
inputBuffer,
0,
inputBuffer.Length);
return outputBuffer;
}
}
2So my EnryptFile in its entirety would be:
private static void EncryptFile()
{
using (var inputStream = File.OpenRead(Environment.CurrentDirectory + "\\Test.txt"))
using (var outputStream = File.Create(Environment.CurrentDirectory + "\\Encrypted.txt"))
using (var aes = Aes.Create())
using (var cStream = new CryptoStream(
inputStream,
aes.CreateEncryptor(key, iv),
CryptoStreamMode.Read))
{
cStream.CopyTo(outputStream);
}
}
Or an async variant which which uses await cStream.CopyToAsync(outputStream); as it's innermost statement. DecryptFile would be similarly simplified.
I was facing the same problem then I created a customized function for encryption/decryption and using this function also supports large files because we are reading and writing a file chunk by chunk. there is an EncryptMode that is what do you want by this method like if you want to encryption then send _mode as _mode.ENCRYPT and if you want decryption then send _mode as _mode.DECRYPT.
private enum EncryptMode { ENCRYPT, DECRYPT };
public void encryptDecryptChunkByChunk(string _inputPath, string _outputPath, string _encryptionKey, EncryptMode _mode, string _initVector)
{
string _out = "";// output string
//_encryptionKey = MD5Hash (_encryptionKey);
_pwd = Encoding.UTF8.GetBytes(_encryptionKey);
_ivBytes = Encoding.UTF8.GetBytes(_initVector);
int len = _pwd.Length;
if (len > _key.Length)
{
len = _key.Length;
}
int ivLenth = _ivBytes.Length;
if (ivLenth > _iv.Length)
{
ivLenth = _iv.Length;
}
Array.Copy(_pwd, _key, len);
Array.Copy(_ivBytes, _iv, ivLenth);
_rcipher.Key = _key;
_rcipher.IV = _iv;
if (_mode.Equals(EncryptMode.ENCRYPT))
{
//encrypt
using (FileStream fs = new FileStream(_inputPath, FileMode.Open, FileAccess.Read))
{
using (BinaryReader br = new BinaryReader(fs, new ASCIIEncoding()))
{
System.IO.StreamWriter file = new System.IO.StreamWriter(_outputPath);
try
{
byte[] chunk;
chunk = br.ReadBytes(CHUNK_SIZE);
while (chunk.Length > 0)
{
var base641 = Convert.ToBase64String(chunk);
//DumpBytes(chunk, chunk.Length);
chunk = br.ReadBytes(CHUNK_SIZE);
var base64 = Convert.ToBase64String(chunk);
byte[] plainText = _rcipher.CreateEncryptor().TransformFinalBlock(_enc.GetBytes(base641), 0, base641.Length);
var bas64Encrypted = Convert.ToBase64String(plainText);
//fsCrypt.Write(bas64Encrypted);
file.WriteLine(bas64Encrypted);
}
file.Close();
}
catch (Exception ex)
{
file.Close();
}
}
}
}
if (_mode.Equals(EncryptMode.DECRYPT))
{
FileStream fsOut = new FileStream(_outputPath, FileMode.OpenOrCreate, FileAccess.Write);
try
{
foreach (string line in File.ReadLines(_inputPath))
{
// Process your line here....
var p = line;
var x2 = Convert.FromBase64String(p);
byte[] plainText = _rcipher.CreateDecryptor().TransformFinalBlock(x2, 0, x2.Length);
var y1 = _enc.GetString(plainText);
var y2 = Convert.FromBase64String(y1);
fsOut.Write(y2, 0, y2.Length);
}
fsOut.Close();
}
catch (Exception ex)
{
fsOut.Close();
}
}
_rcipher.Dispose();
}
I have implemented a class as shown below which is responsible for encrypting/decrypting the text data to a utility class called TextEncryptionData.
It works fine for %99.99 of the time. But sometime (very rare) it fails to decrypt the text and I don't know why it happens. Is there any problem in the way I implemented it?
public class SubscriptionStateEncryptionLogic : IEncryptionLogic
{
private static byte[] KEY = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 71 };
private static byte[] IV = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8};
public EncryptionData Encrypt(EncryptionData source)
{
if (source == null)
{
return null;
}
try
{
TextEncryptionData data = source as TextEncryptionData;
using (TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider())
{
cryptoProvider.KeySize = 128;
cryptoProvider.Key = KEY;
cryptoProvider.IV = IV;
cryptoProvider.Mode = CipherMode.CBC;
cryptoProvider.Padding = PaddingMode.PKCS7;
ICryptoTransform transform = cryptoProvider.CreateEncryptor();
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
{
using (StreamWriter writer = new StreamWriter(cryptoStream))
{
writer.Write(data.Data);
writer.Flush();
cryptoStream.FlushFinalBlock();
writer.Flush();
return new TextEncryptionData() { Data = Convert.ToBase64String(memoryStream.GetBuffer(), 0, (int)memoryStream.Length) };
}
}
}
}
}
catch (Exception ex)
{
throw new SubscriptionStateEncryptionException("Error in encrypting the subscription status.", ex);
}
}
public EncryptionData Decrypt(EncryptionData source)
{
if (source == null)
{
return null;
}
try
{
TextEncryptionData data = source as TextEncryptionData;
using (TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider())
{
cryptoProvider.KeySize = 128;
cryptoProvider.Key = KEY;
cryptoProvider.IV = IV;
cryptoProvider.Mode = CipherMode.CBC;
cryptoProvider.Padding = PaddingMode.PKCS7;
ICryptoTransform transform = cryptoProvider.CreateDecryptor();
using (MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(data.Data)))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Read))
{
using (StreamReader reader = new StreamReader(cryptoStream))
{
return new TextEncryptionData() { Data = reader.ReadToEnd() };
}
}
}
}
}
catch (Exception ex)
{
throw new SubscriptionStateEncryptionException("Error in decrypting the subscription status.", ex);
}
}
}
Hello everyone I am developing a chat application for school. Its in C#, a language I have never worked with before. Now I have a winform that needs to encrypt some data, I have the encryption code in is own class but for some reason I can't use any of the functions in the cipher class.
Here is a very simplified version of the code.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Data;
using System.Security.Cryptography;
namespace WindowsFormsApplication2
{
public class SimpleAES
{
// Change these keys
private byte[] Key = { 123, 217, 19, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 112, 222, 209, 241, 24, 175, 144, 173, 53, 196, 29, 24, 26, 17, 218, 131, 236, 53, 209 };
private byte[] Vector = { 146, 64, 191, 111, 23, 3, 113, 119, 231, 121, 252, 112, 79, 32, 114, 156 };
private ICryptoTransform EncryptorTransform, DecryptorTransform;
private System.Text.UTF8Encoding UTFEncoder;
public SimpleAES()
{
//This is our encryption method
RijndaelManaged rm = new RijndaelManaged();
//Create an encryptor and a decryptor using our encryption method, key, and vector.
EncryptorTransform = rm.CreateEncryptor(this.Key, this.Vector);
DecryptorTransform = rm.CreateDecryptor(this.Key, this.Vector);
//Used to translate bytes to text and vice versa
UTFEncoder = new System.Text.UTF8Encoding();
}
/// -------------- Two Utility Methods (not used but may be useful) -----------
/// Generates an encryption key.
public byte[] Encrypt(string TextValue)
{
//Translates our text value into a byte array.
Byte[] bytes = UTFEncoder.GetBytes(TextValue);
//Used to stream the data in and out of the CryptoStream.
MemoryStream memoryStream = new MemoryStream();
/*
* We will have to write the unencrypted bytes to the stream,
* then read the encrypted result back from the stream.
*/
#region Write the decrypted value to the encryption stream
CryptoStream cs = new CryptoStream(memoryStream, EncryptorTransform, CryptoStreamMode.Write);
cs.Write(bytes, 0, bytes.Length);
cs.FlushFinalBlock();
#endregion
#region Read encrypted value back out of the stream
memoryStream.Position = 0;
byte[] encrypted = new byte[memoryStream.Length];
memoryStream.Read(encrypted, 0, encrypted.Length);
#endregion
//Clean up.
cs.Close();
memoryStream.Close();
return encrypted;
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
byte[] result = Encrypt(textBox1.Text);
}
}
}
When I throw this into visual studio the function call to Encrypt() is highlighted in red and the description it gives is the Encrypt does not exist in the current context.
I am much more experienced with C++ and I figured something like what I have would work, but I guess thats incorrect.
Any help would be most appreciated.
SimpleAES is not a static class, so you'll need to create an instance of it before you can call methods on it:
private void button1_Click(object sender, EventArgs e)
{
SimpleAES simpleAes = new SimpleAES();
byte[] result = simpleAes.Encrypt(textBox1.Text);
}
Make instance of SimpleAES like answer in #PoweredByOrange or change to static like #Bob or make extenstion method on a string like mine answer:
private void button1_Click(object sender, EventArgs e)
{
byte[] result = textBox1.Text.Encrypt();
}
public class Extensionmethods
{
public static byte[] Encrypt(this string TextValue)
{
//Your code here
}
}
I'm try to use AES encryption for some text, but the decrypted text is not identical to original one.
Original text: abcd
Decrypted text: ?9T?o??G???x;*
Here is my code:
public static void Main(string[] args)
{
byte[] original = { 97, 98, 99, 100 }; //"abcd"
byte[] key = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
byte[] encrypt = Encrypt(original, key, iv);
byte[] decrypt = Decrypt(encrypt, key, iv);
Console.WriteLine(Encoding.UTF8.GetString(original));
Console.WriteLine(Encoding.UTF8.GetString(decrypt));
Console.ReadKey();
}
public static byte[] Encrypt(byte[] original, byte[] key, byte[] iv)
{
using (var memoryStream = new MemoryStream())
{
using (var aes = new AesManaged { Key = key, IV = iv, Padding = PaddingMode.PKCS7, Mode = CipherMode.CBC })
{
using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cryptoStream.Write(original, 0, original.Length);
}
}
return memoryStream.ToArray();
}
}
public static byte[] Decrypt(byte[] encrypt, byte[] key, byte[] iv)
{
using (var memoryStream = new MemoryStream(encrypt))
{
using (var aes = new AesManaged { Key = key, IV = iv, Padding = PaddingMode.PKCS7, Mode = CipherMode.CBC })
{
using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Read))
{
byte[] decrypt = new byte[encrypt.Length];
cryptoStream.Read(decrypt, 0, decrypt.Length);
return decrypt;
}
}
}
}
What's wrong? Thanks in advance.
You've got this in your decryption code:
using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(),
CryptoStreamMode.Read))
Change it to call aes.CreateDecryptor() and it works fine.
There's something wrong with your decrypt method, use something like this :
public string Decrypt(byte[] EncryptedValue)
{
#region Write the encrypted value to the decryption stream
MemoryStream encryptedStream = new MemoryStream();
CryptoStream decryptStream = new CryptoStream(encryptedStream, DecryptorTransform, CryptoStreamMode.Write);
decryptStream.Write(EncryptedValue, 0, EncryptedValue.Length);
decryptStream.FlushFinalBlock();
#endregion
#region Read the decrypted value from the stream.
encryptedStream.Position = 0;
Byte[] decryptedBytes = new Byte[encryptedStream.Length];
encryptedStream.Read(decryptedBytes, 0, decryptedBytes.Length);
encryptedStream.Close();
#endregion
return UTFEncoder.GetString(decryptedBytes);
}