I'm working in Android, developping an app in which I'm uploading files to dropbox. As i don't want the title of this files to be seen, i'm encrypting them and the enccoding the result bytearray. The problem is that when you use the sentences:
String fileNameEncrypted = Base64.encodeToString(encrypted, Base64.DEFAULT);
File file = new File(mDirectoryPath + "/" + fileNameEncrypted);
The string "fileNameEncrypted" contains forward and back slashes and maybe other characters that are not allowed for a file name. Besides, the forward slashes are confused with subfolders.
How could I solve this problem?
PS: my goal is the filename can't be read in the dropbox app.
[EDIT the whole message according to comments]
Because base64 encode use special char (/) and lower/upper case char, it's seems to not be very compliant with filename for some OS like windows. Where file "aaa.txt" is equals to "AAA.txt".
Even the safe mode of base64 use lower and upper case charset.
The ASCII hex format (base16) provides a more compliant charset 0-9 A-F for store byte array
the char 'A' = 0x41 in base16. You can wrote this as "41"
A more complete example
"test.txt" can be translate to : 746573742E747874
If you need to really hide the name you can combine the encoding with a hash function. Because hash is a one way function you will definitely hide the filename, but you will not be capable to recover the real name from this.
If you need a two way function you can use a simple crypto method like aes with a internal key
You can use the Guava library to perform the transformation on base16 or base32 who has a more compliant charset than base64 for windows.
byte[] encrypted = "test.txt".getBytes();
BaseEncoding encoder = BaseEncoding.base16().lowerCase();
String newFilename = encoder.encode(encrypted);
If you want to use base32 juste change the encoder.
You can use the base64 encoder in filename safe mode with
Base64.encodeToString(encrypted, Base64.URL_SAFE)
Documentation:
Encoder/decoder flag bit to indicate using the "URL and filename safe" variant of Base64 (see RFC 3548 section 4) where - and _ are used in place of + and /.
Related
I'm creating files in my app with '{' and '}' in the filename (e.g. {foo}.xml). However, the special characters are being replaced with the ASCII hex values instead (i.e. {foo}.xml is created as %7Bfoo%7D.xml). Any thoughts on how to get around this and have it actually create '{foo}.xml' ?
new File("/sdcard/{file name}.xml").createNewFile() successfully creates a file with name "{file name}.xml" on SD card in my case.
new File(context.getFilesDir() + "/{file name}.xml").createNewFile() successfully creates such file in private app files area.
I checked that all right using ADB shell and file explorer.
I'm using mp4parser to mux h264 and aac file which are re-encoded from orginal video file,how can I write the metadata of the original video to the new mp4 file? Or is there a common method to write metadata to mp4 file?
metadata and MP4 is a really problem. There is no generally supported specification. But this is only one part of the problem.
Prob (1): When to write metadata
Prob (2): What to write
Prob (1) is relatively easy to solve: Just extend the DefaultMp4Builder or the FragmentedMp4Builder on your own and override the
protected ParsableBox createUdta(Movie movie) {
return null;
}
with something meaningful. E.g.:
protected ParsableBox createUdta(Movie movie) {
UserDataBox udta = new UserDataBox();
CopyrightBox copyrightBox = new CopyrightBox();
copyrightBox.setCopyright("All Rights Reserved, me, myself and I, 2015");
copyrightBox.setLanguage("eng");
udta.addBox(copyrightBox);
return udta;
}
some people used that to write apple compatible metadata but even though there are some classes in my code I never really figured out what works and what not. You might want to have a look into Apple's specification here
And yes: I'm posting this a year to late.
It seems that the 'mp4parser' library (https://code.google.com/p/mp4parser/), supports writing Metadata to mp4 files in Android. However, I've found there's little-to-no documentation on how to do this, beyond a few examples in their codebase. I've had some luck with the following example, which writes XML metadata into the 'moov/udta/meta' box:
https://github.com/copiousfreetime/mp4parser/blob/master/examples/src/main/java/com/googlecode/mp4parser/stuff/ChangeMetaData.java
If you consider the alternatives you might want to look at JCodec for this purpose. It now has the org.jcodec.movtool.MetadataEditor API (and a matching CLI org.jcodec.movtool.MetadataEditorMain).
Their documentation contains many samples: http://jcodec.org/docs/working_with_mp4_metadata.html
So basically when you want to add some metadata you need to know what key(s) it corresponds to. One way to find out is to inspect a sample file that already has the metadata you need. For this you can run the JCodec's CLI tool that will just print out all the existing metadata fields (keys with values):
./metaedit <file.mp4>
Then when you know the key you want to work with you can either use the same CLI tool:
# Changes the author of the movie
./metaedit -f -si ©ART=New\ value file.mov
or the same thing via the Java API:
MetadataEditor mediaMeta = MetadataEditor.createFrom(new
File("file.mp4"));
Map<Integer, MetaValue> meta = mediaMeta.getItunesMeta();
meta.put(0xa9415254, MetaValue.createString("New value")); // fourcc for '©ART'
mediaMeta.save(false); // fast mode is off
To delete a metadata field from a file:
MetadataEditor mediaMeta = MetadataEditor.createFrom(new
File("file.mp4"));
Map<Integer, MetaValue> meta = mediaMeta.getItunesMeta();
meta.remove(0xa9415254); // removes the '©ART'
mediaMeta.save(false); // fast mode is off
To convert string to integer fourcc you can use something like:
byte[] bytes = "©ART".getBytes("iso8859-1");
int fourcc =
ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getInt();
If you want to edit/delete the android metadata you'll need to use a different set of fucntion (because it's stored differently than iTunes metadata):
./metaedit -sk com.android.capture.fps,float=25.0 file.mp4
OR alternatively the same through the API:
MetadataEditor mediaMeta = MetadataEditor.createFrom(new
File("file.mp4"));
Map<String, MetaValue> meta = mediaMeta.getKeyedMeta();
meta.put("com.android.capture.fps", MetaValue.createFloat(25.));
mediaMeta.save(false); // fast mode is off
When i save a pdf file in my android from my application.
I use Zip4J Library to unzip the file that i download, and then, save the pdf file in android folder.
The pdf files that have accents (special characters) appears like:
é = ╠ü
â = ╠é
and so on.
You know what is the charset of these files and why are they been saved like this?
Looks like UTF-8 octets displayed as DOS code page 850:
╠ is 0xcc in cp850
ü is 0x81 in cp850
UTF-8 octets cc 81 are combining acute accent and if preceded by e, it will make it é
Similarly the ̂ makes up to a combining circumflex accent.
So the data seems to be saved all right as UTF-8. You are just displaying it incorrectly.
I'm trying to generate filenames in my Android app from a 4 byte byte array. I'm Base64 encoding the byte array with the URL_SAFE option. However, the generated string seems to end with a newline character, which makes it unusable as a filename. Is there anyway to remove the newline?
My code is as follows:
byte[] myByteArray = new byte[4];
myByteArray = generateBytes(myByteArray); // fills the byte array with some data
final String byteString = Base64.encodeToString(myByteArray, Base64.URL_SAFE);
After some googling, I found out that in Android, Base64 encoding automatically inserts a newline after the string, and that using the NO_WRAP flag would solve this. However, is the NO_WRAP flag generated output filename safe?
Thanks.
OK, turns out I can use (Base64.URL_SAFE | Base64.NO_WRAP) to apply both flags.
I'm working on an app that among other things plays sound files. My problem is the sound files are encrypted with a command line tool that can be found on aescrypt.com just providing the file and a password. I have used the java-code on aescrypt.com to successfully decrypt the files in the android app but I can't for the life of me not get it to work in iOS.
I have tried to decrypt all the bytes of the file and the bytes that does not include the header of the file. I get a result set of bytes back but it won't play and the estimated length of the sound is about one fourth of the actual length.
NSRange range = NSMakeRange(0, self.length);
unsigned char* encrypteddata = malloc(range.length);
[self getBytes:encrypteddata range:range];
size_t outSize;
unsigned char* result = malloc(range.length + 16);
CCCryptorStatus status = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, 0x00, decryptkey, sizeof(decryptkey), nil, encrypteddata, self.length, result, self.length + 16, &outSize);
NSData *returnData = nil;
if (status == kCCSuccess) {
returnData = [NSData dataWithBytesNoCopy:result length:outSize];
}
The decryptkey is just the bytes from the password used to encrypt the file.
I have been working on a solution for at least a week now and not made any progress. There are so many things that can be done wrong and so many possible (and impossible) combinations.
Update:
What I need is a tool that is simple enough for our customer to use to encrypt the sound files on their end and also is simple for the apps both on Android and iOS to decrypt on the other end. It does not need to be very secure, it only needs to prevent the common user on Android from just opening and play the file from disc. If aescrypt.com tools isn't optimal for this, I gladly welcome other suggestions.
Why do you stick to that AESCrypt applications? They write their custom header to the encrypted file.
They distribute source code, which will give you enough information about how to decrypt this (and, probably you'll be able to re-use their sources). Check their AESCryptWorkerThreads.cpp in AES crypto source code.
The AESCrypt format carries significant configuration information. Most of the format is detailed at their site (aes_file_format.html). This page doesn't explain their custom KDF, unfortunately. You'll have to use or reverse-engineer their encrypt_stream function in aescrypt.c:
// Hash the IV and password 8192 times
memset(digest, 0, 32);
memcpy(digest, IV, 16);
for(i=0; i<8192; i++)
{
sha256_starts( &sha_ctx);
sha256_update( &sha_ctx, digest, 32);
sha256_update( &sha_ctx,
(unsigned char*)passwd,
(unsigned long)passlen);
sha256_finish( &sha_ctx,
digest);
}
They don't use CommonCryptor, so if you want hardware-optimized code, you'll have to reimplement this format yourself in CommonCryptor.
Note that your decrypt code has no IV, no KDF, and no HMAC, so anything that actually encrypted that way would be highly insecure. AESCrypt does provide a proper IV and HMAC, and its KDF is likely secure, though non-standard, so it is a reasonable choice.