-
Notifications
You must be signed in to change notification settings - Fork 310
Error: Bad MAC #41
Comments
I found my error in the code. |
Hi Ivan. Are you able to remember what was wrong with your code? I'm getting the exact same error implementing an extremely basic version of signal: let user1 = {}
let user2 = {}
//Create stores
user1.store = new SignalProtocolStore();
user2.store = new SignalProtocolStore();
//Create registration IDs
user1.registrationId = KeyHelper.generateRegistrationId();
user1.store.put('registrationId', user1.registrationId);
user2.registrationId = KeyHelper.generateRegistrationId();
user2.store.put('registrationId', user2.registrationId);
//Generate identity key pairs
user1.identityKeyPair = await KeyHelper.generateIdentityKeyPair()
user1.store.put('identityKey', user1.identityKeyPair);
user2.identityKeyPair = await KeyHelper.generateIdentityKeyPair()
user2.store.put('identityKey', user2.identityKeyPair);
//Generate signed pre-key
user1.signedPreKey = await KeyHelper.generateSignedPreKey(user1.identityKeyPair, 0)
user1.store.storeSignedPreKey(0, user1.signedPreKey.keyPair)
user2.signedPreKey = await KeyHelper.generateSignedPreKey(user2.identityKeyPair, 0)
user2.store.storeSignedPreKey(0, user2.signedPreKey.keyPair)
//Generate pre-key
user1.preKey = await KeyHelper.generatePreKey(0)
user1.store.storePreKey(0, user1.preKey.keyPair);
user2.preKey = await KeyHelper.generatePreKey(0)
user2.store.storePreKey(0, user2.preKey.keyPair);
//Create session
user1.session = {}
user1.session.address = new libsignal.SignalProtocolAddress(user2.registrationId, 1);
user1.session.sessionBuilder = new libsignal.SessionBuilder(user1.store, user1.session.address);
await user1.session.sessionBuilder.processPreKey({
registrationId: user2.registrationId,
identityKey: user2.identityKeyPair.pubKey,
signedPreKey: {
keyId : user2.signedPreKey.keyId,
publicKey : user2.signedPreKey.keyPair.pubKey,
signature : user2.signedPreKey.signature
},
preKey: {
keyId : user2.preKey.keyId,
publicKey : user2.preKey.keyPair.pubKey
}
});
//Encrypt message
user1.message = {}
user1.message.address = new libsignal.SignalProtocolAddress(user2.registrationId, 1);
user1.message.sessionCipher = new libsignal.SessionCipher(user1.store, user1.message.address);
user1.message.cipherText = await user1.message.sessionCipher.encrypt("A message from user 1")
//Encode message as base 64 (Avoids issues with JS encoding)
user1.message.cipherText.body = window.btoa(user1.message.cipherText.body)
//Decrypt message
user2.message = {}
user2.message.address = new libsignal.SignalProtocolAddress(user2.registrationId, 1);
user2.message.sessionCipher = new libsignal.SessionCipher(user2.store, user2.message.address);
user2.message.plainText = ""
if (user1.message.cipherText.type === 3) {
user2.message.plainText = await user2.message.sessionCipher.decryptPreKeyWhisperMessage(user1.message.cipherText.body, 'base64')
} else {
user2.message.plainText = await user2.message.sessionCipher.decryptWhisperMessage(user1.message.cipherText.body, 'base64')
}
console.log(user2.message.plainText) Error: Bad MAC at libsignal-protocol.js:35294:27 |
@ivanlemeshev @matthewroche Could you share the fix of the error? |
Hi @changeweb The library will not accept preKeys or signedPreKeys with an id of 0. All that is required to make the code I posted above work is to change the keyIds to 1. The only other change I have made to the working code below is to convert the final ArrayBuffer output to a string.
It looks like you've already found the Simple-Signal-Protocol-Demonstration library I created. I'll update the readme so that it's clear how to get this up and running though. |
@matthewroche thanks for your response. Yes I found the library. It was very helpful. |
@matthewroche Can I ask you a question. It’s introduced in the document: 'This protocol uses a concept called 'PreKeys'. A PreKey is an ECPublicKey and an associated unique ID which are stored together by a server. PreKeys can also be signed. At install time, clients generate a single signed PreKey, as well as a large list of unsigned PreKeys, and transmit all of them to the server.'. |
@1111mp I'm afraid I'm not working with this package anymore so my knowledge is a bit rusty. From memory each client needs to generate one signed prekey and multiple unsigned prekeys at install time, save it locally and send the public parts to the server. The unsigned prekeys are used to create a session, and can only be used once. You therefore need to regularly check that there are sufficient prekeys available on the server and create new ones once you fall below a threshold. The signed prekey is static, but I think for optimal encryption security is supposed to be rotated within a certain time interval. These keys are only used to set up the session. The actual keys used to encrypt the messages are created within the session and are updated with each message. Using this package means you don't need to worry about any of that though. Further details for the session set up are found here: https://signal.org/docs/specifications/x3dh/ Hope this helps |
@matthewroche Thank you very much for your reply. I'll go and study X3DH first. Thank you. |
@matthewroche Excuse me,how can an encrypted message be decrypted the next session is established?
When I click on the Button, the decryption fails again. |
I don't have time to load your code and play around with it right now. After a quick overview I think encryption fails because you're trying to decrypt the same message twice. If you create a new message and try to decrypt that I believe it should work. If you wish to decrypt the same message on multiple devices, each device needs to create its own session, and each device has to have its own keys. I'm afraid I don't use this library any more, so I'm not best placed to help you. You might be best looking for help at https://community.signalusers.org/ |
@matthewroche You have helped me a lot, thank you very much. In the case of multiple devices, for example, Alice has two devices A1 and A2, and then Bob sends a message to Alice. At this time, Bob's device should send two messages M1 and M2, encrypted with the public key of A1 and the public key of A2, respectively. Then A1 and A2 receive M1 and M2 respectively, and then use their own keys to decrypt. Is this correct? In other words, you only need to send a message, and then there is a way to support both devices A1 and A2 to decrypt. |
@matthewroche I have tried to find answers in the community, but the relevant content is too little, I am really sorry. |
I tried to write code to encrypt and decrypt the message. But every time I get an error
Error: Bad MAC at libsignal-protocol.js:35296
. Here is my code. Tell me please, what's wrong?The text was updated successfully, but these errors were encountered: