Java.Lang.UnsupportedOperationException: 'For encrypted files, please open the relevant FileInput/FileOutputStream.'
Version Information
- Visual Studio version (eg. 16.8 or 8.8): 16.11.3
- Xamarin.Android version (eg. 11.1): 11.4.0.5
- Using AndroidX or Support Libraries: Xamarin.Android.Support.Design 27.0.2.1 Xamarin.Android.Support.v4 27.0.2.1 Xamarin.Android.Support.v7.AppCompat 27.0.2.1 Xamarin.Android.Support.v7.CardView 27.0.2.1 Xamarin.Android.Support.v7.MediaRouter 27.0.2.1 Xamarin.AndroidX.AppCompat.Resources 1.1.0 Xamarin.AndroidX.Arch.Core.Runtime 2.1.0.8 Xamarin.AndroidX.Legacy.Support.V4 1.0.0.7 Xamarin.AndroidX.MediaRouter 1.2.4 Xamarin.AndroidX.Palette 1.0.07 Xamarin.AndroidX.Security.SecurityCrypto 1.0.0.3
- If Support Libraries, version (eg 28.0.0): 27.0.2.1
Describe your Issue:
When trying to open encrypted stream to read file with AndroidX.Security.Crypto.EncryptedFile.OpenFileInput() exception Java.Lang.UnsupportedOperationException with message: 'For encrypted files, please open the relevant FileInput/FileOutputStream.' is thrown
Steps to Reproduce (with link to sample solution if possible):
string masterKeyAlias = MasterKeys.GetOrCreate(MasterKeys.Aes256GcmSpec);
Java.IO.File file = new File(Android.App.Application.Context.FilesDir, Settings.Settings.DataFileName);
bool fileExists = file.Exists();
if (fileExists)
{
file.Delete();
}
AndroidX.Security.Crypto.EncryptedFile.Builder builder = new EncryptedFile.Builder(
file,
Android.App.Application.Context,
masterKeyAlias,
EncryptedFile.FileEncryptionScheme.Aes256GcmHkdf4kb);
AndroidX.Security.Crypto.EncryptedFile encryptedFile = builder.Build();
using (System.IO.Stream output = encryptedFile.OpenFileOutput())
{
await output.WriteAsync(Encoding.UTF8.GetBytes("Just sample text"));
}
using (System.IO.Stream input = encryptedFile.OpenFileInput())
{
int notReachable = input.ReadByte();
}
Include any relevant Exception Stack traces, build logs, adb logs:
at Java.Interop.JniEnvironment+InstanceMethods.CallObjectMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x0006e] in <bd6bd528a8784b7caf03e9f25c9f0d7b>:0
at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeVirtualObjectMethod (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x0002a] in <bd6bd528a8784b7caf03e9f25c9f0d7b>:0
at Java.IO.FileInputStream.get_Channel () [0x00000] in /Users/builder/azdo/_work/1/s/xamarin-android/src/Mono.Android/obj/Release/monoandroid10/android-30/mcw/Java.IO.FileInputStream.cs:160
at Android.Runtime.InputStreamInvoker..ctor (Java.IO.InputStream stream) [0x00025] in /Users/builder/azdo/_work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/InputStreamInvoker.cs:21
at (wrapper remoting-invoke-with-check) Android.Runtime.InputStreamInvoker..ctor(Java.IO.InputStream)
at Android.Runtime.InputStreamInvoker.FromJniHandle (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer) [0x00035] in /Users/builder/azdo/_work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/InputStreamInvoker.cs:168
at AndroidX.Security.Crypto.EncryptedFile.OpenFileInput () [0x00018] in D:\a\1\s\generated\androidx.security.security-crypto\obj\Release\monoandroid9.0\generated\src\AndroidX.Security.Crypto.EncryptedFile.cs:223
at ProactisMobileApp.Data.ExpenseData.WriteDataFile (System.String text) [0x00227] in D:\Work\Projects\Proactis\MobileApp\ProactisMobileApp\ProactisMobileApp\ProactisMobileApp\Data\ExpenseData.cs:324
--- End of managed Java.Lang.UnsupportedOperationException stack trace ---
java.lang.UnsupportedOperationException: For encrypted files, please open the relevant FileInput/FileOutputStream.
at androidx.security.crypto.EncryptedFile$EncryptedFileInputStream.getChannel(EncryptedFile.java:319)
at mono.java.lang.RunnableImplementor.n_run(Native Method)
at mono.java.lang.RunnableImplementor.run(RunnableImplementor.java:30)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:235)
at android.app.ActivityThread.main(ActivityThread.java:7441)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
Tried to investigate the issue. Have a guess that it is connected to mapping of Java androidx.security.crypto.EncryptedFile.openFileOutput() return type from FileInputStream to System.IO.Stream. Somewhere in initialization it calls FileInputStream.getChannel() that throws the exception.
But FileInputStream.getChannel() looks like this:
@Override
public FileChannel getChannel() {
throw new UnsupportedOperationException("For encrypted files, please open the "
+ "relevant FileInput/FileOutputStream.");
}
Are you using Android.Support?
Tried to investigate the issue. Have a guess that it is connected to mapping of Java
androidx.security.crypto.EncryptedFile.openFileOutput()return type fromFileInputStreamtoSystem.IO.Stream. Somewhere in initialization it callsFileInputStream.getChannel()that throws the exception. ButFileInputStream.getChannel()looks like this:@Override public FileChannel getChannel() { throw new UnsupportedOperationException("For encrypted files, please open the " + "relevant FileInput/FileOutputStream."); }
True. So, this is not issue with the bindings.
You need to see what must be done in java or kotlin (native) and then port that code. This exception would happen with java or kotlin.
this is not issue with the bindings.
I thought that the issue is in mapping to general System.IO.Stream class instead more specific one (that is used in native).
You need to see what must be done in java or kotlin (native) and then port that code.
That's exactly what I've tried to do.
In java/kotlin call of androidx.security.crypto.EncryptedFile.openFileOutput() does not lead to call of FileInputStream.getChannel(). But in C# it does.
From android documentation sample usage is: https://developer.android.com/reference/androidx/security/crypto/EncryptedFile
String masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC);
File file = new File(context.getFilesDir(), "secret_data");
EncryptedFile encryptedFile = EncryptedFile.Builder(
file,
context,
masterKeyAlias,
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build();
// write to the encrypted file
FileOutputStream encryptedOutputStream = encryptedFile.openFileOutput();
// read the encrypted file
FileInputStream encryptedInputStream = encryptedFile.openFileInput();
So, as you can see in steps to reproduce, I tried to do the same in my code (just added small file existence check, usings and explicit types), but opening the file always throws this exception.
Maybe you could introduce FileInputStream class, similar to native one with no getChannel() call on file open?
Are you using Android.Support?
Yes, we use some:
Xamarin.Android.Support.Design 27.0.2.1 Xamarin.Android.Support.v4 27.0.2.1 Xamarin.Android.Support.v7.AppCompat 27.0.2.1 Xamarin.Android.Support.v7.CardView 27.0.2.1 Xamarin.Android.Support.v7.MediaRouter 27.0.2.1
I'm running into the same issue with the latest 1.1.0-alpha05.