]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/util/KeyUtils.java
8db8d0a4018946436142e25e3a9e34dbc3da65a7
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / util / KeyUtils.java
1 package org.asamk.signal.manager.util;
2
3 import org.signal.libsignal.protocol.IdentityKey;
4 import org.signal.libsignal.protocol.IdentityKeyPair;
5 import org.signal.libsignal.protocol.InvalidKeyException;
6 import org.signal.libsignal.protocol.ecc.Curve;
7 import org.signal.libsignal.protocol.ecc.ECPrivateKey;
8 import org.signal.libsignal.protocol.kem.KEMKeyPair;
9 import org.signal.libsignal.protocol.kem.KEMKeyType;
10 import org.signal.libsignal.protocol.state.KyberPreKeyRecord;
11 import org.signal.libsignal.protocol.state.PreKeyRecord;
12 import org.signal.libsignal.protocol.state.SignedPreKeyRecord;
13 import org.signal.libsignal.zkgroup.InvalidInputException;
14 import org.signal.libsignal.zkgroup.profiles.ProfileKey;
15 import org.whispersystems.signalservice.api.kbs.MasterKey;
16
17 import java.security.SecureRandom;
18 import java.util.ArrayList;
19 import java.util.Base64;
20 import java.util.List;
21
22 import static org.asamk.signal.manager.config.ServiceConfig.PREKEY_MAXIMUM_ID;
23
24 public class KeyUtils {
25
26 private static final SecureRandom secureRandom = new SecureRandom();
27
28 private KeyUtils() {
29 }
30
31 public static IdentityKeyPair getIdentityKeyPair(byte[] publicKeyBytes, byte[] privateKeyBytes) {
32 try {
33 IdentityKey publicKey = new IdentityKey(publicKeyBytes);
34 ECPrivateKey privateKey = Curve.decodePrivatePoint(privateKeyBytes);
35
36 return new IdentityKeyPair(publicKey, privateKey);
37 } catch (InvalidKeyException e) {
38 throw new AssertionError(e);
39 }
40 }
41
42 public static IdentityKeyPair generateIdentityKeyPair() {
43 var djbKeyPair = Curve.generateKeyPair();
44 var djbIdentityKey = new IdentityKey(djbKeyPair.getPublicKey());
45 var djbPrivateKey = djbKeyPair.getPrivateKey();
46
47 return new IdentityKeyPair(djbIdentityKey, djbPrivateKey);
48 }
49
50 public static List<PreKeyRecord> generatePreKeyRecords(final int offset, final int batchSize) {
51 var records = new ArrayList<PreKeyRecord>(batchSize);
52 for (var i = 0; i < batchSize; i++) {
53 var preKeyId = (offset + i) % PREKEY_MAXIMUM_ID;
54 var keyPair = Curve.generateKeyPair();
55 var record = new PreKeyRecord(preKeyId, keyPair);
56
57 records.add(record);
58 }
59 return records;
60 }
61
62 public static SignedPreKeyRecord generateSignedPreKeyRecord(
63 final IdentityKeyPair identityKeyPair, final int signedPreKeyId
64 ) {
65 var keyPair = Curve.generateKeyPair();
66 byte[] signature;
67 try {
68 signature = Curve.calculateSignature(identityKeyPair.getPrivateKey(), keyPair.getPublicKey().serialize());
69 } catch (InvalidKeyException e) {
70 throw new AssertionError(e);
71 }
72 return new SignedPreKeyRecord(signedPreKeyId, System.currentTimeMillis(), keyPair, signature);
73 }
74
75 public static List<KyberPreKeyRecord> generateKyberPreKeyRecords(
76 final int offset, final int batchSize, final ECPrivateKey privateKey
77 ) {
78 var records = new ArrayList<KyberPreKeyRecord>(batchSize);
79 for (var i = 0; i < batchSize; i++) {
80 var preKeyId = (offset + i) % PREKEY_MAXIMUM_ID;
81 records.add(generateKyberPreKeyRecord(preKeyId, privateKey));
82 }
83 return records;
84 }
85
86 public static KyberPreKeyRecord generateKyberPreKeyRecord(final int preKeyId, final ECPrivateKey privateKey) {
87 KEMKeyPair keyPair = KEMKeyPair.generate(KEMKeyType.KYBER_1024);
88 byte[] signature = privateKey.calculateSignature(keyPair.getPublicKey().serialize());
89
90 return new KyberPreKeyRecord(preKeyId, System.currentTimeMillis(), keyPair, signature);
91 }
92
93 public static ProfileKey createProfileKey() {
94 try {
95 return new ProfileKey(getSecretBytes(32));
96 } catch (InvalidInputException e) {
97 throw new AssertionError("Profile key is guaranteed to be 32 bytes here");
98 }
99 }
100
101 public static String createPassword() {
102 return getSecret(18);
103 }
104
105 public static byte[] createStickerUploadKey() {
106 return getSecretBytes(32);
107 }
108
109 public static MasterKey createMasterKey() {
110 return MasterKey.createNew(secureRandom);
111 }
112
113 private static String getSecret(int size) {
114 var secret = getSecretBytes(size);
115 return Base64.getEncoder().encodeToString(secret);
116 }
117
118 public static byte[] getSecretBytes(int size) {
119 var secret = new byte[size];
120 secureRandom.nextBytes(secret);
121 return secret;
122 }
123
124 public static int getRandomInt(int bound) {
125 return secureRandom.nextInt(bound);
126 }
127 }