Estoy AES
encriptando algo de texto usando una clave generada aleatoriamente y luego RSA
encriptando esa clave con una clave privada para poder subirla a una base de datos.
Las RSA
claves se generan usando KeyPairGenerator
in Java
y se guardan como un archivo. Las claves se leen usando File.ReadAllBytes()
.
Cuando hago esto en Java todo funciona perfectamente y la clave encriptada es siempre 172 bytes
, pero cuando lo hago en C#
la clave encriptada es siempre 844 bytes
. Estoy bastante seguro de que el texto se está cifrando correctamente AES
, pero algo va mal con el RSA
cifrado.
He comprobado los tamaños de clave en Java y C # y siempre coinciden. Literalmente, la única diferencia que puedo ver es la longitud del texto cifrado encriptado RSA, que hace que los datos sean inutilizables. Creo que tiene algo que ver con el acolchado, pero no sé cómo arreglarlo.
Java
public String encryptText(String msg, PrivateKey key)
throws NoSuchAlgorithmException, NoSuchPaddingException,
UnsupportedEncodingException, IllegalBlockSizeException,
BadPaddingException, InvalidKeyException {
KeyGenerator generator;
this.cipher.init(Cipher.ENCRYPT_MODE, key); //cipher is initialized earlier with this.cipher = Cipher.getInstance("RSA");
try {
generator = KeyGenerator.getInstance(AES);
generator.init(128); // The AES key size in number of bits
SecretKey secKey = generator.generateKey();
Cipher aesCipher = Cipher.getInstance(AES);
aesCipher.init(Cipher.ENCRYPT_MODE, secKey);
String encText = Base64.getEncoder().encodeToString(aesCipher.doFinal(msg.getBytes("UTF-8")));
String encKey = Base64.getEncoder().encodeToString(cipher.doFinal(secKey.getEncoded()));
return "(" + encText + ")" + encKey;
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
C#
public String EncryptText(byte[] privateKeyBytes, string msg)
{
try
{
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSAParameters RSAKeyInfo = RSA.ExportParameters(false);
RSAKeyInfo.Modulus = privateKeyBytes;
RSA.ImportParameters(RSAKeyInfo);
RijndaelManaged aes = new RijndaelManaged();
aes.BlockSize = 128;
aes.KeySize = 128;
aes.Mode = CipherMode.ECB;
byte[] keyGenerated = aes.Key;
string keyStr = Convert.ToBase64String(keyGenerated);
byte[] keyArr = Convert.FromBase64String(keyStr);
byte[] KeyArrBytes16Value = new byte[16];
Array.Copy(keyArr, KeyArrBytes16Value, 16);
aes.Key = KeyArrBytes16Value;
ICryptoTransform encrypto = aes.CreateEncryptor();
byte[] plainTextByte = ASCIIEncoding.UTF8.GetBytes(msg);
byte[] CipherText = encrypto.TransformFinalBlock(plainTextByte, 0, plainTextByte.Length);
string encText = Convert.ToBase64String(CipherText);
string encKey = Convert.ToBase64String(RSA.Encrypt(aes.Key, true));
return "(" + encText + ")" + encKey;
}
catch (CryptographicException e)
{
Console.WriteLine("FAILED: " + e.Message);
}
return null;
}
ACTUALIZAR
Gracias a Henno por señalar que el problema estaba en cómo estaba leyendo la clave. Terminé usando Bouncy Castle para manejar el cifrado RSA en C #. También cambié mi código Java para cifrarlo con la clave pública en lugar de la clave privada.
Nuevo C #
public String EncryptText(byte[] keyBytes, string msg)
{
try
{
AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
RSAParameters rsaParameters = new RSAParameters();
rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);
RijndaelManaged aes = new RijndaelManaged();
aes.BlockSize = 128;
aes.KeySize = 128;
aes.Mode = CipherMode.ECB;
byte[] keyGenerated = aes.Key;
string keyStr = Convert.ToBase64String(keyGenerated);
byte[] keyArr = Convert.FromBase64String(keyStr);
byte[] KeyArrBytes16Value = new byte[16];
Array.Copy(keyArr, KeyArrBytes16Value, 16);
aes.Key = KeyArrBytes16Value;
ICryptoTransform encrypto = aes.CreateEncryptor();
byte[] plainTextByte = ASCIIEncoding.UTF8.GetBytes(msg);
byte[] CipherText = encrypto.TransformFinalBlock(plainTextByte, 0, plainTextByte.Length);
string encText = Convert.ToBase64String(CipherText);
string encKey = Convert.ToBase64String(rsa.Encrypt(aes.Key, false));
return "(" + encText + ")" + encKey;
}
catch (CryptographicException e)
{
Console.WriteLine("FAILED: " + e.Message);
}
return null;
}
Lo que parece salir mal es que lee en el "archivo de clave privada" guardado en C #, presumiblemente en la variable privateKeyBytes
(pero su código está incompleto, supongo) y luego lo hace RSAKeyInfo.Modulus = privateKeyBytes
, lo cual es extraño y criptográficamente inverosímil. También debe crear una instancia de algún tipo de clase RSA en C #, según los bytes que lee, que es lo que creo que está tratando de hacer al principio del código C # (primeras cuatro líneas). Creo que debería haber otra API para eso, buscando en los documentos:
RSA.ImportParameters(RSAKeyInfo)
y luego quizás establezca RSAKeyInfo a partir de esos bytes, pero no es el módulo. La lectura en bytes debe ser el formato PKCS1 o algo similar, puede estar codificado en base64 en un archivo, o sin formato, etc. Tendría que ver qué formato usa Java para exportar claves completas al disco.
Usas los bytes sin procesar que lees desde el archivo como módulo, lo que seguramente dará problemas y da una "clave" que no es válida y también demasiado grande.
Este artículo se recopila de Internet, indique la fuente cuando se vuelva a imprimir.
En caso de infracción, por favor [email protected] Eliminar
Déjame decir algunas palabras