Проблема шифрования Java и C # - PullRequest
1 голос
/ 11 октября 2011

У меня есть библиотека DLL на C #, которая шифрует и дешифрует строковые тексты (что-то базовое), но теперь мне нужно реализовать тот же метод шифрования в Java, чтобы некоторые приложения могли шифровать данные и отправлять их в библиотеку.

Я не могу изменить код C #, потому что он уже находится в производстве, но Java не делает, поэтому, пожалуйста, любые предложения должны быть сделаны на стороне Java.

В основном я пытаюсьреализовать тот же метод шифрования C # в Java.Вот мои коды C #:

ПРИМЕЧАНИЕ : значения парольной фразы, соли и т. Д., Очевидно, являются просто ссылочными.

    const string PassPhrase = "IhDyHz6bgQyS0Ff1/1s="; 
    const string SaltValue = "0A0Qvv09OXd3GsYHVrA=";   
    const string HashAlgorithm = "SHA1";                
    const int PasswordIterations = 3;                 
    const string InitVector = "GjrlRZ6INgNckBqv";      
    const int KeySize = 256;


public static string Encrypt(string plainText)
    {

        byte[] initVectorBytes = Encoding.ASCII.GetBytes(InitVector);
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(SaltValue);


        byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);


        PasswordDeriveBytes password = new PasswordDeriveBytes(
                                                        PassPhrase,
                                                        saltValueBytes,
                                                        HashAlgorithm,
                                                        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;
    }


public static string Decrypt(string cipherText)
    {

        byte[] initVectorBytes = Encoding.ASCII.GetBytes(InitVector);
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(SaltValue);


        byte[] cipherTextBytes = Convert.FromBase64String(cipherText);

        PasswordDeriveBytes password = new PasswordDeriveBytes(
                                                        PassPhrase,
                                                        saltValueBytes,
                                                        HashAlgorithm,
                                                        PasswordIterations);


        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();


        string plainText = Encoding.UTF8.GetString(plainTextBytes,
                                                   0,
                                                   decryptedByteCount);


        return plainText;
    }

Вот мой код Java, он шифруетданные, но не так, как код шифрования C #, поэтому при попытке расшифровать их с помощью библиотеки C # выдается исключение: «Длина данных для расшифровки недопустима»

    static final String PassPhrase = "IhDyHz6bgQyS0Ff1/1s=";   
    static final String SaltValue = "0A0Qvv09OXd3GsYHVrA=";    
    static final String HashAlgorithm = "SHA1";               
    static final int PasswordIterations = 3;                   
    static final String InitVector = "GjrlRZ6INgNckBqv";       
    static final int KeySize = 256;

public static String encrypt(String plainText)
{
    char[] password = PassPhrase.toCharArray();
    byte[] salt = SaltValue.getBytes();
    byte[] iv = InitVector.getBytes();
    byte[] ciphertext = new byte[0];

    SecretKeyFactory factory;
    try {
        factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

        KeySpec spec = new PBEKeySpec(password, salt, PasswordIterations, 256);
        SecretKey tmp;

        tmp = factory.generateSecret(spec);

        SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secret);
        AlgorithmParameters params = cipher.getParameters();
        //iv = params.getParameterSpec(IvParameterSpec.class).getIV();
        ciphertext = cipher.doFinal(plainText.getBytes("UTF-8"));

    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeySpecException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } 
    //catch (InvalidParameterSpecException e) {
    //  // TODO Auto-generated catch block
    //  e.printStackTrace();
    //} 
    catch (IllegalBlockSizeException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (BadPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return Base64.encode(new String(ciphertext));
}

EDIT 1 : я исправил окончательное преобразование массива байтов в String в коде Java, как предложил Джон Скит.

Ответы [ 2 ]

3 голосов
/ 11 октября 2011

Это неправильно в коде Java:

return Base64.encode(ciphertext.toString());

Вы вызываете toString() в байтовом массиве, который всегда выдаст строку, такую ​​как [B@3e25a5.

РЕДАКТИРОВАТЬ: Ох, только что заметил, что вы можете изменить сторону Java.Ура.

По сути, вам нужно использовать API Base64, который позволяет:

return Base64.encode(ciphertext);

Я всегда разочарован в API Base64, которые позволяют вам "кодировать"если честно, строка ... base64 кодирует двоичные данные в текст и декодирует текстовые данные в двоичный.Ну что ж ...

В любом случае, используйте этот API (метод encodeBytes), если вам нужен тот, который позволяет передавать байтовый массив.

IЯ не проверял детализацию фактического шифрования, но код C # по крайней мере выглядит как будто он делает правильные вещи с точки зрения кодирования.Это может быть сделано с using заявлениями:)

1 голос
/ 15 октября 2013

Вот пример C #, вам нужны IterationCount и PaddingMode.None

protected void Page_Load(object sender, EventArgs e)
{
    string value = "";
    string password = "";
    string salt = "";
    string iv = "";


    byte[] vectorBytes = Convert.FromBase64String(Server.UrlDecode(iv)); 
    byte[] cipherText = Convert.FromBase64String(Server.UrlDecode(value));

    Rfc2898DeriveBytes key1 = new Rfc2898DeriveBytes(password, StringToByteArray(salt)); //same as PBKDF2WithHmacSHA1
    key1.IterationCount = 32;
    byte[] keyBytes = key1.GetBytes(16);

    string Answer = DecryptDataAES(cipherText, keyBytes, vectorBytes); //vectorBytes is good

    //litAnswer.Text = Answer;
}

public static string DecryptDataAES(byte[] cipherText, byte[] key, byte[] iv)
{
    string plaintext = null;

    using (Rijndael rijndael = Rijndael.Create())
    {
        rijndael.Key = key;
        rijndael.IV = iv;
        rijndael.Padding = PaddingMode.None;

        ICryptoTransform decryptor = rijndael.CreateDecryptor(rijndael.Key, rijndael.IV);

        // Create the streams used for decryption. 
        using (MemoryStream msDecrypt = new MemoryStream(cipherText))
        {
            using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
            {
                using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                {
                    plaintext = srDecrypt.ReadToEnd();
                }
            }
        }
    }
    return plaintext;
}

public static byte[] StringToByteArray(String hex)
{
    int NumberChars = hex.Length / 2;
    byte[] bytes = new byte[NumberChars];
    using (var sr = new StringReader(hex))
    {
        for (int i = 0; i < NumberChars; i++)
            bytes[i] =
              Convert.ToByte(new string(new char[2] { (char)sr.Read(), (char)sr.Read() }), 16);
    }
    return bytes;
}
...