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;
}
Related
I wrote code that decrypts the input string completely. But since this is an ECB mode, I wanted to somehow decrypt not the entire input text, but only a separate block of it.
As far as I understand, ECB AES encrypts in blocks of 8 bytes. How can I add the AES_Decrypt function to it so that it decrypts only the last 8 bytes of the input string, for example.
byte[] bytesToBeDecrypted = new byte[32];
byte[] 8_bytesToBeDecrypted = new byte[8]; // Only 8 bytes of bytesToBeDecrypted
public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
string salt = "12345678";
Encoding unicode = Encoding.Unicode;
byte[] saltBytes = unicode.GetBytes(salt);
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
AES.Padding = PaddingMode.Zeros;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 65535);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.ECB;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
You can likely just Seek the MemoryStream with a multiple of 16 bytes from the beginning (or apparently even 16 bytes from the last part of the stream) and then connect the CryptoStream to decrypt whatever is left. With CBC that would be a bit more tricky as you would have to set the IV to the previous ciphertext block, but with ECB this should be a breeze.
Notes:
Of course, you don't need to set the IV for the ECB mode, that should not be required.
Rijndael with a block size of 128 is actually AES. C#/.NET only supports a subset of Rijndael by the way: only 64 increments of the block size and key size are supported, if I remember correctly.
I'd still use aes = Aes.Create() rather than aes = new RijndaelManaged() as that leaves the choice of the AES implementation to the system, and it will probably choose the hardware accelerated one over the managed one.
In ms SQL server, I have a field text with data look like below:
"!"$$$$$$!#$$$$!!!!! !!!!!!!!!!!!!! "!! ! " !" ! !" !!!! ! !!"!".
I belive that from a plain text string, they using a Rijndael algorithm to encrypted this string. from encrypted string, it was transform to string above.
Can anyone recognize what the algorithm to decrypt from string above to the encrypted string of Rijndael algorithm?
thanks
Hi me drona please find the below code. It will useful from you.
public static class Encrypt
{
// This size of the IV (in bytes) must = (keysize / 8). Default keysize is 256, so the IV must be
// 32 bytes long. Using a 16 character string here gives us 32 bytes when converted to a byte array.
private const string initVector = "pemgail9uzpgzl88";
// This constant is used to determine the keysize of the encryption algorithm
private const int keysize = 256;
//Encrypt
public static string EncryptString(string plainText, string passPhrase)
{
byte[] initVectorBytes = Encoding.UTF8.GetBytes(initVector);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
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();
return Convert.ToBase64String(cipherTextBytes);
}
//Decrypt
public static string DecryptString(string cipherText, string passPhrase)
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
byte[] keyBytes = password.GetBytes(keysize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
enter code here
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);
}
Why can I encrypt only 16 characters of text?
Works:
string plainText = "1234567890123456";
Doesn't work:
string plainText = "12345678901234561";
Doesn't work:
string plainText = "123456789012345";
Code:
string plainText = "1234567890123456";
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
byte[] keyBytes = System.Text.Encoding.UTF8.GetBytes("1234567890123456");
byte[] initVectorBytes = System.Text.Encoding.UTF8.GetBytes("1234567890123456");
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.Zeros;
ICryptoTransform encryptor = symmetricKey.CreateDecryptor(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);
Console.ReadLine();
Not sure I understand the question, but looking at what I assume the intent is of the code the following
symmetricKey.CreateDecryptor
Should probably be
symmetricKey.CreateEncryptor
Probably because AES is a block cipher with 128 bits per block.. maybe you just need to add a padding such that length % 128 == 0.
(I'm not a C# developer but it can happen that an implementation doesn't care about adding padding by itself)
Just a hint: try if it works with 256 bits
The encryption is in java:
String salt = "DC14DBE5F917C7D03C02CD5ADB88FA41";
String password = "25623F17-0027-3B82-BB4B-B7DD60DCDC9B";
char[] passwordChars = new char[password.length()];
password.getChars(0,password.length(), passwordChars, 0);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(passwordChars, salt.getBytes(), 2, 256);
SecretKey sKey = factory.generateSecret(spec);
byte[] raw = _sKey.getEncoded();
String toEncrypt = "The text to be encrypted.";
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, skey);
AlgorithmParameters params = cipher.getParameters();
byte[] initVector = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] encryptedBytes = cipher.doFinal(toEncrypt.getBytes());
While the decryption is in c#:
string hashAlgorithm = "SHA1";
int passwordIterations = 2;
int keySize = 256;
byte[] saltValueBytes = Encoding.ASCII.GetBytes( salt );
byte[] cipherTextBytes = Convert.FromBase64String( cipherText );
PasswordDeriveBytes passwordDB = new PasswordDeriveBytes(password, saltValueBytes, hashAlgorithm passwordIterations );
byte[] keyBytes = passwordDB.GetBytes( keySize / 8 );
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform decryptor = symmetricKey.CreateDecryptor( keyBytes, initVector );
MemoryStream memoryStream = new MemoryStream( cipherTextBytes );
CryptoStream cryptoStream = new CryptoStream( memoryStream, decryptor, CryptoStreamMode.Read );
byte[] plainTextBytes = new byte[ cipherTextBytes.Length ];
int decryptedByteCount = cryptoStream.Read( plainTextBytes, 0, plainTextBytes.Length );
memoryStream.Close();
cryptoStream.Close();
string plainText = Encoding.UTF8.GetString( plainTextBytes, 0, decryptedByteCount );
The decryption failed with exception "Padding is invalid and cannot be removed."
Any idea what might be the problem?
This generally indicates that decryption has failed. I suggest you check the output of the key generation functions, to see if you are actually using the same key. I notice, for instance, that the Java code implies you are using a SHA1-based HMAC, whereas the .NET code implies you are using an unkeyed SHA1 hash to generate the key.
Alternatively, it could be a mismatch in the padding. I don't see where you are explicitly setting the PaddingMode to PKCS7 in the .NET code.