0

我根据Signal 的文档使用libsignal-protocol-java在消息传递应用程序中实现端到端加密。

假设 Alice 向 Bob 发送一个(成对的)序列化密文消息。Bob 怎么知道如何反序列化它?他不是首先需要知道密文消息的类型吗?我的理解是,成对的密文消息可以是信号消息(WHISPER_TYPE)或预密钥信号消息(PREKEY_TYPE)。那么 Bob 怎么知道它是哪种类型呢?

Alice 是否也应该向 Bob 发送密文消息的类型(作为明文)?

或者 Bob 有没有其他方法可以检测到类型?例如,Bob 是否应该尝试将其反序列化为信号消息,如果失败,则尝试将其反序列化为预密钥信号消息?

4

2 回答 2

0

在查看Signal Android的源代码后,我认为 Alice 应该也向 Bob 发送密文消息的类型(作为明文)。

在课堂上SignalServiceCipher

于 2020-08-25T18:42:44.413 回答
0

1 - Alice 生成 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 Id、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);
    }

您还可以查看 github 上提供的其他源代码 https://github.com/lvijay/DemoSignal

https://github.com/signalapp/libsignal-protocol-java/pull/21/commits/3496ed996359f6d3d8ee52dcecb8f8b0d45b3cbc(库作者使用的是信号协议的包装器,您可以将包装器库更改为信号协议)

于 2021-08-30T20:13:19.253 回答