Skip to content

Commit

Permalink
Replace libsodium with cryptology (#558)
Browse files Browse the repository at this point in the history
* use bouncycastle in cryptosign auth

* add missing space

* add unit tests for CryptosignAuth

* replace libsodium with bouncy castle in SecretBox

* add missing EOL

* add function to create sealedbox nonce

* add function to compute shared secret for sealedbox

* implement the libsodium compatible seal function

* implement the libsodium compatible unseal function

* make encrypt to only use the new code

* remove dependency of libsodium

* use correct version of web3j

* use correct dependencies

* add HSalsa20 implementation based on bouncy castle

* make HSALSA20_SEED global,static variable

* add lisence for HSalsa20

* update web3j and java

* use cryptology

* exclude bouncy-castle from cryptology

* remove unnecessary checkLength() function

* update cryptology

---------

Co-authored-by: Omer Akram <omer@thing.com>
  • Loading branch information
muzzammilshahid and om26er authored Mar 25, 2024
1 parent 23673d3 commit 9236159
Show file tree
Hide file tree
Showing 13 changed files with 305 additions and 112 deletions.
23 changes: 14 additions & 9 deletions autobahn/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,25 @@ dependencies {
implementation 'com.fasterxml.jackson.core:jackson-databind:2.16.1'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.16.1'
implementation 'org.msgpack:jackson-dataformat-msgpack:0.9.8'
implementation 'org.web3j:core:5.0.0'
implementation 'org.web3j:abi:5.0.0'
implementation 'org.web3j:utils:5.0.0'
implementation('io.xconn:cryptology:1.0.1') {
exclude group: "org.bouncycastle", module: "bcprov-jdk18on"
}
if (IS_ANDROID) {
implementation 'com.github.joshjdevl.libsodiumjni:libsodium-jni-aar:2.0.2'
} else {
implementation 'com.github.joshjdevl.libsodiumjni:libsodium-jni:2.0.2'
implementation 'org.web3j:core:4.8.8-android'
implementation 'org.web3j:abi:4.8.8-android'
implementation 'org.web3j:utils:4.8.8-android'
} else{
implementation 'org.web3j:core:4.11.0'
implementation 'org.web3j:abi:4.11.0'
implementation 'org.web3j:utils:4.11.0'
implementation 'org.json:json:20240205'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.5'
}
if (IS_NETTY) {
implementation 'io.netty:netty-codec-http:4.1.106.Final'
implementation 'io.netty:netty-handler:4.1.106.Final'
}
testImplementation 'junit:junit:4.13.2'
}

// Create the pom configuration:
Expand Down Expand Up @@ -174,8 +179,8 @@ if (IS_ANDROID) {
jar {
version = relVersion
}
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

afterEvaluate {
Expand All @@ -187,7 +192,7 @@ afterEvaluate {
artifactId ARTIFACT_ANDROID
} else {
from components.java
artifactId IS_NEXT ? ARTIFACT_NEXT: ARTIFACT_JAVA
artifactId IS_NEXT ? ARTIFACT_NEXT : ARTIFACT_JAVA
}

artifact sourcesJar
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
package io.crossbar.autobahn.wamp.auth;

import org.libsodium.jni.crypto.Random;
import org.libsodium.jni.keys.SigningKey;
import org.libsodium.jni.keys.VerifyKey;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

import org.bouncycastle.util.encoders.Hex;

import io.xconn.cryptology.CryptoSign;
import io.xconn.cryptology.KeyPair;

import io.crossbar.autobahn.utils.AuthUtil;
import io.crossbar.autobahn.utils.Pair;
import io.crossbar.autobahn.wamp.Session;
import io.crossbar.autobahn.wamp.interfaces.IAuthenticator;
import io.crossbar.autobahn.wamp.types.Challenge;
import io.crossbar.autobahn.wamp.types.ChallengeResponse;

import static org.libsodium.jni.SodiumConstants.SECRETKEY_BYTES;

public class CryptosignAuth implements IAuthenticator {
public static final String authmethod = "cryptosign";
Expand All @@ -28,22 +28,21 @@ public class CryptosignAuth implements IAuthenticator {
private final byte[] privateKeyRaw;

public static Pair<String, String> generateSigningKeyPair() {
VerifyKey key = new VerifyKey(new Random().randomBytes(SECRETKEY_BYTES));
SigningKey signingKey = new SigningKey(key.toBytes());
KeyPair keyPair = CryptoSign.generateKeyPair();

String privateKey = AuthUtil.toHexString(key.toBytes());
String publicKey = AuthUtil.toHexString(signingKey.getVerifyKey().toBytes());
String publicKeyHex = Hex.toHexString(keyPair.getPublicKey());
String privateKeyHex = Hex.toHexString(keyPair.getPrivateKey());

return new Pair<>(publicKey, privateKey);
return new Pair<>(publicKeyHex, privateKeyHex);
}

public CryptosignAuth(String authid, String privateKey) {
this(authid, privateKey, getPublicKey(AuthUtil.toBinary(privateKey)));
}

public static String getPublicKey(byte[] privateKeyRaw) {
SigningKey signingKey = new SigningKey(privateKeyRaw);
return AuthUtil.toHexString(signingKey.getVerifyKey().toBytes());
byte[] publicKeyBytes = CryptoSign.getPublicKey(privateKeyRaw);
return AuthUtil.toHexString(publicKeyBytes);
}

public CryptosignAuth(String authid, String privkey, Map<String, Object> authextra) {
Expand All @@ -68,8 +67,7 @@ public CryptosignAuth(String authid, File privateKeyFile) {
}
}

public CryptosignAuth(String authid, String authrole, String privkey,
Map<String, Object> authextra) {
public CryptosignAuth(String authid, String authrole, String privkey, Map<String, Object> authextra) {
this.authid = authid;
this.authrole = authrole;
this.authextra = authextra;
Expand All @@ -85,8 +83,7 @@ public CompletableFuture<ChallengeResponse> onChallenge(Session session, Challen
String hexChallenge = (String) challenge.extra.get("challenge");
byte[] rawChallenge = AuthUtil.toBinary(hexChallenge);

SigningKey key = new SigningKey(privateKeyRaw);
byte[] signed = key.sign(rawChallenge);
byte[] signed = CryptoSign.sign(privateKeyRaw, rawChallenge);

String signatureHex = AuthUtil.toHexString(signed);
String res = signatureHex + hexChallenge;
Expand Down
23 changes: 11 additions & 12 deletions autobahn/src/main/java/xbr/network/KeySeries.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,21 @@

package xbr.network;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;

import org.libsodium.jni.SodiumConstants;
import org.libsodium.jni.crypto.Random;
import org.web3j.utils.Numeric;

import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.function.Consumer;

import static io.xconn.cryptology.Util.generateRandomBytesArray;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;

import org.web3j.utils.Numeric;

import xbr.network.crypto.SealedBox;
import xbr.network.crypto.SecretBox;

Expand Down Expand Up @@ -94,8 +94,7 @@ byte[] getPrice() {
}

Map<String, Object> encrypt(Object payload) throws JsonProcessingException {
byte[] nonce = new Random().randomBytes(
SodiumConstants.XSALSA20_POLY1305_SECRETBOX_NONCEBYTES);
byte[] nonce = generateRandomBytesArray(Util.NONCE_SIZE);

Map<String, Object> data = new HashMap<>();
data.put("id", mID);
Expand All @@ -112,8 +111,8 @@ byte[] encryptKey(byte[] keyID, byte[] buyerPubKey) {
}

private void onRotate() {
mID = new Random().randomBytes(16);
mKey = new Random().randomBytes(SodiumConstants.XSALSA20_POLY1305_SECRETBOX_KEYBYTES);
mID = generateRandomBytesArray(16);
mKey = generateRandomBytesArray(Util.SECRET_KEY_LEN);
mBox = new SecretBox(mKey);

Map<String, Object> data = new HashMap<>();
Expand Down
11 changes: 5 additions & 6 deletions autobahn/src/main/java/xbr/network/SimpleBuyer.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;

import org.libsodium.jni.SodiumConstants;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.ECKeyPair;
import org.web3j.utils.Numeric;
Expand All @@ -27,6 +26,8 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;

import io.xconn.cryptology.KeyPair;

import io.crossbar.autobahn.utils.ABLogger;
import io.crossbar.autobahn.utils.IABLogger;
import io.crossbar.autobahn.wamp.Session;
Expand All @@ -36,8 +37,6 @@
import xbr.network.pojo.Quote;
import xbr.network.pojo.Receipt;

import static org.libsodium.jni.NaCl.sodium;

public class SimpleBuyer {

private static final IABLogger LOGGER = ABLogger.getLogger(SimpleBuyer.class.getName());
Expand Down Expand Up @@ -69,9 +68,9 @@ public SimpleBuyer(String marketMakerAddr, String buyerKey, BigInteger maxPrice)
mEthPublicKey = mECKey.getPublicKey().toByteArray();
mEthAddr = Numeric.hexStringToByteArray(Credentials.create(mECKey).getAddress());

mPrivateKey = new byte[SodiumConstants.SECRETKEY_BYTES];
mPublicKey = new byte[SodiumConstants.PUBLICKEY_BYTES];
sodium().crypto_box_keypair(mPublicKey, mPrivateKey);
KeyPair pubPriKeyPair = io.xconn.cryptology.SealedBox.generateKeyPair();
mPublicKey = pubPriKeyPair.getPublicKey();
mPrivateKey = pubPriKeyPair.getPrivateKey();

mMaxPrice = maxPrice;
mKeys = new HashMap<>();
Expand Down
5 changes: 3 additions & 2 deletions autobahn/src/main/java/xbr/network/SimpleSeller.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@

package xbr.network;

import static io.xconn.cryptology.Util.generateRandomBytesArray;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;

import org.libsodium.jni.crypto.Random;
import org.web3j.crypto.ECKeyPair;
import org.web3j.crypto.Keys;
import org.web3j.utils.Numeric;
Expand Down Expand Up @@ -93,7 +94,7 @@ public byte[] getPublicKey() {
private void onRotate(KeySeries series) {
mKeysMap.put(Numeric.toHexString(series.getID()), series);
long validFrom = Math.round(System.nanoTime() - 10 * Math.pow(10, 9));
byte[] signature = new Random().randomBytes(65);
byte[] signature = generateRandomBytesArray(65);

List<Object> args = new ArrayList<>();
args.add(series.getID());
Expand Down
3 changes: 3 additions & 0 deletions autobahn/src/main/java/xbr/network/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@

public class Util {

public static final int NONCE_SIZE = 24;
public static final int SECRET_KEY_LEN = 32;

public static BigInteger toXBR(int xbr) {
return BigInteger.valueOf(xbr).multiply(BigInteger.valueOf(10).pow(18));
}
Expand Down
30 changes: 7 additions & 23 deletions autobahn/src/main/java/xbr/network/crypto/SealedBox.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package xbr.network.crypto;

import org.libsodium.jni.encoders.Encoder;

import static org.libsodium.jni.NaCl.sodium;
import static org.libsodium.jni.SodiumConstants.PUBLICKEY_BYTES;
import static org.libsodium.jni.crypto.Util.isValid;
import static io.xconn.cryptology.SealedBox.seal;
import static io.xconn.cryptology.SealedBox.sealOpen;

public class SealedBox {

private static final int MAC_BYTES = 16;
private static int PUBLICKEY_BYTES = 32;
private static final int SEAL_BYTES = PUBLICKEY_BYTES + MAC_BYTES;

private static final byte[] HSALSA20_SEED = new byte[16];
private byte[] publicKey;
private byte[] privateKey;

Expand All @@ -22,9 +21,6 @@ public SealedBox(byte[] publicKey) {
this.privateKey = null;
}

public SealedBox(String publicKey, Encoder encoder) {
this(encoder.decode(publicKey));
}

public SealedBox(byte[] publicKey, byte[] privateKey) {
if (publicKey == null) {
Expand All @@ -37,23 +33,11 @@ public SealedBox(byte[] publicKey, byte[] privateKey) {
this.privateKey = privateKey;
}

public SealedBox(String publicKey, String privateKey, Encoder encoder) {
this(encoder.decode(publicKey), encoder.decode(privateKey));
}

public byte[] encrypt(byte[] message) {
byte[] ct = new byte[message.length + SEAL_BYTES];
isValid(sodium().crypto_box_seal(
ct, message, message.length, publicKey),
"Encryption failed");
return ct;
return seal(message, publicKey);
}

public byte[] decrypt(byte[] ciphertext) {
byte[] message = new byte[ciphertext.length - SEAL_BYTES];
isValid(sodium().crypto_box_seal_open(
message, ciphertext, ciphertext.length, publicKey, privateKey),
"Decryption failed. Ciphertext failed verification");
return message;
public byte[] decrypt(byte[] message) {
return sealOpen(message, privateKey);
}
}
60 changes: 17 additions & 43 deletions autobahn/src/main/java/xbr/network/crypto/SecretBox.java
Original file line number Diff line number Diff line change
@@ -1,65 +1,39 @@
package xbr.network.crypto;

import org.libsodium.jni.crypto.Random;
import org.libsodium.jni.crypto.Util;
import org.libsodium.jni.encoders.Encoder;

import java.util.Arrays;

import static org.libsodium.jni.NaCl.sodium;
import static org.libsodium.jni.SodiumConstants.BOXZERO_BYTES;
import static org.libsodium.jni.SodiumConstants.XSALSA20_POLY1305_SECRETBOX_KEYBYTES;
import static org.libsodium.jni.SodiumConstants.XSALSA20_POLY1305_SECRETBOX_NONCEBYTES;
import static org.libsodium.jni.SodiumConstants.ZERO_BYTES;
import static org.libsodium.jni.crypto.Util.checkLength;
import static org.libsodium.jni.crypto.Util.isValid;
import static org.libsodium.jni.crypto.Util.removeZeros;
import static io.xconn.cryptology.SecretBox.box;
import static io.xconn.cryptology.SecretBox.boxOpen;
import static io.xconn.cryptology.Util.checkLength;
import static io.xconn.cryptology.Util.generateRandomBytesArray;

import static xbr.network.Util.NONCE_SIZE;
import static xbr.network.Util.SECRET_KEY_LEN;

public class SecretBox {

private byte[] mKey;
private Encoder mEncoder;
private final byte[] mKey;

public SecretBox(byte[] key) {
checkLength(key, XSALSA20_POLY1305_SECRETBOX_KEYBYTES);
mEncoder = Encoder.RAW;
mKey = key;
checkLength(key, SECRET_KEY_LEN);
mKey = Arrays.copyOf(key, key.length);
}

public byte[] encrypt(byte[] message) {
byte[] nonce = new Random().randomBytes(XSALSA20_POLY1305_SECRETBOX_NONCEBYTES);
byte[] nonce = generateRandomBytesArray(NONCE_SIZE);
return encrypt(nonce, message);
}

public byte[] encrypt(byte[] nonce, byte[] message) {
checkLength(nonce, XSALSA20_POLY1305_SECRETBOX_NONCEBYTES);
byte[] msg = org.libsodium.jni.crypto.Util.prependZeros(ZERO_BYTES, message);
byte[] ct = org.libsodium.jni.crypto.Util.zeros(msg.length);
isValid(sodium().crypto_secretbox_xsalsa20poly1305(ct, msg, msg.length,
nonce, mKey), "Encryption failed");
byte[] cipherWithoutNonce = removeZeros(BOXZERO_BYTES, ct);
byte[] ciphertext = new byte[cipherWithoutNonce.length +
XSALSA20_POLY1305_SECRETBOX_NONCEBYTES];
public byte[] encrypt(byte[] nonce, byte[] plaintext) {
byte[] cipherWithoutNonce = box(nonce, plaintext, mKey);
byte[] ciphertext = new byte[cipherWithoutNonce.length + NONCE_SIZE];
System.arraycopy(nonce, 0, ciphertext, 0, nonce.length);
System.arraycopy(cipherWithoutNonce, 0, ciphertext, nonce.length,
cipherWithoutNonce.length);
System.arraycopy(cipherWithoutNonce, 0, ciphertext, nonce.length, cipherWithoutNonce.length);
return ciphertext;
}

public byte[] decrypt(byte[] ciphertext) {
byte[] nonce = Arrays.copyOfRange(ciphertext, 0, XSALSA20_POLY1305_SECRETBOX_NONCEBYTES);
byte[] message = Arrays.copyOfRange(ciphertext, XSALSA20_POLY1305_SECRETBOX_NONCEBYTES,
ciphertext.length);
return decrypt(nonce, message);
}

public byte[] decrypt(byte[] nonce, byte[] ciphertext) {
checkLength(nonce, XSALSA20_POLY1305_SECRETBOX_NONCEBYTES);
byte[] ct = org.libsodium.jni.crypto.Util.prependZeros(BOXZERO_BYTES, ciphertext);
byte[] message = Util.zeros(ct.length);
isValid(sodium().crypto_secretbox_xsalsa20poly1305_open(message, ct,
ct.length, nonce, mKey), "Decryption failed. Ciphertext failed verification");
return removeZeros(ZERO_BYTES, message);
byte[] nonce = Arrays.copyOfRange(ciphertext, 0, NONCE_SIZE);
byte[] message = Arrays.copyOfRange(ciphertext, NONCE_SIZE, ciphertext.length);
return boxOpen(nonce, message, mKey);
}
}
Loading

0 comments on commit 9236159

Please sign in to comment.