Google Cloud Storage management with Android - android

I'm using pliablematter simple-cloud-storage to manage uploads/downloads of files using Google Cloud Storage. But I'm not able to make it work, there's a property file with this content:
project.id=0000000000
application.name=Application Name
account.id=0000000000#developer.gserviceaccount.com
private.key.path=/var/key
I know my project.id, aplication name and account id but what should I put in private key path?? I generated and downloaded the service account private key but no matter which path location I always get java.io.FileNotFoundException
Moreover, where should I save private keys in Android applications?
Github project https://github.com/pliablematter/simple-cloud-storage
Please help! Thanks

I was able to solve this by copying the private key to an internal storage folder, then I put the path location in private.key.path
Don't know if this is the right way but it worked for me.

Here are the changed which you need to make after using that example to make it functional in android.
Download the private_key.p12 file from Google Console and put in Assets.
Save your cloudstorage.properties file in Assets as well.
Now make these method changes in CloudStorage class.
private Properties getProperties() throws Exception {
if (properties == null) {
properties = new Properties();
AssetManager manager = context.getAssets();
InputStream stream = manager.open("cloudstorage.properties");
try {
properties.load(stream);
} catch (IOException
e) {
throw new RuntimeException(
"cloudstorage.properties must be present in classpath",
e);
} finally {
if (stream != null)
stream.close();
}
}
return properties;
}
private Storage getStorage() throws Exception {
if (storage == null) {
HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
List<String> scopes = new ArrayList<>();
scopes.add(StorageScopes.DEVSTORAGE_FULL_CONTROL);
Credential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(
getProperties().getProperty(ACCOUNT_ID_PROPERTY))
.setServiceAccountPrivateKeyFromP12File(getPrivateKeyFile())
.setServiceAccountScopes(scopes).build();
storage = new Storage.Builder(httpTransport, jsonFactory,
credential).setApplicationName(
getProperties().getProperty(APPLICATION_NAME_PROPERTY))
.build();
}
return storage;
}
private File getPrivateKeyFile() {
File f = new File(context.getCacheDir() + “/my_private_key.p12");
if (!f.exists())
try {
InputStream is = context.getAssets().open(“private_key.p12");
FileOutputStream fos = new FileOutputStream(f);
byte[] buffer = new byte[4 * 1024];
int read;
while ((read = is.read(buffer)) != -1)
fos.write(buffer, 0, read);
fos.flush();
is.close();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.e("FILE", "FETCHED FILE:: " + f.getAbsolutePath() + " with data: " + f.length());
return f;
}

Related

No matching key found for the ciphertext in the stream Exception

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;
}
Main 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
This is android-crypto library internal implementation problem. Try to update to latest version, this helped me.

How to create a shared folder usable by my android app?

I've got a question that probably borders on opinion, but I've not any related questions or documentation that answers, so I feel like it's a fair one to ask.
I'm trying to build an android app which modifies music files, and what I'd like to do is have a shared folder so that the files and the results can be accessible and shared. I'd like it if it was among the other folders like Music, Downloads, Movies, etc, or even under Music since it's music related. However this seems like it's a security no no in Android, as after I've made something and put it in there I have to use an intent to access it again, where as I'd rather just be able to open the files and not have a permissions based fiasco. Maybe some type of symbolic link like in Linux that pointed to my apps internal folder could be used, but of this I'm still uncertain.
In any case, is there a way I should go about this? If so, are there some resources I could be pointed to?
Thank you in advance to anyone who takes this up!
Edit for CommonsWare:
I used the following to create the folder:
File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), APP_NAME);
And this to copy files from elsewhere to there:
public void copyFileToHomeDirectory(Uri uri)
{
try
{
ContentResolver contentResolver = getApplicationContext().getContentResolver();
String fileName = queryName(contentResolver, uri);
//Get file extension
String fileType = fileName.substring(fileName.length() - 4, fileName.length());
if(fileType.equalsIgnoreCase(MP3_EXTENSION))
{
String path = Environment.getExternalStorageDirectory() + APP_FOLDER;
InputStream in = contentResolver.openInputStream(uri);
File outputFile = new File(path + File.separator + fileName);
outputFile.createNewFile();
OutputStream out = new FileOutputStream(outputFile);
//First we crack open the file to copy it's contents:
byte[] buffer = new byte[KB_SIZE];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
in.close();
in = null;
// write the output file (You have now copied the file)
out.flush();
out.close();
out = null;
}
}
catch(FileNotFoundException fnfe)
{
Log.e(TAG, "FileNotFoundException");
Log.e(TAG, Log.getStackTraceString(fnfe));
}
catch(IOException ioe)
{
Log.e(TAG, "IOException");
Log.e(TAG, Log.getStackTraceString(ioe));
}
catch(Exception e)
{
Log.e(TAG, "General Exception");
Log.e(TAG, Log.getStackTraceString(e));
}
}
I've tried other methods that I've overwritten in the process, but accessing the files to be used again I need something like this:
public void openDirectory(View view)
{
// Choose a directory using the system's file picker.
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
// Provide read access to files and sub-directories in the user-selected
// directory.
//intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
//intent.addCategory(Intent.CATEGORY_OPENABLE);
// Optionally, specify a URI for the directory that should be opened in
// the system file picker when it loads.
//intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, uriToLoad);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*"); //use image/* for photos, etc.
//The result of this code will be calling the onActivityResult function below
startActivityForResult(intent, REQUEST_MUSIC_DIR);
}
Edit2:
I've reorganized the folders to what I think I should be doing so that I can work with the files freely, however, even in my internal cache storage (getCacheDir() + folder_name) either isn't letting me create the files (outputFile.createNewFile doesn't throw an error) or it isn't letting me open them when I go to get a directory listing.
Here's my code for creating the file:
String path = getCacheDir() + MY_SUB_FOLDER;
//uri is obtained through ACTION_OPEN_DOCUMENT intent
InputStream in = contentResolver.openInputStream(uri);
File outputFile = new File(path + "/" + fileName);
outputFile.createNewFile();
Log.i(TAG, "The new file's directory/path is: " + outputFile.getAbsolutePath());
//NOTE: This is returning /data/user/0/com.example.myapplication/cache/MY_SUB_FOLDER/file_name.mp3
OutputStream out = new FileOutputStream(outputFile);
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
in.close();
in = null;
out.flush();
out.close();
out = null;
This is my code for attempting to open and read these newly created files
File directory = new File(getCacheDir(), MY_SUB_FOLDER);
Log.i(TAG, "This is the directory we're trying to get the files from: " + directory.getAbsolutePath());
//NOTE: This returns /data/user/0/com.example.myapplication/cache/MY_SUB_FOLDER
File[] files = directory.listFiles();
if(files != null)
{
for(int i = 0; i < files.length; i++)
{
Log.d(TAG, "Files found: " + files[i].getAbsolutePath());
}
}
The files variable isn't null but it's length is 0 and no files are found.
Edit3:
I am catching the exceptions and logging any stack traces, which currently returns nothing.
catch(FileNotFoundException fnfe)
{
Log.i(TAG, "FileNotFoundException");
Log.i(TAG, Log.getStackTraceString(fnfe));
}
catch(IOException ioe)
{
Log.i(TAG, "IOException");
Log.i(TAG, Log.getStackTraceString(ioe));
}
catch(Exception e)
{
Log.i(TAG, "General Exception");
Log.i(TAG, Log.getStackTraceString(e));
}

File Copy Flutter Plugin in Android with Kotlin

Trying to create a Flutter plugin that copies an asset file to the native Application Documents Folder.
For iOS, I achieved this by the following code (see below).
However, since I do not have much knowledge of the Android architecture, I would like to know how my Android MethodChannel code should look like.
My Android part of this Flutter plugin needs to be in KOTLIN !
I need a file copy from the Android assets folder to the Documents Folder of Android - all this done inside the Flutter plugin and in Kotlin!
Again, I have iOS in Swift ready made. What is missing is the Android in Kotlin counter part. Do you have any help on this ?
.
Here is the working code for the iOS FlutterMethodChannel in Swift:
(i.e. it copies a file from the main-bundle to the Documents-Directory of the iPhone...)
import UIKit
private func copyFile(fileName: String) -> String {
let fileManager = FileManager.default
let documentsUrl = fileManager.urls(for: .documentDirectory,
in: .userDomainMask)
guard documentsUrl.count != 0 else {
return "Could not find documents URL"
}
let finalURL = documentsUrl.first!.appendingPathComponent(fileName)
if !( (try? finalURL.checkResourceIsReachable()) ?? false) {
let documentsURL = Bundle.main.resourceURL?.appendingPathComponent(fileName)
do {
try fileManager.copyItem(atPath: (documentsURL?.path)!, toPath: finalURL.path)
return "\(finalURL.path)"
} catch let error as NSError {
return "Couldn't copy file to final location! Error:\(error.description)"
}
} else {
return "\(finalURL.path)"
}
}
In Kotlin, I tried this - but it does not work at all....:(
import java.io.File
private fun copyFileTrial1(fileName: String): String {
File src = new File("../../assets/${fileName}");
File dst = new File("../../DocumentsFolder/${fileName}", src.getName());
FileInputStream inStream = new FileInputStream(src);
FileOutputStream outStream = new FileOutputStream(dst);
FileChannel inChannel = inStream.getChannel();
FileChannel outChannel = outStream.getChannel();
inChannel.transferTo(0, inChannel.size(), outChannel);
inStream.close();
outStream.close();
return "hello1"
}
Or I tried this - but again - completely without success :(
private fun copyFileTrial2(fileName: String): String {
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(fileName);
String outDir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/X/Y/Z/" ;
File outFile = new File(outDir, filenfileNameame);
out = new FileOutputStream(outFile);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch(IOException e) {
Log.e("tag", "Failed to copy asset file: " + fileName, e);
}
return "hello2"
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1){
out.write(buffer, 0, read);
}
}
I have finally found a solution to file copy issue in Kotlin !
It was especially helpful in achieving my very first Flutter plugin.
Here is the solution of the file-copy in Kotlin
import java.io.File
import java.io.InputStream
import io.flutter.util.PathUtils
private fun copyFile(fileName: String): String {
val assetStream: InputStream = mRegistrar.context().assets.open(fileName)
val appliationDocumentsFolderPath: String = PathUtils.getDataDirectory(mRegistrar.context())
val outputFilePath: String = appliationDocumentsFolderPath + "/" + fileName
if (!File(outputFilePath).exists()) {
File(outputFilePath).copyInputStreamToFile(assetStream)
}
return outputFilePath
}
private fun File.copyInputStreamToFile(inputStream: InputStream) {
inputStream.use { input ->
this.outputStream().use { fileOut ->
input.copyTo(fileOut)
}
}
}

Saving an DataItemAsset received from Android Wear

I'm relatively new to Android. I'm transferring a file from an Android Wear device to a phone, which I did through PutDataRequest. On the phone side I get a DataItemAsset which can provide me a file descriptor using Wearable.DataApi.getFdForAsset(). My question is how do I save this file to external storage?
Thank you!
Here's how I managed to upload a text file from an Android Wear watch to it's paired mobile phone. There may be a simpler way, but this is what worked for me.
(1) On the watch side, create a text file, and read it into an Asset which you can put through the DataApi:
public void SendTextFile()
{
// Get folder for output
File sdcard = Environment.getExternalStorageDirectory();
File dir = new File(sdcard.getAbsolutePath()+ "/MyAppFolder/");
if (!dir.exists()) {dir.mkdirs();} // Create folder if needed
final File file = new File(dir, "test.txt");
if (file.exists()) file.delete();
// Write a text file to external storage on the watch
try {
Date now = new Date();
long nTime = now.getTime();
FileOutputStream fOut = new FileOutputStream(file);
PrintStream ps = new PrintStream(fOut);
ps.println("Time = "+Long.toString(nTime)); // A value that changes each time
ps.close();
} catch (Exception e) {
}
// Read the text file into a byte array
FileInputStream fileInputStream = null;
byte[] bFile = new byte[(int) file.length()];
try {
fileInputStream = new FileInputStream(file);
fileInputStream.read(bFile);
fileInputStream.close();
} catch (Exception e) {
}
// Create an Asset from the byte array, and send it via the DataApi
Asset asset = Asset.createFromBytes(bFile);
PutDataMapRequest dataMap = PutDataMapRequest.create("/txt");
dataMap.getDataMap().putAsset("com.example.company.key.TXT", asset);
PutDataRequest request = dataMap.asPutDataRequest();
PendingResult<DataApi.DataItemResult> pendingResult = Wearable.DataApi
.putDataItem(mGoogleApiClient, request);
}
(2) On the mobile side, receive the asset and write it back out to a file:
public void onDataChanged(DataEventBuffer dataEvents) {
for (DataEvent event : dataEvents) {
if (event.getType() == DataEvent.TYPE_CHANGED &&
event.getDataItem().getUri().getPath().equals("/txt"))
{
// Get the Asset object
DataMapItem dataMapItem = DataMapItem.fromDataItem(event.getDataItem());
Asset asset = dataMapItem.getDataMap().getAsset("com.example.company.key.TXT");
ConnectionResult result =
mGoogleApiClient.blockingConnect(10000, TimeUnit.MILLISECONDS);
if (!result.isSuccess()) {return;}
// Convert asset into a file descriptor and block until it's ready
InputStream assetInputStream = Wearable.DataApi.getFdForAsset(
mGoogleApiClient, asset).await().getInputStream();
mGoogleApiClient.disconnect();
if (assetInputStream == null) { return; }
// Get folder for output
File sdcard = Environment.getExternalStorageDirectory();
File dir = new File(sdcard.getAbsolutePath() + "/MyAppFolder/");
if (!dir.exists()) { dir.mkdirs(); } // Create folder if needed
// Read data from the Asset and write it to a file on external storage
final File file = new File(dir, "test.txt");
try {
FileOutputStream fOut = new FileOutputStream(file);
int nRead;
byte[] data = new byte[16384];
while ((nRead = assetInputStream.read(data, 0, data.length)) != -1) {
fOut.write(data, 0, nRead);
}
fOut.flush();
fOut.close();
}
catch (Exception e)
{
}
// Rescan folder to make it appear
try {
String[] paths = new String[1];
paths[0] = file.getAbsolutePath();
MediaScannerConnection.scanFile(this, paths, null, null);
} catch (Exception e) {
}
}
}
}
You will also need to add the following permission to your manifests at both ends to write to external storage: android.permission.WRITE_EXTERNAL_STORAGE
Note: the most frustrating thing to watch out for is this: if the data does not change, no transfer will occur. So, when you're testing if you write the same data file contents twice, it will only come across the first time - even if you deleted the file from the first run. I lost quite a few hours to this insidious feature of the DataApi ! That's why my code above is writing the current time into the text file.
Also, of course make sure that you set up the GoogleApiClient object to connect, add listeners, etc as described here:
http://developer.android.com/training/wearables/data-layer/index.html

EACCES (Permission denied). Trying to access a file created by another application Android

I'm trying to read a file created by another Android application.
File file = new File("/data/data/air.br.com.screencorp.MobilePlayer/br.com.screencorp.MobilePlayer/Local Store/token");
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
Log.d("SIZE", "Total file size to read (in bytes) : "
+ fis.available());
int content;
StringBuilder token = new StringBuilder();
while ((content = fis.read()) != -1) {
token.append((char) content);
}
Log.d("TOKEN", token.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null)
fis.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
I don't know why, but I'm not allowed to access that file. I have the READ_EXTERNAL_STORAGE permission on my manifest.
Should I use SharedPreferences?
Thanks.
Data of other applications private data can not be accessed from your app. This is the security model of android. The app should have set MODE_WORLD_READABLE permission on the file, only then can you access the file

Categories

Resources