英文:
How to get the type of a serialized ciphertext message?
问题
我正在根据Signal的文档使用libsignal-protocol-java来在一个消息应用程序中实现端到端加密。
假设Alice向Bob发送了一个(一对一的)序列化密文消息。那么Bob如何知道如何对其进行反序列化?他不是首先需要知道密文消息的类型吗?我理解的是,一对一的密文消息既可以是信号消息(WHISPER_TYPE
),也可以是预密钥信号消息(PREKEY_TYPE
)。那么Bob如何知道它是哪种类型?
Alice是否也需要将密文消息的类型(作为明文)发送给Bob?
还是Bob可以通过其他方式检测到类型?例如,Bob是否应该尝试将其反序列化为信号消息,如果失败了,再尝试将其反序列化为预密钥信号消息?
英文:
I'm using libsignal-protocol-java according to Signal's Documentation to implement end-to-end encryption in a messaging app.
Let's say Alice sends Bob a (pairwise) serialized ciphertext message. How does Bob know how to deserialize it? Doesn't he first need to know the type of the ciphertext message? My understanding is that a pairwise ciphertext message could either be a signal message (WHISPER_TYPE
) or a pre key signal message (PREKEY_TYPE
). So how does Bob know which type it is?
Is Alice supposed to also send Bob the type (as plaintext) of the ciphertext message?
Or is there another way that Bob could detect the type? For example, is Bob supposed to try to deserialize it as if it's a signal message, and if that fails, then try to deserialize it as if it's a pre key signal message?
答案1
得分: 2
在审查了Signal Android的源代码之后,我认为Alice应该还需要将消息的类型(以明文形式)一并发送给Bob。
-
实例方法
encrypt(SignalProtocolAddress, Optional<UnidentifiedAccess>, byte[])
返回一个OutgoingPushMessage
实例,其中type
属性设置为密文消息的类型,body
属性设置为Base64编码的序列化密文消息。 -
实例方法
decrypt(SignalServiceEnvelope, byte[])
从其第一个参数中获取密文消息的类型,该参数是一个SignalServiceEnvelope实例。
英文:
After reviewing the source code of Signal Android, I think Alice is supposed to also send Bob the type (as plaintext) of the ciphertext message.
In the class SignalServiceCipher
:
-
The instance method
encrypt(SignalProtocolAddress, Optional<UnidentifiedAccess>, byte[])
returns an instance ofOutgoingPushMessage
with itstype
property set to that of the ciphertext message and itsbody
property set to the Base64 encoded serialized ciphertext message. -
The instance method
decrypt(SignalServiceEnvelope, byte[])
gets the type of the ciphertext message from its first argument, which is an instance of SignalServiceEnvelope.
答案2
得分: 0
1 - Alice生成身份密钥对(长期)、已签名的预密钥(中期)和临时预密钥,并将这些密钥以Base64格式保存到存储中。
例如:
public static String generateIdentityKeyPair() {
IdentityKeyPair identityKeyPair = KeyHelper.generateIdentityKeyPair();
return encodeToBase64(identityKeyPair.serialize());
}
2 - 发送:
- 将预密钥ID和公钥以序列化格式发送至服务器
- 已签名的预密钥ID、已签名的预密钥公钥、已签名的预密钥记录签名
- 身份密钥对的公钥
- 注册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;
// 会话
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(库的作者正在使用信号协议的封装库,您可以将封装库更改为信号协议)
英文:
1 - Alice generate identityKeyPair(Long Term), signedPreKey(Medium Term) & Ephemeral PreKeys & save those keys into storage in base64.
e.g
public static String generateIdentityKeyPair() {
IdentityKeyPair identityKeyPair = KeyHelper.generateIdentityKeyPair();
return encodeToBase64(identityKeyPair.serialize());
}
2 - Send
- List of PreKey Id & Public key to server in Serialized format
- Signed PreKey Id, signedPreKeyPublicKey, signedPreKeyRecordSignature
- Public Key of IdentityKeyPair
- Registration Id
For Encryption and Decryption you first have to make to encrypted session
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);
}
Encryption & Decryption
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);
}
You can also look other source code which are available on github
https://github.com/lvijay/DemoSignal
https://github.com/signalapp/libsignal-protocol-java/pull/21/commits/3496ed996359f6d3d8ee52dcecb8f8b0d45b3cbc (The Library author is using is wrapper of signal protocol you can change wrapper library to signal protocol)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论