diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 99fc223e..ba0269a3 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -39,3 +39,6 @@ newArchEnabled=true # Use this property to enable or disable the Hermes JS engine. # If set to false, you will be using JSC instead. hermesEnabled=true + +# Use this property to enable or disable the libsodium support. +sodiumEnabled=true \ No newline at end of file diff --git a/example/ios/Podfile b/example/ios/Podfile index dcc6051c..5ad47e5d 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,4 +1,5 @@ ENV['RCT_NEW_ARCH_ENABLED'] = '1' +ENV['SODIUM_ENABLED'] = '1' # Resolve react_native_pods.rb with node to allow for hoisting require Pod::Executable.execute_command('node', ['-p', diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index a8e789dc..56a7e29c 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1995,7 +1995,7 @@ SPEC CHECKSUMS: hermes-engine: 9e868dc7be781364296d6ee2f56d0c1a9ef0bb11 NitroModules: fdc6fcf8f397091615951004ae81022b759e27bc OpenSSL-Universal: 6082b0bf950e5636fe0d78def171184e2b3899c2 - QuickCrypto: 283efc5368936a4731c55b5a6409588d550dd0b1 + QuickCrypto: e8b3449a68c118319ce3bbf4f570547029342a16 RCT-Folly: ea9d9256ba7f9322ef911169a9f696e5857b9e17 RCTDeprecation: ebe712bb05077934b16c6bf25228bdec34b64f83 RCTRequired: ca91e5dd26b64f577b528044c962baf171c6b716 @@ -2059,6 +2059,6 @@ SPEC CHECKSUMS: SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 Yoga: feb4910aba9742cfedc059e2b2902e22ffe9954a -PODFILE CHECKSUM: bcfd7840a8f657993e5e9504fdac2d1397cbc14a +PODFILE CHECKSUM: 63c4c1ca9d3ee6394f468b17e19efd3e548b5357 -COCOAPODS: 1.16.2 +COCOAPODS: 1.15.2 diff --git a/example/package.json b/example/package.json index d8b79034..7f277e40 100644 --- a/example/package.json +++ b/example/package.json @@ -15,7 +15,7 @@ "format": "prettier --check \"**/*.{js,ts,tsx}\"", "format:fix": "prettier --write \"**/*.{js,ts,tsx}\"", "start": "react-native start", - "pods": "RCT_NEW_ARCH_ENABLED=1 bundle exec pod install --project-directory=ios", + "pods": "bundle exec pod install --project-directory=ios", "build:android": "cd android && ./gradlew assembleDebug --no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a", "build:ios": "cd ios && xcodebuild -workspace QuickCrytpExample.xcworkspace -scheme QuickCrytpExample -configuration Debug -sdk iphonesimulator CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ GCC_OPTIMIZATION_LEVEL=0 GCC_PRECOMPILE_PREFIX_HEADER=YES ASSETCATALOG_COMPILER_OPTIMIZATION=time DEBUG_INFORMATION_FORMAT=dwarf COMPILER_INDEX_STORE_ENABLE=NO" }, diff --git a/packages/react-native-quick-crypto/QuickCrypto.podspec b/packages/react-native-quick-crypto/QuickCrypto.podspec index cf3f8745..b4d56bf9 100644 --- a/packages/react-native-quick-crypto/QuickCrypto.podspec +++ b/packages/react-native-quick-crypto/QuickCrypto.podspec @@ -19,32 +19,43 @@ Pod::Spec.new do |s| s.source = { :git => "https://github.com/margelo/react-native-quick-crypto.git", :tag => "#{s.version}" } - # cocoapod for Sodium has not been updated for a while, so we need to build it ourselves - # https://github.com/jedisct1/swift-sodium/issues/264#issuecomment-2864963850 - s.prepare_command = <<-CMD - # Create ios directory if it doesn't exist - mkdir -p ios + sodium_enabled = ENV['SODIUM_ENABLED'] == '1' + Pod::UI.puts("[QuickCrypto] Has libsodium #{sodium_enabled ? "enabled" : "disabled"}!") - # Download libsodium - curl -L -s -o ios/libsodium.tar.gz https://download.libsodium.org/libsodium/releases/libsodium-1.0.20-stable.tar.gz + if sodium_enabled + # cocoapod for Sodium has not been updated for a while, so we need to build it ourselves + # https://github.com/jedisct1/swift-sodium/issues/264#issuecomment-2864963850 + s.prepare_command = <<-CMD + # Create ios directory if it doesn't exist + mkdir -p ios - # Clean previous extraction - rm -rf ios/libsodium-stable + # Download libsodium + curl -L -s -o ios/libsodium.tar.gz https://download.libsodium.org/libsodium/releases/libsodium-1.0.20-stable.tar.gz - # Extract the full tarball - tar -xzf ios/libsodium.tar.gz -C ios + # Clean previous extraction + rm -rf ios/libsodium-stable - # Run configure and make to generate all headers including private ones - cd ios/libsodium-stable && \ - ./configure --disable-shared --enable-static && \ - make -j$(sysctl -n hw.ncpu) + # Extract the full tarball + tar -xzf ios/libsodium.tar.gz -C ios - # Cleanup - cd ../../ - rm -f ios/libsodium.tar.gz - CMD + # Run configure and make to generate all headers including private ones + cd ios/libsodium-stable && \ + ./configure --disable-shared --enable-static && \ + make -j$(sysctl -n hw.ncpu) - s.source_files = [ + # Cleanup + cd ../../ + rm -f ios/libsodium.tar.gz + CMD + else + s.prepare_command = <<-CMD + # Clean up libsodium files if they exist + rm -rf ios/libsodium-stable + rm -f ios/libsodium.tar.gz + CMD + end + + base_source_files = [ # implementation (Swift) "ios/**/*.{swift}", # ios (Objective-C++) @@ -55,25 +66,35 @@ Pod::Spec.new do |s| "deps/**/*.{hpp,cpp}", # dependencies (C) "deps/**/*.{h,c}", - # libsodium sources - "ios/libsodium-stable/src/libsodium/**/*.{h,c}" ] - s.pod_target_xcconfig = { + if sodium_enabled + base_source_files += ["ios/libsodium-stable/src/libsodium/**/*.{h,c}"] + end + + s.source_files = base_source_files + + xcconfig = { # C++ compiler flags, mainly for folly. "GCC_PREPROCESSOR_DEFINITIONS" => "$(inherited) FOLLY_NO_CONFIG FOLLY_CFG_NO_COROUTINES", # Set C++ standard to C++20 "CLANG_CXX_LANGUAGE_STANDARD" => "c++20", - # Header search paths for vendored libsodium - "HEADER_SEARCH_PATHS" => [ + "CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES" => "YES" + } + + if sodium_enabled + sodium_headers = [ "\"$(PODS_TARGET_SRCROOT)/ios/libsodium-stable/src/libsodium/include\"", "\"$(PODS_TARGET_SRCROOT)/ios/libsodium-stable/src/libsodium/include/sodium\"", "\"$(PODS_TARGET_SRCROOT)/ios/libsodium-stable\"", "\"$(PODS_ROOT)/../../packages/react-native-quick-crypto/ios/libsodium-stable/src/libsodium/include\"", "\"$(PODS_ROOT)/../../packages/react-native-quick-crypto/ios/libsodium-stable/src/libsodium/include/sodium\"" - ].join(' '), - "CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES" => "YES" - } + ] + xcconfig["HEADER_SEARCH_PATHS"] = sodium_headers.join(' ') + xcconfig["GCC_PREPROCESSOR_DEFINITIONS"] = "$(inherited) BLSALLOC_SODIUM=1" + end + + s.pod_target_xcconfig = xcconfig # Add all files generated by Nitrogen load "nitrogen/generated/ios/QuickCrypto+autolinking.rb" diff --git a/packages/react-native-quick-crypto/android/CMakeLists.txt b/packages/react-native-quick-crypto/android/CMakeLists.txt index 53289477..13b718c9 100644 --- a/packages/react-native-quick-crypto/android/CMakeLists.txt +++ b/packages/react-native-quick-crypto/android/CMakeLists.txt @@ -41,7 +41,6 @@ include_directories( find_library(LOG_LIB log) find_package(openssl REQUIRED CONFIG) -find_package(sodium REQUIRED CONFIG) # Link all libraries together target_link_libraries( @@ -49,9 +48,17 @@ target_link_libraries( ${LOG_LIB} # <-- Logcat logger android # <-- Android core openssl::crypto # <-- OpenSSL (Crypto) - sodium::sodium # <-- libsodium (Crypto) ) +if(SODIUM_ENABLED) + add_definitions(-DBLSALLOC_SODIUM) + find_package(sodium REQUIRED CONFIG) + target_link_libraries( + ${PACKAGE_NAME} + sodium::sodium + ) +endif() + if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 76) target_link_libraries( ${PACKAGE_NAME} diff --git a/packages/react-native-quick-crypto/android/build.gradle b/packages/react-native-quick-crypto/android/build.gradle index 3b8331f4..b357bff9 100644 --- a/packages/react-native-quick-crypto/android/build.gradle +++ b/packages/react-native-quick-crypto/android/build.gradle @@ -37,6 +37,9 @@ def getExtOrIntegerDefault(name) { return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["QuickCrypto_" + name]).toInteger() } +def sodiumEnabled = hasProperty('sodiumEnabled') ? project.property('sodiumEnabled').toBoolean() : false // Default to false +logger.warn("[QuickCrypto] Has libsodium ${sodiumEnabled ? "enabled" : "disabled"}!") + android { namespace "com.margelo.nitro.quickcrypto" ndkVersion getExtOrDefault("ndkVersion") @@ -50,7 +53,7 @@ android { externalNativeBuild { cmake { cppFlags "-frtti -fexceptions -Wall -fstack-protector-all" - arguments "-DANDROID_STL=c++_shared" + arguments "-DANDROID_STL=c++_shared", "-DSODIUM_ENABLED=${sodiumEnabled}" abiFilters (*reactNativeArchitectures()) buildTypes { @@ -140,8 +143,10 @@ dependencies { // Add a dependency on OpenSSL implementation 'io.github.ronickg:openssl:3.3.2' - // Add a dependency on libsodium - implementation 'io.github.ronickg:sodium:1.0.20' + if (sodiumEnabled) { + // Add a dependency on libsodium + implementation 'io.github.ronickg:sodium:1.0.20' + } } if (isNewArchitectureEnabled()) { diff --git a/packages/react-native-quick-crypto/cpp/cipher/XSalsa20Cipher.cpp b/packages/react-native-quick-crypto/cpp/cipher/XSalsa20Cipher.cpp index c76c36b3..f857846b 100644 --- a/packages/react-native-quick-crypto/cpp/cipher/XSalsa20Cipher.cpp +++ b/packages/react-native-quick-crypto/cpp/cipher/XSalsa20Cipher.cpp @@ -34,6 +34,9 @@ void XSalsa20Cipher::init(const std::shared_ptr cipher_key, const s * xsalsa20 call to sodium implementation */ std::shared_ptr XSalsa20Cipher::update(const std::shared_ptr& data) { +#ifndef BLSALLOC_SODIUM + throw std::runtime_error("XSalsa20Cipher: libsodium must be enabled to use this cipher (BLSALLOC_SODIUM is not defined)."); +#else auto native_data = ToNativeArrayBuffer(data); auto output = new uint8_t[native_data->size()]; int result = crypto_stream_xor(output, native_data->data(), native_data->size(), nonce, key); @@ -41,13 +44,18 @@ std::shared_ptr XSalsa20Cipher::update(const std::shared_ptr(output, native_data->size(), [=]() { delete[] output; }); +#endif } /** * xsalsa20 does not have a final step, returns empty buffer */ std::shared_ptr XSalsa20Cipher::final() { +#ifndef BLSALLOC_SODIUM + throw std::runtime_error("XSalsa20Cipher: libsodium must be enabled to use this cipher (BLSALLOC_SODIUM is not defined)."); +#else return std::make_shared(nullptr, 0, nullptr); +#endif } } // namespace margelo::nitro::crypto diff --git a/packages/react-native-quick-crypto/cpp/cipher/XSalsa20Cipher.hpp b/packages/react-native-quick-crypto/cpp/cipher/XSalsa20Cipher.hpp index e4c31e3a..a4d8bba1 100644 --- a/packages/react-native-quick-crypto/cpp/cipher/XSalsa20Cipher.hpp +++ b/packages/react-native-quick-crypto/cpp/cipher/XSalsa20Cipher.hpp @@ -1,6 +1,12 @@ #pragma once +#if BLSALLOC_SODIUM #include "sodium.h" +#else +// Define XSalsa20 constants when sodium is disabled (for compilation purposes) +#define crypto_stream_KEYBYTES 32 // XSalsa20 key size (32 bytes) +#define crypto_stream_NONCEBYTES 24 // XSalsa20 nonce size (24 bytes) +#endif #include "HybridCipher.hpp" #include "NitroModules/ArrayBuffer.hpp"