Skip to content

Commit

Permalink
Changed encryption to AES/GCM/NoPadding
Browse files Browse the repository at this point in the history
  • Loading branch information
ehsan6sha committed May 12, 2023
1 parent b1188cd commit aa30030
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 29 deletions.
37 changes: 25 additions & 12 deletions android/src/main/java/land/fx/fula/Cryptography.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
import android.util.Base64;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.SecureRandom;
import java.nio.ByteBuffer;
import java.security.spec.InvalidParameterSpecException;

import javax.crypto.BadPaddingException;
Expand All @@ -17,24 +20,34 @@
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.GCMParameterSpec;

public class Cryptography {
public static String encryptMsg(String message, SecretKey secret)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
Cipher cipher = null;
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
byte[] cipherText = cipher.doFinal(message.getBytes("UTF-8"));
return Base64.encodeToString(cipherText, Base64.NO_WRAP);
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
byte[] iv = new byte[12]; // Ensure this is randomly generated for each encryption.
new SecureRandom().nextBytes(iv);
GCMParameterSpec spec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.ENCRYPT_MODE, secret, spec);
byte[] cipherText = cipher.doFinal(message.getBytes(StandardCharsets.UTF_8));
ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + cipherText.length);
byteBuffer.put(iv);
byteBuffer.put(cipherText);
return Base64.encodeToString(byteBuffer.array(), Base64.NO_WRAP);
}

public static String decryptMsg(String cipherText, SecretKey secret)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidParameterSpecException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {
Cipher cipher = null;
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret);
byte[] decode = Base64.decode(cipherText, Base64.NO_WRAP);
String decryptString = new String(cipher.doFinal(decode), "UTF-8");
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
ByteBuffer byteBuffer = ByteBuffer.wrap(Base64.decode(cipherText, Base64.NO_WRAP));
byte[] iv = new byte[12];
byteBuffer.get(iv);
byte[] cipherBytes = new byte[byteBuffer.remaining()];
byteBuffer.get(cipherBytes);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.DECRYPT_MODE, secret, spec);
String decryptString = new String(cipher.doFinal(cipherBytes), StandardCharsets.UTF_8);
return decryptString;
}

Expand Down
55 changes: 39 additions & 16 deletions android/src/main/java/land/fx/fula/FulaModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,17 @@
import org.jetbrains.annotations.Contract;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;

import java.util.concurrent.Executors;
Expand Down Expand Up @@ -414,24 +422,32 @@ private boolean retryFailedActionsInternal(int timeout) throws Exception {
}

@NonNull
private byte[] createPeerIdentity(byte[] privateKey) throws Exception {
private byte[] createPeerIdentity(byte[] privateKey) throws GeneralSecurityException, IOException {
try {
// 1: First: create public key from provided private key
// 2: Should read the local keychain store (if it is key-value, key is public key above,
// 3: if found, decrypt using the private key
// 4: If not found or decryption not successful, generate an identity
// 5: then encrypt and store in keychain

String encryptedKey = sharedPref.getValue(PRIVATE_KEY_STORE_ID);
SecretKey secretKey = Cryptography.generateKey(privateKey);
if (encryptedKey == null) {
byte[] autoGeneratedIdentity = Fulamobile.generateEd25519Key();
encryptedKey = Cryptography.encryptMsg(StaticHelper.bytesToBase64(autoGeneratedIdentity), secretKey);

if (encryptedKey == null || !encryptedKey.startsWith("FULA_ENC_V2:")) {
byte[] autoGeneratedIdentity;
try {
autoGeneratedIdentity = Fulamobile.generateEd25519Key();
} catch (Exception e) {
Log.d("ReactNative", "Failed to generate key: " + e.getMessage());
throw new GeneralSecurityException("Failed to generate key", e);
}
encryptedKey = "FULA_ENC_V2:" + Cryptography.encryptMsg(StaticHelper.bytesToBase64(autoGeneratedIdentity), secretKey);
sharedPref.add(PRIVATE_KEY_STORE_ID, encryptedKey);
}
return StaticHelper.base64ToBytes(Cryptography.decryptMsg(encryptedKey, secretKey));

} catch (Exception e) {
String decryptedKey = Cryptography.decryptMsg(encryptedKey.replace("FULA_ENC_V2:", ""), secretKey);
return StaticHelper.base64ToBytes(decryptedKey);

} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) {
Log.d("ReactNative", "createPeerIdentity failed with Error: " + e.getMessage());
throw (e);
}
Expand Down Expand Up @@ -512,7 +528,8 @@ public fulamobile.Client getFulaClient() {
}

@NonNull
private byte[] newClientInternal(byte[] identity, String storePath, String bloxAddr, String exchange, boolean autoFlush, boolean useRelay, boolean refresh) throws Exception {
private byte[] newClientInternal(byte[] identity, String storePath, String bloxAddr, String exchange, boolean autoFlush, boolean useRelay, boolean refresh) throws GeneralSecurityException, IOException {
byte[] peerIdentity = null;
try {
fulaConfig = new Config();
if (storePath == null || storePath.trim().isEmpty()) {
Expand All @@ -522,7 +539,7 @@ private byte[] newClientInternal(byte[] identity, String storePath, String bloxA
}
Log.d("ReactNative", "newClientInternal storePath is set: " + fulaConfig.getStorePath());

byte[] peerIdentity = this.createPeerIdentity(identity);
peerIdentity = this.createPeerIdentity(identity);
fulaConfig.setIdentity(peerIdentity);
Log.d("ReactNative", "peerIdentity is set: " + toString(fulaConfig.getIdentity()));
fulaConfig.setBloxAddr(bloxAddr);
Expand All @@ -535,19 +552,25 @@ private byte[] newClientInternal(byte[] identity, String storePath, String bloxA
}
if (this.fula == null || refresh) {
Log.d("ReactNative", "Creating a new Fula instance");
shutdownInternal();
this.fula = Fulamobile.newClient(fulaConfig);
}
if (this.fula != null) {
this.fula.flush();
try {
shutdownInternal();
this.fula = Fulamobile.newClient(fulaConfig);
if (this.fula != null) {
this.fula.flush();
}
} catch (Exception e) {
Log.d("ReactNative", "Failed to create new Fula instance: " + e.getMessage());
throw new IOException("Failed to create new Fula instance", e);
}
}
return peerIdentity;
} catch (Exception e) {
} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) {
Log.d("ReactNative", "newclientInternal failed with Error: " + e.getMessage());
throw (e);
}
return peerIdentity;
}


@NonNull
private String[] initInternal(byte[] identity, String storePath, String bloxAddr, String exchange, boolean autoFlush, String rootCid, boolean useRelay, boolean refresh) throws Exception {
try {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@functionland/react-native-fula",
"version": "1.2.2",
"version": "1.2.3",
"description": "This package is a bridge to use the Fula libp2p protocols in the react-native which is using wnfs",
"main": "lib/commonjs/index",
"module": "lib/module/index",
Expand Down

0 comments on commit aa30030

Please sign in to comment.