Шифрование и дешифрование строки с использованием Java-эквивалента C# CryptoStream
Я смотрю на разработку приложения на Java для операционной системы мобильной платформы.
Я разработал приложение в C# WPF для среды Windows. Я использую криптопоток, чтобы зашифровать и расшифровать строку, используя следующий код. приведенный ниже код является только шифрованием
public string encrypt(string encryptionString)
{
byte[] clearTextBytes = Encoding.UTF8.GetBytes(encryptionString);
SymmetricAlgorithm rijn = SymmetricAlgorithm.Create();
MemoryStream ms = new MemoryStream();
byte[] rgbIV = Encoding.ASCII.GetBytes("ryojvlzmdalyglrj");
byte[] key = Encoding.ASCII.GetBytes("hcxilkqbbhczfeultgbskdmaunivmfuo");
CryptoStream cs = new CryptoStream(ms, rijn.CreateEncryptor(key, rgbIV), CryptoStreamMode.Write);
cs.Write(clearTextBytes, 0, clearTextBytes.Length);
cs.Close();
return Convert.ToBase64String(ms.ToArray());
}
Зашифрованная строка хранится в онлайн-базе данных. Что мне нужно сделать, так это чтобы приложение java могло читать строку из базы данных и дешифровать строку, используя те же ключи шифрования из приложения C#.
Спасибо за вашу помощь.
7 ответов
Лично мне нравится криптография BouncyCastle для Java. Этот код (использующий облегченный API BouncyCastle) должен выполнить свою задачу:
String decrypt(byte[] cryptoBytes, byte[] key, byte[] iv) {
BlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()));
cipher.init(false, new ParametersWithIV(new KeyParameter(key), iv));
byte[] out = new byte[cipher.getOutputSize(cryptoBytes.length)];
int offset = cipher.processBytes(cryptoBytes, 0, cryptoBytes.length, out, 0);
cipher.doFinal(out, offset);
return new String(out);
}
Я считаю, что облегченный API BouncyCastle менее болезнен, чем JCE-провайдер, но вы можете использовать его в качестве провайдера, если хотите.
Похоже как.net SymmetricAlgorithm
и до н.э. PaddedBufferedBlockCipher
по умолчанию используется заполнение PKCS7, так что вы должны быть в порядке с использованием значений по умолчанию.
Вы можете проверить javax.crypto.CipherInputStream и javax.crypto.CipherOutputStream.
http://download.oracle.com/javase/1.5.0/docs/api/javax/crypto/CipherInputStream.html http://download.oracle.com/javase/1.5.0/docs/api/javax/crypto /CipherOutputStream.html
Они используются почти так же, как и в приведенном выше примере, хотя инициализация объектов Cipher может немного отличаться.
Я вроде как смог решить проблему. Расшифровка теперь работает нормально. Используя следующий код
String plainPassword = "";
try
{
SecretKeySpec key = new SecretKeySpec("hcxilkqbbhczfeultgbskdmaunivmfuo".getBytes("US-ASCII"), "AES");
IvParameterSpec iv = new IvParameterSpec("ryojvlzmdalyglrj".getBytes("US_ASCII"));
Cipher cipher = Cipher.getInsta
nce("AES/CBC/PKCS7Padding");
cipher.init(Cipher.DECRYPT_MODE, key, iv);
byte[] encoded = cipher.doFinal(Base64.decodeBase64(encryptedPassword.getBytes()));
plainPassword = new String(encoded);
}
catch (Exception ex)
{
Log.d("Decryption Error", ex.toString());
}
return plainPassword;
Проблема сейчас с шифрованием. Я использовал тот же код, за исключением того, что изменил шифр из режима дешифрования в режим шифрования, но по какой-то причине, когда я распечатываю зашифрованную строку, она просто печатает кучу мусора, который не похож на строку, которую создает C#. Ниже приведен код для шифрования
public String encrypt(String plainPasword)
{
String password = "";
try
{
SecretKeySpec key = new SecretKeySpec("hcxilkqbbhczfeultgbskdmaunivmfuo".getBytes("US-ASCII"), "AES");
IvParameterSpec iv = new IvParameterSpec("ryojvlzmdalyglrj".getBytes("US_ASCII"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] encoded = cipher.doFinal(plainPasword.getBytes());
password = new String(encoded);
}
catch (Exception ex)
{
Log.d("Encryption Error", ex.toString());
}
return password;
}
Что, кажется, не так с этим, я не могу решить это. Спасибо
Я использую следующие для шифрования между.net и Java
В.net я использую:
/// <summary>
/// DES Encryption method - used to encryp password for the java.
/// </summary>
/// <param name="plainText"></param>
/// <returns></returns>
public string EncryptData(string plainText)
{
DES des = new DESCryptoServiceProvider();
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.PKCS7;
des.Key = Encoding.UTF8.GetBytes(_secretPhrase.Substring(0, 8));
des.IV = Encoding.UTF8.GetBytes(_secretPhrase.Substring(0, 8));
byte[] bytes = Encoding.UTF8.GetBytes(plainText);
byte[] resultBytes = des.CreateEncryptor().TransformFinalBlock(bytes, 0, bytes.Length);
return Convert.ToBase64String(resultBytes);
}
/// <summary>
/// DES Decryption method - used the decrypt password encrypted in java
/// </summary>
/// <param name="encryptedText"></param>
/// <returns></returns>
public string DecryptData(string encryptedText)
{
DES des = new DESCryptoServiceProvider();
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.PKCS7;
des.Key = Encoding.UTF8.GetBytes(_secretPhrase.Substring(0, 8));
des.IV = System.Text.Encoding.UTF8.GetBytes(_secretPhrase.Substring(0, 8));
byte[] bytes = Convert.FromBase64String(encryptedText);
byte[] resultBytes = des.CreateDecryptor().TransformFinalBlock(bytes, 0, bytes.Length);
return Encoding.UTF8.GetString(resultBytes);
}
и в Java я использую:
открытый класс CryptoUtil {
public static final Logger LOG = Logger.getLogger(CryptoUtil.class);
private Cipher cipher = null;
private SecretKey key = null;
// This variable holds a string based on which a unique key will be generated
private static final String SECRET_PHRASE = "SECRET PHRASE GOES HERE";
// Charset will be used to convert between String and ByteArray
private static final String CHARSET = "UTF8";
// The algorithm to be used for encryption/decryption DES(Data Encryption Standard)
private static final String ALGORITHM = "DES";
public CryptoUtil() throws DDICryptoException {
try {
// generate a key from SecretKeyFactory
DESKeySpec keySpec = new DESKeySpec(SECRET_PHRASE.getBytes(CHARSET));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
key = keyFactory.generateSecret(keySpec);
cipher = Cipher.getInstance(ALGORITHM);
} catch (Exception e) {
LOG.error(e);
throw new DDICryptoException(e);
}
}
/**
* This method takes a plain text string and returns encrypted string using DES algorithm
* @param plainText
* @return String
* @throws DDICryptoException
*/
public String encrypt(String plainText) throws DDICryptoException {
String encryptedString = null;
try {
// initializes the cipher with a key.
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plainTextAsUTF8 = plainText.getBytes(CHARSET);
// decrypts data in a single-part or multi-part operation
byte[] encryptedBytes = cipher.doFinal(plainTextAsUTF8);
encryptedString = new sun.misc.BASE64Encoder().encode(encryptedBytes);
} catch (Exception e) {
LOG.error(e);
throw new DDICryptoException(e);
}
return encryptedString;
}
/**
* This method takes a plain text string and returns encrypted string using DES algorithm
* @param encryptedString
* @return
* @throws DDICryptoException
*/
public String decrypt(String encryptedString) throws DDICryptoException {
String decryptedString = null;
try {
byte[] decodedString = new sun.misc.BASE64Decoder().decodeBuffer(encryptedString);
// initializes the cipher with a key.
cipher.init(Cipher.DECRYPT_MODE, key);
// decrypts data in a single-part or multi-part operation
byte[] decryptedBytes = cipher.doFinal(decodedString);
decryptedString = new String(decryptedBytes, CHARSET);
} catch (Exception e) {
LOG.error(e);
throw new DDICryptoException(e);
}
return decryptedString;
}
}
StringBuffer strbuf = new StringBuffer(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++) {
if (((int) buf[i] & 0xff) < 0x10) {
strbuf.append("0");
}
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
}
Вы должны закодировать полученный байтовый массив перед преобразованием его в строку. Приведенный выше код помог мне, в то время как моя настоящая функция шифрования приведена ниже.
public String encrypt(String data) throws Exception{
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
Key k = new SecretKeySpec(key.getBytes(), 0, key.length(), "AES");
// Calculate ciphertext size.
int blocksize = 16;
int ciphertextLength = 0;
int remainder = data.getBytes().length % blocksize;
if (remainder == 0) {
ciphertextLength = data.getBytes().length + blocksize;
} else {
ciphertextLength = data.getBytes().length - remainder + blocksize;
}
cipher.init(Cipher.ENCRYPT_MODE, k);
byte[] buf = new byte[ciphertextLength];
cipher.doFinal(data.getBytes(), 0, data.length(), buf, 0);
StringBuffer strbuf = new StringBuffer(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++) {
if (((int) buf[i] & 0xff) < 0x10) {
strbuf.append("0");
}
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strbuf.toString();
} catch (Exception e) {
Logger.logException(e);
}
return null;
}
См. Ответ № 5 об эквивалентах CryptoStream .NET в Java?
Обязательно прочитайте комментарии внизу...
KeySpec ks = new DESKeySpec("key12345".getBytes("UTF-8"));
SecretKey key = SecretKeyFactory.getInstance("DES").generateSecret(ks);
IvParameterSpec iv = new IvParameterSpec(
Hex.decodeHex("1234567890ABCDEF".toCharArray()));
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, iv);
byte[] decoded = cipher.doFinal(Base64.decodeBase64("B3xogi/Qfsc="));
System.out.println("Decoded: " + new String(decoded, "UTF-8"));
Надеюсь это поможет...
JK
Cemeron, аккуратный код там!
Я столкнулся с интересной ситуацией, когда наш клиент дал IV такой же, как ключ.
После того, как я попробовал различные комбинации, в которых я получал исключение плохого заполнения, решение, которое работало, было
byte[] iv=new byte[8]; // assuming RC2
System.arraycopy(key.getBytes(), 0, iv, 0, key.getBytes().length > iv.length ? key.getBytes().length);
// Now decrypt and hopefully this should work