RSA .NET шифрование Java дешифрование
Я пытаюсь зашифровать строки в.NET с помощью алгоритма RSA и расшифровать результат в Java. На данный момент я смог сделать противоположное (шифрование в Java, расшифровка в.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 байт... и т. Д.) Как я должен это сделать?
Здесь я добавляю текущий нерабочий код:
.СЕТЬ
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;
}
Джава
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();
}
3 ответа
Последние несколько строк вашего 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.
Как вы просили, есть несколько фрагментов кода. Ключи 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);
}
C#.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();
}
Вот ответ, который я не смог опубликовать вчера, связанный с первым ответом на мой пост.
Ну, я проверил код, и у меня есть некоторые проблемы. Я пытался ничего не менять, если это не было абсолютно необходимо. Сначала я получаю ошибку здесь:
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, но не наоборот.
В очередной раз благодарим за помощь!!