Подтвердить что ты не робот

Шифрование RSA.NET Расшифровка Java

Я пытаюсь зашифровать строки в .NET с помощью RSA-алгоритма и расшифровать результат на Java. На данный момент я смог сделать обратное (Encrypt in Java, Decrypt в .NET). Здесь у меня есть мой код, который фактически работает (шифрование JAVA):

byte[] modulusBytes = Base64.decode("2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=");
byte[] exponentBytes = Base64.decode("AQAB");
BigInteger modulus = new BigInteger(1, modulusBytes );
BigInteger exponent = new BigInteger(1, exponentBytes);

RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(rsaPubKey);

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);

byte[] plainBytes = new String("big kitty dancing").getBytes("UTF-8");
byte[] cipherData = cipher.doFinal( plainBytes );
String encryptedString = Base64.encode(cipherData);
return encryptedString;

И (расшифровка .NET)

const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "Tracker";

CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(cspParams);
rsa1.FromXmlString("<RSAKeyValue><Modulus>2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=</Modulus><Exponent>AQAB</Exponent><P>+lXMCEwIN/7+eMpBrq87kQppxu3jJBTwztGTfXNaPUTx+A6uqRwug5oHBbSpYXKNDNCBzVm/0VxB3bo4FJx+ZQ==</P><Q>yasOGaJaE9xlF9T2xRuKeG9ZxCiyjhYaYB/mbtL+SIbtkRLi/AxaU4g2Il/UxhxhSXArKxIzV28zktispPJx1Q==</Q><DP>ueRgQIEFUV+fY979a1RgrVHIPpqEI1URhOMH3Q59oiXCcOumM5njyIHmWQxRAzXnG+7xlKXi1PrnRll0L4oOKQ==</DP><DQ>dfEMNgG1HJhwpxdtmqkYuoakwQvsIRzcIAuIAJh1DoWaupWJGk8/JEstHb1d+t7uJrzrAi2KyT/HscH2diE0YQ==</DQ><InverseQ>YoYF9PF6FiC0YngVeaC/eqt/ea8wMYNN3YO1LuzWpcy2exPRj2U0ZbWMvHXMUb4ea2qmhZGx1QlK4ULAuWKpXQ==</InverseQ><D>g1WAWI4pEK9TA7CA2Yyy/2FzzNiu0uQCuE2TZYRNiomo96KQXpxwqAzZLw+VDXfJMypwDMAVZe/SqzSJnFEtZxjdxaEo3VLcZ1mnbIL0vS7D6iFeYutF9kF231165qGd3k2tgymNMMpY7oYKjS11Y6JqWDU0WE5hjS2X35iG6mE=</D></RSAKeyValue>");

string data2Decrypt = "BaB21vY+RD/jiY3AAsb269fIWTEH38s0xLUfJ7CoVUgaQ6vYzB0tiJ1Ag9HNEdCcuZdGchhqnms8jpsqsHC1iKrz6QCLsgUU7VNWDfQqZYR6Rl/GwR0biK2STnOL+g06f/JUdixHOHOgROify1m8qppYo5plpOVMqYFzEMREMkM=";

byte[] encyrptedBytes = Convert.FromBase64String(data2Decrypt);

byte[] plain = rsa1.Decrypt(encyrptedBytes, false);
string decryptedString = System.Text.Encoding.UTF8.GetString(plain);
Console.WriteLine("SALIDA: " + decryptedString);

Теперь я хочу сделать обратное... Но я получаю некоторые ошибки (размер ключа должен быть 128 байтов... и т.д.) Как мне это сделать?

Здесь я добавляю текущий нерабочий код:

.NET

public string Encrypt(string text)
{
    const int PROVIDER_RSA_FULL = 1;
    const string CONTAINER_NAME = "Tracker";

    CspParameters cspParams;
    cspParams = new CspParameters(PROVIDER_RSA_FULL);
    cspParams.KeyContainerName = CONTAINER_NAME;
    RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(cspParams);
    rsa1.FromXmlString("<RSAKeyValue><Modulus>2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=</Modulus><Exponent>AQAB</Exponent><P>92jJJyzFBSx6gL4Y1YpALmc5CNjoE/wETjqb3ci2v0+3rZWvJKmKy1ZEdlXpyuvXVksJ6cMdUpNAkMknUk9pTQ==</P><Q>4kxkABZOXyDLryYGCGY0b8N0FIdu5BTCFDYEdcatxl/f7ZGDS1NgHJpUWxkVXFfHy2Y/GuDOIbpcwlsO739H+w==</Q><DP>5bNFvrdUHF+VRN45VFjNCcgQLeSkY5mBrdfASoNFGA29LM5iE5nNIMfxPCS7sQiRnq6Af6YFHVtVgJchiMvtqQ==</DP><DQ>j+ng1qVY5epnXlWiFIla45C7K6sNfIMvAcdwgq39KWEjeWPGyYqWXtpOtzh2eylf6Bx4GVHKBW0NPJTIJMsfLQ==</DQ><InverseQ>8uu0dfPVDqB2qFM1Vdi8hl+2uZtN7gjT2co1cEWy29HVYBZD0k9KKCf2PbkeuSfpgFpE70wW5Hrp8V7l/SwSOw==</InverseQ><D>MM/c18zroJ2Iqi9s5/asvUBF3pjO3NSEbFjFpP/NT6WdKimvECWPz2xT6NlV0Vc6tQaAAmtn7Bt+HPhfVdrA4/ysYVe3/6TWkPjW+bvAhMWu/ZqISx11/jPYSGD9g3ZXgUiqcQM8UbOjlswoq4fpheEXTB0xdVutDLpO3qgHN6k=</D></RSAKeyValue>");

    System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
    byte[] textBytes = encoding.GetBytes(text);
    byte[] encryptedOutput = rsa1.Encrypt(textBytes, false);
    string outputB64 = Convert.ToBase64String(encryptedOutput);
    Console.WriteLine(outputB64);
    return outputB64;
}

Java

public static String Decrypt(String encodedString) throws IllegalBlockSizeException, UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, BadPaddingException
{
    byte[] modulusBytes = Base64.decode("2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=");
    byte[] exponentBytes = Base64.decode("AQAB");
    BigInteger modulus = new BigInteger(1, modulusBytes );
    BigInteger exponent = new BigInteger(1, exponentBytes);

    RSAPrivateKeySpec rsaPrivKey = new RSAPrivateKeySpec(modulus, exponent);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PrivateKey privKey = fact.generatePrivate(rsaPrivKey);

    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.DECRYPT_MODE, privKey);

    byte[] base64String = Base64.decode(encodedString);
    byte[] plainBytes = new String(base64String).getBytes("UTF-8");
    byte[] cipherData = cipher.doFinal(plainBytes);

    System.out.println(cipherData);
    return cipherData.toString();
}
4b9b3361

Ответ 1

Последние несколько строк вашего кода расшифровки Java не имеют смысла. Эти строки:

byte[] base64String = Base64.decode(encodedString);
byte[] plainBytes = new String(base64String).getBytes("UTF-8");
byte[] cipherData = cipher.doFinal(plainBytes);

System.out.println(cipherData);
return cipherData.toString();

Вы должны отменить порядок шагов, которые вы использовали для шифрования в .NET. Во-первых, вы должны Base64 декодировать закодированную строку, чтобы получить байты шифрования. Вы сделали это, но вы пометили результат как base64String. Вероятно, вы должны назвать этот результат cipherData. Во-вторых, вам нужно дешифровать cipherData, чтобы получить простой текст. В-третьих, вы должны создать строку из простых строк, используя конструктор String из двух аргументов с Charset для второго аргумента. Вот как должен выглядеть код или близко к нему.

byte[] cipherData = Base64.decode(encodedString);
byte[] plainBytes = cipher.doFinal(cipherData);

return new String(plainBytes, "UTF-8");

Наконец, в Java каждый объект имеет метод toString(), но он не всегда делает то, что вы хотите. Для массивов метод toString() просто возвращает представление идентификатора объекта для этого массива, сорт эквивалента JVM адреса памяти.

ИЗМЕНИТЬ:

Я пропустил, что вы также используете неправильный ключ в своем расшифрованном коде. Вы используете открытый ключ RSA, но вместо этого вы должны использовать закрытый ключ RSA.

Ответ 2

По мере того, как вы просили, заявляют некоторые фрагменты кода. Ключи RSA относятся к сертификатам x509.

Java RSA/AES:

// symmetric algorithm for data encryption
final String ALGORITHM = "AES";
// Padding for symmetric algorithm
final String PADDING_MODE = "/CBC/PKCS5Padding";
// character encoding
final String CHAR_ENCODING = "UTF-8";
// provider for the crypto
final String CRYPTO_PROVIDER = "Entrust";
// RSA algorithm used to encrypt symmetric key
final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
// symmetric key size (128, 192, 256) if using 192+ you must have the Java
// Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files
// installed
int AES_KEY_SIZE = 256;

private byte[] encryptWithRSA(byte[] aesKey, X509Certificate cert)
        throws NoSuchAlgorithmException, NoSuchPaddingException,
        InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
    // get the public key from the encryption certificate to encrypt with
    PublicKey pubKey = cert.getPublicKey();

    // get an instance of the RSA Cipher
    Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM);

    // set the cipher to use the public key
    rsaCipher.init(Cipher.ENCRYPT_MODE, pubKey);

    // encrypt the aesKey
    return rsaCipher.doFinal(aesKey);
}

private AESEncryptedContents encryptWithAes(byte[] dataToEncrypt)
        throws NoSuchAlgorithmException, NoSuchPaddingException,
        InvalidKeyException, IllegalBlockSizeException,
        BadPaddingException, NoSuchProviderException {
    // get the symmetric key generator
    KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM);
    keyGen.init(AES_KEY_SIZE); // set the key size

    // generate the key
    SecretKey skey = keyGen.generateKey();

    // convert to binary
    byte[] rawAesKey = skey.getEncoded();

    // initialize the secret key with the appropriate algorithm
    SecretKeySpec skeySpec = new SecretKeySpec(rawAesKey, ALGORITHM);

    // get an instance of the symmetric cipher
    Cipher aesCipher = Cipher.getInstance(ALGORITHM + PADDING_MODE,
            CRYPTO_PROVIDER);

    // set it to encrypt mode, with the generated key
    aesCipher.init(Cipher.ENCRYPT_MODE, skeySpec);

    // get the initialization vector being used (to be returned)
    byte[] aesIV = aesCipher.getIV();

    // encrypt the data
    byte[] encryptedData = aesCipher.doFinal(dataToEncrypt);

    // package the aes key, IV, and encrypted data and return them
    return new AESEncryptedContents(rawAesKey, aesIV, encryptedData);
}

private byte[] decryptWithAES(byte[] aesKey, byte[] aesIV,
        byte[] encryptedData) throws NoSuchAlgorithmException,
        NoSuchPaddingException, InvalidKeyException,
        InvalidAlgorithmParameterException, IllegalBlockSizeException,
        BadPaddingException, UnsupportedEncodingException,
        NoSuchProviderException {
    // initialize the secret key with the appropriate algorithm
    SecretKeySpec skeySpec = new SecretKeySpec(aesKey, ALGORITHM);

    // get an instance of the symmetric cipher
    Cipher aesCipher = Cipher.getInstance(ALGORITHM + PADDING_MODE,
            CRYPTO_PROVIDER);

    // set it to decrypt mode with the AES key, and IV
    aesCipher.init(Cipher.DECRYPT_MODE, skeySpec,
            new IvParameterSpec(aesIV));

    // decrypt and return the data
    byte[] decryptedData = aesCipher.doFinal(encryptedData);

    return decryptedData;
}

private byte[] decryptWithRSA(byte[] encryptedAesKey, PrivateKey privKey)
        throws IllegalBlockSizeException, BadPaddingException,
        InvalidKeyException, NoSuchAlgorithmException,
        NoSuchPaddingException, NoSuchProviderException {
    // get an instance of the RSA Cipher
    Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM, CRYPTO_PROVIDER);

    // set the cipher to use the public key
    rsaCipher.init(Cipher.DECRYPT_MODE, privKey);

    // encrypt the aesKey
    return rsaCipher.doFinal(encryptedAesKey);
}

С#.Net:

public byte[] encryptData(byte[] data, out byte[] encryptedAesKey, out byte[] aesIV) {
    if (data == null)
        throw new ArgumentNullException("data");

    byte[] encryptedData; // data to return

    // begin AES key generation
    RijndaelManaged aesAlg = new RijndaelManaged();
    aesAlg.KeySize = AES_KEY_SIZE;
    aesAlg.GenerateKey();
    aesAlg.GenerateIV();
    aesAlg.Mode = CipherMode.CBC;
    aesAlg.Padding = PaddingMode.PKCS7;

    // aes Key to be encrypted
    byte[] aesKey = aesAlg.Key;

    // aes IV that is passed back by reference
    aesIV = aesAlg.IV;

    //get a new RSA crypto service provider to encrypt the AES key with the certificates public key
    using (RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider())
    {
        //add the certificates public key to the RSA crypto provider
        rsaCSP.FromXmlString(encryptionCertificate.PublicKey.Key.ToXmlString(false));

        //encrypt AES key with RSA Public key
        //passed back by reference
        encryptedAesKey = rsaCSP.Encrypt(aesKey, false);

        //get an aes encryptor instance
        ICryptoTransform aesEncryptor = aesAlg.CreateEncryptor();

        encryptedData = encryptWithAes(aesEncryptor, data);
    }

    if (encryptedData == null)
        throw new CryptographicException(
                "Fatal error while encrypting with AES");

    return encryptedData;
}

private byte[] encryptWithAes(ICryptoTransform aesEncryptor, byte[] data) {
    MemoryStream memStream = null; // stream to write encrypted data to
    CryptoStream cryptoStream = null; // crypto stream to encrypted data

    try {
        memStream = new MemoryStream();

        // initiate crypto stream telling it to write the encrypted data to
        // the memory stream
        cryptoStream = new CryptoStream(memStream, aesEncryptor,
                CryptoStreamMode.Write);

        // write the data to the memory stream
        cryptoStream.Write(data, 0, data.Length);
    } catch (Exception ee) {
        // rethrow
        throw new Exception("Error while encrypting with AES: ", ee);
    } finally {
        // close 'em
        if (cryptoStream != null)
            cryptoStream.Close();
        if (memStream != null)
            memStream.Close();
    }

    // return the encrypted data
    return memStream.ToArray();
}

Ответ 3

Вот ответ, который я не мог опубликовать вчера, связанный с первым ответом на мой пост.

Ну, я проверил код, и у меня есть некоторые проблемы. Я старался ничего не менять, если это не было полностью необходимо. Сначала я получаю сообщение об ошибке:

Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM, CRYPTO_PROVIDER);

Поставщик криптографии "Entrust" не распознается... Поэтому я оставил только первый параметр. Затем я получаю эту ошибку:

javax.crypto.BadPaddingException: Data must start with zero

Я пробовал через WebService, написанный в .NET, который возвращает всегда байтовые массивы. Возможно, в переводе есть какая-то проблема. Я знаю, что мне нужно использовать номера Base64 и (если я не использую AES), мне приходится разбивать свои строки на части размером 128 байт (ограниченные ключом RSA). Я все еще работаю над проблемой, чтобы понять, почему я могу шифровать в Java и расшифровывать в .NET, но не наоборот.

Еще раз спасибо за вашу помощь!