title: Java RSA/ECB/PKCS1Padding encryption with .NET
body: <p>I need to encrypt a password on a web site using a public key. The public key is delivered through a Java web service with the information: The key is a RSA key to be used with RSA/ECB/PKCS1Padding algorithm. The public key is delivered as JSON in the form:</p>
  
  <pre><code>{
      "kid":"PWD",
      "kty":"RSA",
      "use":"enc",
      "n":"MTA0OTgzNjg0OTMxMzE2NjkwNTU4Mjg3NDIwMDg1NTY0ODEyMjg1MDk2NTcwNzU5NDIzNzM0O
      DA3OTA2MzA0MDczNTU0NDQ2Njg3ODY2ODk2NTk0NjYzNTAxMzg0NzE1OTExMjA0MjU1MzMzOTIzMjA
      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
      zcwMjA3MzQxOTcwNzc4NDAwNzM3MTY2NDMyNzIwNjMwMDQwOTMwOTQ0MTA2OTE1NDEzMDAwNTMyMTE
      5ODM0MTA2MjAzMDIyODEwMjYyMDM3MDQ0NzkxNzIzNTU1MjQyNjYxMzE2ODc4OTc5NzY1OTgzMjg4M
      zQ0NDc3OTYwNTg3MzE2NTUwMDgx",
      "e":"NjU1Mzc"
   }
  </code></pre>
  
  <p>I tried to encrypt the password using the public key but the key generated is not correct. Here is my code:</p>
  
  <pre><code>encryptedPassword = EncrypIt("Password01", "MTA1MzQxNzIwODA3NjUwNzg5ND
  Y4ODU2Mjc0NDA3ODIwMjQ1ODQ5NDE1MDk1MDIzMTM3MjM0NzAwNzYzNjc2MTgwNjg3ODMxMjA3
  NTY0NTcxMjg2MzM4NjQ1NzEwMDcyMjY2MTQyNDIzMTczMjkwMDk0MTc0MTA5MTc5MzI0NjYwMjQ4NzI3NzM0MTQ5NDY0MjUwODkwO
  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  c2OTAzNjc3NzQzODM3NzM0MjE2ODM0NjY4MjM4MTQ0OTA3MDQ3MTk1Njc1NzU3OTE2NjEyNzkzMzM2MzI3MDUyNjg0NDI5NDExNjI
  2MzA0MzM5", "NjU1Mzc");
  
      public static string EncrypIt(string password, string publicKey, string exponent)
      {
          UnicodeEncoding ByteConverter = new UnicodeEncoding();
          byte[] publicKeyByte = ByteConverter.GetBytes(publicKey);
          byte[] passwordByte = ByteConverter.GetBytes(password);
  
          RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
          RSAParameters RSAKeyInfo = new RSAParameters();
          RSAKeyInfo = RSA.ExportParameters(false); //Export only public key
          //Set RSAKeyInfo to the public key values. 
          RSAKeyInfo.Modulus = publicKeyByte;
          //RSAKeyInfo.Exponent = exponentBytes; //I tried to set exponent but I have an error
          RSA.ImportParameters(RSAKeyInfo);
          byte[] encryptedPassword = RSA.Encrypt(passwordByte, false);
          return Convert.ToBase64String(encryptedPassword);
      }
  </code></pre>
  
  <p>(The public key is different between the JSON and my code but don't pay attention to it, I just copied information from different sources)</p>
  
  <ul>
  <li>The encrypted password I obtained is far too long: The encrypted password should be 172 characters (I know because I have a small Java program that allows me to encrypt passwords correctly) but I get 1100 characters.</li>
  <li>I do not use the exponent: Should I ?</li>
  <li>Could I not use the JSON to directly configure the RSACryptoServiceProvider correctly ?</li>
  </ul>
  
  <p>The answer from <strong>owlstead</strong> helped me to get an encrypted password with the right string size but the service using the encrypted string reject it with the message: <code>javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes</code></p>
  
  <p>I otained the code of the java program wich is doing the correct encryption (see below). I need to achieve the same encryption using .NET.</p>
  
  <pre><code>public class EncryptionServiceImpl
  {
  
      private static final Charset UTF8 = Charset.forName("UTF-8");
  
      @Resource(name = "briqueAuthentificationClient")
      private BriqueAuthentificationClientImpl briqueAuthentificationClient;
  
      protected static final String ALGORITHM_RSA = "RSA";
  
      protected static final String TRANSFORMATION_RSA_ECB_PKCS1PADDING = "RSA/ECB/PKCS1Padding";
  
      private static final Logger LOG = LoggerFactory.getLogger(EncryptionServiceImpl.class);
  
      public EncryptionServiceImpl() {
          LOG.info("constructeur EncryptionServiceImpl");
      }
  
      /**
       * @param briqueAuthentificationClient the briqueAuthentificationClient to set
       */
      public void setBriqueAuthentificationClient(final BriqueAuthentificationClientImpl briqueAuthentificationClient) {
          this.briqueAuthentificationClient = briqueAuthentificationClient;
      }
  
      public String encrypt(final String input) throws GeneralSecurityException {
  
          if (StringUtils.isNotBlank(input)) {
              final CertificateDto certificate = this.briqueAuthentificationClient.getCurrentCertificate();
  
              if (certificate != null) {
                  return new String(this.encryptAndEncode(input.getBytes(), certificate), EncryptionServiceImpl.UTF8);
              } else {
                  throw new RuntimeException("Certificate is null");
              }
          }
          return null;
      }
  
      protected byte[] encryptAndEncode(final byte[] input, final CertificateDto currentCertificate)
              throws GeneralSecurityException {
  
          // CrÃ©ation de la clÃ© publique
          final PublicKey publicKey = this.buildPublicKey(currentCertificate);
  
          // Chiffre
          final byte[] inputEncrypted = this.encrypte(input, publicKey);
  
          // Encode
          return this.encodeBase64Url(inputEncrypted);
      }
  
      protected PublicKey buildPublicKey(final CertificateDto currentCertificate) throws GeneralSecurityException {
  
          if ("RSA".equals(currentCertificate.getKeyType())) {
              return this.buildRSAPublicKey(currentCertificate);
          }
          LOG.error(String.format("Tentative de crÃ©ation d'une clÃ© publique avec un algorithme non connu [%s]",
                  currentCertificate.getKeyType()));
          return null;
      }
  
      protected PublicKey buildRSAPublicKey(final CertificateDto currentCertificate) throws GeneralSecurityException {
  
          final BigInteger modulus = new BigInteger(new String(Base64.decodeBase64(currentCertificate.getModulus()),
                  EncryptionServiceImpl.UTF8));
          final BigInteger publicExponent = new BigInteger(new String(Base64.decodeBase64(currentCertificate
                  .getPublicExponent()), EncryptionServiceImpl.UTF8));
  
          try {
              return KeyFactory.getInstance(ALGORITHM_RSA).generatePublic(new RSAPublicKeySpec(modulus, publicExponent));
          } catch (InvalidKeySpecException e) {
              throw e;
          } catch (NoSuchAlgorithmException e) {
              throw e;
          }
      }
  
      protected byte[] encrypte(final byte[] input, final RSAPublicKeySpec rsaPublicKeySpec)
              throws GeneralSecurityException {
  
          PublicKey publicKey;
          try {
              publicKey = KeyFactory.getInstance(ALGORITHM_RSA).generatePublic(
                      new RSAPublicKeySpec(rsaPublicKeySpec.getModulus(), rsaPublicKeySpec.getPublicExponent()));
          } catch (InvalidKeySpecException e) {
              throw e;
          } catch (NoSuchAlgorithmException e) {
              throw e;
          }
          return this.encrypte(input, publicKey);
      }
  
      protected byte[] encrypte(final byte[] input, final PublicKey publicKey) throws GeneralSecurityException {
  
          try {
              final Cipher cipher = Cipher.getInstance(TRANSFORMATION_RSA_ECB_PKCS1PADDING);
              cipher.init(Cipher.ENCRYPT_MODE, publicKey);
              return cipher.doFinal(input);
          } catch (NoSuchAlgorithmException e) {
              throw e;
          } catch (NoSuchPaddingException e) {
              throw e;
          } catch (IllegalBlockSizeException e) {
              throw e;
          } catch (BadPaddingException e) {
              throw e;
          }
  
      }
  
      protected byte[] decrypte(final byte[] input, final RSAPrivateKeySpec rsaPrivateKeySpec)
              throws GeneralSecurityException {
  
          final BigInteger modulus = rsaPrivateKeySpec.getModulus();
          final BigInteger privateExponent = rsaPrivateKeySpec.getPrivateExponent();
  
          try {
              final PrivateKey privateKey = KeyFactory.getInstance(ALGORITHM_RSA).generatePrivate(
                      new RSAPrivateKeySpec(modulus, privateExponent));
  
              final Cipher cipher = Cipher.getInstance(TRANSFORMATION_RSA_ECB_PKCS1PADDING);
              cipher.init(Cipher.DECRYPT_MODE, privateKey);
              return cipher.doFinal(input);
  
          } catch (NoSuchAlgorithmException e) {
              throw e;
          } catch (NoSuchPaddingException e) {
              throw e;
          } catch (IllegalBlockSizeException e) {
              throw e;
          } catch (BadPaddingException e) {
              throw e;
          } catch (InvalidKeySpecException e) {
              throw e;
          } catch (InvalidKeyException e) {
              throw e;
          }
  
      }
  
      protected byte[] encodeBase64Url(final byte[] input) {
          return Base64.encodeBase64(input, false);
      }
  
      protected byte[] decodeBase64Url(final byte[] input) {
          return Base64.decodeBase64(input);
      }
  
      /**
       * Method to connect to an url
       * 
       * @param httpclient the http connection
       * @return the response GetMethod
       * @throws OAuthException in cas of connection error
       */
      private GetMethod connect(final HttpClient httpclient, final String url) {
  
          final GetMethod httpget = new GetMethod(url);
          try {
  
              httpclient.executeMethod(httpget);
  
          } catch (final UnknownHostException e) {
              throw new RuntimeException("Connection ERROR - Host could not be determined.", e);
          } catch (final IOException e) {
              throw new RuntimeException("Connection ERROR - Input/Output error.", e);
          }
          return httpget;
      }
  
  }
  </code></pre>
  
  <p>The steps I accomplished with the help of <strong>owlstead</strong> are in the answer below.
  When I use this Java program to encode the string <strong>Password01</strong> I obtain a string like:</p>
  
  <pre><code>sy5/XElHvuYA4Rbq8OBydLymT82R+z77jy6MU2sNal7VenzPEbARgy7p3zWgYgG13Cypk+zbnnB5L37fVUhgOgCqCyLtikzxJBNmPyzUK9+beiHJKyONZwifDzQ44hXTeXcZ0bmF9b5dLFy9QS/N5m28vIyBSGY8K2B7EB2FF38=  
  </code></pre>
  
  <p>This encrypted password can be decrypted on Java side  </p>
  
  <p>When I use the .NET code the string is like:</p>
  
  <pre><code>ACZXYj/KudyxKBB510SxSouKaVwssmEUM6Jpreh8jTtrIH9eGb18GIdkBU7rXzMuLYbAhyREbFLbR87zW/2DNa4tN97FOlqr6k1JppJ/SSS/9fGdMvSOAQbWjsxksDH7fRu9dCvK0m0exFtGfXG7Yua9bB1m0dTNiwCZUZM0LnEM  
  </code></pre>
  
  <p>This encrypted password failed to be decrypted on Java side. Failed with the error message:</p>
  
  <pre><code>javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes
  </code></pre>