Represent identity keys as byte arrays

This commit is contained in:
Jon Chambers
2023-05-19 10:35:42 -04:00
committed by Jon Chambers
parent 796863341d
commit d832eaa759
32 changed files with 224 additions and 195 deletions

View File

@@ -334,9 +334,9 @@ class AccountControllerTest {
});
when(changeNumberManager.changeNumber(any(), any(), any(), any(), any(), any(), any())).thenAnswer((Answer<Account>) invocation -> {
final Account account = invocation.getArgument(0, Account.class);
final String number = invocation.getArgument(1, String.class);
final String pniIdentityKey = invocation.getArgument(2, String.class);
final Account account = invocation.getArgument(0);
final String number = invocation.getArgument(1);
final byte[] pniIdentityKey = invocation.getArgument(2);
final UUID uuid = account.getUuid();
final UUID pni = number.equals(account.getNumber()) ? account.getPhoneNumberIdentifier() : UUID.randomUUID();
@@ -358,8 +358,8 @@ class AccountControllerTest {
});
when(changeNumberManager.updatePniKeys(any(), any(), any(), any(), any(), any())).thenAnswer((Answer<Account>) invocation -> {
final Account account = invocation.getArgument(0, Account.class);
final String pniIdentityKey = invocation.getArgument(1, String.class);
final Account account = invocation.getArgument(0);
final byte[] pniIdentityKey = invocation.getArgument(1);
final String number = account.getNumber();
final UUID uuid = account.getUuid();
@@ -1641,7 +1641,7 @@ class AccountControllerTest {
final String number = "+18005559876";
final String code = "987654";
final ECKeyPair pniIdentityKeyPair = Curve.generateKeyPair();
final String pniIdentityKey = KeysHelper.serializeIdentityKey(pniIdentityKeyPair);
final byte[] pniIdentityKey = pniIdentityKeyPair.getPublicKey().serialize();
final byte[] sessionId = "session-id".getBytes(StandardCharsets.UTF_8);
Device device2 = mock(Device.class);
@@ -1695,7 +1695,7 @@ class AccountControllerTest {
void testChangePhoneNumberSameNumberChangePrekeys() throws Exception {
final String code = "987654";
final ECKeyPair pniIdentityKeyPair = Curve.generateKeyPair();
final String pniIdentityKey = KeysHelper.serializeIdentityKey(pniIdentityKeyPair);
final byte[] pniIdentityKey = pniIdentityKeyPair.getPublicKey().serialize();
final byte[] sessionId = "session-id".getBytes(StandardCharsets.UTF_8);
Device device2 = mock(Device.class);

View File

@@ -138,9 +138,9 @@ class AccountControllerV2Test {
when(changeNumberManager.changeNumber(any(), any(), any(), any(), any(), any(), any())).thenAnswer(
(Answer<Account>) invocation -> {
final Account account = invocation.getArgument(0, Account.class);
final String number = invocation.getArgument(1, String.class);
final String pniIdentityKey = invocation.getArgument(2, String.class);
final Account account = invocation.getArgument(0);
final String number = invocation.getArgument(1);
final byte[] pniIdentityKey = invocation.getArgument(2);
final UUID uuid = account.getUuid();
final List<Device> devices = account.getDevices();
@@ -180,7 +180,7 @@ class AccountControllerV2Test {
.header(HttpHeaders.AUTHORIZATION,
AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(
new ChangeNumberRequest(encodeSessionId("session"), null, NEW_NUMBER, "123", "123",
new ChangeNumberRequest(encodeSessionId("session"), null, NEW_NUMBER, "123", "123".getBytes(StandardCharsets.UTF_8),
Collections.emptyList(),
Collections.emptyMap(), null, Collections.emptyMap()),
MediaType.APPLICATION_JSON_TYPE), AccountIdentityResponse.class);
@@ -203,7 +203,7 @@ class AccountControllerV2Test {
AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(
new ChangeNumberRequest(encodeSessionId("session"), null, AuthHelper.VALID_NUMBER, null,
"pni-identity-key",
"pni-identity-key".getBytes(StandardCharsets.UTF_8),
Collections.emptyList(),
Collections.emptyMap(), null, Collections.emptyMap()),
MediaType.APPLICATION_JSON_TYPE), AccountIdentityResponse.class);
@@ -462,8 +462,8 @@ class AccountControllerV2Test {
void setUp() throws Exception {
when(changeNumberManager.updatePniKeys(any(), any(), any(), any(), any(), any())).thenAnswer(
(Answer<Account>) invocation -> {
final Account account = invocation.getArgument(0, Account.class);
final String pniIdentityKey = invocation.getArgument(1, String.class);
final Account account = invocation.getArgument(0);
final byte[] pniIdentityKey = invocation.getArgument(1);
final UUID uuid = account.getUuid();
final UUID pni = account.getPhoneNumberIdentifier();
@@ -498,7 +498,7 @@ class AccountControllerV2Test {
AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.put(Entity.json(requestJson()), AccountIdentityResponse.class);
verify(changeNumberManager).updatePniKeys(eq(AuthHelper.VALID_ACCOUNT), eq("pni-identity-key"), any(), any(), any(), any());
verify(changeNumberManager).updatePniKeys(eq(AuthHelper.VALID_ACCOUNT), eq("pni-identity-key".getBytes(StandardCharsets.UTF_8)), any(), any(), any(), any());
assertEquals(AuthHelper.VALID_UUID, accountIdentityResponse.uuid());
assertEquals(AuthHelper.VALID_NUMBER, accountIdentityResponse.number());
@@ -554,15 +554,15 @@ class AccountControllerV2Test {
* Valid request JSON for a {@link org.whispersystems.textsecuregcm.entities.PhoneNumberIdentityKeyDistributionRequest}
*/
private static String requestJson() {
return """
return String.format("""
{
"pniIdentityKey": "pni-identity-key",
"pniIdentityKey": "%s",
"deviceMessages": [],
"devicePniSignedPrekeys": {},
"devicePniSignedPqPrekeys": {},
"pniRegistrationIds": {}
}
""";
""", Base64.getEncoder().encodeToString("pni-identity-key".getBytes(StandardCharsets.UTF_8)));
}
/**
@@ -798,8 +798,8 @@ class AccountControllerV2Test {
account.setUnrestrictedUnidentifiedAccess(unrestrictedUnidentifiedAccess);
account.setDiscoverableByPhoneNumber(discoverableByPhoneNumber);
account.setBadges(Clock.systemUTC(), new ArrayList<>(badges));
account.setIdentityKey(KeysHelper.serializeIdentityKey(aciIdentityKeyPair));
account.setPhoneNumberIdentityKey(KeysHelper.serializeIdentityKey(pniIdentityKeyPair));
account.setIdentityKey(aciIdentityKeyPair.getPublicKey().serialize());
account.setPhoneNumberIdentityKey(pniIdentityKeyPair.getPublicKey().serialize());
assert !devices.isEmpty();

View File

@@ -124,10 +124,10 @@ class ProfileControllerTest {
private static final ServerZkProfileOperations zkProfileOperations = mock(ServerZkProfileOperations.class);
private static final byte[] UNIDENTIFIED_ACCESS_KEY = "test-uak".getBytes(StandardCharsets.UTF_8);
private static final String ACCOUNT_IDENTITY_KEY = "barz";
private static final String ACCOUNT_PHONE_NUMBER_IDENTITY_KEY = "bazz";
private static final String ACCOUNT_TWO_IDENTITY_KEY = "bar";
private static final String ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY = "baz";
private static final byte[] ACCOUNT_IDENTITY_KEY = "barz".getBytes(StandardCharsets.UTF_8);
private static final byte[] ACCOUNT_PHONE_NUMBER_IDENTITY_KEY = "bazz".getBytes(StandardCharsets.UTF_8);
private static final byte[] ACCOUNT_TWO_IDENTITY_KEY = "bar".getBytes(StandardCharsets.UTF_8);
private static final byte[] ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY = "baz".getBytes(StandardCharsets.UTF_8);
private static final String BASE_64_URL_USERNAME_HASH = "9p6Tip7BFefFOJzv4kv4GyXEYsBVfk_WbjNejdlOvQE";
private static final byte[] USERNAME_HASH = Base64.getUrlDecoder().decode(BASE_64_URL_USERNAME_HASH);
@SuppressWarnings("unchecked")
@@ -1153,13 +1153,13 @@ class ProfileControllerTest {
try (final Response response = resources.getJerseyTest().target("/v1/profile/identity_check/batch").request()
.post(Entity.json(new BatchIdentityCheckRequest(List.of(
new BatchIdentityCheckRequest.Element(AuthHelper.VALID_UUID, null,
convertStringToFingerprint(ACCOUNT_IDENTITY_KEY)),
convertKeyToFingerprint(ACCOUNT_IDENTITY_KEY)),
new BatchIdentityCheckRequest.Element(null, AuthHelper.VALID_PNI_TWO,
convertStringToFingerprint(ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY)),
convertKeyToFingerprint(ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY)),
new BatchIdentityCheckRequest.Element(null, AuthHelper.VALID_UUID_TWO,
convertStringToFingerprint(ACCOUNT_TWO_IDENTITY_KEY)),
convertKeyToFingerprint(ACCOUNT_TWO_IDENTITY_KEY)),
new BatchIdentityCheckRequest.Element(AuthHelper.INVALID_UUID, null,
convertStringToFingerprint(ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY))
convertKeyToFingerprint(ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY))
))))) {
assertThat(response).isNotNull();
assertThat(response.getStatus()).isEqualTo(200);
@@ -1170,11 +1170,11 @@ class ProfileControllerTest {
final Condition<BatchIdentityCheckResponse.Element> isAnExpectedUuid = new Condition<>(element -> {
if (AuthHelper.VALID_UUID.equals(element.aci())) {
return Arrays.equals(Base64.getDecoder().decode(ACCOUNT_IDENTITY_KEY), element.identityKey());
return Arrays.equals(ACCOUNT_IDENTITY_KEY, element.identityKey());
} else if (AuthHelper.VALID_PNI_TWO.equals(element.uuid())) {
return Arrays.equals(Base64.getDecoder().decode(ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY), element.identityKey());
return Arrays.equals(ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY, element.identityKey());
} else if (AuthHelper.VALID_UUID_TWO.equals(element.uuid())) {
return Arrays.equals(Base64.getDecoder().decode(ACCOUNT_TWO_IDENTITY_KEY), element.identityKey());
return Arrays.equals(ACCOUNT_TWO_IDENTITY_KEY, element.identityKey());
} else {
return false;
}
@@ -1182,12 +1182,14 @@ class ProfileControllerTest {
try (final Response response = resources.getJerseyTest().target("/v1/profile/identity_check/batch").request()
.post(Entity.json(new BatchIdentityCheckRequest(List.of(
new BatchIdentityCheckRequest.Element(AuthHelper.VALID_UUID, null, convertStringToFingerprint("else1234")),
new BatchIdentityCheckRequest.Element(AuthHelper.VALID_UUID, null,
convertKeyToFingerprint("else1234".getBytes(StandardCharsets.UTF_8))),
new BatchIdentityCheckRequest.Element(null, AuthHelper.VALID_PNI_TWO,
convertStringToFingerprint("another1")),
convertKeyToFingerprint("another1".getBytes(StandardCharsets.UTF_8))),
new BatchIdentityCheckRequest.Element(null, AuthHelper.VALID_UUID_TWO,
convertStringToFingerprint("another2")),
new BatchIdentityCheckRequest.Element(AuthHelper.INVALID_UUID, null, convertStringToFingerprint("456"))
convertKeyToFingerprint("another2".getBytes(StandardCharsets.UTF_8))),
new BatchIdentityCheckRequest.Element(AuthHelper.INVALID_UUID, null,
convertKeyToFingerprint("456".getBytes(StandardCharsets.UTF_8)))
))))) {
assertThat(response).isNotNull();
assertThat(response.getStatus()).isEqualTo(200);
@@ -1200,13 +1202,13 @@ class ProfileControllerTest {
}
final List<BatchIdentityCheckRequest.Element> largeElementList = new ArrayList<>(List.of(
new BatchIdentityCheckRequest.Element(AuthHelper.VALID_UUID, null, convertStringToFingerprint("else1234")),
new BatchIdentityCheckRequest.Element(null, AuthHelper.VALID_PNI_TWO, convertStringToFingerprint("another1")),
new BatchIdentityCheckRequest.Element(AuthHelper.INVALID_UUID, null, convertStringToFingerprint("456"))));
new BatchIdentityCheckRequest.Element(AuthHelper.VALID_UUID, null, convertKeyToFingerprint("else1234".getBytes(StandardCharsets.UTF_8))),
new BatchIdentityCheckRequest.Element(null, AuthHelper.VALID_PNI_TWO, convertKeyToFingerprint("another1".getBytes(StandardCharsets.UTF_8))),
new BatchIdentityCheckRequest.Element(AuthHelper.INVALID_UUID, null, convertKeyToFingerprint("456".getBytes(StandardCharsets.UTF_8)))));
for (int i = 0; i < 900; i++) {
largeElementList.add(
new BatchIdentityCheckRequest.Element(UUID.randomUUID(), null, convertStringToFingerprint("abcd")));
new BatchIdentityCheckRequest.Element(UUID.randomUUID(), null, convertKeyToFingerprint("abcd".getBytes(StandardCharsets.UTF_8))));
}
try (final Response response = resources.getJerseyTest().target("/v1/profile/identity_check/batch").request()
@@ -1226,9 +1228,9 @@ class ProfileControllerTest {
final Condition<BatchIdentityCheckResponse.Element> isAnExpectedUuid = new Condition<>(element -> {
if (AuthHelper.VALID_UUID.equals(element.aci())) {
return Arrays.equals(Base64.getDecoder().decode(ACCOUNT_IDENTITY_KEY), element.identityKey());
return Arrays.equals(ACCOUNT_IDENTITY_KEY, element.identityKey());
} else if (AuthHelper.VALID_PNI_TWO.equals(element.uuid())) {
return Arrays.equals(Base64.getDecoder().decode(ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY), element.identityKey());
return Arrays.equals(ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY, element.identityKey());
} else {
return false;
}
@@ -1243,9 +1245,9 @@ class ProfileControllerTest {
{ "aci": "%s", "fingerprint": "%s" }
]
}
""", AuthHelper.VALID_UUID, Base64.getEncoder().encodeToString(convertStringToFingerprint("else1234")),
AuthHelper.VALID_PNI_TWO, Base64.getEncoder().encodeToString(convertStringToFingerprint("another1")),
AuthHelper.INVALID_UUID, Base64.getEncoder().encodeToString(convertStringToFingerprint("456")));
""", AuthHelper.VALID_UUID, Base64.getEncoder().encodeToString(convertKeyToFingerprint("else1234".getBytes(StandardCharsets.UTF_8))),
AuthHelper.VALID_PNI_TWO, Base64.getEncoder().encodeToString(convertKeyToFingerprint("another1".getBytes(StandardCharsets.UTF_8))),
AuthHelper.INVALID_UUID, Base64.getEncoder().encodeToString(convertKeyToFingerprint("456".getBytes(StandardCharsets.UTF_8))));
try (final Response response = resources.getJerseyTest().target("/v1/profile/identity_check/batch").request()
.post(Entity.entity(json, "application/json"))) {
@@ -1311,13 +1313,13 @@ class ProfileControllerTest {
]
}
""", AuthHelper.VALID_UUID, AuthHelper.VALID_PNI,
Base64.getEncoder().encodeToString(convertStringToFingerprint("else1234"))))
Base64.getEncoder().encodeToString(convertKeyToFingerprint("else1234".getBytes(StandardCharsets.UTF_8)))))
);
}
private static byte[] convertStringToFingerprint(String base64) {
private static byte[] convertKeyToFingerprint(byte[] key) {
try {
return Util.truncate(MessageDigest.getInstance("SHA-256").digest(Base64.getDecoder().decode(base64)), 4);
return Util.truncate(MessageDigest.getInstance("SHA-256").digest(key), 4);
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}

View File

@@ -368,8 +368,8 @@ class RegistrationControllerTest {
}
static Stream<Arguments> atomicAccountCreationConflictingChannel() {
final Optional<String> aciIdentityKey;
final Optional<String> pniIdentityKey;
final Optional<byte[]> aciIdentityKey;
final Optional<byte[]> pniIdentityKey;
final Optional<SignedPreKey> aciSignedPreKey;
final Optional<SignedPreKey> pniSignedPreKey;
final Optional<SignedPreKey> aciPqLastResortPreKey;
@@ -378,8 +378,8 @@ class RegistrationControllerTest {
final ECKeyPair aciIdentityKeyPair = Curve.generateKeyPair();
final ECKeyPair pniIdentityKeyPair = Curve.generateKeyPair();
aciIdentityKey = Optional.of(KeysHelper.serializeIdentityKey(aciIdentityKeyPair));
pniIdentityKey = Optional.of(KeysHelper.serializeIdentityKey(pniIdentityKeyPair));
aciIdentityKey = Optional.of(aciIdentityKeyPair.getPublicKey().serialize());
pniIdentityKey = Optional.of(pniIdentityKeyPair.getPublicKey().serialize());
aciSignedPreKey = Optional.of(KeysHelper.signedECPreKey(1, aciIdentityKeyPair));
pniSignedPreKey = Optional.of(KeysHelper.signedECPreKey(2, pniIdentityKeyPair));
aciPqLastResortPreKey = Optional.of(KeysHelper.signedKEMPreKey(3, aciIdentityKeyPair));
@@ -457,8 +457,8 @@ class RegistrationControllerTest {
}
static Stream<Arguments> atomicAccountCreationPartialSignedPreKeys() {
final Optional<String> aciIdentityKey;
final Optional<String> pniIdentityKey;
final Optional<byte[]> aciIdentityKey;
final Optional<byte[]> pniIdentityKey;
final Optional<SignedPreKey> aciSignedPreKey;
final Optional<SignedPreKey> pniSignedPreKey;
final Optional<SignedPreKey> aciPqLastResortPreKey;
@@ -467,8 +467,8 @@ class RegistrationControllerTest {
final ECKeyPair aciIdentityKeyPair = Curve.generateKeyPair();
final ECKeyPair pniIdentityKeyPair = Curve.generateKeyPair();
aciIdentityKey = Optional.of(KeysHelper.serializeIdentityKey(aciIdentityKeyPair));
pniIdentityKey = Optional.of(KeysHelper.serializeIdentityKey(pniIdentityKeyPair));
aciIdentityKey = Optional.of(aciIdentityKeyPair.getPublicKey().serialize());
pniIdentityKey = Optional.of(pniIdentityKeyPair.getPublicKey().serialize());
aciSignedPreKey = Optional.of(KeysHelper.signedECPreKey(1, aciIdentityKeyPair));
pniSignedPreKey = Optional.of(KeysHelper.signedECPreKey(2, pniIdentityKeyPair));
aciPqLastResortPreKey = Optional.of(KeysHelper.signedKEMPreKey(3, aciIdentityKeyPair));
@@ -570,8 +570,8 @@ class RegistrationControllerTest {
@MethodSource
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
void atomicAccountCreationSuccess(final RegistrationRequest registrationRequest,
final String expectedAciIdentityKey,
final String expectedPniIdentityKey,
final byte[] expectedAciIdentityKey,
final byte[] expectedPniIdentityKey,
final SignedPreKey expectedAciSignedPreKey,
final SignedPreKey expectedPniSignedPreKey,
final SignedPreKey expectedAciPqLastResortPreKey,
@@ -636,8 +636,8 @@ class RegistrationControllerTest {
}
private static Stream<Arguments> atomicAccountCreationSuccess() {
final Optional<String> aciIdentityKey;
final Optional<String> pniIdentityKey;
final Optional<byte[]> aciIdentityKey;
final Optional<byte[]> pniIdentityKey;
final Optional<SignedPreKey> aciSignedPreKey;
final Optional<SignedPreKey> pniSignedPreKey;
final Optional<SignedPreKey> aciPqLastResortPreKey;
@@ -646,8 +646,8 @@ class RegistrationControllerTest {
final ECKeyPair aciIdentityKeyPair = Curve.generateKeyPair();
final ECKeyPair pniIdentityKeyPair = Curve.generateKeyPair();
aciIdentityKey = Optional.of(KeysHelper.serializeIdentityKey(aciIdentityKeyPair));
pniIdentityKey = Optional.of(KeysHelper.serializeIdentityKey(pniIdentityKeyPair));
aciIdentityKey = Optional.of(aciIdentityKeyPair.getPublicKey().serialize());
pniIdentityKey = Optional.of(pniIdentityKeyPair.getPublicKey().serialize());
aciSignedPreKey = Optional.of(KeysHelper.signedECPreKey(1, aciIdentityKeyPair));
pniSignedPreKey = Optional.of(KeysHelper.signedECPreKey(2, pniIdentityKeyPair));
aciPqLastResortPreKey = Optional.of(KeysHelper.signedKEMPreKey(3, aciIdentityKeyPair));