Represent identity keys as IdentityKey instances

This commit is contained in:
Jon Chambers
2023-06-08 11:36:58 -04:00
committed by GitHub
parent 1c8443210a
commit 234707169e
34 changed files with 390 additions and 263 deletions

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.util;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.util.Base64;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Metrics;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.protocol.ecc.ECPublicKey;
import org.whispersystems.textsecuregcm.metrics.MetricsUtil;
public class IdentityKeyAdapter {
private static final Counter IDENTITY_KEY_WITHOUT_VERSION_BYTE_COUNTER =
Metrics.counter(MetricsUtil.name(IdentityKeyAdapter.class), "identityKeyWithoutVersionByte");
public static class Serializer extends JsonSerializer<IdentityKey> {
@Override
public void serialize(final IdentityKey identityKey,
final JsonGenerator jsonGenerator,
final SerializerProvider serializers) throws IOException {
jsonGenerator.writeString(Base64.getEncoder().encodeToString(identityKey.serialize()));
}
}
public static class Deserializer extends JsonDeserializer<IdentityKey> {
@Override
public IdentityKey deserialize(final JsonParser parser, final DeserializationContext context) throws IOException {
final byte[] identityKeyBytes;
try {
identityKeyBytes = Base64.getDecoder().decode(parser.getValueAsString());
} catch (final IllegalArgumentException e) {
throw new JsonParseException(parser, "Could not parse identity key as a base64-encoded value", e);
}
try {
return new IdentityKey(identityKeyBytes);
} catch (final InvalidKeyException e) {
if (identityKeyBytes.length == ECPublicKey.KEY_SIZE - 1) {
IDENTITY_KEY_WITHOUT_VERSION_BYTE_COUNTER.increment();
return new IdentityKey(ECPublicKey.fromPublicKeyBytes(identityKeyBytes));
}
throw new JsonParseException(parser, "Could not interpret identity key bytes as an EC public key", e);
}
}
}
}

View File

@@ -1,22 +0,0 @@
package org.whispersystems.textsecuregcm.util;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
import java.util.Base64;
import java.util.Optional;
public class OptionalBase64ByteArrayDeserializer extends JsonDeserializer<Optional<byte[]>> {
@Override
public Optional<byte[]> deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException {
return Optional.of(Base64.getDecoder().decode(jsonParser.getValueAsString()));
}
@Override
public Optional<byte[]> getNullValue(DeserializationContext ctxt) {
return Optional.empty();
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.util;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.util.Base64;
import java.util.Optional;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.InvalidKeyException;
public class OptionalIdentityKeyAdapter {
public static class Serializer extends JsonSerializer<Optional<IdentityKey>> {
@Override
public void serialize(final Optional<IdentityKey> maybePublicKey,
final JsonGenerator jsonGenerator,
final SerializerProvider serializers) throws IOException {
if (maybePublicKey.isPresent()) {
jsonGenerator.writeString(Base64.getEncoder().encodeToString(maybePublicKey.get().serialize()));
} else {
jsonGenerator.writeNull();
}
}
}
public static class Deserializer extends JsonDeserializer<Optional<IdentityKey>> {
@Override
public Optional<IdentityKey> deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException {
try {
return Optional.of(new IdentityKey(Base64.getDecoder().decode(jsonParser.getValueAsString())));
} catch (final InvalidKeyException e) {
throw new IOException(e);
}
}
@Override
public Optional<IdentityKey> getNullValue(DeserializationContext ctxt) {
return Optional.empty();
}
}
}