Skip to content

Commit 9236159

Browse files
Replace libsodium with cryptology (#558)
* 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 <[email protected]>
1 parent 23673d3 commit 9236159

File tree

13 files changed

+305
-112
lines changed

13 files changed

+305
-112
lines changed

autobahn/build.gradle

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,25 @@ dependencies {
2424
implementation 'com.fasterxml.jackson.core:jackson-databind:2.16.1'
2525
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.16.1'
2626
implementation 'org.msgpack:jackson-dataformat-msgpack:0.9.8'
27-
implementation 'org.web3j:core:5.0.0'
28-
implementation 'org.web3j:abi:5.0.0'
29-
implementation 'org.web3j:utils:5.0.0'
27+
implementation('io.xconn:cryptology:1.0.1') {
28+
exclude group: "org.bouncycastle", module: "bcprov-jdk18on"
29+
}
3030
if (IS_ANDROID) {
31-
implementation 'com.github.joshjdevl.libsodiumjni:libsodium-jni-aar:2.0.2'
32-
} else {
33-
implementation 'com.github.joshjdevl.libsodiumjni:libsodium-jni:2.0.2'
31+
implementation 'org.web3j:core:4.8.8-android'
32+
implementation 'org.web3j:abi:4.8.8-android'
33+
implementation 'org.web3j:utils:4.8.8-android'
34+
} else{
35+
implementation 'org.web3j:core:4.11.0'
36+
implementation 'org.web3j:abi:4.11.0'
37+
implementation 'org.web3j:utils:4.11.0'
3438
implementation 'org.json:json:20240205'
3539
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.5'
3640
}
3741
if (IS_NETTY) {
3842
implementation 'io.netty:netty-codec-http:4.1.106.Final'
3943
implementation 'io.netty:netty-handler:4.1.106.Final'
4044
}
45+
testImplementation 'junit:junit:4.13.2'
4146
}
4247

4348
// Create the pom configuration:
@@ -174,8 +179,8 @@ if (IS_ANDROID) {
174179
jar {
175180
version = relVersion
176181
}
177-
sourceCompatibility = JavaVersion.VERSION_1_8
178-
targetCompatibility = JavaVersion.VERSION_1_8
182+
sourceCompatibility = JavaVersion.VERSION_17
183+
targetCompatibility = JavaVersion.VERSION_17
179184
}
180185

181186
afterEvaluate {
@@ -187,7 +192,7 @@ afterEvaluate {
187192
artifactId ARTIFACT_ANDROID
188193
} else {
189194
from components.java
190-
artifactId IS_NEXT ? ARTIFACT_NEXT: ARTIFACT_JAVA
195+
artifactId IS_NEXT ? ARTIFACT_NEXT : ARTIFACT_JAVA
191196
}
192197

193198
artifact sourcesJar

autobahn/src/main/java/io/crossbar/autobahn/wamp/auth/CryptosignAuth.java

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
package io.crossbar.autobahn.wamp.auth;
22

3-
import org.libsodium.jni.crypto.Random;
4-
import org.libsodium.jni.keys.SigningKey;
5-
import org.libsodium.jni.keys.VerifyKey;
6-
73
import java.io.File;
84
import java.util.HashMap;
95
import java.util.Map;
106
import java.util.concurrent.CompletableFuture;
117

8+
import org.bouncycastle.util.encoders.Hex;
9+
10+
import io.xconn.cryptology.CryptoSign;
11+
import io.xconn.cryptology.KeyPair;
12+
1213
import io.crossbar.autobahn.utils.AuthUtil;
1314
import io.crossbar.autobahn.utils.Pair;
1415
import io.crossbar.autobahn.wamp.Session;
1516
import io.crossbar.autobahn.wamp.interfaces.IAuthenticator;
1617
import io.crossbar.autobahn.wamp.types.Challenge;
1718
import io.crossbar.autobahn.wamp.types.ChallengeResponse;
1819

19-
import static org.libsodium.jni.SodiumConstants.SECRETKEY_BYTES;
2020

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

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

34-
String privateKey = AuthUtil.toHexString(key.toBytes());
35-
String publicKey = AuthUtil.toHexString(signingKey.getVerifyKey().toBytes());
33+
String publicKeyHex = Hex.toHexString(keyPair.getPublicKey());
34+
String privateKeyHex = Hex.toHexString(keyPair.getPrivateKey());
3635

37-
return new Pair<>(publicKey, privateKey);
36+
return new Pair<>(publicKeyHex, privateKeyHex);
3837
}
3938

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

4443
public static String getPublicKey(byte[] privateKeyRaw) {
45-
SigningKey signingKey = new SigningKey(privateKeyRaw);
46-
return AuthUtil.toHexString(signingKey.getVerifyKey().toBytes());
44+
byte[] publicKeyBytes = CryptoSign.getPublicKey(privateKeyRaw);
45+
return AuthUtil.toHexString(publicKeyBytes);
4746
}
4847

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

71-
public CryptosignAuth(String authid, String authrole, String privkey,
72-
Map<String, Object> authextra) {
70+
public CryptosignAuth(String authid, String authrole, String privkey, Map<String, Object> authextra) {
7371
this.authid = authid;
7472
this.authrole = authrole;
7573
this.authextra = authextra;
@@ -85,8 +83,7 @@ public CompletableFuture<ChallengeResponse> onChallenge(Session session, Challen
8583
String hexChallenge = (String) challenge.extra.get("challenge");
8684
byte[] rawChallenge = AuthUtil.toBinary(hexChallenge);
8785

88-
SigningKey key = new SigningKey(privateKeyRaw);
89-
byte[] signed = key.sign(rawChallenge);
86+
byte[] signed = CryptoSign.sign(privateKeyRaw, rawChallenge);
9087

9188
String signatureHex = AuthUtil.toHexString(signed);
9289
String res = signatureHex + hexChallenge;

autobahn/src/main/java/xbr/network/KeySeries.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,21 @@
1111

1212
package xbr.network;
1313

14-
import com.fasterxml.jackson.core.JsonProcessingException;
15-
import com.fasterxml.jackson.databind.ObjectMapper;
16-
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
17-
18-
import org.libsodium.jni.SodiumConstants;
19-
import org.libsodium.jni.crypto.Random;
20-
import org.web3j.utils.Numeric;
21-
2214
import java.math.BigInteger;
2315
import java.util.HashMap;
2416
import java.util.Map;
2517
import java.util.Timer;
2618
import java.util.TimerTask;
2719
import java.util.function.Consumer;
2820

21+
import static io.xconn.cryptology.Util.generateRandomBytesArray;
22+
23+
import com.fasterxml.jackson.core.JsonProcessingException;
24+
import com.fasterxml.jackson.databind.ObjectMapper;
25+
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
26+
27+
import org.web3j.utils.Numeric;
28+
2929
import xbr.network.crypto.SealedBox;
3030
import xbr.network.crypto.SecretBox;
3131

@@ -94,8 +94,7 @@ byte[] getPrice() {
9494
}
9595

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

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

114113
private void onRotate() {
115-
mID = new Random().randomBytes(16);
116-
mKey = new Random().randomBytes(SodiumConstants.XSALSA20_POLY1305_SECRETBOX_KEYBYTES);
114+
mID = generateRandomBytesArray(16);
115+
mKey = generateRandomBytesArray(Util.SECRET_KEY_LEN);
117116
mBox = new SecretBox(mKey);
118117

119118
Map<String, Object> data = new HashMap<>();

autobahn/src/main/java/xbr/network/SimpleBuyer.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import com.fasterxml.jackson.databind.ObjectMapper;
1616
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
1717

18-
import org.libsodium.jni.SodiumConstants;
1918
import org.web3j.crypto.Credentials;
2019
import org.web3j.crypto.ECKeyPair;
2120
import org.web3j.utils.Numeric;
@@ -27,6 +26,8 @@
2726
import java.util.concurrent.CompletableFuture;
2827
import java.util.concurrent.atomic.AtomicReference;
2928

29+
import io.xconn.cryptology.KeyPair;
30+
3031
import io.crossbar.autobahn.utils.ABLogger;
3132
import io.crossbar.autobahn.utils.IABLogger;
3233
import io.crossbar.autobahn.wamp.Session;
@@ -36,8 +37,6 @@
3637
import xbr.network.pojo.Quote;
3738
import xbr.network.pojo.Receipt;
3839

39-
import static org.libsodium.jni.NaCl.sodium;
40-
4140
public class SimpleBuyer {
4241

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

72-
mPrivateKey = new byte[SodiumConstants.SECRETKEY_BYTES];
73-
mPublicKey = new byte[SodiumConstants.PUBLICKEY_BYTES];
74-
sodium().crypto_box_keypair(mPublicKey, mPrivateKey);
71+
KeyPair pubPriKeyPair = io.xconn.cryptology.SealedBox.generateKeyPair();
72+
mPublicKey = pubPriKeyPair.getPublicKey();
73+
mPrivateKey = pubPriKeyPair.getPrivateKey();
7574

7675
mMaxPrice = maxPrice;
7776
mKeys = new HashMap<>();

autobahn/src/main/java/xbr/network/SimpleSeller.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111

1212
package xbr.network;
1313

14+
import static io.xconn.cryptology.Util.generateRandomBytesArray;
15+
1416
import com.fasterxml.jackson.core.JsonProcessingException;
1517
import com.fasterxml.jackson.core.type.TypeReference;
1618

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

9899
List<Object> args = new ArrayList<>();
99100
args.add(series.getID());

autobahn/src/main/java/xbr/network/Util.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727

2828
public class Util {
2929

30+
public static final int NONCE_SIZE = 24;
31+
public static final int SECRET_KEY_LEN = 32;
32+
3033
public static BigInteger toXBR(int xbr) {
3134
return BigInteger.valueOf(xbr).multiply(BigInteger.valueOf(10).pow(18));
3235
}
Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
package xbr.network.crypto;
22

3-
import org.libsodium.jni.encoders.Encoder;
4-
5-
import static org.libsodium.jni.NaCl.sodium;
6-
import static org.libsodium.jni.SodiumConstants.PUBLICKEY_BYTES;
7-
import static org.libsodium.jni.crypto.Util.isValid;
3+
import static io.xconn.cryptology.SealedBox.seal;
4+
import static io.xconn.cryptology.SealedBox.sealOpen;
85

96
public class SealedBox {
107

118
private static final int MAC_BYTES = 16;
9+
private static int PUBLICKEY_BYTES = 32;
1210
private static final int SEAL_BYTES = PUBLICKEY_BYTES + MAC_BYTES;
1311

12+
private static final byte[] HSALSA20_SEED = new byte[16];
1413
private byte[] publicKey;
1514
private byte[] privateKey;
1615

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

25-
public SealedBox(String publicKey, Encoder encoder) {
26-
this(encoder.decode(publicKey));
27-
}
2824

2925
public SealedBox(byte[] publicKey, byte[] privateKey) {
3026
if (publicKey == null) {
@@ -37,23 +33,11 @@ public SealedBox(byte[] publicKey, byte[] privateKey) {
3733
this.privateKey = privateKey;
3834
}
3935

40-
public SealedBox(String publicKey, String privateKey, Encoder encoder) {
41-
this(encoder.decode(publicKey), encoder.decode(privateKey));
42-
}
43-
4436
public byte[] encrypt(byte[] message) {
45-
byte[] ct = new byte[message.length + SEAL_BYTES];
46-
isValid(sodium().crypto_box_seal(
47-
ct, message, message.length, publicKey),
48-
"Encryption failed");
49-
return ct;
37+
return seal(message, publicKey);
5038
}
5139

52-
public byte[] decrypt(byte[] ciphertext) {
53-
byte[] message = new byte[ciphertext.length - SEAL_BYTES];
54-
isValid(sodium().crypto_box_seal_open(
55-
message, ciphertext, ciphertext.length, publicKey, privateKey),
56-
"Decryption failed. Ciphertext failed verification");
57-
return message;
40+
public byte[] decrypt(byte[] message) {
41+
return sealOpen(message, privateKey);
5842
}
5943
}
Lines changed: 17 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,39 @@
11
package xbr.network.crypto;
22

3-
import org.libsodium.jni.crypto.Random;
4-
import org.libsodium.jni.crypto.Util;
5-
import org.libsodium.jni.encoders.Encoder;
6-
73
import java.util.Arrays;
84

9-
import static org.libsodium.jni.NaCl.sodium;
10-
import static org.libsodium.jni.SodiumConstants.BOXZERO_BYTES;
11-
import static org.libsodium.jni.SodiumConstants.XSALSA20_POLY1305_SECRETBOX_KEYBYTES;
12-
import static org.libsodium.jni.SodiumConstants.XSALSA20_POLY1305_SECRETBOX_NONCEBYTES;
13-
import static org.libsodium.jni.SodiumConstants.ZERO_BYTES;
14-
import static org.libsodium.jni.crypto.Util.checkLength;
15-
import static org.libsodium.jni.crypto.Util.isValid;
16-
import static org.libsodium.jni.crypto.Util.removeZeros;
5+
import static io.xconn.cryptology.SecretBox.box;
6+
import static io.xconn.cryptology.SecretBox.boxOpen;
7+
import static io.xconn.cryptology.Util.checkLength;
8+
import static io.xconn.cryptology.Util.generateRandomBytesArray;
179

10+
import static xbr.network.Util.NONCE_SIZE;
11+
import static xbr.network.Util.SECRET_KEY_LEN;
1812

1913
public class SecretBox {
20-
21-
private byte[] mKey;
22-
private Encoder mEncoder;
14+
private final byte[] mKey;
2315

2416
public SecretBox(byte[] key) {
25-
checkLength(key, XSALSA20_POLY1305_SECRETBOX_KEYBYTES);
26-
mEncoder = Encoder.RAW;
27-
mKey = key;
17+
checkLength(key, SECRET_KEY_LEN);
18+
mKey = Arrays.copyOf(key, key.length);
2819
}
2920

3021
public byte[] encrypt(byte[] message) {
31-
byte[] nonce = new Random().randomBytes(XSALSA20_POLY1305_SECRETBOX_NONCEBYTES);
22+
byte[] nonce = generateRandomBytesArray(NONCE_SIZE);
3223
return encrypt(nonce, message);
3324
}
3425

35-
public byte[] encrypt(byte[] nonce, byte[] message) {
36-
checkLength(nonce, XSALSA20_POLY1305_SECRETBOX_NONCEBYTES);
37-
byte[] msg = org.libsodium.jni.crypto.Util.prependZeros(ZERO_BYTES, message);
38-
byte[] ct = org.libsodium.jni.crypto.Util.zeros(msg.length);
39-
isValid(sodium().crypto_secretbox_xsalsa20poly1305(ct, msg, msg.length,
40-
nonce, mKey), "Encryption failed");
41-
byte[] cipherWithoutNonce = removeZeros(BOXZERO_BYTES, ct);
42-
byte[] ciphertext = new byte[cipherWithoutNonce.length +
43-
XSALSA20_POLY1305_SECRETBOX_NONCEBYTES];
26+
public byte[] encrypt(byte[] nonce, byte[] plaintext) {
27+
byte[] cipherWithoutNonce = box(nonce, plaintext, mKey);
28+
byte[] ciphertext = new byte[cipherWithoutNonce.length + NONCE_SIZE];
4429
System.arraycopy(nonce, 0, ciphertext, 0, nonce.length);
45-
System.arraycopy(cipherWithoutNonce, 0, ciphertext, nonce.length,
46-
cipherWithoutNonce.length);
30+
System.arraycopy(cipherWithoutNonce, 0, ciphertext, nonce.length, cipherWithoutNonce.length);
4731
return ciphertext;
4832
}
4933

5034
public byte[] decrypt(byte[] ciphertext) {
51-
byte[] nonce = Arrays.copyOfRange(ciphertext, 0, XSALSA20_POLY1305_SECRETBOX_NONCEBYTES);
52-
byte[] message = Arrays.copyOfRange(ciphertext, XSALSA20_POLY1305_SECRETBOX_NONCEBYTES,
53-
ciphertext.length);
54-
return decrypt(nonce, message);
55-
}
56-
57-
public byte[] decrypt(byte[] nonce, byte[] ciphertext) {
58-
checkLength(nonce, XSALSA20_POLY1305_SECRETBOX_NONCEBYTES);
59-
byte[] ct = org.libsodium.jni.crypto.Util.prependZeros(BOXZERO_BYTES, ciphertext);
60-
byte[] message = Util.zeros(ct.length);
61-
isValid(sodium().crypto_secretbox_xsalsa20poly1305_open(message, ct,
62-
ct.length, nonce, mKey), "Decryption failed. Ciphertext failed verification");
63-
return removeZeros(ZERO_BYTES, message);
35+
byte[] nonce = Arrays.copyOfRange(ciphertext, 0, NONCE_SIZE);
36+
byte[] message = Arrays.copyOfRange(ciphertext, NONCE_SIZE, ciphertext.length);
37+
return boxOpen(nonce, message, mKey);
6438
}
6539
}

0 commit comments

Comments
 (0)