That fuck shit the fascists are using
at master 277 lines 12 kB view raw
1/* 2 * Copyright (C) 2013-2018 Open Whisper Systems 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18package org.tm.archive.crypto; 19 20import androidx.annotation.NonNull; 21 22import org.signal.core.util.logging.Log; 23import org.signal.libsignal.protocol.InvalidKeyException; 24import org.signal.libsignal.protocol.InvalidKeyIdException; 25import org.signal.libsignal.protocol.ecc.Curve; 26import org.signal.libsignal.protocol.ecc.ECKeyPair; 27import org.signal.libsignal.protocol.ecc.ECPrivateKey; 28import org.signal.libsignal.protocol.kem.KEMKeyPair; 29import org.signal.libsignal.protocol.kem.KEMKeyType; 30import org.signal.libsignal.protocol.state.KyberPreKeyRecord; 31import org.signal.libsignal.protocol.state.PreKeyRecord; 32import org.signal.libsignal.protocol.state.SignalProtocolStore; 33import org.signal.libsignal.protocol.state.SignedPreKeyRecord; 34import org.signal.libsignal.protocol.util.Medium; 35import org.tm.archive.crypto.storage.PreKeyMetadataStore; 36import org.whispersystems.signalservice.api.SignalServiceAccountDataStore; 37 38import java.util.ArrayList; 39import java.util.Comparator; 40import java.util.LinkedList; 41import java.util.List; 42import java.util.concurrent.TimeUnit; 43 44public class PreKeyUtil { 45 46 @SuppressWarnings("unused") 47 private static final String TAG = Log.tag(PreKeyUtil.class); 48 49 private static final int BATCH_SIZE = 100; 50 private static final long ARCHIVE_AGE = TimeUnit.DAYS.toMillis(30); 51 52 public synchronized static @NonNull List<PreKeyRecord> generateAndStoreOneTimeEcPreKeys(@NonNull SignalServiceAccountDataStore protocolStore, @NonNull PreKeyMetadataStore metadataStore) { 53 int startingId = metadataStore.getNextEcOneTimePreKeyId(); 54 final List<PreKeyRecord> records = generateOneTimeEcPreKeys(startingId); 55 56 protocolStore.markAllOneTimeEcPreKeysStaleIfNecessary(System.currentTimeMillis()); 57 storeOneTimeEcPreKeys(protocolStore, metadataStore, records); 58 59 return records; 60 } 61 62 public synchronized static List<PreKeyRecord> generateOneTimeEcPreKeys(int startingId) { 63 Log.i(TAG, "Generating one-time EC prekeys..."); 64 65 List<PreKeyRecord> records = new ArrayList<>(BATCH_SIZE); 66 67 for (int i = 0; i < BATCH_SIZE; i++) { 68 int preKeyId = (startingId + i) % Medium.MAX_VALUE; 69 ECKeyPair keyPair = Curve.generateKeyPair(); 70 PreKeyRecord record = new PreKeyRecord(preKeyId, keyPair); 71 72 records.add(record); 73 } 74 75 return records; 76 } 77 78 public synchronized static void storeOneTimeEcPreKeys(@NonNull SignalProtocolStore protocolStore, PreKeyMetadataStore metadataStore, List<PreKeyRecord> prekeys) { 79 Log.i(TAG, "Storing one-time EC prekeys..."); 80 81 if (prekeys.isEmpty()) { 82 Log.w(TAG, "Empty list of one-time EC prekeys! Nothing to store."); 83 return; 84 } 85 86 for (PreKeyRecord record : prekeys) { 87 protocolStore.storePreKey(record.getId(), record); 88 } 89 90 int lastId = prekeys.get(prekeys.size() - 1).getId(); 91 92 metadataStore.setNextEcOneTimePreKeyId((lastId + 1) % Medium.MAX_VALUE); 93 94 } 95 96 public synchronized static @NonNull List<KyberPreKeyRecord> generateAndStoreOneTimeKyberPreKeys(@NonNull SignalServiceAccountDataStore protocolStore, @NonNull PreKeyMetadataStore metadataStore) { 97 int startingId = metadataStore.getNextKyberPreKeyId(); 98 List<KyberPreKeyRecord> records = generateOneTimeKyberPreKeyRecords(startingId, protocolStore.getIdentityKeyPair().getPrivateKey()); 99 100 protocolStore.markAllOneTimeKyberPreKeysStaleIfNecessary(System.currentTimeMillis()); 101 storeOneTimeKyberPreKeys(protocolStore, metadataStore, records); 102 103 return records; 104 } 105 106 @NonNull 107 public static List<KyberPreKeyRecord> generateOneTimeKyberPreKeyRecords(int startingId, @NonNull ECPrivateKey privateKey) { 108 Log.i(TAG, "Generating one-time kyber prekeys..."); 109 110 List<KyberPreKeyRecord> records = new LinkedList<>(); 111 112 for (int i = 0; i < BATCH_SIZE; i++) { 113 int preKeyId = (startingId + i) % Medium.MAX_VALUE; 114 KyberPreKeyRecord record = generateKyberPreKey(preKeyId, privateKey); 115 116 records.add(record); 117 } 118 119 return records; 120 } 121 122 public synchronized static void storeOneTimeKyberPreKeys(@NonNull SignalProtocolStore protocolStore, PreKeyMetadataStore metadataStore, List<KyberPreKeyRecord> prekeys) { 123 Log.i(TAG, "Storing one-time kyber prekeys..."); 124 125 if (prekeys.isEmpty()) { 126 Log.w(TAG, "Empty list of kyber prekeys! Nothing to store."); 127 return; 128 } 129 130 for (KyberPreKeyRecord record : prekeys) { 131 protocolStore.storeKyberPreKey(record.getId(), record); 132 } 133 134 int lastId = prekeys.get(prekeys.size() - 1).getId(); 135 136 metadataStore.setNextKyberPreKeyId((lastId + 1) % Medium.MAX_VALUE); 137 } 138 139 public synchronized static @NonNull SignedPreKeyRecord generateAndStoreSignedPreKey(@NonNull SignalProtocolStore protocolStore, @NonNull PreKeyMetadataStore metadataStore) { 140 return generateAndStoreSignedPreKey(protocolStore, metadataStore, protocolStore.getIdentityKeyPair().getPrivateKey()); 141 } 142 143 public synchronized static @NonNull SignedPreKeyRecord generateAndStoreSignedPreKey(@NonNull SignalProtocolStore protocolStore, 144 @NonNull PreKeyMetadataStore metadataStore, 145 @NonNull ECPrivateKey privateKey) 146 { 147 int signedPreKeyId = metadataStore.getNextSignedPreKeyId(); 148 SignedPreKeyRecord record = generateSignedPreKey(signedPreKeyId, privateKey); 149 150 storeSignedPreKey(protocolStore, metadataStore, record); 151 152 return record; 153 } 154 155 public synchronized static @NonNull SignedPreKeyRecord generateSignedPreKey(int signedPreKeyId, @NonNull ECPrivateKey privateKey) { 156 Log.i(TAG, "Generating signed prekeys..."); 157 158 try { 159 ECKeyPair keyPair = Curve.generateKeyPair(); 160 byte[] signature = Curve.calculateSignature(privateKey, keyPair.getPublicKey().serialize()); 161 162 return new SignedPreKeyRecord(signedPreKeyId, System.currentTimeMillis(), keyPair, signature); 163 } catch (InvalidKeyException e) { 164 throw new AssertionError(e); 165 } 166 } 167 168 public synchronized static void storeSignedPreKey(@NonNull SignalProtocolStore protocolStore, @NonNull PreKeyMetadataStore metadataStore, SignedPreKeyRecord record) { 169 Log.i(TAG, "Storing signed prekey..."); 170 171 protocolStore.storeSignedPreKey(record.getId(), record); 172 metadataStore.setNextSignedPreKeyId((record.getId() + 1) % Medium.MAX_VALUE); 173 } 174 175 public synchronized static @NonNull KyberPreKeyRecord generateAndStoreLastResortKyberPreKey(@NonNull SignalServiceAccountDataStore protocolStore, @NonNull PreKeyMetadataStore metadataStore) { 176 return generateAndStoreLastResortKyberPreKey(protocolStore, metadataStore, protocolStore.getIdentityKeyPair().getPrivateKey()); 177 } 178 179 public synchronized static @NonNull KyberPreKeyRecord generateAndStoreLastResortKyberPreKey(@NonNull SignalServiceAccountDataStore protocolStore, 180 @NonNull PreKeyMetadataStore metadataStore, 181 @NonNull ECPrivateKey privateKey) 182 { 183 int id = metadataStore.getNextKyberPreKeyId(); 184 KyberPreKeyRecord record = generateKyberPreKey(id, privateKey); 185 186 storeLastResortKyberPreKey(protocolStore, metadataStore, record); 187 188 return record; 189 } 190 191 public synchronized static @NonNull KyberPreKeyRecord generateLastResortKyberPreKey(int id, @NonNull ECPrivateKey privateKey) { 192 Log.i(TAG, "Generating last resort kyber prekey..."); 193 return generateKyberPreKey(id, privateKey); 194 } 195 196 private synchronized static @NonNull KyberPreKeyRecord generateKyberPreKey(int id, @NonNull ECPrivateKey privateKey) { 197 KEMKeyPair keyPair = KEMKeyPair.generate(KEMKeyType.KYBER_1024); 198 byte[] signature = privateKey.calculateSignature(keyPair.getPublicKey().serialize()); 199 200 return new KyberPreKeyRecord(id, System.currentTimeMillis(), keyPair, signature); 201 } 202 203 public synchronized static void storeLastResortKyberPreKey(@NonNull SignalServiceAccountDataStore protocolStore, @NonNull PreKeyMetadataStore metadataStore, KyberPreKeyRecord record) { 204 Log.i(TAG, "Storing last resort kyber prekeys..."); 205 protocolStore.storeLastResortKyberPreKey(record.getId(), record); 206 metadataStore.setNextKyberPreKeyId((record.getId() + 1) % Medium.MAX_VALUE); 207 } 208 209 210 /** 211 * Finds all of the signed prekeys that are older than the archive age, and archive all but the youngest of those. 212 */ 213 public synchronized static void cleanSignedPreKeys(@NonNull SignalProtocolStore protocolStore, @NonNull PreKeyMetadataStore metadataStore) { 214 Log.i(TAG, "Cleaning signed prekeys..."); 215 216 int activeSignedPreKeyId = metadataStore.getActiveSignedPreKeyId(); 217 if (activeSignedPreKeyId < 0) { 218 return; 219 } 220 221 try { 222 long now = System.currentTimeMillis(); 223 SignedPreKeyRecord currentRecord = protocolStore.loadSignedPreKey(activeSignedPreKeyId); 224 List<SignedPreKeyRecord> allRecords = protocolStore.loadSignedPreKeys(); 225 226 allRecords.stream() 227 .filter(r -> r.getId() != currentRecord.getId()) 228 .filter(r -> (now - r.getTimestamp()) > ARCHIVE_AGE) 229 .sorted(Comparator.comparingLong(SignedPreKeyRecord::getTimestamp).reversed()) 230 .skip(1) 231 .forEach(record -> { 232 Log.i(TAG, "Removing signed prekey record: " + record.getId() + " with timestamp: " + record.getTimestamp()); 233 protocolStore.removeSignedPreKey(record.getId()); 234 }); 235 } catch (InvalidKeyIdException e) { 236 Log.w(TAG, e); 237 } 238 } 239 240 /** 241 * Finds all of the signed prekeys that are older than the archive age, and archive all but the youngest of those. 242 */ 243 public synchronized static void cleanLastResortKyberPreKeys(@NonNull SignalServiceAccountDataStore protocolStore, @NonNull PreKeyMetadataStore metadataStore) { 244 Log.i(TAG, "Cleaning kyber prekeys..."); 245 246 int activeLastResortKeyId = metadataStore.getLastResortKyberPreKeyId(); 247 if (activeLastResortKeyId < 0) { 248 return; 249 } 250 251 try { 252 long now = System.currentTimeMillis(); 253 KyberPreKeyRecord currentRecord = protocolStore.loadKyberPreKey(activeLastResortKeyId); 254 List<KyberPreKeyRecord> allRecords = protocolStore.loadLastResortKyberPreKeys(); 255 256 allRecords.stream() 257 .filter(r -> r.getId() != currentRecord.getId()) 258 .filter(r -> (now - r.getTimestamp()) > ARCHIVE_AGE) 259 .sorted(Comparator.comparingLong(KyberPreKeyRecord::getTimestamp).reversed()) 260 .skip(1) 261 .forEach(record -> { 262 Log.i(TAG, "Removing kyber prekey record: " + record.getId() + " with timestamp: " + record.getTimestamp()); 263 protocolStore.removeKyberPreKey(record.getId()); 264 }); 265 } catch (InvalidKeyIdException e) { 266 Log.w(TAG, e); 267 } 268 } 269 270 public synchronized static void cleanOneTimePreKeys(@NonNull SignalServiceAccountDataStore protocolStore) { 271 long threshold = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(90); 272 int minCount = 200; 273 274 protocolStore.deleteAllStaleOneTimeEcPreKeys(threshold, minCount); 275 protocolStore.deleteAllStaleOneTimeKyberPreKeys(threshold, minCount); 276 } 277}