Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ android {

dependencies {
implementation "com.facebook.react:react-android:+"
api 'io.github.webrtc-sdk:android:137.7151.01'
api 'io.github.webrtc-sdk:android:137.7151.04'
implementation "androidx.core:core:1.7.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.oney.WebRTCModule;

import android.util.Log;

import org.webrtc.DataPacketCryptor;
import org.webrtc.DataPacketCryptorFactory;
import org.webrtc.FrameCryptorAlgorithm;
import org.webrtc.FrameCryptorKeyProvider;

import javax.annotation.Nullable;

public class DataPacketCryptorManager {
private static final String TAG = DataPacketCryptorManager.class.getSimpleName();
private final DataPacketCryptor dataPacketCryptor;
private boolean isDisposed = false;

public DataPacketCryptorManager(FrameCryptorAlgorithm algorithm, FrameCryptorKeyProvider keyProvider) {
dataPacketCryptor =
DataPacketCryptorFactory.createDataPacketCryptor(FrameCryptorAlgorithm.AES_GCM, keyProvider);
}

@Nullable
public synchronized DataPacketCryptor.EncryptedPacket encrypt(String participantId, int keyIndex, byte[] payload) {
if (isDisposed) {
return null;
}

DataPacketCryptor.EncryptedPacket packet = dataPacketCryptor.encrypt(participantId, keyIndex, payload);

if (packet == null) {
Log.i(TAG, "Error encrypting packet: null packet");
return null;
}

if (packet.payload == null) {
Log.i(TAG, "Error encrypting packet: null payload");
return null;
}
if (packet.iv == null) {
Log.i(TAG, "Error encrypting packet: null iv returned");
return null;
}

return packet;
}

@Nullable
public synchronized byte[] decrypt(String participantId, DataPacketCryptor.EncryptedPacket packet) {
if (isDisposed) {
return null;
}

return dataPacketCryptor.decrypt(participantId, packet);
}

public synchronized void dispose() {
if (isDisposed) {
return;
}
isDisposed = true;
dataPacketCryptor.dispose();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;

import org.webrtc.DataPacketCryptor;
import org.webrtc.FrameCryptor;
import org.webrtc.FrameCryptorAlgorithm;
import org.webrtc.FrameCryptorFactory;
Expand All @@ -24,14 +25,15 @@
import java.util.Objects;
import java.util.UUID;

public class RTCFrameCryptor {
public class RTCCryptoManager {
private static final String TAG = "RTCFrameCryptor";
private final Map<String, FrameCryptor> frameCryptos = new HashMap<>();
private final Map<String, FrameCryptorStateObserver> frameCryptoObservers = new HashMap<>();
private final Map<String, FrameCryptorKeyProvider> keyProviders = new HashMap<>();
private final Map<String, DataPacketCryptorManager> dataPacketCryptors = new HashMap<>();
private final WebRTCModule webRTCModule;

public RTCFrameCryptor(WebRTCModule webRTCModule) {
public RTCCryptoManager(WebRTCModule webRTCModule) {
this.webRTCModule = webRTCModule;
}

Expand Down Expand Up @@ -275,7 +277,7 @@ public void keyProviderRatchetSharedKey(ReadableMap params, @NonNull Promise res
byte[] newKey = keyProvider.ratchetSharedKey(keyIndex);

WritableMap paramsResult = Arguments.createMap();
paramsResult.putString("result", Base64.encodeToString(newKey, Base64.DEFAULT));
paramsResult.putString("result", Base64.encodeToString(newKey, Base64.NO_WRAP));
result.resolve(paramsResult);
}

Expand All @@ -291,7 +293,7 @@ public void keyProviderExportSharedKey(ReadableMap params, @NonNull Promise resu
byte[] key = keyProvider.exportSharedKey(keyIndex);

WritableMap paramsResult = Arguments.createMap();
paramsResult.putString("result", Base64.encodeToString(key, Base64.DEFAULT));
paramsResult.putString("result", Base64.encodeToString(key, Base64.NO_WRAP));
result.resolve(paramsResult);
}

Expand Down Expand Up @@ -325,7 +327,7 @@ public void keyProviderRatchetKey(ReadableMap params, @NonNull Promise result) {
byte[] newKey = keyProvider.ratchetKey(participantId, keyIndex);

WritableMap paramsResult = Arguments.createMap();
paramsResult.putString("result", Base64.encodeToString(newKey, Base64.DEFAULT));
paramsResult.putString("result", Base64.encodeToString(newKey, Base64.NO_WRAP));
result.resolve(paramsResult);
}

Expand All @@ -342,7 +344,7 @@ public void keyProviderExportKey(ReadableMap params, @NonNull Promise result) {
byte[] key = keyProvider.exportKey(participantId, keyIndex);

WritableMap paramsResult = Arguments.createMap();
paramsResult.putString("result", Base64.encodeToString(key, Base64.DEFAULT));
paramsResult.putString("result", Base64.encodeToString(key, Base64.NO_WRAP));
result.resolve(paramsResult);
}

Expand All @@ -353,7 +355,7 @@ public void keyProviderSetSifTrailer(ReadableMap params, @NonNull Promise result
result.reject("keyProviderSetSifTrailerFailed", "keyProvider not found", (Throwable) null);
return;
}
byte[] sifTrailer = Base64.decode(params.getString("sifTrailer"), Base64.DEFAULT);
byte[] sifTrailer = Base64.decode(params.getString("sifTrailer"), Base64.NO_WRAP);
keyProvider.setSifTrailer(sifTrailer);

WritableMap paramsResult = Arguments.createMap();
Expand All @@ -375,8 +377,110 @@ public void keyProviderDispose(ReadableMap params, @NonNull Promise result) {
result.resolve(paramsResult);
}

private byte[] getBytesFromMap(ReadableMap map, String key, String isBase64Key) {
boolean isBase64 = map.getBoolean(isBase64Key);
public void dataPacketCryptorFactoryCreateDataPacketCryptor(ReadableMap params, @NonNull Promise result) {
int algorithm = params.getInt("algorithm");
String keyProviderId = params.getString("keyProviderId");

FrameCryptorKeyProvider keyProvider = keyProviders.get(keyProviderId);
if (keyProvider == null) {
result.reject(
"dataPacketCryptorFactoryCreateDataPacketCryptorFailed", "keyProvider not found", (Throwable) null);
return;
}

DataPacketCryptorManager cryptor =
new DataPacketCryptorManager(frameCryptorAlgorithmFromInt(algorithm), keyProvider);

String dataPacketCryptorId = UUID.randomUUID().toString();
dataPacketCryptors.put(dataPacketCryptorId, cryptor);

WritableMap paramsResult = Arguments.createMap();
paramsResult.putString("dataPacketCryptorId", dataPacketCryptorId);
result.resolve(paramsResult);
}

public void dataPacketCryptorEncrypt(ReadableMap params, @NonNull Promise result) {
String dataPacketCryptorId = params.getString("dataPacketCryptorId");
String participantId = params.getString("participantId");
int keyIndex = params.getInt("keyIndex");
byte[] data = getBytesFromMap(params, "data", null);

DataPacketCryptorManager cryptor = dataPacketCryptors.get(dataPacketCryptorId);

if (cryptor == null) {
result.reject("dataPacketCryptorEncryptFailed", "data packet cryptor not found", (Throwable) null);
return;
}

DataPacketCryptor.EncryptedPacket packet = cryptor.encrypt(participantId, keyIndex, data);

if (packet == null) {
result.reject("dataPacketCryptorEncryptFailed", "null packet", (Throwable) null);
return;
}

WritableMap paramsResult = Arguments.createMap();
paramsResult.putString("payload", Base64.encodeToString(packet.payload, Base64.NO_WRAP));
paramsResult.putString("iv", Base64.encodeToString(packet.iv, Base64.NO_WRAP));
paramsResult.putInt("keyIndex", packet.keyIndex);
result.resolve(paramsResult);
}

public void dataPacketCryptorDecrypt(ReadableMap params, @NonNull Promise result) {
String dataPacketCryptorId = params.getString("dataPacketCryptorId");
String participantId = params.getString("participantId");
int keyIndex = params.getInt("keyIndex");
byte[] payload = getBytesFromMap(params, "payload", null);
byte[] iv = getBytesFromMap(params, "iv", null);

DataPacketCryptorManager cryptor = dataPacketCryptors.get(dataPacketCryptorId);

if (cryptor == null) {
result.reject("dataPacketCryptorDecryptFailed", "data packet cryptor not found", (Throwable) null);
return;
}

DataPacketCryptor.EncryptedPacket packet = new DataPacketCryptor.EncryptedPacket(payload, iv, keyIndex);

byte[] decryptedData = cryptor.decrypt(participantId, packet);

if (decryptedData == null) {
result.reject("dataPacketCryptorDecryptFailed", "null decrypted data", (Throwable) null);
return;
}

WritableMap paramsResult = Arguments.createMap();
paramsResult.putString("data", Base64.encodeToString(decryptedData, Base64.NO_WRAP));
result.resolve(paramsResult);
}

public void dataPacketCryptorDispose(ReadableMap params, @NonNull Promise result) {
String dataPacketCryptorId = params.getString("dataPacketCryptorId");

DataPacketCryptorManager cryptor = dataPacketCryptors.get(dataPacketCryptorId);

if (cryptor == null) {
result.reject("dataPacketCryptorDisposeFailed", "data packet cryptor not found", (Throwable) null);
return;
}

cryptor.dispose();
dataPacketCryptors.remove(dataPacketCryptorId);
WritableMap paramsResult = Arguments.createMap();
paramsResult.putString("result", "success");

result.resolve(paramsResult);
}

private byte[] getBytesFromMap(ReadableMap map, String key, @Nullable String isBase64Key) {
boolean isBase64;

if (isBase64Key != null) {
isBase64 = map.getBoolean(isBase64Key);
} else {
isBase64 = true;
}

byte[] bytes;

if (isBase64) {
Expand Down
22 changes: 21 additions & 1 deletion android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -1461,7 +1461,7 @@ public void dataChannelSend(int peerConnectionId, String reactTag, String data,

// Frame Cryptor methods
////////////////////////////////
RTCFrameCryptor frameCryptor = new RTCFrameCryptor(this);
RTCCryptoManager frameCryptor = new RTCCryptoManager(this);

@ReactMethod(isBlockingSynchronousMethod = true)
public String frameCryptorFactoryCreateFrameCryptor(ReadableMap config) {
Expand Down Expand Up @@ -1538,6 +1538,26 @@ public void keyProviderDispose(ReadableMap config, Promise promise) {
frameCryptor.keyProviderDispose(config, promise);
}

@ReactMethod
public void dataPacketCryptorFactoryCreateDataPacketCryptor(ReadableMap params, @NonNull Promise result) {
frameCryptor.dataPacketCryptorFactoryCreateDataPacketCryptor(params, result);
}

@ReactMethod
public void dataPacketCryptorEncrypt(ReadableMap params, @NonNull Promise result) {
frameCryptor.dataPacketCryptorEncrypt(params, result);
}

@ReactMethod
public void dataPacketCryptorDecrypt(ReadableMap params, @NonNull Promise result) {
frameCryptor.dataPacketCryptorDecrypt(params, result);
}

@ReactMethod
public void dataPacketCryptorDispose(ReadableMap params, @NonNull Promise result) {
frameCryptor.dataPacketCryptorDispose(params, result);
}

@ReactMethod
public void addListener(String eventName) {
// Keep: Required for RN built in Event Emitter Calls.
Expand Down
Loading