Encrypt user's record index - c#

My ASP.NET MVC web application creates some data on behalf of a user and stores it in a SQL database in a record with a numeric primary key. I access the data via the primary key.
I want my authenticated users to be able to navigate to a URL that contains the (numeric) primary key, but I don't want to expose the actual key value. So, it seems to me that I would want to encrypt the numeric key (using a symmetrical encryption algorithm) with a password consisting of a string baked into my code plus the logged-in user's UserID. The resultant URL would look something like: https://foo.com/123abc, where "123abc" is the encrypted key value (converted from bytes to characters). In theory (to my beginner brain) this encrypted value, even if acquired by a malicious party, would not be useful unless that party could log in to my website using the user's credentials.
Question 1: Is this the correct way to do this sort of thing, and
Question 2: Can someone who knows this stuff point me at a simple symmetrical encryption API that I can use for this purpose.

Rather than use the PK, you can add a column to your SQL table and setting its type to uniqueidentifier and it's value to NEWID() and then display that to the user, this solution would have the least amount of overhead, while still providing a seemingly random series that you can tie back to that user later.
ALTER TABLE foo ADD foobar uniqueIdentifier default newid();
http://msdn.microsoft.com/en-us/library/ms187942.aspx

Symmetrical encryption of an integer would be so ridiculously easy to crack you might as well not even bother. Now, you could salt it or obfuscate it a bit by Base64 encoding it or something like that, but still, this is pretty pointless. A database primary key is not sensitive data. It's meaningless without access to the database, and if they have access to the database, looking up a particular user by their id is the absolutely least of your problems. Even symmetrical encryption is going to add significant overhead to your application for something that's simply not necessary.
If you really don't want the PK exposed, then use something else like the username in the URL and look up the user by that.

You can do that, sure.
Store the salt in your session, generate one randomly every time or use the session ID as salt.
Below are two methods that could encrypt/decrypt your string value with salt. You can use the salt in place of initial vector.
public static string Encrypt(string PlainText, string Password, string Salt,
string HashAlgorithm = "SHA1", int PasswordIterations = 16, string InitialVector = "Initial Vector", int KeySize = 256)
{
byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt);
byte[] PlainTextBytes = Encoding.UTF8.GetBytes(PlainText);
PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);
byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);
RijndaelManaged SymmetricKey = new RijndaelManaged();
SymmetricKey.Mode = CipherMode.CBC;
ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes);
MemoryStream MemStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write);
cryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] CipherTextBytes = MemStream.ToArray();
MemStream.Close();
cryptoStream.Close();
Encryptor.Dispose();
Encryptor = null;
return Convert.ToBase64String(CipherTextBytes);
}
public static string Decrypt(string CipherText, string Password, string Salt,
string HashAlgorithm = "SHA1", int PasswordIterations = 16, string InitialVector = "Initial Vector", int KeySize = 256)
{
byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt);
byte[] CipherTextBytes = Convert.FromBase64String(CipherText);
PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);
byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);
RijndaelManaged SymmetricKey = new RijndaelManaged();
SymmetricKey.Mode = CipherMode.CBC;
ICryptoTransform Decryptor = SymmetricKey.CreateDecryptor(KeyBytes, InitialVectorBytes);
MemoryStream MemStream = new MemoryStream(CipherTextBytes);
CryptoStream cryptoStream = new CryptoStream(MemStream, Decryptor, CryptoStreamMode.Read);
byte[] PlainTextBytes = new byte[CipherTextBytes.Length];
int ByteCount = cryptoStream.Read(PlainTextBytes, 0, PlainTextBytes.Length);
MemStream.Close();
cryptoStream.Close();
Decryptor.Dispose();
Decryptor = null;
return Encoding.UTF8.GetString(PlainTextBytes, 0, ByteCount);
}

Related

I am using GUID as key and it's throwing error Specified key is not a valid size for this algorithm

I have below method for symmetric encryption a string content,
public static class EncodeExtension
{
public static string AesEncryptString(this string plainText, string key)
{
byte[] iv = new byte[16];
byte[] array;
using (Aes aes = Aes.Create())
{
aes.Key = Encoding.UTF8.GetBytes(key);
aes.IV = iv;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream))
{
streamWriter.Write(plainText);
}
array = memoryStream.ToArray();
}
}
}
return Convert.ToBase64String(array);
}
}
Now I want to pass a random Guid as a key for each string content string,
var key1 = Guid.NewGuid().ToString();
var encryptedData = "test1".AesEncryptString(key1);
var key2 = Guid.NewGuid().ToString();
var encryptedData = "test2".AesEncryptString(key2);
Here I am getting Specified key is not a valid size for this algorithm? What key size it's expecting here? I do generate a random key size ?
This error comes from the fact that the size in bytes of the GUID UTF8 string isn't a valid key size for AES (128, 192 or 256 bits).
You could use a key derivation function such as PBKDF2 to derive the key from your GUID.
PBKDF2 is implemented in .net by the class Rfc2898DeriveBytes
public static string AesEncryptString(this string plainText, string key) {
byte[] array;
byte[] keyBytes;
using (Aes aes = Aes.Create())
{
using (Rfc2898DeriveBytes pbkdf = new Rfc2898DeriveBytes(key, Encoding.UTF8.GetBytes(key)))
{
// here 16 bytes for AES128
keyBytes = pbkdf.GetBytes(16);
}
aes.Key = keyBytes;
//for convenience here we use the key as iv too
aes.IV = keyBytes;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream))
{
streamWriter.Write(plainText);
}
array = memoryStream.ToArray();
}
}
}
return Convert.ToBase64String(array);
}
Be careful as you will have to use the same behavior to generate the key on decryption too.
Even if you can, never use a GUID for encryption key because they're not guaranteed to produce a cryptographically secure random number. It might be significantly easier to crack a GUID-based key than a securely generated key. Never use GUID for cryptographically sensitive operations.
I don't recommend running a KDF over the GUID either since that doesn't change the low entropy underneath.
As of .NET 6, it's way easier to generate a cryptographically secure random key:
byte[] key = RandomNumberGenerator.GetBytes(32); // generate 256-bits
byte[] iv = new byte[16];
byte[] array;
using var aes = Aes.Create();
aes.Key = Encoding.UTF8.GetBytes(key);
aes.IV = iv;
Everything about this is terribly broken.
16 bytes that represent a valid UTF8 string, is not very random. If I saw your code, I would be able to guess a significant fraction of the bits of your key.
.IV must always be unique. If you ever encrypt two different inputs with the same .Key & .IV, your encryption can be easily broken. It's common to generate a random IV and write it as plain text into the output. eg memoryStream.Write(aes.IV)
Using a salted hash to turn a password string into a key is better, but only if you can ensure that your salt is kept secret.

How implement Php's openssl_encrypt method in c#?

as in the title, I need to implement in my C# code the equivalent of php's openssl_encrypt method, because I need to call a service on a php page, but we work with c#.
The php code is this:
$textToEncrypt = "test";
$algo = "AES256";
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($algo));
$key = "1234567890987654"; //Not this key, but just same length
$parametri_enc = openssl_encrypt($textToEncrypt , $algo, $key, 0, $iv);
$iv = bin2hex($iv);
I tried many thing, actually my code is:
string textToEncrypt = "test";
string secretCode = "1234567890987654"
// Create sha256 hash
SHA256 mySHA256 = SHA256Managed.Create();
byte[] key = mySHA256.ComputeHash(Encoding.ASCII.GetBytes(secretCode));
// Create secret IV
byte[] iv = new byte[16];
RandomNumberGenerator generator = RandomNumberGenerator.Create();
generator.GetBytes(iv);
string encryptedText = EncryptString(textToEncrypt, key, iv);
// And I try to port also the bin2hex method
var sb = new StringBuilder();
foreach (byte b in iv)
{
sb.AppendFormat("{0:x2}", b);
}
var tokenBytesHex = sb.ToString();
And the method EncryptString is
public static string EncryptString(string plainText, byte[] key, byte[] iv)
{
//Instantiate a new Aes object to perform string symmetric encryption
Aes encryptor = Aes.Create();
encryptor.Mode = CipherMode.CBC;
// Set key and IV
byte[] aesKey = new byte[32];
Array.Copy(key, 0, aesKey, 0, 32);
encryptor.Key = aesKey;
encryptor.IV = iv;
// Instantiate a new MemoryStream object to contain the encrypted bytes
MemoryStream memoryStream = new MemoryStream();
// Instantiate a new encryptor from our Aes object
ICryptoTransform aesEncryptor = encryptor.CreateEncryptor();
// Instantiate a new CryptoStream object to process the data and write it to the
// memory stream
CryptoStream cryptoStream = new CryptoStream(memoryStream, aesEncryptor, CryptoStreamMode.Write);
// Convert the plainText string into a byte array
byte[] plainBytes = Encoding.ASCII.GetBytes(plainText);
// Encrypt the input plaintext string
cryptoStream.Write(plainBytes, 0, plainBytes.Length);
// Complete the encryption process
cryptoStream.FlushFinalBlock();
// Convert the encrypted data from a MemoryStream to a byte array
byte[] cipherBytes = memoryStream.ToArray();
// Close both the MemoryStream and the CryptoStream
memoryStream.Close();
cryptoStream.Close();
// Convert the encrypted byte array to a base64 encoded string
string cipherText = Convert.ToBase64String(cipherBytes, 0, cipherBytes.Length);
// Return the encrypted data as a string
return cipherText;
}
I tried many variation about this porting (that I've found on internet), but without result. If I use a correct encrypted string from my code, I can call the service, so it is working. I need only to encrypt correctly that string, but until now, I've failed
Ok i solved my own problem. I'll share it so if anyone has the same problem, this could work. Basically I saw a decryption c# code here so I update my code in this way
First, I pass my secretCode in string format instead of byte[]
So i changed my method signature in this way:
public static string EncryptString(string plainText, string secretcode, byte[] iv)
and inside I changed the way I manipulate the secretCode (passphrase in php equivalent method)
// Set key and IV
var aesKey = Encoding.ASCII.GetBytes(secretcode);
//pad key out to 32 bytes (256bits) if its too short
if (aesKey.Length < 32)
{
var paddedkey = new byte[32];
Buffer.BlockCopy(aesKey, 0, paddedkey, 0, aesKey.Length);
aesKey = paddedkey;
}
So it worked! No other change, just this two small change from my previous post
Updated method
public static string EncryptString(string plainText, string secretcode, byte[] iv)
{
// Instantiate a new Aes object to perform string symmetric encryption
Aes encryptor = Aes.Create();
encryptor.Mode = CipherMode.CBC;
// Set key and IV
var aesKey = Encoding.ASCII.GetBytes(secretcode);
//pad key out to 32 bytes (256bits) if its too short
if (aesKey.Length < 32)
{
var paddedkey = new byte[32];
Buffer.BlockCopy(aesKey, 0, paddedkey, 0, aesKey.Length);
aesKey = paddedkey;
}
encryptor.Key = aesKey;
encryptor.IV = iv;
// Instantiate a new MemoryStream object to contain the encrypted bytes
MemoryStream memoryStream = new MemoryStream();
// Instantiate a new encryptor from our Aes object
ICryptoTransform aesEncryptor = encryptor.CreateEncryptor();
// Instantiate a new CryptoStream object to process the data and write it to the
// memory stream
CryptoStream cryptoStream = new CryptoStream(memoryStream, aesEncryptor, CryptoStreamMode.Write);
// Convert the plainText string into a byte array
byte[] plainBytes = Encoding.ASCII.GetBytes(plainText);
// Encrypt the input plaintext string
cryptoStream.Write(plainBytes, 0, plainBytes.Length);
// Complete the encryption process
cryptoStream.FlushFinalBlock();
// Convert the encrypted data from a MemoryStream to a byte array
byte[] cipherBytes = memoryStream.ToArray();
// Close both the MemoryStream and the CryptoStream
memoryStream.Close();
cryptoStream.Close();
// Convert the encrypted byte array to a base64 encoded string
string cipherText = Convert.ToBase64String(cipherBytes, 0, cipherBytes.Length);
// Return the encrypted data as a string
return cipherText;
}

AES256 JAVA encryption doesn't match C# encryption

I have been requested to encrypt some data while talking to my partner's JAVA API, and he sent me the following details about encryption algorithm:
Algorithm : AES256
Key Size : 256 bits
Encryption Mode: CBC (16 bits blocks, PKCS5Padding with 0)
Output Type : Base-64
Password: 0xA8703827AE586460105696504327B7BB0806FEAE96BD664F89E36868FBB48E3D
IV: is a byte[16] with 0 values
I used the below code, but I didn't get a matched result with him:
public byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
byte[] encryptedBytes = null;
byte[] saltBytes = new byte[16] { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.KeySize = 256;
aes.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
aes.Key = key.GetBytes(aes.KeySize / 8);
aes.IV = key.GetBytes(aes.BlockSize / 8);
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedBytes = ms.ToArray();
}
}
return encryptedBytes;
}
public string EncryptText(string input, string password)
{
byte[] bytesToBeEncrypted = Encoding.UTF8.GetBytes(input);
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes);
string result = Convert.ToBase64String(bytesEncrypted);
return result;
}
So, when we tried to encrypt Hello, How are you?, I got a different result and I should get the same result he had as he will decrypt my sent data on his side and will process it. The given example should have this result: TJTojNoVgoqnhCj4uTv1jLBiZU7r+s/0Bm234bHU+S0=
I did some testing and now able to match your expected result.
2 changes to be done.
IV
IV is the easiest, as you said IV = 0, so set IV as follows:
aes.IV = new byte[16];
In AES, IV is 16 bytes. The above would create a byte array of 16 bytes with each value initialized to zero.
Key
The password you have given starts with "0x" - this essentially means that this is hexadecimal representation of the password string. I converted this password to byte array using this
string password = "A8703827AE586460105696504327B7BB0806FEAE96BD664F89E36868FBB48E3D";
Please note I removed the starting "0x" from the above
byte[] passwordBytes = StringToByteArray(password);
The above converts the hexadecimal password representation to a byte array.
In your AES_Encrypt method, directly assign this byte[] as the Key
aes.Key = passwordBytes;
Now, my result is TJTojNoVgoqnhCj4uTv1jLBiZU7r+s/0Bm234bHU+S0= which exactly matches with your expected output.

Decrypt string with Rijndael return "System.SecureString" (as a string) but not the string

I'm using Rijndael Algorithm to encrypt strings (user passwords), but when I decrypt them, it returns me "System.SecureString", and not my decrypted password.
I'm using this basic code:
public static string DecryptString(string cipherText, string password)
{
byte[] key, iv;
Rfc2898DeriveBytes rfcDb = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(password));
key = rfcDb.GetBytes(16);
iv = rfcDb.GetBytes(16);
byte[] cipheredData = Convert.FromBase64String(cipherText);
RijndaelManaged rijndael = new RijndaelManaged();
rijndael.Mode = CipherMode.CBC;
ICryptoTransform decryptor = rijndael.CreateDecryptor(key, iv);
MemoryStream ms = new MemoryStream(cipheredData);
CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
byte[] plainTextData = new byte[cipheredData.Length];
int decryptedByteCount = cs.Read(plainTextData, 0, plainTextData.Length);
ms.Close();
cs.Close();
return Encoding.UTF8.GetString(plainTextData, 0, decryptedByteCount);
}
The real problem is that it's sending me back "System.SecureString", and I can't do anything.
I think it comes from the conversion at the end but I really don't know how to change that (it seems good btw)
return Encoding.UTF8.GetString(plainTextData, 0, decryptedByteCount);
So if you have an idea or a working code sample, I'm interested.
Have a nice day
I have implemented rijndael in the past, and here is my version if this is any help:
private static string Encrypt(string plainText, string passPhrase, string saltValue, string hashAlgorithm, int passwordIterations, string initVector, int keySize)
{
// Convert strings into byte arrays.
// Let us assume that strings only contain ASCII codes.
// If strings include Unicode characters, use Unicode, UTF7, or UTF8
// encoding.
var initVectorBytes = Encoding.ASCII.GetBytes(initVector);
var saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
// Convert our plaintext into a byte array.
// Let us assume that plaintext contains UTF8-encoded characters.
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
// 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.
var password = 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).
var keyBytes = password.GetBytes(keySize / 8);
// Create uninitialized Rijndael encryption object.
// It is reasonable to set encryption mode to Cipher Block Chaining
// (CBC). Use default options for other symmetric key parameters.
var symmetricKey = new RijndaelManaged { 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.
var encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
// Define memory stream which will be used to hold encrypted data.
var memoryStream = new MemoryStream();
// Define cryptographic stream (always use Write mode for encryption).
var 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.
var cipherTextBytes = memoryStream.ToArray();
// Close both streams.
memoryStream.Close();
cryptoStream.Close();
// Convert encrypted data into a base64-encoded string.
var cipherText = Convert.ToBase64String(cipherTextBytes);
// Return encrypted string.
return cipherText;
}
private static string Decrypt(string cipherText, string passPhrase, string saltValue, string hashAlgorithm, int passwordIterations, string initVector, int keySize)
{
// 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.
var initVectorBytes = Encoding.ASCII.GetBytes(initVector);
var saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
// Convert our ciphertext into a byte array.
var cipherTextBytes = 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.
var password = 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).
var keyBytes = password.GetBytes(keySize / 8);
// Create uninitialized Rijndael encryption object.
// It is reasonable to set encryption mode to Cipher Block Chaining
// (CBC). Use default options for other symmetric key parameters.
var symmetricKey = new RijndaelManaged { 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.
var decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
// Define memory stream which will be used to hold encrypted data.
var memoryStream = new MemoryStream(cipherTextBytes);
// Define cryptographic stream (always use Read mode for encryption).
var 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.
var plainTextBytes = new byte[cipherTextBytes.Length];
// Start decrypting.
var 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.
var plainText = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
// Return decrypted string.
return plainText;
}
public static string EncryptData(string encryptText, string passPhrase, string saltValue, string hashAlgorithm, int passwordIterations, string initVector, int keySize)
{
return Encrypt(encryptText, passPhrase, saltValue, hashAlgorithm, passwordIterations, initVector, keySize);
}
public static string DecryptData(string decryptText, string passPhrase, string saltValue, string hashAlgorithm, int passwordIterations, string initVector, int keySize)
{
return Decrypt(decryptText, passPhrase, saltValue, hashAlgorithm, passwordIterations, initVector, keySize);
}
I then had some public methods that call into the above methods...
public static string EncryptData(string encryptText)
{
return EncryptionHelper.EncryptData(encryptText, ConfigHelper.PassPhrase, ConfigHelper.SaltValue, ConfigHelper.HashAlgorithm, ConfigHelper.PasswordIterations, ConfigHelper.InitVector, ConfigHelper.KeySize);
}
public static string DecryptData(string decryptText)
{
return EncryptionHelper.DecryptData(decryptText, ConfigHelper.PassPhrase, ConfigHelper.SaltValue, ConfigHelper.HashAlgorithm, ConfigHelper.PasswordIterations, ConfigHelper.InitVector, ConfigHelper.KeySize);
}
I then had these in a config file...
<add key="passPhrase" value=""/>
<add key="saltValue" value=""/>
<add key="hashAlgorithm" value="SHA1"/>
<add key="passwordIterations" value="5"/>
<add key="initVector" value=""/>
<add key="keySize" value="256"/>

Rijndael or AES to match java encryption - with salt and key

I need to encrypt a string using a salt and a key to match a java encryption so that the 3rd party provider can decrypt the values on the other side.
I have tried several StackOverflow articles as I am no expert in encryption and just cannot get the same encryption string using SALT and KEY as the 3rd party provider.
I need to know which encryption type and mode in C# to use to match java's AES encryptions as used here
https://gist.github.com/ca958d5921d47c4c0a0f
OK - I figured it out even though it's cheating to a degree. Because I could not find any encryption technique that would match the plain AES encryption provided by the 3rd party I asked them to change it to
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
With this I amended my C# code and finally got the integration working:
public static string Encrypt2(string plainText)
{
string PassPhrase = "somepassphrase";
string SaltValue = "somesalt";
int PasswordIterations = 0; //amend to match java encryption iteration
string InitVector = "someiv";
int KeySize = 0; //amend to match java encryption key size
byte[] initVectorBytes = Encoding.ASCII.GetBytes(InitVector);
byte[] saltValueBytes = Encoding.ASCII.GetBytes(SaltValue);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
Rfc2898DeriveBytes password = new Rfc2898DeriveBytes(
PassPhrase,
saltValueBytes,
PasswordIterations);
byte[] keyBytes = password.GetBytes(KeySize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(
keyBytes,
initVectorBytes);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream,
encryptor,
CryptoStreamMode.Write);
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
string cipherText = Convert.ToBase64String(cipherTextBytes);
return cipherText;
}

Categories

Resources