That fuck shit the fascists are using
at master 329 lines 9.0 kB view raw
1package org.tm.archive.groups; 2 3import androidx.annotation.NonNull; 4import androidx.annotation.Nullable; 5 6import org.signal.core.util.DatabaseId; 7import org.signal.core.util.Hex; 8import org.signal.libsignal.protocol.kdf.HKDFv3; 9import org.signal.libsignal.zkgroup.InvalidInputException; 10import org.signal.libsignal.zkgroup.groups.GroupIdentifier; 11import org.signal.libsignal.zkgroup.groups.GroupMasterKey; 12import org.signal.libsignal.zkgroup.groups.GroupSecretParams; 13import org.tm.archive.util.LRUCache; 14import org.tm.archive.util.Util; 15 16import java.io.IOException; 17import java.security.SecureRandom; 18 19import okio.ByteString; 20 21public abstract class GroupId implements DatabaseId { 22 23 private static final String ENCODED_SIGNAL_GROUP_V1_PREFIX = "__textsecure_group__!"; 24 private static final String ENCODED_SIGNAL_GROUP_V2_PREFIX = "__signal_group__v2__!"; 25 private static final String ENCODED_MMS_GROUP_PREFIX = "__signal_mms_group__!"; 26 private static final int MMS_BYTE_LENGTH = 16; 27 private static final int V1_MMS_BYTE_LENGTH = 16; 28 private static final int V1_BYTE_LENGTH = 16; 29 private static final int V2_BYTE_LENGTH = GroupIdentifier.SIZE; 30 31 private final String encodedId; 32 33 private static final LRUCache<GroupMasterKey, GroupIdentifier> groupIdentifierCache = new LRUCache<>(1000); 34 35 private GroupId(@NonNull String prefix, @NonNull byte[] bytes) { 36 this.encodedId = prefix + Hex.toStringCondensed(bytes); 37 } 38 39 public static @NonNull GroupId.Mms mms(byte[] mmsGroupIdBytes) { 40 return new GroupId.Mms(mmsGroupIdBytes); 41 } 42 43 public static @NonNull GroupId.V1 v1orThrow(byte[] gv1GroupIdBytes) { 44 try { 45 return v1(gv1GroupIdBytes); 46 } catch (BadGroupIdException e) { 47 throw new AssertionError(e); 48 } 49 } 50 51 public static @NonNull GroupId.V1 v1(byte[] gv1GroupIdBytes) throws BadGroupIdException { 52 if (gv1GroupIdBytes.length != V1_BYTE_LENGTH) { 53 throw new BadGroupIdException(); 54 } 55 return new GroupId.V1(gv1GroupIdBytes); 56 } 57 58 public static GroupId.V1 createV1(@NonNull SecureRandom secureRandom) { 59 return v1orThrow(Util.getSecretBytes(secureRandom, V1_MMS_BYTE_LENGTH)); 60 } 61 62 public static GroupId.Mms createMms(@NonNull SecureRandom secureRandom) { 63 return mms(Util.getSecretBytes(secureRandom, MMS_BYTE_LENGTH)); 64 } 65 66 /** 67 * Private because it's too easy to pass the {@link GroupMasterKey} bytes directly to this as they 68 * are the same length as the {@link GroupIdentifier}. 69 */ 70 private static GroupId.V2 v2(@NonNull byte[] bytes) throws BadGroupIdException { 71 if (bytes.length != V2_BYTE_LENGTH) { 72 throw new BadGroupIdException(); 73 } 74 return new GroupId.V2(bytes); 75 } 76 77 public static GroupId.V2 v2(@NonNull GroupIdentifier groupIdentifier) { 78 try { 79 return v2(groupIdentifier.serialize()); 80 } catch (BadGroupIdException e) { 81 throw new AssertionError(e); 82 } 83 } 84 85 public static GroupId.V2 v2(@NonNull GroupMasterKey masterKey) { 86 return v2(getIdentifierForMasterKey(masterKey)); 87 } 88 89 public static GroupIdentifier getIdentifierForMasterKey(@NonNull GroupMasterKey masterKey) { 90 GroupIdentifier cachedIdentifier; 91 synchronized (groupIdentifierCache) { 92 cachedIdentifier = groupIdentifierCache.get(masterKey); 93 } 94 if (cachedIdentifier == null) { 95 cachedIdentifier = GroupSecretParams.deriveFromMasterKey(masterKey) 96 .getPublicParams() 97 .getGroupIdentifier(); 98 synchronized (groupIdentifierCache) { 99 groupIdentifierCache.put(masterKey, cachedIdentifier); 100 } 101 } 102 return cachedIdentifier; 103 } 104 105 public static GroupId.Push push(ByteString bytes) throws BadGroupIdException { 106 return push(bytes.toByteArray()); 107 } 108 109 public static GroupId.Push push(byte[] bytes) throws BadGroupIdException { 110 return bytes.length == V2_BYTE_LENGTH ? v2(bytes) : v1(bytes); 111 } 112 113 public static GroupId.Push pushOrThrow(byte[] bytes) { 114 try { 115 return push(bytes); 116 } catch (BadGroupIdException e) { 117 throw new AssertionError(e); 118 } 119 } 120 121 public static GroupId.Push pushOrNull(byte[] bytes) { 122 try { 123 return GroupId.push(bytes); 124 } catch (BadGroupIdException e) { 125 return null; 126 } 127 } 128 129 public static @NonNull GroupId parseOrThrow(@NonNull String encodedGroupId) { 130 try { 131 return parse(encodedGroupId); 132 } catch (BadGroupIdException e) { 133 throw new AssertionError(e); 134 } 135 } 136 137 public static @NonNull GroupId parse(@NonNull String encodedGroupId) throws BadGroupIdException { 138 try { 139 if (!isEncodedGroup(encodedGroupId)) { 140 throw new BadGroupIdException("Invalid encoding"); 141 } 142 143 byte[] bytes = extractDecodedId(encodedGroupId); 144 145 if (encodedGroupId.startsWith(ENCODED_SIGNAL_GROUP_V2_PREFIX)) return v2(bytes); 146 else if (encodedGroupId.startsWith(ENCODED_SIGNAL_GROUP_V1_PREFIX)) return v1(bytes); 147 else if (encodedGroupId.startsWith(ENCODED_MMS_GROUP_PREFIX)) return mms(bytes); 148 149 throw new BadGroupIdException(); 150 } catch (IOException e) { 151 throw new BadGroupIdException(e); 152 } 153 } 154 155 public static @Nullable GroupId parseNullable(@Nullable String encodedGroupId) throws BadGroupIdException { 156 if (encodedGroupId == null) { 157 return null; 158 } 159 160 return parse(encodedGroupId); 161 } 162 163 public static @Nullable GroupId parseNullableOrThrow(@Nullable String encodedGroupId) { 164 if (encodedGroupId == null) { 165 return null; 166 } 167 168 return parseOrThrow(encodedGroupId); 169 } 170 171 public static boolean isEncodedGroup(@NonNull String groupId) { 172 return groupId.startsWith(ENCODED_SIGNAL_GROUP_V2_PREFIX) || 173 groupId.startsWith(ENCODED_SIGNAL_GROUP_V1_PREFIX) || 174 groupId.startsWith(ENCODED_MMS_GROUP_PREFIX); 175 } 176 177 private static byte[] extractDecodedId(@NonNull String encodedGroupId) throws IOException { 178 return Hex.fromStringCondensed(encodedGroupId.split("!", 2)[1]); 179 } 180 181 public byte[] getDecodedId() { 182 try { 183 return extractDecodedId(encodedId); 184 } catch (IOException e) { 185 throw new AssertionError(e); 186 } 187 } 188 189 @Override 190 public boolean equals(@Nullable Object obj) { 191 if (obj instanceof GroupId) { 192 return ((GroupId) obj).encodedId.equals(encodedId); 193 } 194 195 return false; 196 } 197 198 @Override 199 public int hashCode() { 200 return encodedId.hashCode(); 201 } 202 203 @Override 204 public @NonNull String toString() { 205 return encodedId; 206 } 207 208 @Override 209 public @NonNull String serialize() { 210 return encodedId; 211 } 212 213 public abstract boolean isMms(); 214 215 public abstract boolean isV1(); 216 217 public abstract boolean isV2(); 218 219 public abstract boolean isPush(); 220 221 public GroupId.Mms requireMms() { 222 if (this instanceof GroupId.Mms) return (GroupId.Mms) this; 223 throw new AssertionError(); 224 } 225 226 public GroupId.V1 requireV1() { 227 if (this instanceof GroupId.V1) return (GroupId.V1) this; 228 throw new AssertionError(); 229 } 230 231 public GroupId.V2 requireV2() { 232 if (this instanceof GroupId.V2) return (GroupId.V2) this; 233 throw new AssertionError(); 234 } 235 236 public GroupId.Push requirePush() { 237 if (this instanceof GroupId.Push) return (GroupId.Push) this; 238 throw new AssertionError(); 239 } 240 241 public static final class Mms extends GroupId { 242 243 private Mms(@NonNull byte[] bytes) { 244 super(ENCODED_MMS_GROUP_PREFIX, bytes); 245 } 246 247 @Override 248 public boolean isMms() { 249 return true; 250 } 251 252 @Override 253 public boolean isV1() { 254 return false; 255 } 256 257 @Override 258 public boolean isV2() { 259 return false; 260 } 261 262 @Override 263 public boolean isPush() { 264 return false; 265 } 266 } 267 268 public static abstract class Push extends GroupId { 269 private Push(@NonNull String prefix, @NonNull byte[] bytes) { 270 super(prefix, bytes); 271 } 272 273 @Override 274 public boolean isMms() { 275 return false; 276 } 277 278 @Override 279 public boolean isPush() { 280 return true; 281 } 282 } 283 284 public static final class V1 extends GroupId.Push { 285 286 private V1(@NonNull byte[] bytes) { 287 super(ENCODED_SIGNAL_GROUP_V1_PREFIX, bytes); 288 } 289 290 @Override 291 public boolean isV1() { 292 return true; 293 } 294 295 @Override 296 public boolean isV2() { 297 return false; 298 } 299 300 public GroupMasterKey deriveV2MigrationMasterKey() { 301 try { 302 return new GroupMasterKey(new HKDFv3().deriveSecrets(getDecodedId(), "GV2 Migration".getBytes(), GroupMasterKey.SIZE)); 303 } catch (InvalidInputException e) { 304 throw new AssertionError(e); 305 } 306 } 307 308 public GroupId.V2 deriveV2MigrationGroupId() { 309 return v2(deriveV2MigrationMasterKey()); 310 } 311 } 312 313 public static final class V2 extends GroupId.Push { 314 315 private V2(@NonNull byte[] bytes) { 316 super(ENCODED_SIGNAL_GROUP_V2_PREFIX, bytes); 317 } 318 319 @Override 320 public boolean isV1() { 321 return false; 322 } 323 324 @Override 325 public boolean isV2() { 326 return true; 327 } 328 } 329}