React Native - using Crypto functions on android - 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}`
);

Related

Is there a way to access Flutter resources from native code?

I want to use the main logo from Flutter resources in my native Android code — for example, to display a notification. As you know, in Android you usually get resources from drawable folder like this R.drawable.icon. But then I have to copy the icon to Android drawable folder as well. Maybe there is a way to access Flutter resources (read — assets) from native code?
There's a nice section sort-of about this in the flutter documentation.
Given an asset "icons/heart.png", for android (since 1.22):
FlutterLoader loader = FlutterInjector.instance().flutterLoader();
String key = loader.getLookupKeyForAsset("icons/heart.png");
For iOS (swift):
let key = registrar.lookupKey(forAsset: "icons/heart.png");
let path = Bundle.main.path(forResource: key, ofType: nil)
For iOS (obj-c):
NSString* key = [registrar lookupKeyForAsset:#"icons/heart.png"];
NSString* path = [[NSBundle mainBundle] pathForResource:key
ofType:nil];
For android previous to Flutter version 1.22 (deprecated):
AssetManager assetManager = registrar.context().getAssets();
String key = registrar.lookupKeyForAsset("icons/heart.png");
AssetFileDescriptor fd = assetManager.openFd(key);
However, you won't be able to share a drawable item directly to flutter, and the main icon is a bit of a special case that you definitely can't share with flutter either. Flutter doesn't know what a 'drawable' is but rather deals with resources its own cross-platform way.
UPDATE FOR NEW VERSION
For flutter release 1.22 or above, FlutterLoader is only accessible via FlutterInjector.
import io.flutter.FlutterInjector;
FlutterLoader loader = FlutterInjector.instance().flutterLoader();
String key = loader.getLookupKeyForAsset("assets_file_name");
You need to get relative path of asset file.
Below is the helper method to access the file/image path from swift native code.
func flutterAssetLottieFilePath(imageName : String) -> String {
var flutterViewController = FlutterViewController()
flutterViewController = UIWindow.init(frame: UIScreen.main.bounds).rootViewController as! FlutterViewController
let key = flutterViewController.lookupKey(forAsset:"assets/images/\(imageName).png")
let path = Bundle.main.path(forResource: key, ofType: nil)
return path ?? ""
}
As of when I wrote this, the documentation was out of date. On my version of flutter, 1.17.1 here is an kotlin android example with the necessary imports above:
import android.content.Context
import io.flutter.embedding.engine.loader.FlutterLoader
import java.io.InputStream
val myAssetPath : Sting = "assets/my_asset"
val assetLookupKey = FlutterLoader.getInstance().getLookupKeyForAsset(myAssetPath)
val inputStream: InputStream = applicationContext.assets.open(assetLookupKey)
// Read in the file from the InputStream...
It should be noted that the value returned from this getLookupKeyForAsset method is usually your asset path, as included it on your pubspec.yaml under assets, simply prefixed with "flutter_assets/". So in the case of the above example, it would return flutter_assets/assets/my_asset

aes-256-cbc encryption and decryption

I am encrypting an audio file using crypto npm module in node.js and trying to decrypt it in the android side using the same algorithm and the key.
The encryption code is :
encyption parameters
var crypto = require('crypto'),
algorithm = 'aes-256-cbc',
password = 'somepassword'; //encyption parameters
encryption function
function encrypt(buffer) {
var cipher = crypto.createCipher(algorithm, password);
var crypted = Buffer.concat([cipher.update(buffer), cipher.final()]);
return crypted;
}
Now,for Decryption , we need to use some IV(Initialisation Vector) and as research says not to use same IV for any two files.
So, I just want to know now how customized IV can be set and random or separate IVs can be generated for each file in node.js using crypto or any other module during encryption.
It will be great if someone can help me out in this.
to create the IV, use the following command to get 16 random bytes:
var iv = crypto.randomBytes(16)
then, when creating the cipher, change
var cipher = crypto.createCipher(algorithm, password);
to
var cipher = crypto.createCipheriv(algorithm, password, iv);
The IV will not be attached to the resulting ciphertext, so you will need to send it separately to the android side (it can be sent in plaintext).

storage key not a valid base64 encoding - azure storage - android

I am trying to upload a text blob to azure storage blob using the following code:
public static final String storageConnectionString = "DefaultEndpointsProtocol=http;"
+ "AccountName=MY_STORAGE_ACNT;"
+ "AccountKey=[MYKEY]";
CloudStorageAccount account = CloudStorageAccount.parse(storageConnectionString);
CloudBlobClient blobClient = account.createCloudBlobClient();
CloudBlobContainer container = blobClient.getContainerReference("ubiety");
container.createIfNotExists();
BlobContainerPermissions containerPermissions = new BlobContainerPermissions();
containerPermissions.setPublicAccess(BlobContainerPublicAccessType.CONTAINER);
container.uploadPermissions(containerPermissions);
CloudBlockBlob blob1 = container.getBlockBlobReference("storage_name");
blob1.uploadText("Hello, World1");
This is a mere copy paste of the sample at BlobBasics Sample, still
I get the error
StorageKey is not a valid Base64 Encoded string.
Can someone please help. I am very sure, i am using the correct key provided at the azure portal
Thank you.
I got this message as well and it turned out I was using the wrong key. I was using the shared access signature obtained from the azure storage explorer. That's wrong. You need to grab the key from the azure portal. Go to the dashboard.
Select your storage account. You can then select "Access keys". Just pick the top key.
Then run code like this ( Scala, but Python is possible too )
var storage_account_name:String = = "storageaccountname"
// This is key1 from access keys in my user interface
var storage_account_access_key: String = "UU8udCiTs/3CEmjH3xVVFtSR7EAWZifGlSf3QoNNUDYL2GjxQ4mQ3GhuoZvO8G/eO9Z+SgY1uXrVBGHBc5u7tA=="
spark.conf.set(
"fs.azure.account.key."+storage_account_name+".blob.core.windows.net",
storage_account_access_key)
spark.read.format("csv").load("wasbs://blobname#storageaccountname.blob.core.windows.net/csvfile.csv")
In the example storageaccountname is the name of my storage account. blobname is the name of the blob in the storage account.
Good luck
Looking at the sample link you've given it looks like you're using the Java Storage library rather than the Android Storage library. If you use the Android storage library and it's associated samples that should work correctly.
Azure Account Keys with forward slash (/) does not work. See https://github.com/Azure/azure-xplat-cli/issues/3135
What I did -
com.microsoft.azure.storage.StorageCredentialsAccountAndKey creds =
new StorageCredentialsAccountAndKey(accountName, key_with_slash);
com.microsoft.azure.storage.CloudStorageAccount account = new CloudStorageAccount(creds, false);
on linux you can use the base64 program and it worked for me. Do not include the % at the end
echo -n '<ONE OF YOUR ACCESS KEY FROM BLOB STORAGE ACCOUNT>' | base64 -w 0

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

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

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.

Categories

Resources