title: Java Send Encrypted Text from Client through Socket using RSA and Decrypt it in the Server
body: <p>I have been trying to implement RSA encryption in a very simple client-server Java application.</p>
  
  <p>To try and understand how the encryption works, I made my own scenario: </p>
  
  <ol>
  <li>Alice (Server) wants to send a message to Bob (Client).</li>
  <li>When Bob connects to Alice, they exchange public keys (e, n). </li>
  <li>Once they have exchanged public keys, Alice encrypts the message "Hello!" with Bob's public key and sends it to Bob. </li>
  <li>Bob receives the encrypted message and decrypts it using his private key (d, n).</li>
  </ol>
  
  <p>This all makes sense to me, but when I tried to implement it in Java I'm getting inconsistent results. Sometimes I'd get a <code>NegativeArrayException</code>, or <code>ArithmeticException: BigInteger would overflow supported range</code>, and I have never decrypted the String successfully.</p>
  
  <p>Here is my implementation:</p>
  
  <p><strong>RSA.java</strong></p>
  
  <pre><code>import java.math.BigInteger;
  import java.security.SecureRandom;
  
  public class RSA {
      private BigInteger n;
      private BigInteger d;
      private BigInteger e;
  
      private PrivateKey privateKey;
      private PublicKey publicKey;
  
      public static class PublicKey {
          public byte[] getE() {
              return e;
          }
  
          public byte[] getN() {
              return n;
          }
  
          private final byte[] e;
          private final byte[] n;
  
          public PublicKey(byte[] e, byte[] n) {
              this.e = e;
              this.n = n;
          }
      }
  
      public static class PrivateKey {
          public byte[] getD() {
              return d;
          }
          public byte[] getN() {
              return n;
          }
          private final byte[] d;
          private final byte[] n;
  
          public PrivateKey(byte[] n, byte[] d) {
              this.n = n;
              this.d = d;
          }
      }
  
      public RSA() {
          generateKeyPair(1024);
      }
  
      public RSA(int bits) {
          generateKeyPair(bits);
      }
  
      public final void generateKeyPair(int bits) {
  
          SecureRandom random = new SecureRandom();
  
          BigInteger p = new BigInteger(bits/2, 100, random);
          BigInteger q = new BigInteger(bits/2, 100, random);
          BigInteger phi = (p.subtract(new BigInteger("1"))).multiply(q.subtract(new BigInteger("1")));
  
          n = p.multiply(q);
          e = new BigInteger("3");
  
  
          while (phi.gcd(e).intValue() &gt; 1) {
              e = e.add(new BigInteger("2"));
          }
  
          System.out.println(e.toString());
          System.out.println(n.toString());
  
          d = e.modInverse(phi);
          publicKey = new PublicKey(e.toByteArray(), n.toByteArray());
          privateKey = new PrivateKey(d.toByteArray(), n.toByteArray());
      }
  
  
      public byte[] encrypt(byte[] plainData, PublicKey publicKey) {
          return ((new BigInteger(plainData)).modPow(new BigInteger(publicKey.getE()), new BigInteger(publicKey.getN()))).toByteArray();
      }
  
      public byte[] decrypt(byte[] encryptedData) {
          return ((new BigInteger(encryptedData)).modPow(d, n)).toByteArray();
      }
  
      // (d, n)
      public PrivateKey getPrivateKey() {
          return privateKey;
      }
  
      // (e, n)
      public PublicKey getPublicKey() {
          return publicKey;
      }
  }
  </code></pre>
  
  <p><strong>Alice.java</strong></p>
  
  <pre><code>import crypto.RSA.PublicKey;
  import java.io.DataInputStream;
  import java.io.DataOutputStream;
  import java.io.IOException;
  import java.net.ServerSocket;
  import java.net.Socket;
  
  public class Alice {
      private final RSA encryption;
      public Alice() {
          encryption = new RSA();
  
          try {
              ServerSocket alice = new ServerSocket(2424);
  
              while(true) {
                  Socket bob = alice.accept();
  
                  DataInputStream inputStream = new DataInputStream(bob.getInputStream());
                  DataOutputStream outputStream = new DataOutputStream(bob.getOutputStream());
  
                  byte[] bobE = new byte[1];
                  byte[] bobN = new byte[inputStream.readInt()];
  
                  // Read Bob's Public Key to encrypt Alice's Message.
                  inputStream.read(bobE);
                  inputStream.read(bobN);
  
                  PublicKey bobPublicKey = new PublicKey(bobE, bobN);
  
                  byte[] aliceE = encryption.getPublicKey().getE();
                  byte[] aliceN = encryption.getPublicKey().getN();
  
                  // Send Alice's Public Key to Bob just in case he wants to send Alice a message.
                  outputStream.writeInt(aliceN.length); // N length
                  outputStream.write(aliceE, 0, aliceE.length);
                  outputStream.write(aliceN, 0, aliceN.length);   
  
                  outputStream.flush();
  
                  String messageToBob = "Hello!";
  
                  byte[] encryptedMessage = encryption.encrypt(messageToBob.getBytes(), bobPublicKey);
  
                  outputStream.writeInt(encryptedMessage.length);
                  outputStream.write(encryptedMessage, 1, encryptedMessage.length-1);
  
                  outputStream.flush();
              }
  
          } catch (IOException ex) {}
      }
  }
  </code></pre>
  
  <p><strong>Bob.java</strong></p>
  
  <pre><code>import crypto.RSA.PublicKey;
  import java.io.DataInputStream;
  import java.io.DataOutputStream;
  import java.io.IOException;
  import java.net.Socket;
  
  public class Bob {
      private final RSA encryption;
      public Bob() {
          encryption = new RSA();
  
          try {
              Socket alice = new Socket("127.0.0.1", 2424);
  
              DataInputStream inputStream = new DataInputStream(alice.getInputStream());
              DataOutputStream outputStream = new DataOutputStream(alice.getOutputStream());
  
              // Send Bob's public E and N to Alice.
              byte[] bobE = encryption.getPublicKey().getE();
              byte[] bobN = encryption.getPublicKey().getN();
  
              outputStream.writeInt(bobN.length); // N length
              outputStream.write(bobE, 0, bobE.length);
              outputStream.write(bobN, 0, bobN.length);
              outputStream.flush();
  
              byte[] aliceE = new byte[1];
              byte[] aliceN = new byte[inputStream.readInt()];
  
              // Read Alice's public key. (unused)
              inputStream.read(aliceE);
              inputStream.read(aliceN);
  
              PublicKey alicePublicKey = new PublicKey(aliceE, aliceN);
  
              // Read Alice's Message Size.
              int encryptedMessageSize = inputStream.readInt();
  
              byte[] encryptedMessageFromAlice = new byte[encryptedMessageSize];
  
              // Read Alice's Message.
              // Here is where everything goes wrong.
              inputStream.read(encryptedMessageFromAlice, 1, encryptedMessageSize-1);
  
              System.out.println("Got a message from alice (" + encryptedMessageFromAlice.length + "): ");
              System.out.println(new String(encryption.decrypt(encryptedMessageFromAlice)));
  
          } catch (IOException ex) {}
      }
  }
  </code></pre>
  
  <p><strong>Main method</strong></p>
  
  <pre><code>(new Thread() {
      @Override
      public void run() {
          Alice alice = new Alice();
  
      }
  }).start();
  
  Bob bob = new Bob();
  </code></pre>
  
  <p>I feel like I may be missing some fundamentals, but I've read how it works, checked out examples (all of them incomplete, though), and I don't see where the mistake is.</p>
  
  <p>I know there are libraries that make this much easier, but I need to learn the basic implementation of it, using BigInteger.</p>
  
  <p>Any help and guidance would be appreciated. Thanks!</p>
  
  <p><strong>UPDATE 1:</strong> 
  I have made the length of the moduli non-hardcoded as James said.</p>
  
  <p>After running the program, here is what is printed out (the message is always the same "Hello!"):</p>
  
  <p><strong>Try 1</strong></p>
  
  <pre><code>Got a message from alice (41): 
  N�qpfcc�d�����J��
  �$P�m�1�qj?��K�����s�����IQ@��g�u�)^���\m"ݒ�M��7p�}�!����
  </code></pre>
  
  <p><strong>Try 2</strong></p>
  
  <pre><code>Got a message from alice (41): 
  W��LW\t� b�w��P�3Ꟊ��?�g��ϔSx�N���&lt;Vx� �ĝJ:h1��ޟ�KY�:vtad��0\R-�ǰ���3D4~_�
  ~���Cy�$$y��#{�^U$;՞�RU��ݘN�C'0��S
  </code></pre>
  
  <p><strong>Try 3</strong></p>
  
  <pre><code>Got a message from alice (18): 
  Rq���ҞlapZ�L����t�,��@k��&amp;��=�.o�� ��   ��������؉I�g&gt;+h��ʸz��=��l���a��+�\Gഢ��ccn�n�1[1���Bu�A�]    �n�b�Tu�o!
  </code></pre>