2

I'm trying to encrypt data in my C# client with public RSA key from the Java server. To do this I generated KeyPair in Java

KeyPairGenerator.java

KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(2048); KeyPair kp = kpg.generateKeyPair(); Key pub = kp.getPublic(); Key pvt = kp.getPrivate(); String outFile = "rsa_key"; FileOutputStream outPvt = new FileOutputStream(outFile + ".key"); outPvt.write(pvt.getEncoded()); outPvt.close(); FileOutputStream outPub = new FileOutputStream(outFile + ".pub"); outPub.write(pub.getEncoded()); outPub.close(); 

It gave me two files (rsa_key.key and rsa_key.pub) and then I encoded public key with Base64 so C# could read it:

PublicKeyBase64.java

String keyFile2 = "rsa_key.pub"; Path path2 = Paths.get(keyFile2); byte[] bytes2 = Files.readAllBytes(path2); X509EncodedKeySpec ks2 = new X509EncodedKeySpec(bytes2); KeyFactory kf2 = KeyFactory.getInstance("RSA"); PublicKey pub = kf2.generatePublic(ks2); Base64.Encoder encoder = Base64.getEncoder(); String outFile = "en_rsa_key"; Writer out = new FileWriter(outFile + ".pub"); out.write(encoder.encodeToString(pub.getEncoded())); out.close(); 

Then I created my C# class to encrypt data

Encrypter.cs

class Encrypter { private const string PATH = "..\\..\\key\\en_rsa_key.pub"; private string PublicKey; public Encrypter() { PublicKey = File.ReadAllText(PATH); Console.WriteLine(PublicKey.Length); } public string encryptData(string dataToEncrypt) { Asn1Object obj = Asn1Object.FromByteArray(Convert.FromBase64String(PublicKey)); DerSequence publicKeySequence = (DerSequence)obj; DerBitString encodedPublicKey = (DerBitString)publicKeySequence[1]; DerSequence publicKey = (DerSequence)Asn1Object.FromByteArray(encodedPublicKey.GetBytes()); DerInteger modulus = (DerInteger)publicKey[0]; DerInteger exponent = (DerInteger)publicKey[1]; RsaKeyParameters keyParameters = new RsaKeyParameters(false, modulus.PositiveValue, exponent.PositiveValue); RSAParameters parameters = DotNetUtilities.ToRSAParameters(keyParameters); RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.ImportParameters(parameters); //Console.WriteLine(dataToEncrypt); byte[] encryptedData = rsa.Encrypt(Encoding.UTF8.GetBytes(dataToEncrypt), true); //Console.WriteLine(Convert.ToBase64String(encryptedData)); return Convert.ToBase64String(encryptedData); } } 

And at last my Decrypter class


public class Decrypter { private static final String PATH = "I:\\rsa_key.key"; private File privateKeyFile = new File(PATH); private RSAPrivateKey privateKey; public Decrypter() throws Exception { DataInputStream dis = new DataInputStream(new FileInputStream(privateKeyFile)); byte[] privateKeyBytes = new byte[(int)privateKeyFile.length()]; dis.read(privateKeyBytes); dis.close(); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(privateKeyBytes); privateKey = (RSAPrivateKey) keyFactory.generatePrivate(privSpec); } public String decrypt(String data) throws Exception{ Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, privateKey); return new String(cipher.doFinal(data.getBytes())); } } 

I send encrypted data in C# via WebSocket and receive it without any problem because data while sending and receiving is the same. The problem is that data length is 344 characters (bytes) so when I decrypt my data it shows me and error: javax.crypto.IllegalBlockSizeException: Data must not be longer than 245 bytes I'm using 2048 bit key so it's 256B - 11B for padding that's why it's 245B. But the problem is that it always generates 344B and it doesn't depend on message to encode length. For example encoding "A" gives 344B and "Hello world" also 344B.

In this topic people say to use symmetric key, Encrypt the data with the symmetric key and then Encrypt the symmetric key with rsa. But it won't help because any encrypted string in my code has 344B size, so I won't be able to decrypt encrypted symmetric key.

What's wrong with my code?

12
  • The 334 bytes you see I guess is because you are looking at the Base64 encoded output text length not the actual encryptedData buffer length - which will not exceed 256 bytes with a 2048 bit RSA key. As you say the way to deal with this is to use RSA to encrypt say an AES-256 key which at 32 bytes is no problem for RSA. Commented Jul 20, 2018 at 12:03
  • Length of my public key is 393 - I checked it in class constructor just after reading key file Commented Jul 20, 2018 at 12:09
  • Length property returns number of characters so each character is a byte - 393 bytes then Commented Jul 20, 2018 at 12:15
  • 1
    The length of the raw .pub file is not the length of the key, the file content will likely be PKCS#8 encoded, so Base64 with --delimiters-- which is longer than the binary key data it actually encodes. Commented Jul 20, 2018 at 12:19
  • 1
    yes, but it doen't define public key length. Check 8gwifi.org/RSAFunctionality?keysize=2048 . It also generates that long public key. Commented Jul 20, 2018 at 12:20

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.