Skip to content

Commit

Permalink
Merge pull request #2 from om26er/sealedbox-bouncy
Browse files Browse the repository at this point in the history
Change SealedBox implementation to use bouncycastle
  • Loading branch information
muzzammilshahid authored Feb 26, 2024
2 parents 967e127 + af76c2c commit 2ce33d2
Show file tree
Hide file tree
Showing 3 changed files with 213 additions and 17 deletions.
146 changes: 146 additions & 0 deletions autobahn/src/main/java/xbr/network/crypto/Salsa.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package xbr.network.crypto;

/**
*/
public class Salsa {
public static byte[] SIGMA = {'e', 'x', 'p', 'a', 'n', 'd', ' ', '3', '2', '-', 'b', 'y', 't', 'e', ' ', 'k'};

// HSalsa20 applies the HSalsa20 core function to a 16-byte input in, 32-byte
// key k, and 16-byte constant c, and returns the result as the 32-byte array
// out.
public static byte[] HSalsa20(byte[] in, byte[] k, byte[] c) {
long x0 = (0xFFl & c[0]) | (0xFFl & c[1]) << 8 | (0xFFl & c[2]) << 16 | (0xFFl & c[3]) << 24;
long x1 = (0xFFl & k[0]) | (0xFFl & k[1]) << 8 | (0xFFl & k[2]) << 16 | (0xFFl & k[3]) << 24;
long x2 = (0xFFl & k[4]) | (0xFFl & k[5]) << 8 | (0xFFl & k[6]) << 16 | (0xFFl & k[7]) << 24;
long x3 = (0xFFl & k[8]) | (0xFFl & k[9]) << 8 | (0xFFl & k[10]) << 16 | (0xFFl & k[11]) << 24;
long x4 = (0xFFl & k[12]) | (0xFFl & k[13]) << 8 | (0xFFl & k[14]) << 16 | (0xFFl & k[15]) << 24;
long x5 = (0xFFl & c[4]) | (0xFFl & c[5]) << 8 | (0xFFl & c[6]) << 16 | (0xFFl & c[7]) << 24;
long x6 = (0xFFl & in[0]) | (0xFFl & in[1]) << 8 | (0xFFl & in[2]) << 16 | (0xFFl & in[3]) << 24;
long x7 = (0xFFl & in[4]) | (0xFFl & in[5]) << 8 | (0xFFl & in[6]) << 16 | (0xFFl & in[7]) << 24;
long x8 = (0xFFl & in[8]) | (0xFFl & in[9]) << 8 | (0xFFl & in[10]) << 16 | (0xFFl & in[11]) << 24;
long x9 = (0xFFl & in[12]) | (0xFFl & in[13]) << 8 | (0xFFl & in[14]) << 16 | (0xFFl & in[15]) << 24;
long x10 = (0xFFl & c[8]) | (0xFFl & c[9]) << 8 | (0xFFl & c[10]) << 16 | (0xFFl & c[11]) << 24;
long x11 = (0xFFl & k[16]) | (0xFFl & k[17]) << 8 | (0xFFl & k[18]) << 16 | (0xFFl & k[19]) << 24;
long x12 = (0xFFl & k[20]) | (0xFFl & k[21]) << 8 | (0xFFl & k[22]) << 16 | (0xFFl & k[23]) << 24;
long x13 = (0xFFl & k[24]) | (0xFFl & k[25]) << 8 | (0xFFl & k[26]) << 16 | (0xFFl & k[27]) << 24;
long x14 = (0xFFl & k[28]) | (0xFFl & k[29]) << 8 | (0xFFl & k[30]) << 16 | (0xFFl & k[31]) << 24;
long x15 = (0xFFl & c[12]) | (0xFFl & c[13]) << 8 | (0xFFl & c[14]) << 16 | (0xFFl & c[15]) << 24;

long mask = 0xFFFFFFFFl;
for (int i = 0; i < 20; i += 2) {
long u = mask & (x0 + x12);
x4 ^= mask & (u << 7 | u >>> (32 - 7));
u = mask & (x4 + x0);
x8 ^= mask & (u << 9 | u >>> (32 - 9));
u = mask & (x8 + x4);
x12 ^= mask & (u << 13 | u >>> (32 - 13));
u = mask & (x12 + x8);
x0 ^= mask & (u << 18 | u >>> (32 - 18));

u = mask & (x5 + x1);
x9 ^= mask & (u << 7 | u >>> (32 - 7));
u = mask & (x9 + x5);
x13 ^= mask & (u << 9 | u >>> (32 - 9));
u = mask & (x13 + x9);
x1 ^= mask & (u << 13 | u >>> (32 - 13));
u = mask & (x1 + x13);
x5 ^= mask & (u << 18 | u >>> (32 - 18));

u = mask & (x10 + x6);
x14 ^= mask & (u << 7 | u >>> (32 - 7));
u = mask & (x14 + x10);
x2 ^= mask & (u << 9 | u >>> (32 - 9));
u = mask & (x2 + x14);
x6 ^= mask & (u << 13 | u >>> (32 - 13));
u = mask & (x6 + x2);
x10 ^= mask & (u << 18 | u >>> (32 - 18));

u = mask & (x15 + x11);
x3 ^= mask & (u << 7 | u >>> (32 - 7));
u = mask & (x3 + x15);
x7 ^= mask & (u << 9 | u >>> (32 - 9));
u = mask & (x7 + x3);
x11 ^= mask & (u << 13 | u >>> (32 - 13));
u = mask & (x11 + x7);
x15 ^= mask & (u << 18 | u >>> (32 - 18));

u = mask & (x0 + x3);
x1 ^= mask & (u << 7 | u >>> (32 - 7));
u = mask & (x1 + x0);
x2 ^= mask & (u << 9 | u >>> (32 - 9));
u = mask & (x2 + x1);
x3 ^= mask & (u << 13 | u >>> (32 - 13));
u = mask & (x3 + x2);
x0 ^= mask & (u << 18 | u >>> (32 - 18));

u = mask & (x5 + x4);
x6 ^= mask & (u << 7 | u >>> (32 - 7));
u = mask & (x6 + x5);
x7 ^= mask & (u << 9 | u >>> (32 - 9));
u = mask & (x7 + x6);
x4 ^= mask & (u << 13 | u >>> (32 - 13));
u = mask & (x4 + x7);
x5 ^= mask & (u << 18 | u >>> (32 - 18));

u = mask & (x10 + x9);
x11 ^= mask & (u << 7 | u >>> (32 - 7));
u = mask & (x11 + x10);
x8 ^= mask & (u << 9 | u >>> (32 - 9));
u = mask & (x8 + x11);
x9 ^= mask & (u << 13 | u >>> (32 - 13));
u = mask & (x9 + x8);
x10 ^= mask & (u << 18 | u >>> (32 - 18));

u = mask & (x15 + x14);
x12 ^= mask & (u << 7 | u >>> (32 - 7));
u = mask & (x12 + x15);
x13 ^= mask & (u << 9 | u >>> (32 - 9));
u = mask & (x13 + x12);
x14 ^= mask & (u << 13 | u >>> (32 - 13));
u = mask & (x14 + x13);
x15 ^= mask & (u << 18 | u >>> (32 - 18));
}

byte out[] = new byte[32];
out[0] = (byte) x0;
out[1] = (byte) (x0 >> 8);
out[2] = (byte) (x0 >> 16);
out[3] = (byte) (x0 >> 24);

out[4] = (byte) (x5);
out[5] = (byte) (x5 >> 8);
out[6] = (byte) (x5 >> 16);
out[7] = (byte) (x5 >> 24);

out[8] = (byte) (x10);
out[9] = (byte) (x10 >> 8);
out[10] = (byte) (x10 >> 16);
out[11] = (byte) (x10 >> 24);

out[12] = (byte) (x15);
out[13] = (byte) (x15 >> 8);
out[14] = (byte) (x15 >> 16);
out[15] = (byte) (x15 >> 24);

out[16] = (byte) (x6);
out[17] = (byte) (x6 >> 8);
out[18] = (byte) (x6 >> 16);
out[19] = (byte) (x6 >> 24);

out[20] = (byte) (x7);
out[21] = (byte) (x7 >> 8);
out[22] = (byte) (x7 >> 16);
out[23] = (byte) (x7 >> 24);

out[24] = (byte) (x8);
out[25] = (byte) (x8 >> 8);
out[26] = (byte) (x8 >> 16);
out[27] = (byte) (x8 >> 24);

out[28] = (byte) (x9);
out[29] = (byte) (x9 >> 8);
out[30] = (byte) (x9 >> 16);
out[31] = (byte) (x9 >> 24);
return out;
}
}
81 changes: 66 additions & 15 deletions autobahn/src/main/java/xbr/network/crypto/SealedBox.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
package xbr.network.crypto;

import org.bouncycastle.crypto.digests.Blake2bDigest;
import org.bouncycastle.crypto.engines.XSalsa20Engine;
import org.bouncycastle.crypto.macs.Poly1305;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.math.ec.rfc7748.X25519;
import org.bouncycastle.util.Arrays;
import org.libsodium.jni.encoders.Encoder;

import static org.libsodium.jni.NaCl.sodium;
import static org.libsodium.jni.SodiumConstants.NONCE_BYTES;
import static org.libsodium.jni.SodiumConstants.PUBLICKEY_BYTES;
import static org.libsodium.jni.crypto.Util.isValid;
import static org.libsodium.jni.SodiumConstants.SECRETKEY_BYTES;

import io.crossbar.autobahn.utils.Pair;
import xbr.network.Util;

public class SealedBox {

Expand Down Expand Up @@ -42,18 +52,59 @@ public SealedBox(String publicKey, String privateKey, Encoder encoder) {
}

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;
}

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;
Pair<byte[], byte[]> keyPair = Util.generateX25519KeyPair();
byte[] nonce = createNonce(keyPair.first, publicKey);
byte[] sharedSecret = computeSharedSecret(publicKey, keyPair.second);

XSalsa20Engine cipher = new XSalsa20Engine();
ParametersWithIV params = new ParametersWithIV(new KeyParameter(sharedSecret), nonce);
cipher.init(true, params);

byte[] sk = new byte[SECRETKEY_BYTES];
cipher.processBytes(sk, 0, sk.length, sk, 0);

// encrypt the message
byte[] ciphertext = new byte[message.length];
cipher.processBytes(message, 0, message.length, ciphertext, 0);

// create the MAC
Poly1305 mac = new Poly1305();
byte[] macBuf = new byte[mac.getMacSize()];
mac.init(new KeyParameter(sk));
mac.update(ciphertext, 0, ciphertext.length);
mac.doFinal(macBuf, 0);

return Arrays.concatenate(keyPair.first, macBuf, ciphertext);
}

private byte[] createNonce(byte[] ephemeralPublicKey, byte[] recipientPublicKey) {
Blake2bDigest blake2b = new Blake2bDigest(NONCE_BYTES * 8);
byte[] nonce = new byte[blake2b.getDigestSize()];

blake2b.update(ephemeralPublicKey, 0, ephemeralPublicKey.length);
blake2b.update(recipientPublicKey, 0, recipientPublicKey.length);

blake2b.doFinal(nonce, 0);

return nonce;
}

public byte[] computeSharedSecret(byte[] publicKey, byte[] privateKey) {
byte[] sharedSecret = new byte[32];
// compute the raw shared secret
X25519.scalarMult(privateKey, 0, publicKey, 0, sharedSecret, 0);
// encrypt the shared secret
byte[] nonce = new byte[32];
return Salsa.HSalsa20(nonce, sharedSecret, Salsa.SIGMA);
}

public byte[] decrypt(byte[] message) {
byte[] ephemeralPublicKey = Arrays.copyOf(message, PUBLICKEY_BYTES);
byte[] ciphertext = Arrays.copyOfRange(message, PUBLICKEY_BYTES, message.length);
byte[] nonce = createNonce(ephemeralPublicKey, publicKey);
byte[] sharedSecret = computeSharedSecret(ephemeralPublicKey, privateKey);

SecretBox box = new SecretBox(sharedSecret);
return box.decrypt(nonce, ciphertext);
}
}
3 changes: 1 addition & 2 deletions autobahn/src/main/java/xbr/network/crypto/SecretBox.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ public byte[] decrypt(byte[] ciphertext) {
return decrypt(nonce, message);
}


private byte[] decrypt(byte[] nonce, byte[] ciphertext) {
public byte[] decrypt(byte[] nonce, byte[] ciphertext) {
checkLength(nonce, NONCE_SIZE);

XSalsa20Engine xsalsa20 = new XSalsa20Engine();
Expand Down

0 comments on commit 2ce33d2

Please sign in to comment.