i am using following encryption method to encrypt a string
private static byte[] mKey = { };
private static byte[] mIV = { 89, 23, 13, 17, 69, 32, 02, 79 };
private static string mStringKey = "lkj#788*";
private static string Encrypt(string pText)
{
try
{
mKey = Encoding.UTF8.GetBytes(mStringKey.Substring(0, 8));
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
Byte[] byteArray = Encoding.UTF8.GetBytes(pText);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream,
des.CreateEncryptor(mKey, mIV), CryptoStreamMode.Write);
cryptoStream.Write(byteArray, 0, byteArray.Length);
cryptoStream.FlushFinalBlock();
return Convert.ToBase64String(memoryStream.ToArray());
}
catch (Exception ex)
{
return string.Empty;
}
}
I want to build a discount code for customers with this format "CustomerId-PurchasedItem-DiscountValue" and encrypt these (CustomerId,PurchasedItem,DiscountValue) strings individually and combine encrypted values adding "-" char between them to build discount code .while decrypting above encoded string ,i will split it with "-" char,and decode individually ,but i am afraid that while encrypting if it get "-" char then my logic will fail..is this method is safe or can any one suggest me another trick?or is there any trick that encryption of a string result to fixed length?
I believe that .NET's base64 encoding will never contain a '-' character, so you should be okay.
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've written a simple encryp/decrypt method in c# which uses the AES alg. When I try to encrypt and then decrypt a string with certain lengths like 4 or 7 characters, it works fine, with other lengths however It says that the padding is invalid and cannot be removed.
public static string Decrypt(string text)
{
Aes a = System.Security.Cryptography.AesCryptoServiceProvider.Create();
a.Padding = PaddingMode.PKCS7;
a.Key = Convert.FromBase64String("UDlArN63HCk15fHBski/zvaWiMZJi+jR1BADvVgenCU=");
a.IV = Convert.FromBase64String("xZG/eLY8eq0mQhUXvKbUDQ==");
var dc = a.CreateDecryptor();
byte[] encryptedBytes = Encoding.Unicode.GetBytes(text);
byte[] decryptedBytes = dc.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
return Encoding.Unicode.GetString(decryptedBytes);
}
public static string Encrypt(string text)
{
Aes a = System.Security.Cryptography.AesCryptoServiceProvider.Create();
a.Padding = PaddingMode.PKCS7;
a.Key = Convert.FromBase64String("UDlArN63HCk15fHBski/zvaWiMZJi+jR1BADvVgenCU=");
a.IV = Convert.FromBase64String("xZG/eLY8eq0mQhUXvKbUDQ==");
var dc = a.CreateEncryptor();
byte[] decryptedBytes = Encoding.Unicode.GetBytes(text);
byte[] encryptedBytes = dc.TransformFinalBlock(decryptedBytes, 0, decryptedBytes.Length);
return Encoding.Unicode.GetString(encryptedBytes);
}
Ciphertexts are binary data which might contain bytes that are not printable. If try to encode the byte array as a Unicode string, you will lose some bytes. It will be impossible to recover them during decryption.
If you actually want to handle the ciphertext as a string, you need to convert it into a textual representation like Base 64 or Hex.
// encryption
return Convert.ToBase64String(decryptedBytes);
// decryption
byte[] decryptedBytes = Convert.FromBase64String(text);
I have a method in my .net project to encrypt a password
public string Encrypt(string plainText)
{
string PassPhrase = "#$^&*!#!$";
string SaltValue = "R#j#}{BAe";
int PasswordIterations = Convert.ToInt32(textBox5.Text); //amend to match java encryption iteration
string InitVector = "#1B2c3D4e5F6g7H8";
int KeySize = 256; //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);
PasswordDeriveBytes password= new PasswordDeriveBytes(
PassPhrase,
saltValueBytes,
"MD5",
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;
}
I have been tasked to convert this method to java but in java I don't get the same result as the .Net version
My java code is
package com.andc.billing.pdc.security;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.management.openmbean.InvalidKeyException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class PasswordCrypto {
private static final String password = "#$^&*!#!$";
private static String initializationVector = "#1B2c3D4e5F6g7H8";
private static String salt = "R#j#}{BAe";
private static int pswdIterations = 2;
private static int keySize = 128;
private static final Log log = LogFactory.getLog(PasswordCrypto.class);
public static String encrypt(String plainText) throws
NoSuchAlgorithmException,
InvalidKeySpecException,
NoSuchPaddingException,
InvalidParameterSpecException,
IllegalBlockSizeException,
BadPaddingException,
UnsupportedEncodingException,
InvalidKeyException,
InvalidAlgorithmParameterException, java.security.InvalidKeyException, NoSuchProviderException
{
byte[] saltBytes = salt.getBytes("ASCII");//"UTF-8");
byte[] ivBytes = initializationVector.getBytes("ASCII");//"UTF-8");
// Derive the key, given password and salt.
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");//PBEWithMD5AndDES");
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
saltBytes,
pswdIterations,
keySize
);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //Cipher.getInstance("AES/CBC/PKCSPadding"
cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(ivBytes));
byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("ASCII"));//UTF-8"));
String str=new org.apache.commons.codec.binary.Base64().encodeAsString(encryptedTextBytes);
log.info(str);
return str;
}
}
.net result of encryption of "1" is :
7mPh3/E/olBGbFpoA18oqw==
while java is
7RPk77AIKAhOttNLW4e5yQ==
Would you please help me solve this problem ?
First thing i've noticed is that the algorithms you are using are different, in .Net it's an extension of PBKDF1 and in java it's PBKDF2, PBKDF2 replaced PBKDF1.
In .net you are using the PasswordDeriveBytes class which "derives a key from a password using an extension of the PBKDF1 algorithm."
I also notice that the password iterations is hard-coded to 2 in Java and comes from a text box in .Net... ensure they are the same.
Correct that and let us know the outcome.
Update: For PBKDF2 in .net use the Rfc2898DeriveBytes class.
For some very good relevant information have a read of this page
EDIT: This link should be helpful and if you can use the Chilkat library
It's a complicated difference between 1 and 2, 1 is only supposed to do upto 20 bytes, MS has built an extension which allows more than that and the following code should reporduce the .net output more accurately. Taken from here.
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.encoders.Hex;
public class PKCS5Test
{
/**
* #param args
*/
public static void main(String[] args) throws Exception
{
byte[] password = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
byte[] salt = PKCS5S1ParametersGenerator.PKCS5PasswordToBytes("MyTesting".toCharArray());
PKCS5S1ParametersGenerator generator = new PasswordDeriveBytes(new SHA1Digest());
generator.init(password, salt, 100);
byte[] key = ((KeyParameter)generator.generateDerivedParameters(512)).getKey();
System.out.println( "64 " + new String(Hex.encode(key)).toUpperCase() );
}
static class PasswordDeriveBytes extends PKCS5S1ParametersGenerator
{
private final Digest d;
private byte[] output = null;
public PasswordDeriveBytes(Digest d)
{
super(d);
this.d = d;
}
public CipherParameters generateDerivedParameters(int keySize)
{
keySize = keySize / 8;
byte[] result = new byte[keySize];
int done = 0;
int count = 0;
byte[] b = null;
while (done < result.length)
{
if (b == null)
{
b = generateInitialKey();
}
else if (++count < 1000)
{
b = generateExtendedKey(++count);
}
else
{
throw new RuntimeException("Exceeded limit");
}
int use = Math.min(b.length, result.length - done);
System.arraycopy(b, 0, result, done, use);
done += use;
}
return new KeyParameter(result);
}
private byte[] generateOutput()
{
byte[] digestBytes = new byte[d.getDigestSize()];
d.update(password, 0, password.length);
d.update(salt, 0, salt.length);
d.doFinal(digestBytes, 0);
for (int i = 1; i < (iterationCount - 1); i++)
{
d.update(digestBytes, 0, digestBytes.length);
d.doFinal(digestBytes, 0);
}
return digestBytes;
}
private byte[] generateInitialKey()
{
output = generateOutput();
d.update(output, 0, output.length);
byte[] digestBytes = new byte[d.getDigestSize()];
d.doFinal(digestBytes, 0);
return digestBytes;
}
private byte[] generateExtendedKey(int count)
{
byte[] prefix = Integer.toString(count).getBytes();
d.update(prefix, 0, prefix.length);
d.update(output, 0, output.length);
byte[] digestBytes = new byte[d.getDigestSize()];
d.doFinal(digestBytes, 0);
//System.err.println( "X: " + new String(Hex.encode(digestBytes)).toUpperCase() );
return digestBytes;
}
}
}
Thank you very much for the provided solution - it works very well but with a small correction (according to initial post mentioned below):
Please use:
b = generateExtendedKey(count);
instead of:
b = generateExtendedKey(++count);
It'll work even for 256 key size:
Here is a small code which decrypts C# Rijndael encoded data using 256 bits keys:
public static String decrypt(final String cipherText, final String passPhrase, final String saltValue, final int passwordIterations, final String initVector, final int keySize)
throws Exception {
final byte[] initVectorBytes = initVector.getBytes("ASCII");
final byte[] saltValueBytes = saltValue.getBytes("ASCII");
final byte[] cipherTextBytes = Base64.decode(cipherText);
final PKCS5S1ParametersGenerator generator = new PasswordDeriveBytes(new SHA1Digest());
generator.init(passPhrase.getBytes("ASCII"), saltValueBytes, passwordIterations);
final byte[] key = ((KeyParameter) generator.generateDerivedParameters(keySize)).getKey();
final SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);
final Cipher cipher = Cipher.getInstance(TRANSFORMATION);
final IvParameterSpec iv = new IvParameterSpec(initVectorBytes);
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
final byte[] decryptedVal = cipher.doFinal(cipherTextBytes);
return new String(decryptedVal);
}
Addon:
In case you care about key size limitation, you may use this solution which works just fine (tested under Ubuntu 12, Java 1.7 64 bits (java version "1.7.0_25"
Java(TM) SE Runtime Environment (build 1.7.0_25-b15)
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode))
How should I specify a text input and output using this code?
I need to open a file and read its contents (which I know how to do) and then decrypt it using this code.
public string DecryptUsernamePassword(string cipherText)
{
if (string.IsNullOrEmpty(cipherText))
{
return cipherText;
}
byte[] salt = new byte[]
{
(byte)0xc7,
(byte)0x73,
(byte)0x21,
(byte)0x8c,
(byte)0x7e,
(byte)0xc8,
(byte)0xee,
(byte)0x99
};
PKCSKeyGenerator crypto = new PKCSKeyGenerator("PASSWORD HERE", salt, 20, 1);
ICryptoTransform cryptoTransform = crypto.Decryptor;
byte[] cipherBytes = System.Convert.FromBase64String(cipherText);
byte[] clearBytes = cryptoTransform.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length);
return Encoding.UTF8.GetString(clearBytes);
}
cipherText is the encrypted text and clearBytes are the unencrypted bytes but I need to use a textBox with C# forms for input and output.
This is how it needs to work: textBox1.Text (input) -> bytes -> ^above^ string -> bytes -> textBox2.Text (output) Anything works tbh as long as my input is encrypted text and my output is decrypted text.
Based on your comments, assuming I'm still understanding the question properly. Make this into it's own class:
public class UsernameDecryptor
{
public string Decrypt(string cipherText)
{
if (string.IsNullOrEmpty(cipherText))
return cipherText;
byte[] salt = new byte[]
{
(byte)0xc7,
(byte)0x73,
(byte)0x21,
(byte)0x8c,
(byte)0x7e,
(byte)0xc8,
(byte)0xee,
(byte)0x99
};
PKCSKeyGenerator crypto = new PKCSKeyGenerator("PASSWORD HERE", salt, 20, 1);
ICryptoTransform cryptoTransform = crypto.Decryptor;
byte[] cipherBytes = System.Convert.FromBase64String(cipherText);
byte[] clearBytes = cryptoTransform.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length);
return Encoding.UTF8.GetString(clearBytes);
}
}
Then, inside your button handler:
private void button1_Click (object sender, System.EventArgs e)
{
UsernameDecryptor decryptor = new UsernameDecryptor();
string result = decryptor.Decrypt(inputTextBox.Text);
outputTextBox.Text = result;
}
I need to decrypt a string using Rijndael and those values:
key size - 192
block size - 128
key - cmdAj45F37I5ud2134FDg2fF
When I'm using the code below I get an error : string size illigle, can anyone help me?
public static string DecryptRijndael(string value, string encryptionKey)
{
var key = Encoding.UTF8.GetBytes(encryptionKey); //must be 16 chars
var rijndael = new RijndaelManaged
{
BlockSize = 128,
IV = key,
KeySize = 192,
Key = key
};
var buffer = Convert.FromBase64String(value);
var transform = rijndael.CreateDecryptor();
string decrypted;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, transform, CryptoStreamMode.Write))
{
cs.Write(buffer, 0, buffer.Length);
cs.FlushFinalBlock();
decrypted = Encoding.UTF8.GetString(ms.ToArray());
cs.Close();
}
ms.Close();
}
return decrypted;
}
One (big) problem is in using UTF8.GetBytes() to get the byte[] from string. It is hard to control the number of bytes and it is not very safe.
Use Rfc2898DeriveBytes.GetBytes() instead. And then you can specify the desired length.
But of course you have to do that while encrypting as well.
And I agrre with Luke's remarks about the IV
Can you see the comment in your code that says the key "must be 16 chars"? Your key looks more like 24 characters to me!
In this case you're re-using the key as the IV -- not recommended best practice anyway -- but the size of the IV must match the block size, which is set to 128 bits/16 bytes.
Having said that, the problem I just described should give you the error "Specified initialization vector (IV) does not match the block size for this algorithm", not "string size illigle", so this might be a red herring.
Error is because of the input being 64 bit encoded.
IV and key is not the same. IV is for salting. Anyway the error you are getting is because the input is 64bit encoded. so do this and the error will go.
var decodedEncryptionKey= Base64Decode(encryptionKey);
var key = Encoding.UTF8.GetBytes(decodedEncryptionKey);
here is the full code:
private string decyptInit(string toBeDecrypted, string key, string initVector)
{
var keyByte = Encoding.Default.GetBytes(key);
var decodedIV = Base64Decode(initVector);
var iv = Encoding.Default.GetBytes(decodedIV);
var rijndael = new RijndaelManaged
{
BlockSize = 128,
IV = iv,
KeySize = 192,
Key = keyByte
};
var buffer = Convert.FromBase64String(toBeDecrypted);
var transform = rijndael.CreateDecryptor();
string decrypted;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, transform, CryptoStreamMode.Write))
{
cs.Write(buffer, 0, buffer.Length);
cs.FlushFinalBlock();
decrypted = Encoding.UTF8.GetString(ms.ToArray());
cs.Close();
}
ms.Close();
}
return decrypted;
} public static string Base64Decode(string base64EncodedData)
{
var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}