tink icon indicating copy to clipboard operation
tink copied to clipboard

No matching key found for the ciphertext in the stream.

Open sanketmthakare opened this issue 4 years ago • 16 comments

Hi, I am using jetpack security encryption library for encrypting the file. I have generate Master Key with below code.

MasterKey masterKey = null; try { masterKey = new MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build(); } catch (GeneralSecurityException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }

I have encrypted my text file Sample.txt and write encrypted file to device external storage. The code as given below.

InputStream inputStream = new BufferedInputStream(appCtx.getAssets().open("Sample.txt")); byte[] fileBytes=new byte[inputStream.available()]; inputStream.read(fileBytes); File file = new File(Environment.getExternalStorageDirectory(), "Sample.txt"); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { EncryptedFile encryptedFile = new EncryptedFile.Builder( appCtx, file, masterKey, EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB ).build(); OutputStream outputStream = encryptedFile.openFileOutput(); outputStream.write(fileBytes); outputStream.flush(); outputStream.close();

I put encrypted file in asset folder and now trying to decrypt but as per documentation EncryptedFile.Builder always have file Object as parameter and currently i have Inputstream after reading file from asset. So, to get file object i am writing this Inutstream to external storage as Temp.txt and passing this file for decryption. But I am getting exception as java.io.IOException: No matching key found for the ciphertext in the stream.

The code for decryption as follows:

InputStream myInputstream = new BufferedInputStream(appCtx.getAssets().open("Sample.txt")); File enfile = createFileFromInputStream(myInputstream,appCtx); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { EncryptedFile encryptedFile = new EncryptedFile.Builder( appCtx, enfile, masterKey, EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB ).build(); InputStream inputStream1 = encryptedFile.openFileInput(); BufferedOutputStream os1 = new BufferedOutputStream( new FileOutputStream(new File(dstPath))); int length = 0; byte[] buffer = new byte[1024]; while ((length = inputStream1.read(buffer)) != -1) { os1.write(buffer, 0, length); } os1.close(); }

private static File createFileFromInputStream(InputStream stream, Context context) {
        File f = new File(Environment.getExternalStorageDirectory(), "Temp.txt");
        BufferedOutputStream os1 = null;
        try {
            os1 = new BufferedOutputStream( new FileOutputStream(f));
            int length = 0;
            byte[] buffer = new  byte[1024];
            while ((length = stream.read(buffer)) != -1) {
                os1.write(buffer, 0, length);
            }
            os1.close();
            stream.close();
            return f;
    } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            //Logging exception
        }

    return null;
}

Scenario: If write encrypted file to external storage and read it for decryption directly from external storage, then everything is working file. But If i paste encrypted file in asset folder and write Inputstream getting from asset folder to some temporary file and then try to decrypt it is giving error java.io.IOException: No matching key found for the ciphertext in the stream.

please anyone help me with this issue. Thanks

sanketmthakare avatar Jul 25 '20 21:07 sanketmthakare

@tholenst @chuckx

Acknowledged. I haven't got cycles to take a closer look, CC a few folks who might be able to assist.

thaidn avatar Aug 14 '20 02:08 thaidn

encrypt an decrypt should use same KeysetHandle and ADD..

YangLang116 avatar Oct 17 '20 05:10 YangLang116

Update: I know what was wrong. I forgot to flush the output when writing. After adding it, everything works.

@1004145468 What do you mean by same KeysetHandle and ADD? I'm having the same issue, although I'm reading and saving files.

Here is my code for saving:

fun save(context: Context, name: String, dir: String, source: Any) : Boolean {
    var realName = name
    val masterKeyAlias = MasterKey.Builder(
            context, MasterKey.DEFAULT_MASTER_KEY_ALIAS)
            .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
            .build()
    var file = File(context.filesDir.path + dir, realName)

    // Check if file doesn't yet exist and change filename if necessary
    var changes: Boolean
    do {
        changes = false
        if (file.exists()) {
            realName += ".1"
            file = File(context.filesDir.path + dir, realName)
            changes = true
        }
    } while (changes)

    // Create missing directories
    if (!file.parentFile!!.exists()) {
        file.parentFile!!.mkdirs()
    }

    val encryptedFile = EncryptedFile.Builder(
            context,
            file,
            masterKeyAlias,
            EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
    ).build()

    val encryptedOutputStream = encryptedFile.openFileOutput()
    val objectOutputStream = ObjectOutputStream(encryptedOutputStream)
    objectOutputStream.writeObject(source)

    // Added this
    // Close streams
    objectOutputStream.close()
    encryptedOutputStream.flush()
    encryptedOutputStream.close()

    return true
}

And here is how I'm reading it:

fun get(context: Context, dir: String) : Array<Any> {
    val directory = File(context.filesDir.path + dir)

    if (directory.exists() && directory.isDirectory) {
        val files = directory.listFiles()
        val masterKeyAlias = MasterKey.Builder(
                context, MasterKey.DEFAULT_MASTER_KEY_ALIAS)
                .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
                .build()
        val list = mutableListOf<Any>()

        files?.forEach {
            ArchipelagoError.d(it.path)
            val encryptedFile = EncryptedFile.Builder(
                    context,
                    it,
                    masterKeyAlias,
                    EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
            ).build()

            val encryptedInputStream = encryptedFile.openFileInput()
            val objectInputStream = ObjectInputStream(encryptedInputStream)
            val sourceObject = objectInputStream.readObject()

            list.add(sourceObject)
        }

        return list.toTypedArray()
    } else {
        return arrayOf()
    }
}

It's in kotlin for Android of course

Edit: ~~Or is the issue that I'm using objectStreams and I should be writing and reading byteArrays?~~ It's not, I checked

Kwasow avatar Dec 27 '20 23:12 Kwasow

@Kwasow Thanks for that, it worked. I was having the same issue! :D

alejandro-ordonez avatar Jan 27 '21 17:01 alejandro-ordonez

@Kwasow As I can see you have read file from directory but the main issue is we are unable to read file from assets in android. When I tried to read, I got this issue 'No matching key found for the ciphertext in the stream' . I have copied the file from assets to filesDir to get the File object so that it can be passed to EncryptedFile.Builder constructor, but no luck. Can anyone help. Stuck in this issue from last 3 days. Thanks in advance.

mittalkartik1 avatar Feb 05 '21 19:02 mittalkartik1

Okay thanks, everyone. Finally got the solution. If anyone faces this same issue then make sure the following things:-

  1. Update to the latest version of the library.
  2. The file that will be copied from assets to the external files directory must have the same name as that of the original encrypted file at the time of encryption otherwise it will not work and throw the same error. (This point I was missing. After so many efforts I came to know this. Maybe this is a kind of bug or maybe not.)

mittalkartik1 avatar Feb 06 '21 18:02 mittalkartik1

@mittalkartik1 @Kwasow Does this issue solved for you ? My Condition is below:

  1. Encrypt File using custom key alias
  2. Save file to external directory
  3. Uninstall and reinstall the same application.
  4. While reading the saved file with same key alias , i got this error " No matching key found for the ciphertext in the stream."

Any ideas ???

thangane avatar Mar 15 '21 14:03 thangane

@mittalkartik1 @Kwasow Does this issue solved for you ? My Condition is below:

  1. Encrypt File using custom key alias
  2. Save file to external directory
  3. Uninstall and reinstall the same application.
  4. While reading the saved file with same key alias , i got this error " No matching key found for the ciphertext in the stream."

Any ideas ???

If you're talking about an Android application then the accosiated key is stored in SharedPreferences and it is cleared on app uninstall, so there is no key to be found.

Kwasow avatar Mar 15 '21 14:03 Kwasow

@mittalkartik1 @Kwasow Does this issue solved for you ? My Condition is below:

  1. Encrypt File using custom key alias
  2. Save file to external directory
  3. Uninstall and reinstall the same application.
  4. While reading the saved file with same key alias , i got this error " No matching key found for the ciphertext in the stream."

Any ideas ???

If you're talking about an Android application then the accosiated key is stored in SharedPreferences and it is cleared on app uninstall, so there is no key to be found.

Is there a way to retrive the accosiated key from SharedPreferences ?

thangane avatar Mar 17 '21 04:03 thangane

@mittalkartik1 @Kwasow Does this issue solved for you ? My Condition is below:

  1. Encrypt File using custom key alias
  2. Save file to external directory
  3. Uninstall and reinstall the same application.
  4. While reading the saved file with same key alias , i got this error " No matching key found for the ciphertext in the stream."

Any ideas ???

This approach cannot be used in your case. If you clear app data or reinstall app, then encryption keys will be deleted and next time keys will regenerate. You can retrieve the keys from shared preferences, but if you store them somewhere else, then also they cannot be used as android will regenarate keys everytime on app install making old keys invalid. So, this approach can only be used if want to store encrypted data in file after app install and want to use that until app uninstall or clearing data. (In short for managing specific user session.)

mittalkartik1 avatar Mar 20 '21 14:03 mittalkartik1

I am getting the same error while decrypting the file. error happening in val fileInputStream = ObjectInputStream(encryptedFile.openFileInput())

`fun encryptFile(source: File, destination: File, applicationContext: Context) {
        val mainKey = MasterKey.Builder(applicationContext, MasterKey.DEFAULT_MASTER_KEY_ALIAS)
            .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
            .build()

        val encryptedFile = EncryptedFile.Builder(
            applicationContext,
            destination,
            mainKey,
            EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
        ).build()

        val fileOutputStream = encryptedFile.openFileOutput()
        val fileInputStream = FileInputStream(source)

        val buffer = ByteArray(1024)
        var read: Int
        while (fileInputStream.read(buffer).also { read = it } != -1) {
            fileOutputStream.write(buffer, 0, read)
        }

        fileInputStream.close()
        fileOutputStream.flush()
        fileOutputStream.close()
        source.delete()
        destination.renameTo(source)
}

fun decryptFile(source: File, destination: File, applicationContext: Context){
        val mainKey = MasterKey.Builder(applicationContext, MasterKey.DEFAULT_MASTER_KEY_ALIAS)
            .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
            .build()

        val encryptedFile = EncryptedFile.Builder(
            applicationContext,
            source,
            mainKey,
            EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
        ).build()

        val fileInputStream = ObjectInputStream(encryptedFile.openFileInput())
        val fileOutputStream = BufferedOutputStream(FileOutputStream(destination))

        val buffer = ByteArray(1024)
        var read: Int

        while (fileInputStream.read(buffer).also { read = it } != -1) {
            fileOutputStream.write(buffer, 0, read)
        }

        fileInputStream.close()
        fileOutputStream.flush()
        fileOutputStream.close()
        source.delete()
        destination.renameTo(source)
}`

kirankjolly avatar Jun 07 '21 13:06 kirankjolly

Okay thanks, everyone. Finally got the solution. If anyone faces this same issue then make sure the following things:-

  1. Update to the latest version of the library.
  2. The file that will be copied from assets to the external files directory must have the same name as that of the original encrypted file at the time of encryption otherwise it will not work and throw the same error. (This point I was missing. After so many efforts I came to know this. Maybe this is a kind of bug or maybe not.)

I am hit hard by this hidden behavior when upgrading androidx.security.

must have the same name as that of the original encrypted file at the time of encryption otherwise it will not work

In order to support API level 21, I updated my project with this alpha release:

androidx.security:security-crypto:1.1.0-alpha03

and migrate my code to use the new API with "MasterKey". Then my code began to fail, but only with reading part.

I have tried a lot of ways, only the above hint saved my day at last.

In the old code, I first create a temp file, save the content as encrypted in this temp file, and if all goes well, I will rename the temp file with a desired one.

This code path worked well with demo code from "androidx.security:security-crypto:1.0.0", but after the upgrade, it began to fail with "No matching key" exceptions.

Hint by the discussion here, I just left the file name unchanged after encryption, then the reading part works. Hopefully if the alpha version released, either the document can be updated to reflect this requirement, or the old behavior can be kept.

jerryrt avatar Aug 27 '21 10:08 jerryrt

Okay thanks, everyone. Finally got the solution. If anyone faces this same issue then make sure the following things:-

  1. Update to the latest version of the library.
  2. The file that will be copied from assets to the external files directory must have the same name as that of the original encrypted file at the time of encryption otherwise it will not work and throw the same error. (This point I was missing. After so many efforts I came to know this. Maybe this is a kind of bug or maybe not.)

Thank you! It saved me a lot of time.

coco2015224 avatar Oct 28 '21 07:10 coco2015224

I've recently encountered this problem but unlike others that have had this issue, I am not using the assets folder or moving the EncryptedFile between directories. I also cannot reproduce it but see it showing up occasionally in non-fatal crash logs.

Encrypting:

val fileToWrite = File(baseDir, UUID.randomUUID().toString())
            
val encryptedFile = EncryptedFile.Builder(
                context,
                fileToWrite,
                mainKey,
                EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB).build()

encryptedFile.openFileOutput().use {
                val inputStream = FileInputStream(file)
                inputStream.copyTo(it)
                it.flush()
            }

Decrypting:

val tmpFile = File(baseDir, "${UUID.randomUUID()}.pdf")

val encryptedFile = EncryptedFile.Builder(
                context,
                File(path),
                mainKey,
                EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
            ).build()

            encryptedFile.openFileInput().use { input ->
                FileOutputStream(tmpFile).use { output ->
                    input.copyTo(output)
                    output.flush()
                }
            }

The exception comes from the input.copyTo(output) line when decrypting.

Both methods use the same key and relative base path. Since I can't reproduce it I'm shooting in the dark -- does the file name for the file that it is being decrypted to need to be the same as what the encrypted file name was?

lucaventura avatar Mar 07 '22 18:03 lucaventura

On Mon, Mar 7, 2022, 10:53 AM Luca Ventura @.***> wrote:

I've recently encountered this problem but unlike others that have had this issue, I am not using the assets folder or moving the EncryptedFile between directories. I also cannot reproduce it but see it showing up occasionally in crash logs.

Encrypting:

`val fileToWrite = File(baseDir, UUID.randomUUID().toString()) val encryptedFile = EncryptedFile.Builder( context, fileToWrite, mainKey, EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB ).build()

    encryptedFile.openFileOutput().use {
        val inputStream = FileInputStream(file)
        inputStream.copyTo(it)
        it.flush()
    }`

Decrypting:

`val encryptedFile = EncryptedFile.Builder( context, File(path), mainKey, EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB ).build()

    encryptedFile.openFileInput().use { input ->
        FileOutputStream(tmpFile).use { output ->
            input.copyTo(output)
            output.flush()
        }
    }`

Both use the same key and relative base path. Since I can't reproduce it I'm shooting in the dark -- does the file name for the file that it is being decrypted to need to be the same as what the encrypted file name was?

Yes. If you move the file it won't be decrypted correctly.

— Reply to this email directly, view it on GitHub https://github.com/google/tink/issues/401#issuecomment-1061017946, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAB23HNNGR6UUCSXZBKRWDU6ZGA3ANCNFSM4PHUMTFQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you commented.Message ID: @.***>

thaidn avatar Mar 07 '22 21:03 thaidn

@thaidn The EncryptedFile is never actually moved though, it always stays in the same directory. Even when I decrypt it to a new file of the same name it doesn't resolve the issue (this is an extreme edge case right now, and is only happening like .1% of the time).

lucaventura avatar Mar 08 '22 16:03 lucaventura

There were some race conditions in the AndroidKeysetManager that have been fixed. I think if you use lastest version of androidx security crypto, 1.1.0-alpha06, https://developer.android.com/jetpack/androidx/releases/security#security-crypto-1.1.0-alpha06 the issue should hopefully be resolved.

juergw avatar May 11 '23 08:05 juergw