Rocket.Chat.ReactNative/patches/react-native-simple-crypto+...

439 lines
19 KiB
Diff

diff --git a/node_modules/react-native-simple-crypto/android/src/main/java/com/pedrouid/crypto/RCTAes.java b/node_modules/react-native-simple-crypto/android/src/main/java/com/pedrouid/crypto/RCTAes.java
index 2b52abe..12a7750 100644
--- a/node_modules/react-native-simple-crypto/android/src/main/java/com/pedrouid/crypto/RCTAes.java
+++ b/node_modules/react-native-simple-crypto/android/src/main/java/com/pedrouid/crypto/RCTAes.java
@@ -1,55 +1,31 @@
package com.pedrouid.crypto;
-import android.widget.Toast;
-
-import java.io.IOException;
-import java.security.SecureRandom;
-import java.util.HashMap;
-import java.util.Map;
+import android.util.Base64;
-import java.util.UUID;
+import com.facebook.react.bridge.Promise;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.spec.InvalidKeySpecException;
-import java.security.InvalidKeyException;
+import org.spongycastle.util.encoders.Hex;
-import java.nio.charset.StandardCharsets;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.security.SecureRandom;
+import java.util.UUID;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.PBEKeySpec;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.Mac;
-
-import org.spongycastle.crypto.ExtendedDigest;
-import org.spongycastle.crypto.digests.SHA1Digest;
-import org.spongycastle.crypto.digests.SHA224Digest;
-import org.spongycastle.crypto.digests.SHA256Digest;
-import org.spongycastle.crypto.digests.SHA384Digest;
-import org.spongycastle.crypto.digests.SHA384Digest;
-import org.spongycastle.crypto.digests.SHA512Digest;
-import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator;
-import org.spongycastle.crypto.PBEParametersGenerator;
-import org.spongycastle.crypto.params.KeyParameter;
-import org.spongycastle.util.encoders.Hex;
-
-import android.util.Base64;
-
-import com.facebook.react.bridge.NativeModule;
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.Promise;
-import com.facebook.react.bridge.ReactContext;
-import com.facebook.react.bridge.ReactContextBaseJavaModule;
-import com.facebook.react.bridge.ReactMethod;
-import com.facebook.react.bridge.Callback;
+import javax.crypto.spec.SecretKeySpec;
public class RCTAes extends ReactContextBaseJavaModule {
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS7Padding";
private static final String KEY_ALGORITHM = "AES";
+ private static final String FILE_CIPHER_ALGORITHM = "AES/CTR/NoPadding";
+ private static final int BUFFER_SIZE = 4096;
public RCTAes(ReactApplicationContext reactContext) {
super(reactContext);
@@ -80,6 +56,26 @@ public class RCTAes extends ReactContextBaseJavaModule {
}
}
+ @ReactMethod
+ public void encryptFile(String filePath, String base64UrlKey, String base64Iv, Promise promise) {
+ try {
+ String outputFilePath = encryptFile(filePath, base64UrlKey, base64Iv);
+ promise.resolve(outputFilePath);
+ } catch (Exception e) {
+ promise.reject("-1", e.getMessage());
+ }
+ }
+
+ @ReactMethod
+ public void decryptFile(String filePath, String base64UrlKey, String base64Iv, Promise promise) {
+ try {
+ String outputFilePath = decryptFile(filePath, base64UrlKey, base64Iv);
+ promise.resolve(outputFilePath);
+ } catch (Exception e) {
+ promise.reject("-1", e.getMessage());
+ }
+ }
+
@ReactMethod
public void randomUuid(Promise promise) {
try {
@@ -105,6 +101,12 @@ public class RCTAes extends ReactContextBaseJavaModule {
final static IvParameterSpec emptyIvSpec = new IvParameterSpec(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
+ public static IvParameterSpec generateIV() {
+ byte[] iv = new byte[16]; // AES block size
+ new SecureRandom().nextBytes(iv);
+ return new IvParameterSpec(iv);
+ }
+
public static String encrypt(String textBase64, String hexKey, String hexIv) throws Exception {
if (textBase64 == null || textBase64.length() == 0) {
return null;
@@ -133,4 +135,66 @@ public class RCTAes extends ReactContextBaseJavaModule {
return Base64.encodeToString(decrypted, Base64.NO_WRAP);
}
+ public static String processFile(String inputFile, String base64UrlKey, String base64Iv, String mode) throws Exception {
+ // Decode the key and IV using URL-safe and no-wrap flags
+ byte[] key = Base64.decode(base64UrlKey, Base64.URL_SAFE | Base64.NO_WRAP);
+ byte[] iv = Base64.decode(base64Iv, Base64.NO_WRAP);
+ SecretKey secretKey = new SecretKeySpec(key, "AES");
+
+ // Initialize the cipher
+ Cipher cipher = Cipher.getInstance(FILE_CIPHER_ALGORITHM);
+ IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
+ cipher.init(mode.equals("encrypt") ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
+
+ // Normalize file paths
+ String normalizedInputFilePath = Util.normalizeFilePath(inputFile);
+ File inputFileObj = new File(normalizedInputFilePath);
+ File outputFileObj = new File(inputFileObj.getParent(), "processed_" + inputFileObj.getName());
+
+ // File streams setup
+ try (FileInputStream fis = new FileInputStream(inputFileObj);
+ FileOutputStream fos = new FileOutputStream(outputFileObj)) {
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int numBytesRead;
+
+ while ((numBytesRead = fis.read(buffer)) != -1) {
+ byte[] output = cipher.update(buffer, 0, numBytesRead);
+ if (output != null) {
+ fos.write(output);
+ }
+ }
+ byte[] finalBytes = cipher.doFinal();
+ if (finalBytes != null) {
+ fos.write(finalBytes);
+ }
+ } catch (Exception ex) {
+ outputFileObj.delete(); // Ensure temporary file is removed on error
+ throw ex;
+ }
+
+ if ("decrypt".equals(mode)) {
+ // Overwrite the input file with the decrypted file
+ try (FileInputStream fis = new FileInputStream(outputFileObj);
+ FileOutputStream fos = new FileOutputStream(inputFileObj)) {
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int numBytesRead;
+
+ while ((numBytesRead = fis.read(buffer)) != -1) {
+ fos.write(buffer, 0, numBytesRead);
+ }
+ }
+ outputFileObj.delete(); // Remove the temporary file after overwriting
+ return "file://" + normalizedInputFilePath;
+ } else {
+ return "file://" + outputFileObj.getAbsolutePath();
+ }
+ }
+
+ public static String encryptFile(String inputFile, String base64UrlKey, String base64Iv) throws Exception {
+ return processFile(inputFile, base64UrlKey, base64Iv, "encrypt");
+ }
+
+ public static String decryptFile(String inputFile, String base64UrlKey, String base64Iv) throws Exception {
+ return processFile(inputFile, base64UrlKey, base64Iv, "decrypt");
+ }
}
diff --git a/node_modules/react-native-simple-crypto/android/src/main/java/com/pedrouid/crypto/Util.java b/node_modules/react-native-simple-crypto/android/src/main/java/com/pedrouid/crypto/Util.java
index 25179a9..2ff673b 100644
--- a/node_modules/react-native-simple-crypto/android/src/main/java/com/pedrouid/crypto/Util.java
+++ b/node_modules/react-native-simple-crypto/android/src/main/java/com/pedrouid/crypto/Util.java
@@ -11,4 +11,18 @@ public class Util {
}
return new String(hexChars);
}
+
+ public static byte[] hexStringToByteArray(String s) {
+ int len = s.length();
+ byte[] data = new byte[len / 2];
+ for (int i = 0; i < len; i += 2) {
+ data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ + Character.digit(s.charAt(i+1), 16));
+ }
+ return data;
+ }
+
+ public static String normalizeFilePath(String filePath) {
+ return filePath.startsWith("file://") ? filePath.substring(7) : filePath;
+ }
}
diff --git a/node_modules/react-native-simple-crypto/index.d.ts b/node_modules/react-native-simple-crypto/index.d.ts
index b4fcde6..079c397 100644
--- a/node_modules/react-native-simple-crypto/index.d.ts
+++ b/node_modules/react-native-simple-crypto/index.d.ts
@@ -18,6 +18,16 @@ declare module "react-native-simple-crypto" {
key: ArrayBuffer,
iv: ArrayBuffer
): Promise<ArrayBuffer>;
+ export function encryptFile(
+ filePath: string,
+ key: string,
+ iv: string
+ ): Promise<string>;
+ export function decryptFile(
+ filePath: string,
+ key: string,
+ iv: string
+ ): Promise<string>;
}
export namespace SHA {
diff --git a/node_modules/react-native-simple-crypto/index.js b/node_modules/react-native-simple-crypto/index.js
index d756fbc..6d4ed10 100644
--- a/node_modules/react-native-simple-crypto/index.js
+++ b/node_modules/react-native-simple-crypto/index.js
@@ -92,6 +92,12 @@ const AES = {
const keyHex = convertArrayBufferToHex(keyArrayBuffer);
const ivHex = convertArrayBufferToHex(ivArrayBuffer);
return convertBase64ToArrayBuffer(await NativeModules.Aes.decrypt(cipherTextBase64, keyHex, ivHex));
+ },
+ encryptFile: async function (filePath, key, iv) {
+ return NativeModules.Aes.encryptFile(filePath, key, iv);
+ },
+ decryptFile: async function (filePath, key, iv) {
+ return NativeModules.Aes.decryptFile(filePath, key, iv);
}
};
diff --git a/node_modules/react-native-simple-crypto/ios/RCTCrypto/RCTAes.m b/node_modules/react-native-simple-crypto/ios/RCTCrypto/RCTAes.m
index 6947918..b79f101 100644
--- a/node_modules/react-native-simple-crypto/ios/RCTCrypto/RCTAes.m
+++ b/node_modules/react-native-simple-crypto/ios/RCTCrypto/RCTAes.m
@@ -29,4 +29,26 @@ RCT_EXPORT_METHOD(decrypt:(NSString *)base64 key:(NSString *)key iv:(NSString *)
}
}
+RCT_EXPORT_METHOD(encryptFile:(NSString *)filePath key:(NSString *)key iv:(NSString *)iv
+ resolver:(RCTPromiseResolveBlock)resolve
+ rejecter:(RCTPromiseRejectBlock)reject) {
+ NSString *encryptedFilePath = [Aes encryptFile:filePath key:key iv:iv];
+ if (encryptedFilePath == nil) {
+ reject(@"encrypt_file_fail", @"File encryption failed", nil);
+ } else {
+ resolve(encryptedFilePath);
+ }
+}
+
+RCT_EXPORT_METHOD(decryptFile:(NSString *)filePath key:(NSString *)key iv:(NSString *)iv
+ resolver:(RCTPromiseResolveBlock)resolve
+ rejecter:(RCTPromiseRejectBlock)reject) {
+ NSString *decryptedFilePath = [Aes decryptFile:filePath key:key iv:iv];
+ if (decryptedFilePath == nil) {
+ reject(@"decrypt_file_fail", @"File decryption failed", nil);
+ } else {
+ resolve(decryptedFilePath);
+ }
+}
+
@end
diff --git a/node_modules/react-native-simple-crypto/ios/RCTCrypto/RNRandomBytes.h b/node_modules/react-native-simple-crypto/ios/RCTCrypto/RNRandomBytes.h
index 650a8d7..2dab698 100644
--- a/node_modules/react-native-simple-crypto/ios/RCTCrypto/RNRandomBytes.h
+++ b/node_modules/react-native-simple-crypto/ios/RCTCrypto/RNRandomBytes.h
@@ -9,8 +9,8 @@
#import <Foundation/Foundation.h>
#if __has_include(<React/RCTBridgeModule.h>)
#import <React/RCTBridgeModule.h>
-#elif __has_include("RCTBridgeModule.h")
-#import "RCTBridgeModule.h"
+#elif __has_include(<React/RCTBridgeModule.h>)
+#import <React/RCTBridgeModule.h>
#else
#import "React/RCTBridgeModule.h" // Required when used as a Pod in a Swift project
#endif
diff --git a/node_modules/react-native-simple-crypto/ios/RCTCrypto/RNRandomBytes.m b/node_modules/react-native-simple-crypto/ios/RCTCrypto/RNRandomBytes.m
index 2895dec..0768bfa 100644
--- a/node_modules/react-native-simple-crypto/ios/RCTCrypto/RNRandomBytes.m
+++ b/node_modules/react-native-simple-crypto/ios/RCTCrypto/RNRandomBytes.m
@@ -9,8 +9,8 @@
#import "RNRandomBytes.h"
#if __has_include(<React/RCTBridgeModule.h>)
#import <React/RCTBridgeModule.h>
-#elif __has_include("RCTBridgeModule.h")
-#import "RCTBridgeModule.h"
+#elif __has_include(<React/RCTBridgeModule.h>)
+#import <React/RCTBridgeModule.h>
#else
#import "React/RCTBridgeModule.h" // Required when used as a Pod in a Swift project
#endif
diff --git a/node_modules/react-native-simple-crypto/ios/RCTCrypto/lib/Aes.h b/node_modules/react-native-simple-crypto/ios/RCTCrypto/lib/Aes.h
index 72432fe..8a2020b 100644
--- a/node_modules/react-native-simple-crypto/ios/RCTCrypto/lib/Aes.h
+++ b/node_modules/react-native-simple-crypto/ios/RCTCrypto/lib/Aes.h
@@ -1,7 +1,16 @@
#import <Foundation/Foundation.h>
@interface Aes : NSObject
-+ (NSString *) encrypt: (NSString *)clearText64 key: (NSString *)key iv: (NSString *)iv;
-+ (NSString *) decrypt: (NSString *)cipherText key: (NSString *)key iv: (NSString *)iv;
-+ (NSData *) AES128CBC: (NSString *)operation data: (NSData *)data key: (NSString *)key iv: (NSString *)iv;
+
+// Encrypt and decrypt methods for base64-encoded string data
++ (NSString *)encrypt:(NSString *)clearText64 key:(NSString *)key iv:(NSString *)iv;
++ (NSString *)decrypt:(NSString *)cipherText key:(NSString *)key iv:(NSString *)iv;
+
+// Core AES CBC encryption/decryption method
++ (NSData *)AES128CBC:(NSString *)operation data:(NSData *)data key:(NSString *)key iv:(NSString *)iv;
+
+// File encryption and decryption methods
++ (NSString *)encryptFile:(NSString *)filePath key:(NSString *)key iv:(NSString *)iv;
++ (NSString *)decryptFile:(NSString *)filePath key:(NSString *)key iv:(NSString *)iv;
+
@end
diff --git a/node_modules/react-native-simple-crypto/ios/RCTCrypto/lib/Aes.m b/node_modules/react-native-simple-crypto/ios/RCTCrypto/lib/Aes.m
index 4ef555a..6501791 100644
--- a/node_modules/react-native-simple-crypto/ios/RCTCrypto/lib/Aes.m
+++ b/node_modules/react-native-simple-crypto/ios/RCTCrypto/lib/Aes.m
@@ -45,4 +45,73 @@
return [result base64EncodedStringWithOptions:0];
}
++ (NSString *)processFile:(NSString *)filePath
+ operation:(CCOperation)operation
+ key:(NSString *)keyBase64URL
+ iv:(NSString *)ivBase64 {
+ NSString *keyBase64 = [Shared base64FromBase64URL:keyBase64URL];
+ NSData *keyData = [[NSData alloc] initWithBase64EncodedString:keyBase64 options:0];
+ NSData *ivData = [[NSData alloc] initWithBase64EncodedString:ivBase64 options:0];
+
+ NSString *normalizedFilePath = [filePath stringByReplacingOccurrencesOfString:@"file://" withString:@""];
+ NSString *outputFileName = [@"processed_" stringByAppendingString:[normalizedFilePath lastPathComponent]];
+ NSString *outputFilePath = [[normalizedFilePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:outputFileName];
+ NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath:normalizedFilePath];
+ NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:outputFilePath append:NO];
+ [inputStream open];
+ [outputStream open];
+
+ size_t bufferSize = 4096;
+ uint8_t buffer[bufferSize];
+ CCCryptorRef cryptor = NULL;
+ CCCryptorStatus status = CCCryptorCreateWithMode(operation, kCCModeCTR, kCCAlgorithmAES, ccNoPadding, ivData.bytes, keyData.bytes, keyData.length, NULL, 0, 0, kCCModeOptionCTR_BE, &cryptor);
+ if (status != kCCSuccess) {
+ NSLog(@"Failed to create cryptor: %d", status);
+ return nil;
+ }
+
+ while ([inputStream hasBytesAvailable]) {
+ NSInteger bytesRead = [inputStream read:buffer maxLength:sizeof(buffer)];
+ if (bytesRead > 0) {
+ size_t dataOutMoved;
+ status = CCCryptorUpdate(cryptor, buffer, bytesRead, buffer, bufferSize, &dataOutMoved);
+ if (status == kCCSuccess) {
+ [outputStream write:buffer maxLength:dataOutMoved];
+ } else {
+ NSLog(@"Cryptor update failed: %d", status);
+ break;
+ }
+ }
+ }
+
+ CCCryptorRelease(cryptor);
+ [inputStream close];
+ [outputStream close];
+
+ if (status == kCCSuccess) {
+ if (operation == kCCDecrypt) {
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ // Overwrite the input file with the decrypted file
+ [fileManager removeItemAtPath:normalizedFilePath error:nil];
+ [fileManager moveItemAtPath:outputFilePath toPath:normalizedFilePath error:nil];
+ return [NSString stringWithFormat:@"file://%@", normalizedFilePath];
+ } else {
+ return [NSString stringWithFormat:@"file://%@", outputFilePath];
+ }
+ } else {
+ // Clean up temp file in case of failure
+ [[NSFileManager defaultManager] removeItemAtPath:outputFilePath error:nil];
+ return nil;
+ }
+}
+
+
++ (NSString *)encryptFile:(NSString *)filePath key:(NSString *)key iv:(NSString *)iv {
+ return [self processFile:filePath operation:kCCEncrypt key:key iv:iv];
+}
+
++ (NSString *)decryptFile:(NSString *)filePath key:(NSString *)key iv:(NSString *)iv {
+ return [self processFile:filePath operation:kCCDecrypt key:key iv:iv];
+}
+
@end
diff --git a/node_modules/react-native-simple-crypto/ios/RCTCrypto/lib/Shared.h b/node_modules/react-native-simple-crypto/ios/RCTCrypto/lib/Shared.h
index f92a1a3..398444b 100644
--- a/node_modules/react-native-simple-crypto/ios/RCTCrypto/lib/Shared.h
+++ b/node_modules/react-native-simple-crypto/ios/RCTCrypto/lib/Shared.h
@@ -3,4 +3,7 @@
@interface Shared : NSObject
+ (NSString *) toHex: (NSData *)nsdata;
+ (NSData *) fromHex: (NSString *)string;
++ (NSString *)base64FromBase64URL:(NSString *)base64URL;
++ (NSString *)normalizeFilePath:(NSString *)filePath;
++ (NSString *)restoreFilePathSchemeIfNeeded:(NSString *)filePath originalPath:(NSString *)originalPath;
@end
diff --git a/node_modules/react-native-simple-crypto/ios/RCTCrypto/lib/Shared.m b/node_modules/react-native-simple-crypto/ios/RCTCrypto/lib/Shared.m
index f3bc712..e97098b 100644
--- a/node_modules/react-native-simple-crypto/ios/RCTCrypto/lib/Shared.m
+++ b/node_modules/react-native-simple-crypto/ios/RCTCrypto/lib/Shared.m
@@ -29,4 +29,16 @@
return data;
}
++ (NSString *)base64FromBase64URL:(NSString *)base64URL {
+ NSMutableString *base64 = [NSMutableString stringWithString:base64URL];
+ [base64 replaceOccurrencesOfString:@"-" withString:@"+" options:NSLiteralSearch range:NSMakeRange(0, base64.length)];
+ [base64 replaceOccurrencesOfString:@"_" withString:@"/" options:NSLiteralSearch range:NSMakeRange(0, base64.length)];
+
+ // Pad with '=' to ensure the base64 string length is a multiple of 4
+ while (base64.length % 4 != 0) {
+ [base64 appendString:@"="];
+ }
+ return base64;
+}
+
@end