0

I Hope that you can help me related my code.

Im trying to pass parameters IV to Encrypt/ Decryt

Encrypt Funcion:

I try to concatenate text; IV

encryptedText.setText(Base64.encodeToString(vals, Base64.DEFAULT) + ";" + (Base64.encodeToString(encryptionIv, Base64.DEFAULT)));

I think that is working fine , as the image represents.

 public void encryptString(String alias) {
        try {

            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
            keyStore.load(null);
            SecretKey secretKey = (SecretKey) keyStore.getKey(alias, null);
            String initialText = startText.getText().toString();
            if(initialText.isEmpty()) {
                Toast.makeText(this, "Enter text in the 'Initial Text'", Toast.LENGTH_LONG).show();
                return;
            }
            Cipher inCipher = Cipher.getInstance("AES/GCM/NoPadding");

            inCipher.init(Cipher.ENCRYPT_MODE, secretKey);

            byte[] src= initialText.getBytes("UTF-8");

            byte[] iv = inCipher.getIV();
            assert iv.length == 12;
            byte[] cipherText = inCipher.doFinal(src);
            assert cipherText.length == src.length + 16;
            byte[] message = new byte[12 + src.length + 16];
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            CipherOutputStream cipherOutputStream = new CipherOutputStream(
                    outputStream, inCipher);
            cipherOutputStream.write(src);
            cipherOutputStream.close();
            byte [] vals = outputStream.toByteArray();
            encryptedText.setText(Base64.encodeToString(vals, Base64.DEFAULT));
        } catch (Exception e) {
            Toast.makeText(this, "Exception " + e.getMessage() + " occurred", Toast.LENGTH_LONG).show();
            Log.e(TAG, Log.getStackTraceString(e));
        }
    }

[![enter image description here][1]][1] Could you helpme with an example to get decryption works fine?

Thanks for youl help

Updated: Hello , Im trying to pass the IV as the example:

My code here:

 public void encryptString(String alias) {
        try {
            KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
            RSAPublicKey publicKey = (RSAPublicKey) privateKeyEntry.getCertificate().getPublicKey();

            String initialText = startText.getText().toString();
            if(initialText.isEmpty()) {
                Toast.makeText(this, "Enter text in the 'Initial Text' widget", Toast.LENGTH_LONG).show();
                return;
            }

            Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
            inCipher.init(Cipher.ENCRYPT_MODE, publicKey);

            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            CipherOutputStream cipherOutputStream = new CipherOutputStream(
                    outputStream, inCipher);
            cipherOutputStream.write(initialText.getBytes("UTF-8"));
            cipherOutputStream.close();

            byte [] vals = outputStream.toByteArray();
            encryptedText.setText(Base64.encodeToString(vals, Base64.DEFAULT));
        } catch (Exception e) {
            Toast.makeText(this, "Exception " + e.getMessage() + " occurred", Toast.LENGTH_LONG).show();
            Log.e(TAG, Log.getStackTraceString(e));
        }
    }

[![enter image description here][2]][2]

NEW Updated:

Encryption code

public void encryptString(String alias) {
        try {

            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
            keyStore.load(null);
            SecretKey secretKey = (SecretKey) keyStore.getKey(alias, null);
            String initialText = startText.getText().toString();
            if(initialText.isEmpty()) {
                Toast.makeText(this, "Enter text in the 'Initial Text'", Toast.LENGTH_LONG).show();
                return;
            }
            Cipher inCipher = Cipher.getInstance("AES/GCM/NoPadding");

            inCipher.init(Cipher.ENCRYPT_MODE, secretKey);

            byte[] src= initialText.getBytes("UTF-8");
            byte[] iv = inCipher.getIV();
            assert iv.length == 12;
            byte[] cipherText = inCipher.doFinal(src);
            assert cipherText.length == src.length + 16;
            byte[] message = new byte[12 + src.length + 16];
            System.arraycopy(iv, 0, message, 0, 12);
            System.arraycopy(cipherText, 0, message, 12, cipherText.length);
            //ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            //CipherOutputStream cipherOutputStream = new CipherOutputStream(
              //      outputStream, inCipher);
            //cipherOutputStream.write(message);
            //cipherOutputStream.close();
            //byte [] vals = outputStream.toByteArray();
            encryptedText.setText(Base64.encodeToString(message, Base64.DEFAULT));
        } catch (Exception e) {
            Toast.makeText(this, "Exception " + e.getMessage() + " occurred", Toast.LENGTH_LONG).show();
            Log.e(TAG, Log.getStackTraceString(e));
        }
    }

Decryption code: ( Not working)

public void decryptString(String alias) {
        try {

            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
            keyStore.load(null);
            SecretKey secretKey = (SecretKey) keyStore.getKey(alias, null);
            String cipherText = encryptedText.getText().toString();

            byte[] src = cipherText.getBytes();
            byte[] message = new byte[12 + src.length + 16];
            Cipher output = Cipher.getInstance("AES/GCM/NoPadding");
            GCMParameterSpec params = new GCMParameterSpec(128, message, 0, 12);
            output.init(Cipher.DECRYPT_MODE, secretKey, params);
          //  output.doFinal(message, 12, message.length - 12);



            CipherInputStream cipherInputStream = new CipherInputStream(
             new ByteArrayInputStream(Base64.decode(cipherText, Base64.DEFAULT)), output);
            ArrayList<Byte> values = new ArrayList<>();
           int nextByte;
           while ((nextByte = cipherInputStream.read()) != -1) {
                values.add((byte)nextByte);
            }

          byte[] bytes = new byte[values.size()];
         for(int i = 0; i < bytes.length; i++) {
            bytes[i] = values.get(i).byteValue();
         }

            String finalText = new String(bytes, 0, bytes.length, "UTF-8");
            decryptedText.setText(finalText);

        } catch (Exception e) {
            Toast.makeText(this, "Exception " + e.getMessage() + " occurred", Toast.LENGTH_LONG).show();
            Log.e(TAG, Log.getStackTraceString(e));
        }
    }

Could you help me with the error shows in the image?

[![enter image description here][3]][3]

<<---UPDATED SOLUTION-->

Encript function:

 public void encryptString(String alias) {
        try {
            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
            keyStore.load(null);
            SecretKey secretKey = (SecretKey) keyStore.getKey(alias, null);
            String initialText = startText.getText().toString();
            if(initialText.isEmpty()) {
                Toast.makeText(this, "Enter text in the 'Initial Text'", Toast.LENGTH_LONG).show();
                return;
            }
            Cipher inCipher = Cipher.getInstance("AES/GCM/NoPadding");
            inCipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] src= initialText.getBytes("UTF-8");
            byte[] iv = inCipher.getIV();
            assert iv.length == 12;
            byte[] cipherText = inCipher.doFinal(src);
            assert cipherText.length == src.length + 16;
            byte[] message = new byte[12 + src.length + 16];
            System.arraycopy(iv, 0, message, 0, 12);
            System.arraycopy(cipherText, 0, message, 12, cipherText.length);
            encryptedText.setText(Base64.encodeToString(message, Base64.DEFAULT));
        } catch (Exception e) {
            Toast.makeText(this, "Exception " + e.getMessage() + " occurred", Toast.LENGTH_LONG).show();
            Log.e(TAG, Log.getStackTraceString(e));
        }
    }

Decrypt Function:

    public void decryptString(String alias) {
        try {

            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
            keyStore.load(null);
            SecretKey secretKey = (SecretKey) keyStore.getKey(alias, null);
            String cipherText = encryptedText.getText().toString();
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            byte[] nonceCiphertextTag = Base64.decode(cipherText, Base64.DEFAULT);
            GCMParameterSpec params = new GCMParameterSpec(128, nonceCiphertextTag, 0, 12);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, params);
            byte[] decrypted = cipher.doFinal(nonceCiphertextTag, 12, nonceCiphertextTag.length - 12);
            String finalText = new String(decrypted, 0, decrypted.length, "UTF-8");
            decryptedText.setText(finalText);
        } catch (Exception e) {
            Toast.makeText(this, "Exception " + e.getMessage() + " occurred", Toast.LENGTH_LONG).show();
            Log.e(TAG, Log.getStackTraceString(e));
        }
    }

Thanks a lot for the help @Topaco

Xshell
  • 25
  • 6
  • `encryptedText.getText()` seems to be just a string with two Base64 encoded parts separated by a semicolon. Why can't you separate them, e.g. with `split()`? Then you can Base64 decode the two parts and process/apply them. – Topaco Sep 10 '21 at 11:13
  • 1
    Regarding the use of the IV for decryption take a look [here](https://stackoverflow.com/q/31851612/9014097). You essentially create a `GCMParameterSpec()` which encapsulates the IV and which is passed as 3rd parameter to `cipher.init()`. – Topaco Sep 10 '21 at 11:18
  • 1
    By the way, the linked example also shows a more efficient concatenation, namely on byte level. Here, no separator is required because the separation is based on the known lengths (e.g. 12 bytes for the IV/nonce in the context of GCM). – Topaco Sep 10 '21 at 11:31

1 Answers1

1

In the latest posted encryption code, nonce, ciphertext and tag are concatenated and Base64 encoded, in the following called nonceCiphertextTagB64.

When decrypting

  • nonceCiphertextTagB64 must first be Base64 decoded to nonceCiphertextTag,
  • the nonce must be encapsulated in a GCMParameterSpec instance; the nonce are the first 12 bytes of nonceCiphertextTag,
  • a cipher instance for AES/GCM/NoPadding must be created, which is initialized with the key and the GCMParameterSpec instance in decryption mode,
  • the concatenation of ciphertext and tag is decrypted; the concatenation of ciphertext and tag is the data after the nonce.

In the following example implementation, with respect to a repro, the 32 bytes key 01234567890123456789012345678901 is used (instead of a key from the key store). The ciphertext was created with the posted code for encryption using the same key and the plaintext The quick brown fox jumps over the lazy dog:

...
String nonceCiphertextTagB64 =
        "UpyxMnzPrw+zJGANL4wBbaC+UX5KnMKYwhR0u2iF/GDCcU38YKWlvJp1zJ+mrN0POP7lz9y+eweH\n" +
        "vIxAH4R4U3At8T0fVe0=";
SecretKeySpec secretKey = new SecretKeySpec("01234567890123456789012345678901".getBytes(StandardCharsets.UTF_8),"AES");
byte[] nonceCiphertextTag = Base64.decode(nonceCiphertextTagB64, Base64.DEFAULT);
GCMParameterSpec params = new GCMParameterSpec(128, nonceCiphertextTag, 0, 12);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, params);
byte[] decrypted = cipher.doFinal(nonceCiphertextTag, 12, nonceCiphertextTag.length - 12);
System.out.println(new String(decrypted, StandardCharsets.UTF_8)); // The quick brown fox jumps over the lazy dog
... 

The output is:

The quick brown fox jumps over the lazy dog
Topaco
  • 40,594
  • 4
  • 35
  • 62