Convert Provisioning, ResumeableUploads, and StickerResources protos to wire.
This commit is contained in:
parent
611f074a9d
commit
fba9b46fe9
10 changed files with 78 additions and 78 deletions
|
@ -9,7 +9,8 @@ import org.signal.libsignal.zkgroup.profiles.ProfileKey
|
|||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil
|
||||
import org.whispersystems.signalservice.internal.crypto.PrimaryProvisioningCipher
|
||||
import org.whispersystems.signalservice.internal.push.ProvisioningProtos
|
||||
import org.whispersystems.signalservice.internal.push.ProvisionEnvelope
|
||||
import org.whispersystems.signalservice.internal.push.ProvisionMessage
|
||||
import java.security.InvalidKeyException
|
||||
import java.security.MessageDigest
|
||||
import java.security.NoSuchAlgorithmException
|
||||
|
@ -26,9 +27,9 @@ class SecondaryProvisioningCipher private constructor(private val secondaryIdent
|
|||
|
||||
val secondaryDevicePublicKey: IdentityKey = secondaryIdentityKeyPair.publicKey
|
||||
|
||||
fun decrypt(envelope: ProvisioningProtos.ProvisionEnvelope): ProvisionDecryptResult {
|
||||
val primaryEphemeralPublicKey = envelope.publicKey.toByteArray()
|
||||
val body = envelope.body.toByteArray()
|
||||
fun decrypt(envelope: ProvisionEnvelope): ProvisionDecryptResult {
|
||||
val primaryEphemeralPublicKey = envelope.publicKey!!.toByteArray()
|
||||
val body = envelope.body!!.toByteArray()
|
||||
|
||||
val provisionMessageLength = body.size - VERSION_LENGTH - IV_LENGTH - MAC_LENGTH
|
||||
|
||||
|
@ -64,17 +65,17 @@ class SecondaryProvisioningCipher private constructor(private val secondaryIdent
|
|||
return ProvisionDecryptResult.Error
|
||||
}
|
||||
|
||||
val provisioningMessage = ProvisioningProtos.ProvisionMessage.parseFrom(plaintext)
|
||||
val provisioningMessage = ProvisionMessage.ADAPTER.decode(plaintext)
|
||||
|
||||
return ProvisionDecryptResult.Success(
|
||||
uuid = UuidUtil.parseOrThrow(provisioningMessage.aci),
|
||||
e164 = provisioningMessage.number,
|
||||
identityKeyPair = IdentityKeyPair(IdentityKey(provisioningMessage.aciIdentityKeyPublic.toByteArray()), Curve.decodePrivatePoint(provisioningMessage.aciIdentityKeyPrivate.toByteArray())),
|
||||
profileKey = ProfileKey(provisioningMessage.profileKey.toByteArray()),
|
||||
areReadReceiptsEnabled = provisioningMessage.readReceipts,
|
||||
e164 = provisioningMessage.number!!,
|
||||
identityKeyPair = IdentityKeyPair(IdentityKey(provisioningMessage.aciIdentityKeyPublic!!.toByteArray()), Curve.decodePrivatePoint(provisioningMessage.aciIdentityKeyPrivate!!.toByteArray())),
|
||||
profileKey = ProfileKey(provisioningMessage.profileKey!!.toByteArray()),
|
||||
areReadReceiptsEnabled = provisioningMessage.readReceipts == true,
|
||||
primaryUserAgent = provisioningMessage.userAgent,
|
||||
provisioningCode = provisioningMessage.provisioningCode,
|
||||
provisioningVersion = provisioningMessage.provisioningVersion
|
||||
provisioningCode = provisioningMessage.provisioningCode!!,
|
||||
provisioningVersion = provisioningMessage.provisioningVersion!!
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package org.thoughtcrime.securesms.registration.secondary
|
||||
|
||||
import com.google.protobuf.ByteString
|
||||
import okio.ByteString
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.Matchers.instanceOf
|
||||
import org.hamcrest.Matchers.`is`
|
||||
|
@ -8,9 +8,9 @@ import org.junit.Test
|
|||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
|
||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil
|
||||
import org.whispersystems.signalservice.internal.crypto.PrimaryProvisioningCipher
|
||||
import org.whispersystems.signalservice.internal.push.ProvisioningProtos
|
||||
import org.whispersystems.signalservice.internal.push.ProvisioningProtos.ProvisionMessage
|
||||
import org.whispersystems.signalservice.internal.push.ProvisioningProtos.ProvisioningVersion
|
||||
import org.whispersystems.signalservice.internal.push.ProvisionEnvelope
|
||||
import org.whispersystems.signalservice.internal.push.ProvisionMessage
|
||||
import org.whispersystems.signalservice.internal.push.ProvisioningVersion
|
||||
import java.util.UUID
|
||||
|
||||
class SecondaryProvisioningCipherTest {
|
||||
|
@ -23,16 +23,18 @@ class SecondaryProvisioningCipherTest {
|
|||
val primaryProfileKey = ProfileKeyUtil.createNew()
|
||||
val primaryProvisioningCipher = PrimaryProvisioningCipher(provisioningCipher.secondaryDevicePublicKey.publicKey)
|
||||
|
||||
val message = ProvisionMessage.newBuilder()
|
||||
.setAciIdentityKeyPublic(ByteString.copyFrom(primaryIdentityKeyPair.publicKey.serialize()))
|
||||
.setAciIdentityKeyPrivate(ByteString.copyFrom(primaryIdentityKeyPair.privateKey.serialize()))
|
||||
.setProvisioningCode("code")
|
||||
.setProvisioningVersion(ProvisioningVersion.CURRENT_VALUE)
|
||||
.setNumber("+14045555555")
|
||||
.setAci(UUID.randomUUID().toString())
|
||||
.setProfileKey(ByteString.copyFrom(primaryProfileKey.serialize()))
|
||||
val message = ProvisionMessage(
|
||||
aciIdentityKeyPublic = ByteString.of(*primaryIdentityKeyPair.publicKey.serialize()),
|
||||
aciIdentityKeyPrivate = ByteString.of(*primaryIdentityKeyPair.privateKey.serialize()),
|
||||
provisioningCode = "code",
|
||||
provisioningVersion = ProvisioningVersion.CURRENT.value,
|
||||
number = "+14045555555",
|
||||
aci = UUID.randomUUID().toString(),
|
||||
profileKey = ByteString.of(*primaryProfileKey.serialize()),
|
||||
readReceipts = true
|
||||
)
|
||||
|
||||
val provisionMessage = ProvisioningProtos.ProvisionEnvelope.parseFrom(primaryProvisioningCipher.encrypt(message.build()))
|
||||
val provisionMessage = ProvisionEnvelope.ADAPTER.decode(primaryProvisioningCipher.encrypt(message))
|
||||
|
||||
val result = provisioningCipher.decrypt(provisionMessage)
|
||||
assertThat(result, instanceOf(SecondaryProvisioningCipher.ProvisionDecryptResult.Success::class.java))
|
||||
|
|
|
@ -61,6 +61,8 @@ import org.whispersystems.signalservice.internal.push.BackupAuthCheckResponse;
|
|||
import org.whispersystems.signalservice.internal.push.CdsiAuthResponse;
|
||||
import org.whispersystems.signalservice.internal.push.OneTimePreKeyCounts;
|
||||
import org.whispersystems.signalservice.internal.push.ProfileAvatarData;
|
||||
import org.whispersystems.signalservice.internal.push.ProvisionMessage;
|
||||
import org.whispersystems.signalservice.internal.push.ProvisioningVersion;
|
||||
import org.whispersystems.signalservice.internal.push.PushServiceSocket;
|
||||
import org.whispersystems.signalservice.internal.push.RegistrationSessionMetadataResponse;
|
||||
import org.whispersystems.signalservice.internal.push.RemoteConfigResponse;
|
||||
|
@ -104,9 +106,6 @@ import javax.annotation.Nullable;
|
|||
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
import static org.whispersystems.signalservice.internal.push.ProvisioningProtos.ProvisionMessage;
|
||||
import static org.whispersystems.signalservice.internal.push.ProvisioningProtos.ProvisioningVersion;
|
||||
|
||||
/**
|
||||
* The main interface for creating, registering, and
|
||||
* managing a Signal Service account.
|
||||
|
@ -662,17 +661,17 @@ public class SignalServiceAccountManager {
|
|||
Preconditions.checkArgument(pni != null, "Missing PNI!");
|
||||
|
||||
PrimaryProvisioningCipher cipher = new PrimaryProvisioningCipher(deviceKey);
|
||||
ProvisionMessage.Builder message = ProvisionMessage.newBuilder()
|
||||
.setAciIdentityKeyPublic(ByteString.copyFrom(aciIdentityKeyPair.getPublicKey().serialize()))
|
||||
.setAciIdentityKeyPrivate(ByteString.copyFrom(aciIdentityKeyPair.getPrivateKey().serialize()))
|
||||
.setPniIdentityKeyPublic(ByteString.copyFrom(pniIdentityKeyPair.getPublicKey().serialize()))
|
||||
.setPniIdentityKeyPrivate(ByteString.copyFrom(pniIdentityKeyPair.getPrivateKey().serialize()))
|
||||
.setAci(aci.toString())
|
||||
.setPni(pni.toStringWithoutPrefix())
|
||||
.setNumber(e164)
|
||||
.setProfileKey(ByteString.copyFrom(profileKey.serialize()))
|
||||
.setProvisioningCode(code)
|
||||
.setProvisioningVersion(ProvisioningVersion.CURRENT_VALUE);
|
||||
ProvisionMessage.Builder message = new ProvisionMessage.Builder()
|
||||
.aciIdentityKeyPublic(okio.ByteString.of(aciIdentityKeyPair.getPublicKey().serialize()))
|
||||
.aciIdentityKeyPrivate(okio.ByteString.of(aciIdentityKeyPair.getPrivateKey().serialize()))
|
||||
.pniIdentityKeyPublic(okio.ByteString.of(pniIdentityKeyPair.getPublicKey().serialize()))
|
||||
.pniIdentityKeyPrivate(okio.ByteString.of(pniIdentityKeyPair.getPrivateKey().serialize()))
|
||||
.aci(aci.toString())
|
||||
.pni(pni.toStringWithoutPrefix())
|
||||
.number(e164)
|
||||
.profileKey(okio.ByteString.of(profileKey.serialize()))
|
||||
.provisioningCode(code)
|
||||
.provisioningVersion(ProvisioningVersion.CURRENT.getValue());
|
||||
|
||||
byte[] ciphertext = cipher.encrypt(message.build());
|
||||
this.pushServiceSocket.sendProvisioningMessage(deviceIdentifier, ciphertext);
|
||||
|
|
|
@ -27,7 +27,7 @@ import org.whispersystems.signalservice.internal.configuration.SignalServiceConf
|
|||
import org.whispersystems.signalservice.internal.push.IdentityCheckRequest;
|
||||
import org.whispersystems.signalservice.internal.push.IdentityCheckResponse;
|
||||
import org.whispersystems.signalservice.internal.push.PushServiceSocket;
|
||||
import org.whispersystems.signalservice.internal.sticker.StickerProtos;
|
||||
import org.whispersystems.signalservice.internal.sticker.Pack;
|
||||
import org.whispersystems.signalservice.internal.util.Util;
|
||||
import org.whispersystems.signalservice.internal.util.concurrent.FutureTransformers;
|
||||
import org.whispersystems.signalservice.internal.util.concurrent.ListenableFuture;
|
||||
|
@ -185,15 +185,15 @@ public class SignalServiceMessageReceiver {
|
|||
|
||||
InputStream cipherStream = AttachmentCipherInputStream.createForStickerData(manifestBytes, packKey);
|
||||
|
||||
StickerProtos.Pack pack = StickerProtos.Pack.parseFrom(Util.readFullyAsBytes(cipherStream));
|
||||
List<SignalServiceStickerManifest.StickerInfo> stickers = new ArrayList<>(pack.getStickersCount());
|
||||
SignalServiceStickerManifest.StickerInfo cover = pack.hasCover() ? new SignalServiceStickerManifest.StickerInfo(pack.getCover().getId(), pack.getCover().getEmoji(), pack.getCover().getContentType())
|
||||
: null;
|
||||
Pack pack = Pack.ADAPTER.decode(Util.readFullyAsBytes(cipherStream));
|
||||
List<SignalServiceStickerManifest.StickerInfo> stickers = new ArrayList<>(pack.stickers.size());
|
||||
SignalServiceStickerManifest.StickerInfo cover = pack.cover != null ? new SignalServiceStickerManifest.StickerInfo(pack.cover.id, pack.cover.emoji, pack.cover.contentType)
|
||||
: null;
|
||||
|
||||
for (StickerProtos.Pack.Sticker sticker : pack.getStickersList()) {
|
||||
stickers.add(new SignalServiceStickerManifest.StickerInfo(sticker.getId(), sticker.getEmoji(), sticker.getContentType()));
|
||||
for (Pack.Sticker sticker : pack.stickers) {
|
||||
stickers.add(new SignalServiceStickerManifest.StickerInfo(sticker.id, sticker.emoji, sticker.contentType));
|
||||
}
|
||||
|
||||
return new SignalServiceStickerManifest(pack.getTitle(), pack.getAuthor(), cover, stickers);
|
||||
return new SignalServiceStickerManifest(pack.title, pack.author, cover, stickers);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ import org.whispersystems.signalservice.internal.push.GroupStaleDevices;
|
|||
import org.whispersystems.signalservice.internal.push.MismatchedDevices;
|
||||
import org.whispersystems.signalservice.internal.push.OutgoingPushMessage;
|
||||
import org.whispersystems.signalservice.internal.push.OutgoingPushMessageList;
|
||||
import org.whispersystems.signalservice.internal.push.ProvisioningProtos;
|
||||
import org.whispersystems.signalservice.internal.push.ProvisioningVersion;
|
||||
import org.whispersystems.signalservice.internal.push.PushAttachmentData;
|
||||
import org.whispersystems.signalservice.internal.push.PushServiceSocket;
|
||||
import org.whispersystems.signalservice.internal.push.SendGroupMessageResponse;
|
||||
|
@ -1522,7 +1522,7 @@ public class SignalServiceMessageSender {
|
|||
configurationMessage.setLinkPreviews(configuration.getLinkPreviews().get());
|
||||
}
|
||||
|
||||
configurationMessage.setProvisioningVersion(ProvisioningProtos.ProvisioningVersion.CURRENT_VALUE);
|
||||
configurationMessage.setProvisioningVersion(ProvisioningVersion.CURRENT.getValue());
|
||||
|
||||
return container.setSyncMessage(syncMessage.setConfiguration(configurationMessage)).build();
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
|
||||
package org.whispersystems.signalservice.internal.crypto;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.signal.libsignal.protocol.InvalidKeyException;
|
||||
import org.signal.libsignal.protocol.ecc.Curve;
|
||||
import org.signal.libsignal.protocol.ecc.ECKeyPair;
|
||||
import org.signal.libsignal.protocol.ecc.ECPublicKey;
|
||||
import org.signal.libsignal.protocol.kdf.HKDF;
|
||||
import org.whispersystems.signalservice.internal.push.ProvisionEnvelope;
|
||||
import org.whispersystems.signalservice.internal.push.ProvisionMessage;
|
||||
import org.whispersystems.signalservice.internal.util.Util;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
@ -24,9 +24,7 @@ import javax.crypto.Mac;
|
|||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import static org.whispersystems.signalservice.internal.push.ProvisioningProtos.ProvisionEnvelope;
|
||||
import static org.whispersystems.signalservice.internal.push.ProvisioningProtos.ProvisionMessage;
|
||||
|
||||
import okio.ByteString;
|
||||
|
||||
public class PrimaryProvisioningCipher {
|
||||
|
||||
|
@ -45,15 +43,15 @@ public class PrimaryProvisioningCipher {
|
|||
byte[][] parts = Util.split(derivedSecret, 32, 32);
|
||||
|
||||
byte[] version = {0x01};
|
||||
byte[] ciphertext = getCiphertext(parts[0], message.toByteArray());
|
||||
byte[] ciphertext = getCiphertext(parts[0], message.encode());
|
||||
byte[] mac = getMac(parts[1], Util.join(version, ciphertext));
|
||||
byte[] body = Util.join(version, ciphertext, mac);
|
||||
|
||||
return ProvisionEnvelope.newBuilder()
|
||||
.setPublicKey(ByteString.copyFrom(ourKeyPair.getPublicKey().serialize()))
|
||||
.setBody(ByteString.copyFrom(body))
|
||||
.build()
|
||||
.toByteArray();
|
||||
return new ProvisionEnvelope.Builder()
|
||||
.publicKey(ByteString.of(ourKeyPair.getPublicKey().serialize()))
|
||||
.body(ByteString.of(body))
|
||||
.build()
|
||||
.encode();
|
||||
}
|
||||
|
||||
private byte[] getCiphertext(byte[] key, byte[] message) {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package org.whispersystems.signalservice.internal.push.http;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.signal.protos.resumableuploads.ResumableUploads;
|
||||
import org.signal.protos.resumableuploads.ResumableUpload;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.ResumeLocationInvalidException;
|
||||
import org.whispersystems.util.Base64;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import okio.ByteString;
|
||||
|
||||
public final class ResumableUploadSpec {
|
||||
|
||||
private final byte[] secretKey;
|
||||
|
@ -58,31 +58,31 @@ public final class ResumableUploadSpec {
|
|||
}
|
||||
|
||||
public String serialize() {
|
||||
ResumableUploads.ResumableUpload.Builder builder = ResumableUploads.ResumableUpload.newBuilder()
|
||||
.setSecretKey(ByteString.copyFrom(getSecretKey()))
|
||||
.setIv(ByteString.copyFrom(getIV()))
|
||||
.setTimeout(getExpirationTimestamp())
|
||||
.setCdnNumber(getCdnNumber())
|
||||
.setCdnKey(getCdnKey())
|
||||
.setLocation(getResumeLocation())
|
||||
.setTimeout(getExpirationTimestamp());
|
||||
ResumableUpload.Builder builder = new ResumableUpload.Builder()
|
||||
.secretKey(ByteString.of(getSecretKey()))
|
||||
.iv(ByteString.of(getIV()))
|
||||
.timeout(getExpirationTimestamp())
|
||||
.cdnNumber(getCdnNumber())
|
||||
.cdnKey(getCdnKey())
|
||||
.location(getResumeLocation())
|
||||
.timeout(getExpirationTimestamp());
|
||||
|
||||
return Base64.encodeBytes(builder.build().toByteArray());
|
||||
return Base64.encodeBytes(builder.build().encode());
|
||||
}
|
||||
|
||||
public static ResumableUploadSpec deserialize(String serializedSpec) throws ResumeLocationInvalidException {
|
||||
if (serializedSpec == null) return null;
|
||||
|
||||
try {
|
||||
ResumableUploads.ResumableUpload resumableUpload = ResumableUploads.ResumableUpload.parseFrom(ByteString.copyFrom(Base64.decode(serializedSpec)));
|
||||
ResumableUpload resumableUpload = ResumableUpload.ADAPTER.decode(Base64.decode(serializedSpec));
|
||||
|
||||
return new ResumableUploadSpec(
|
||||
resumableUpload.getSecretKey().toByteArray(),
|
||||
resumableUpload.getIv().toByteArray(),
|
||||
resumableUpload.getCdnKey(),
|
||||
resumableUpload.getCdnNumber(),
|
||||
resumableUpload.getLocation(),
|
||||
resumableUpload.getTimeout()
|
||||
resumableUpload.secretKey.toByteArray(),
|
||||
resumableUpload.iv.toByteArray(),
|
||||
resumableUpload.cdnKey,
|
||||
resumableUpload.cdnNumber,
|
||||
resumableUpload.location,
|
||||
resumableUpload.timeout
|
||||
);
|
||||
} catch (IOException e) {
|
||||
throw new ResumeLocationInvalidException();
|
||||
|
|
Loading…
Add table
Reference in a new issue