439 lines
19 KiB
Diff
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
|