-1

I am trying to implement AES/GCM/NoPadding encryption and decryption in JAVA .. the key used is a shared key from the public key of the receiver and the private key of the sender (ECDH).. encryption works well (with and without iv). However, I am unable to decrypt...

I get the exception: javax.crypto.BadPaddingException: mac check in GCM failed

public static String encryptString(SecretKey key, String plainText) throws NoSuchProviderException, NoSuchAlgorithmException, NoSuchPaddingException, UnsupportedEncodingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {

        //IvParameterSpec ivSpec = new IvParameterSpec(iv);
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");//AES/ECB/PKCS5Padding //"AES/GCM/NoPadding", "BC"
        byte[] plainTextBytes = plainText.getBytes("UTF-8");
        byte[] cipherText;

        //cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);

        cipher.init(Cipher.ENCRYPT_MODE, key);
        return new String(Base64.getEncoder().encode(cipher.doFinal(plainTextBytes)));
      }



           public static String decryptString(SecretKey key, String 
          cipherText) throws NoSuchProviderException, 
          NoSuchAlgorithmException, NoSuchPaddingException, 
          InvalidKeyException, InvalidAlgorithmParameterException, 
          IllegalBlockSizeException, BadPaddingException, 
          UnsupportedEncodingException, ShortBufferException {


        Key decryptionKey = new SecretKeySpec(key.getEncoded(),
                key.getAlgorithm());
       IvParameterSpec ivSpec = new IvParameterSpec(ivString.getBytes("UTF-8"));
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");//AES/GCM/NoPadding", "BC");

        cipher.init(Cipher.DECRYPT_MODE, decryptionKey, ivSpec);
        return new String (Base64.getEncoder().encode(cipher.doFinal(Base64.getDecoder().decode(cipherText.getBytes()))));

    }
Haya Raed
  • 5,921
  • 5
  • 16
  • 19

2 Answers2

2

You must use exactly the same IV for encryption and decryption of the same ciphertext and it must be different for each encryption that produces different ciphertexts. The IV is not secret, so you can send it along with the ciphertext. Usually, it is simply prepended to the ciphertext and sliced off before decryption.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • That may not be the full answer, but it's a start. I don't know how the authentication tag is handled for GCM mode in Java. – Artjom B. May 22 '17 at 17:09
  • It's deemed part of the ciphertext and it will therefore throw an instance of (a class derived from) `BadPaddingException`. This is ugly as hell and is one of the worst design decisions for AEAD ciphers. Then again, for some godforsaken reason, it has been standardized in [RFC 5116](https://tools.ietf.org/html/rfc5116) - showing that bad practices do get standardized as well. – Maarten Bodewes May 22 '17 at 20:59
0

You need to supply an instance of GCMParameterSpec (which includes the IV) for both of the Cipher.init calls. As has already been pointed out, the IV has to be the same for both encryption and decryption, and must be unique.

BSM
  • 1