Decrypt aes-file in iOS encrypted using a tool from AESCrypt.com - android

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.

Related

React Native - using Crypto functions on android

I need to decrypt files on android in a react native app.
The files are encrypted using node crypto 'createCipheriv'.
Is it possible to decrypt files fast in react native?
I tried using browserify to convert the node crypto to browser usable code, but its way too slow. (5 seconds to decrypt a file)
I also checked 'react-native-crypto' but its deprecated and the solution they provide, 'crypto-browserify' does not work.
Thanks.
Use this package https://github.com/margelo/react-native-quick-crypto it is based on JSI and works like a native solution.
const plaintext =
'32|RmVZZkFUVmpRRkp0TmJaUm56ZU9qcnJkaXNNWVNpTTU*|iXmckfRWZBGWWELw' +
'eCBsThSsfUHLeRe0KCsK8ooHgxie0zOINpXxfZi/oNG7uq9JWFVCk70gfzQH8ZUJ' +
'jAfaFg**';
const cipher = crypto.createCipheriv('des-ede3-cbc', key, iv);
let ciph = cipher.update(plaintext, 'utf8', 'hex');
ciph += cipher.final('hex');
const decipher = crypto.createDecipheriv('des-ede3-cbc', key, iv);
let txt = decipher.update(ciph, 'hex', 'utf8');
txt += decipher.final('utf8');
assert.strictEqual(
txt,
plaintext,
`encryption/decryption with key ${key} and iv ${iv}`
);

Using ExoPlayer Input stream with own encryption logic

I am now trying to play an encrypted video(mp4) complete with my own logic. It takes too much time to play back the decoded file because it is too large to create and play. So, what I have found is how to play it while decrypting it with InputStream using ExoPlayer. But it's too difficult at my level to apply it. When I was worried for two days, I had a night, but I still do not see any results. So I ask for help here.
What I am looking for is a reference that can be helpful. I must accept and decode the buffer size (4096). I do not know where to write this code.
And the flow to complete the function I think is as follows.
1. Complete the ExoPlayer UI.
2. Encrypt the downloaded file using my encryption logic. (buffer size is 4096)
3. InputStream receives the file, decodes it at the same time, and plays it. (streaming)
I will do it somehow until 1 and 2, but 3 is very difficult for me. Do you have any specific code and explanation? If you know anyone, please give me a favor. Thank you.
try {
ios = new FileInputStream(params[0]);
fos = context.openFileOutput(params[1] + ".mp4", MODE_PRIVATE);
ScatteringByteChannel sbc = ios.getChannel();
GatheringByteChannel gbc = fos.getChannel();
File file = new File(params[0]);
fileLength = file.length();
startTime = System.currentTimeMillis();
int read = 0;
readb = 0;
ByteBuffer bb = ByteBuffer.allocate(4096);
while ((read = sbc.read(bb)) != -1) {
bb.flip();
gbc.write(ByteBuffer.wrap(enDecryptVideo.combineByteArray(bb.array())));
bb.clear();
readb += read;
if (readb % (4096 * 1024 * 3) == 0){
publishProgress(((int) ( readb * 100 / fileLength)));
} else if (readb == fileLength) {
publishProgress(101);
}
}
ios.close();
fos.close();
} catch (Exception e) {
e.getMessage();
} finally {
Log.d(TAG, "doInBackground: " + (System.currentTimeMillis() - startTime));
}
This is my code when I use File play. The above code is the code I used when I made a decoded file and played it. Now I have to play back at the same time as decoding. It does not create a file. I am very eager. Because I have been working for a month since I started work, but I have received something that does not fit my level. But I really want to hit this target... Teach me please.
You can actually leverage the platforms inbuilt encryption functionality for streamed video, either using a commercial DRM or using a 'clear key' encryption.
If these meet your needs it should much easier to work with as you won't have to implement the encryption and decryption yourself.
This answer provides an example for creating both an HLS / AES stream and a DASH clearkey stream:
https://stackoverflow.com/a/45103073/334402
This does not provide the same security as DRM, as the keys themselves are not encrypted, but it may be sufficient for your needs.
These streams can then be played with the standard iOS, Android or HTML5 players.

How to write metadata to mp4 file using mp4parser?

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

Base64 special characters new File

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 /.

Sharing via Seekable Pipe or Stream with Another Android App?

Lots of Intent actions, like ACTION_VIEW, take a Uri pointing to the content the action should be performed upon. If the content is backed by a file -- whether the Uri points directly to the file, or to a ContentProvider serving the file (see FileProvider) -- this generally works.
There are scenarios in which developers do not want to have the content reside in a file for sharing with other apps. One common scenario is for encryption: the decrypted data should reside in RAM, not on disk, to minimize the risk of somebody getting at that decrypted data.
My classic solution to sharing from RAM is to use ParcelFileDescriptor and createPipe(). However, when the activity responding to ACTION_VIEW (or whatever) gets an InputStream on that pipe, the resulting stream is limited compared to the streams you get when the ContentProvider is serving up content from a file. For example, this sample app works fine with Adobe Reader and crashes QuickOffice.
Based on past related questions, my assumption is that createPipe() is truly creating a pipe, and that pipes are non-seekable. Clients that attempt to "rewind" or "fast forward" run into problems as a result.
I am seeking a reliable solution for sharing in-memory content with a third-party app that gets around this limitation. Specifically:
It has to use a Uri syntax that is likely to be honored by client apps (i.e., ACTION_VIEW implementers); solutions that involve something obtuse that client apps are unlikely to recognize (e.g., pass such-and-so via an Intent extra) do not qualify
The data to be shared cannot be written to a file as part of the sharing (of course, the client app could wind up saving the received bytes to disk, but let's ignore that risk for the moment)
Ideally it does not involve the app looking to share the data opening up a ServerSocket or otherwise exacerbating security risks
Possible suggested ideas include:
Some way to reconfigure createPipe() that results in a seekable pipe
Some way to use a socket-based FileDescriptor that results in a seekable pipe
Some kind of RAM disk or something else that feels like a file to the rest of Android but is not persistent
A key critierion, if you will, of a working solution is if I can get a PDF served from RAM that QuickOffice can read.
Any suggestions?
Thanks!
You've posed a really difficult combination of requirements.
Lets look at your ideas for solutions:
Possible suggested ideas include:
Some way to reconfigure createPipe() that results in a seekable pipe
Some way to use a socket-based FileDescriptor that results in a seekable pipe
Some kind of RAM disk or something else that feels like a file to the rest of Android but is not persistent
The first one won't work. This issue is that the pipe primitive implemented by the OS is fundamentally non-seekable. The reason is supporting seek that would require the OS to buffer the entire pipe "contents" ... until the reading end closes. That is unimplementable ... unless you place a limit on the amount of data that can be sent through the pipe.
The second one won't work either, for pretty much the same reason. OS-level sockets are not seekable.
At one level, the final idea (a RAM file system) works, modulo that such a capability is supported by the Android OS. (A Ramfs file is seekable, after all.) However, a file stream is not a pipe. In particular the behaviour with respect to the end-of-file is different for a file stream and a pipe. And getting a file stream to look like a pipe stream from the perspective of the reader would entail some special code on that side. (The problem is similar to the problem of running tail -f on a log file ...)
Unfortunately, I don't think there's any other way to get a file descriptor that behaves like a pipe with respect to end-of-file and is also seekable ... short of radically modifying the operating system.
If you could change the application that is reading from the stream, you could work around this. This is precluded by the fact that the fd needs to be read and seeked by QuickOffice which (I assume) you can't modify. (But if you could change the application, there are ways to make this work ...)
By the way, I think you'd have the some problems with these requirements on Linux or Windows. And they are not Java specific.
UPDATE
There have been various interesting comments on this, and I want to address some here:
The OP has explained the use-case that is motivating his question. Basically, he wants a scheme where the data passing through the "channel" between the applications is not going to be vulnerable in the event that the users device is stolen (or confiscated) while the applications are actually running.
Is that achievable?
In theory, no. If one postulates a high degree of technical sophistication (and techniques that the public may not know about ...) then the "bad guys" could break into the OS and read the data from shared memory while the "channel" remained active.
I doubt that such attacks are (currently) possible in practice.
However, even if we assume that the "channel" writes nothing to "disc" there could still be traces of the channel in memory: e.g.
a still mounted RAMfs or still active shared memory segments, or
remnants of previous RAMfs / shared memory.
In theory, this data could in theory be retrieved, provided that the "bad guy" doesn't turn of or reboot the device.
It has been suggested that ashmem could be used in this context:
The issue of there being no public Java APIs could be addressed (by writing 3rd-party APIs, for example)
The real stumbling block is the need for a stream API. According the "ashmem" docs, they have a file-like API. But I think that just means that they conform to the "file descriptor" model. These FDs can be passed from one application to another (across fork / exec), and you use "ioctl" to operate on them. But there is no indication that they implement "read" and "write" ... let alone "seek".
Now, you could probably implement a read/write/seekable stream on top of ashmem, using native and Java libraries on both ends of the channel. But both applications would need to be "aware" of this process, probably to the level of providing command line options to set up the channel.
These issues also apply to old-style shmem ... except that the channel setup is probably more difficult.
The other potential option is to use a RAM fs.
This is easier to implement. The files in the RAMfs will behave like "normal" files; when opened by an application you get a file descriptor that can be read, written and seeked ... depending on how it was opened. And (I think) you should be able to pass a seekable FD for a RAMfs file across a fork/exec.
The problem is that the RAMfs needs to be "mounted" by the operating system in order to use it. While it is mounted, another (privileged) application can also open and read files. And the OS won't let you unmount the RAMfs while some application has open fds for RAMfs files.
There is a (hypothetical) scheme that partly mitigates the above.
The source application creates and mounts a "private" RAMfs.
The source application creates/opens the file for read/write and then unlinks it.
The source application writes the file using the fd from the open.
The source application forks / execs the sink application, passing the fd.
The sink application reads from the (I think) still seekable fd, seeking as required.
When the source application notices that the (child) sink application process has exited, it unmounts and destroys the RAMfs.
This would not require modifying the reading (sink) application.
However, a third (privileged) application could still potentially get into the RAMfs, locate the unlinked file in memory, and read it.
However, having re-reviewed all of the above, the most practical solution is still to modify the reading (sink) application to read the entire input stream into a byte[], then open a ByteArrayInputStream on the buffered data. The core application can seek and reset it at will.
It's not a general solution to your problem, but opening a PDF in QuickOffice works for me with the following code (based on your sample):
#Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
try {
byte[] data = getData(uri);
long size = data.length;
ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
new TransferThread(new ByteArrayInputStream(data), new AutoCloseOutputStream(pipe[1])).start();
return new AssetFileDescriptor(pipe[0], 0, size);
} catch (IOException e) {
e.printStackTrace();
}
return null;
};
private byte[] getData(Uri uri) throws IOException {
AssetManager assets = getContext().getResources().getAssets();
InputStream is = assets.open(uri.getLastPathSegment());
ByteArrayOutputStream os = new ByteArrayOutputStream();
copy(is, os);
return os.toByteArray();
}
private void copy(InputStream in, OutputStream out) throws IOException {
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.flush();
out.close();
}
#Override
public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, String sort) {
if (projection == null) {
projection = new String[] { OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE };
}
String[] cols = new String[projection.length];
Object[] values = new Object[projection.length];
int i = 0;
for (String col : projection) {
if (OpenableColumns.DISPLAY_NAME.equals(col)) {
cols[i] = OpenableColumns.DISPLAY_NAME;
values[i++] = url.getLastPathSegment();
}
else if (OpenableColumns.SIZE.equals(col)) {
cols[i] = OpenableColumns.SIZE;
values[i++] = AssetFileDescriptor.UNKNOWN_LENGTH;
}
}
cols = copyOf(cols, i);
values = copyOf(values, i);
final MatrixCursor cursor = new MatrixCursor(cols, 1);
cursor.addRow(values);
return cursor;
}
private String[] copyOf(String[] original, int newLength) {
final String[] result = new String[newLength];
System.arraycopy(original, 0, result, 0, newLength);
return result;
}
private Object[] copyOf(Object[] original, int newLength) {
final Object[] result = new Object[newLength];
System.arraycopy(original, 0, result, 0, newLength);
return result;
}
I believe you're looking for StorageManager.openProxyFileDescriptor, function added in API 26. This will give you ParcelFileDescriptor, needed for your ContentProvider.openAssetFile to work. But you can also grab its file descriptor and use it in file I/O: new FileInputStream(fd.getFileDescriptor())
In function description is :
This can be useful when you want to provide quick access to a large file that isn't backed by a real file on disk, such as a file on a
network share, cloud storage service, etc. As an example, you could
respond to a ContentResolver#openFileDescriptor(android.net.Uri,
String) request by returning a ParcelFileDescriptor created with this
method, and then stream the content on-demand as requested. Another
useful example might be where you have an encrypted file that you're
willing to decrypt on-demand, but where you want to avoid persisting
the cleartext version.
It works with ProxyFileDescriptorCallback, which is your function to provide I/O, mainly read pieces of your file from various offsets (or decrypt it, read from network, generate, etc).
As I tested, it's well suited also for video playback over content:// scheme, because seeking is efficient, no seek-by-read as is the option for pipe-based approach, but Android really asks relevant fragments of your file.
Internally Android uses some fuse driver to transfer the data between processes.
I've been experimenting with #josias code. I found some of the query(...) calls came with a projection of _data. Including the data for that column and setting the actual length means more file types can be opened in more apps. Always including _data even when not in the passed in projection allows opening even more file types.
Here is what I ended up with:
private static final String[] PROJECTION = {OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE, "_data"};
#Override
public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, String sort) {
byte[] data = getData(mSourcePath, url);
final MatrixCursor cursor = new MatrixCursor(PROJECTION, 1);
cursor.newRow()
.add(url.getLastPathSegment())
.add(data.length)
.add(data);
return cursor;
}

Categories

Resources