【问题标题】:How to get the type of a serialized ciphertext message?如何获取序列化密文消息的类型?
【发布时间】:2020-12-14 06:41:55
【问题描述】:

我正在根据Signal's Documentation 使用libsignal-protocol-java 在消息传递应用程序中实现端到端加密。

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

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

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

【问题讨论】:

    标签: e2e-encryption signal-protocol


    【解决方案1】:

    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 的公钥
    • 注册 ID

    对于加密和解密,您首先必须进行加密会话

    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(库作者使用的是信号协议的包装器,您可以将包装器库更改为信号协议)

    【讨论】:

      【解决方案2】:

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

      在课堂上SignalServiceCipher

      【讨论】:

        猜你喜欢
        • 2017-09-09
        • 2021-08-07
        • 1970-01-01
        • 1970-01-01
        • 2017-09-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多