package org.asamk.signal.manager.util;
-import org.signal.zkgroup.InvalidInputException;
-import org.signal.zkgroup.profiles.ProfileKey;
-import org.whispersystems.libsignal.IdentityKey;
-import org.whispersystems.libsignal.IdentityKeyPair;
-import org.whispersystems.libsignal.InvalidKeyException;
-import org.whispersystems.libsignal.ecc.Curve;
-import org.whispersystems.libsignal.ecc.ECKeyPair;
-import org.whispersystems.libsignal.ecc.ECPrivateKey;
-import org.whispersystems.libsignal.state.PreKeyRecord;
-import org.whispersystems.libsignal.state.SignedPreKeyRecord;
-import org.whispersystems.libsignal.util.Medium;
+import org.asamk.signal.manager.storage.SignalAccount;
+import org.signal.libsignal.protocol.IdentityKey;
+import org.signal.libsignal.protocol.IdentityKeyPair;
+import org.signal.libsignal.protocol.InvalidKeyException;
+import org.signal.libsignal.protocol.ecc.Curve;
+import org.signal.libsignal.protocol.ecc.ECPrivateKey;
+import org.signal.libsignal.protocol.kem.KEMKeyPair;
+import org.signal.libsignal.protocol.kem.KEMKeyType;
+import org.signal.libsignal.protocol.state.KyberPreKeyRecord;
+import org.signal.libsignal.protocol.state.PreKeyRecord;
+import org.signal.libsignal.protocol.state.SignedPreKeyRecord;
+import org.signal.libsignal.zkgroup.InvalidInputException;
+import org.signal.libsignal.zkgroup.profiles.ProfileKey;
+import org.whispersystems.signalservice.api.account.PreKeyCollection;
import org.whispersystems.signalservice.api.kbs.MasterKey;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.List;
+import static org.asamk.signal.manager.config.ServiceConfig.PREKEY_BATCH_SIZE;
+import static org.asamk.signal.manager.config.ServiceConfig.PREKEY_MAXIMUM_ID;
+
public class KeyUtils {
private static final SecureRandom secureRandom = new SecureRandom();
private KeyUtils() {
}
+ public static IdentityKeyPair getIdentityKeyPair(byte[] publicKeyBytes, byte[] privateKeyBytes) {
+ try {
+ IdentityKey publicKey = new IdentityKey(publicKeyBytes);
+ ECPrivateKey privateKey = Curve.decodePrivatePoint(privateKeyBytes);
+
+ return new IdentityKeyPair(publicKey, privateKey);
+ } catch (InvalidKeyException e) {
+ throw new AssertionError(e);
+ }
+ }
+
public static IdentityKeyPair generateIdentityKeyPair() {
- ECKeyPair djbKeyPair = Curve.generateKeyPair();
- IdentityKey djbIdentityKey = new IdentityKey(djbKeyPair.getPublicKey());
- ECPrivateKey djbPrivateKey = djbKeyPair.getPrivateKey();
+ var djbKeyPair = Curve.generateKeyPair();
+ var djbIdentityKey = new IdentityKey(djbKeyPair.getPublicKey());
+ var djbPrivateKey = djbKeyPair.getPrivateKey();
return new IdentityKeyPair(djbIdentityKey, djbPrivateKey);
}
- public static List<PreKeyRecord> generatePreKeyRecords(final int offset, final int batchSize) {
- List<PreKeyRecord> records = new ArrayList<>(batchSize);
- for (int i = 0; i < batchSize; i++) {
- int preKeyId = (offset + i) % Medium.MAX_VALUE;
- ECKeyPair keyPair = Curve.generateKeyPair();
- PreKeyRecord record = new PreKeyRecord(preKeyId, keyPair);
+ public static List<PreKeyRecord> generatePreKeyRecords(final int offset) {
+ var records = new ArrayList<PreKeyRecord>(PREKEY_BATCH_SIZE);
+ for (var i = 0; i < PREKEY_BATCH_SIZE; i++) {
+ var preKeyId = (offset + i) % PREKEY_MAXIMUM_ID;
+ var keyPair = Curve.generateKeyPair();
+ var record = new PreKeyRecord(preKeyId, keyPair);
records.add(record);
}
}
public static SignedPreKeyRecord generateSignedPreKeyRecord(
- final IdentityKeyPair identityKeyPair, final int signedPreKeyId
+ final int signedPreKeyId,
+ final ECPrivateKey privateKey
) {
- ECKeyPair keyPair = Curve.generateKeyPair();
+ var keyPair = Curve.generateKeyPair();
byte[] signature;
try {
- signature = Curve.calculateSignature(identityKeyPair.getPrivateKey(), keyPair.getPublicKey().serialize());
+ signature = Curve.calculateSignature(privateKey, keyPair.getPublicKey().serialize());
} catch (InvalidKeyException e) {
throw new AssertionError(e);
}
return new SignedPreKeyRecord(signedPreKeyId, System.currentTimeMillis(), keyPair, signature);
}
- public static String createSignalingKey() {
- return getSecret(52);
+ public static List<KyberPreKeyRecord> generateKyberPreKeyRecords(final int offset, final ECPrivateKey privateKey) {
+ var records = new ArrayList<KyberPreKeyRecord>(PREKEY_BATCH_SIZE);
+ for (var i = 0; i < PREKEY_BATCH_SIZE; i++) {
+ var preKeyId = (offset + i) % PREKEY_MAXIMUM_ID;
+ records.add(generateKyberPreKeyRecord(preKeyId, privateKey));
+ }
+ return records;
+ }
+
+ public static KyberPreKeyRecord generateKyberPreKeyRecord(final int preKeyId, final ECPrivateKey privateKey) {
+ KEMKeyPair keyPair = KEMKeyPair.generate(KEMKeyType.KYBER_1024);
+ byte[] signature = privateKey.calculateSignature(keyPair.getPublicKey().serialize());
+
+ return new KyberPreKeyRecord(preKeyId, System.currentTimeMillis(), keyPair, signature);
}
public static ProfileKey createProfileKey() {
return MasterKey.createNew(secureRandom);
}
+ public static byte[] createRawStorageId() {
+ return getSecretBytes(16);
+ }
+
private static String getSecret(int size) {
- byte[] secret = getSecretBytes(size);
+ var secret = getSecretBytes(size);
return Base64.getEncoder().encodeToString(secret);
}
public static byte[] getSecretBytes(int size) {
- byte[] secret = new byte[size];
+ var secret = new byte[size];
secureRandom.nextBytes(secret);
return secret;
}
+
+ public static int getRandomInt(int bound) {
+ return secureRandom.nextInt(bound);
+ }
+
+ public static PreKeyCollection generatePreKeysForType(final SignalAccount.AccountData<?> accountData) {
+ final var keyPair = accountData.getIdentityKeyPair();
+ final var preKeyMetadata = accountData.getPreKeyMetadata();
+
+ final var nextSignedPreKeyId = preKeyMetadata.getNextSignedPreKeyId();
+ final var signedPreKey = generateSignedPreKeyRecord(nextSignedPreKeyId, keyPair.getPrivateKey());
+
+ final var privateKey = keyPair.getPrivateKey();
+ final var kyberPreKeyIdOffset = preKeyMetadata.getNextKyberPreKeyId();
+ final var lastResortKyberPreKey = generateKyberPreKeyRecord(kyberPreKeyIdOffset, privateKey);
+
+ return new PreKeyCollection(keyPair.getPublicKey(), signedPreKey, lastResortKyberPreKey);
+ }
}