Как получить тип сериализованного зашифрованного сообщения?

Я использую https://github.com/signalapp/libsignal-protocol-java соответствии с документацией Signal для реализации сквозного шифрования в приложении для обмена сообщениями.

Допустим, Алиса отправляет Бобу (попарно) сериализованное сообщение зашифрованного текста. Откуда Боб знает, как его десериализовать? Разве ему сначала не нужно знать тип сообщения зашифрованного текста? Насколько я понимаю, сообщение с парным зашифрованным текстом может быть сигнальным сообщением (WHISPER_TYPE) или сообщение предварительного ключевого сигнала (PREKEY_TYPE). Итак, как Боб узнает, какой это тип?

Должна ли Алиса также послать Бобу тип (в виде открытого текста) зашифрованного сообщения?

Или есть другой способ, которым Боб мог определить тип? Например, должен ли Боб попытаться десериализовать его, как если бы это сигнальное сообщение, а если это не удалось, то попытаться десериализовать его, как если бы это сообщение предварительного ключа?

2 ответа

После просмотра исходного кода Signal Android я думаю, что Алиса должна также отправить Бобу тип (в виде открытого текста) зашифрованного сообщения.

В классе SignalServiceCipher:

  • Метод экземпляра encrypt(SignalProtocolAddress, Optional<UnidentifiedAccess>, byte[]) возвращает экземпляр OutgoingPushMessage с этими type свойство установлено на значение зашифрованного сообщения и его body для свойства установлено значение сериализованного зашифрованного сообщения в кодировке Base64.

  • Метод экземпляра decrypt(SignalServiceEnvelope, byte[]) получает тип сообщения зашифрованного текста из своего первого аргумента, который является экземпляром SignalServiceEnvelope.

1 - Алиса генерирует identityKeyPair (Long Term), signedPreKey (Medium Term) и Ephemeral PreKeys и сохраняет эти ключи в хранилище в base64. например

      public static String generateIdentityKeyPair() {
    IdentityKeyPair identityKeyPair = KeyHelper.generateIdentityKeyPair();
    return encodeToBase64(identityKeyPair.serialize());
}

2 - Отправить

  • Список PreKey Id и открытого ключа к серверу в сериализованном формате
  • Подписанный идентификатор PreKey, signedPreKeyPublicKey, signedPreKeyRecordSignature
  • Открытый ключ IdentityKeyPair
  • Идентификатор регистрации

Для шифрования и дешифрования вам сначала нужно сделать зашифрованный сеанс

      private void initSessionFromPreKey() throws UntrustedIdentityException, InvalidKeyException {
        InMemorySignalProtocolStore protocolStore = new InMemorySignalProtocolStore(localUser.getIdentityKeyPair(), localUser.getRegistrationId());
        protocolStore.storePreKey(localUser.getPreKeys().get(0).getId(), localUser.getPreKeys().get(0));
        protocolStore.storeSignedPreKey(localUser.getSignedPreKey().getId(), localUser.getSignedPreKey());
        this.protocolStore = protocolStore;


        //Session
        SessionBuilder sessionBuilder = new SessionBuilder(protocolStore, remoteUser.getSignalProtocolAddress());
        PreKeyBundle preKeyBundle = new PreKeyBundle(
                remoteUser.getRegistrationId(),
                remoteUser.getSignalProtocolAddress().getDeviceId(),
                remoteUser.getPreKeyId(),
                remoteUser.getPreKeyPublicKey(),
                remoteUser.getSignedPreKeyId(),
                remoteUser.getSignedPreKeyPublicKey(),
                remoteUser.getSignedPreKeySignature(),
                remoteUser.getIdentityKeyPairPublicKey()
        );

        sessionBuilder.process(preKeyBundle);
        mSessionCipher = new SessionCipher(protocolStore, protocolAddress);
    }

Шифрование и дешифрование

      public String encrypt(String message) throws InvalidVersionException, InvalidMessageException, UntrustedIdentityException, InvalidKeyException {
        createSession(Operation.ENCRYPT);
        CiphertextMessage ciphertextMessage = mSessionCipher.encrypt(message.getBytes());
        PreKeySignalMessage preKeySignalMessage = new PreKeySignalMessage(ciphertextMessage.serialize());
        return KeyUtils.encodeToBase64(preKeySignalMessage.serialize());
    }

    public String decrypt(String message) throws InvalidVersionException, InvalidMessageException, InvalidKeyException, DuplicateMessageException, InvalidKeyIdException, UntrustedIdentityException, LegacyMessageException {
        createSession(Operation.DECRYPT);
        byte[] bytes = KeyUtils.decodeToByteArray(message);
        byte[] decryptedMessage = mSessionCipher.decrypt(new PreKeySignalMessage(bytes));
        return new String(decryptedMessage, StandardCharsets.UTF_8);
    }

Вы также можете посмотреть другой исходный код, который доступен на githubhttps://github.com/lvijay/DemoSignal

https://github.com/signalapp/libsignal-protocol-java/pull/21/commit/3496ed996359f6d3d8ee52dcecb8f8b0d45b3cbc (Автор библиотеки использует оболочку сигнального протокола, вы можете изменить библиотеку оболочки на сигнальный протокол)

Другие вопросы по тегам