Merge pull request #1337 from Bilb/fix-ssk

This commit is contained in:
Audric Ackermann 2020-09-15 10:47:00 +10:00 committed by GitHub
commit 1545256cbe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 41 additions and 30 deletions

View file

@ -11,5 +11,5 @@ module.exports = {
ENCRYPTED_MESSAGE_OVERHEAD: 53, ENCRYPTED_MESSAGE_OVERHEAD: 53,
LOKI_FRIEND_REQUEST: 101, FALLBACK_MESSAGE: 101,
}; };

View file

@ -199,8 +199,8 @@ function _createUnidentifiedSenderMessageContentFromBuffer(serialized) {
case TypeEnum.PREKEY_MESSAGE: case TypeEnum.PREKEY_MESSAGE:
type = CiphertextMessage.PREKEY_TYPE; type = CiphertextMessage.PREKEY_TYPE;
break; break;
case TypeEnum.LOKI_FRIEND_REQUEST: case TypeEnum.FALLBACK_MESSAGE:
type = CiphertextMessage.LOKI_FRIEND_REQUEST; type = CiphertextMessage.FALLBACK_MESSAGE;
break; break;
default: default:
throw new Error(`Unknown type: ${message.type}`); throw new Error(`Unknown type: ${message.type}`);
@ -226,8 +226,8 @@ function _getProtoMessageType(type) {
return TypeEnum.MESSAGE; return TypeEnum.MESSAGE;
case CiphertextMessage.PREKEY_TYPE: case CiphertextMessage.PREKEY_TYPE:
return TypeEnum.PREKEY_MESSAGE; return TypeEnum.PREKEY_MESSAGE;
case CiphertextMessage.LOKI_FRIEND_REQUEST: case CiphertextMessage.FALLBACK_MESSAGE:
return TypeEnum.LOKI_FRIEND_REQUEST; return TypeEnum.FALLBACK_MESSAGE;
default: default:
throw new Error(`_getProtoMessageType: type '${type}' does not exist`); throw new Error(`_getProtoMessageType: type '${type}' does not exist`);
} }
@ -481,7 +481,7 @@ SecretSessionCipher.prototype = {
signalProtocolStore, signalProtocolStore,
sender sender
).decryptPreKeyWhisperMessage(message.content); ).decryptPreKeyWhisperMessage(message.content);
case CiphertextMessage.LOKI_FRIEND_REQUEST: case CiphertextMessage.FALLBACK_MESSAGE:
return new libloki.crypto.FallBackSessionCipher(sender).decrypt( return new libloki.crypto.FallBackSessionCipher(sender).decrypt(
message.content message.content
); );

View file

@ -42,7 +42,7 @@ message Content {
message MediumGroupCiphertext { message MediumGroupCiphertext {
optional bytes ciphertext = 1; optional bytes ciphertext = 1;
optional string source = 2; optional bytes source = 2;
optional uint32 keyIdx = 3; optional uint32 keyIdx = 3;
} }

View file

@ -25,7 +25,7 @@ message UnidentifiedSenderMessage {
enum Type { enum Type {
PREKEY_MESSAGE = 1; PREKEY_MESSAGE = 1;
MESSAGE = 2; MESSAGE = 2;
LOKI_FRIEND_REQUEST = 3; FALLBACK_MESSAGE = 3;
} }
optional Type type = 1; optional Type type = 1;

View file

@ -18,6 +18,7 @@ import ByteBuffer from 'bytebuffer';
import { BlockedNumberController } from '../util/blockedNumberController'; import { BlockedNumberController } from '../util/blockedNumberController';
import { decryptWithSenderKey } from '../session/medium_group/ratchet'; import { decryptWithSenderKey } from '../session/medium_group/ratchet';
import { StringUtils } from '../session/utils'; import { StringUtils } from '../session/utils';
import { UserUtil } from '../util';
export async function handleContentMessage(envelope: EnvelopePlus) { export async function handleContentMessage(envelope: EnvelopePlus) {
const plaintext = await decrypt(envelope, envelope.content); const plaintext = await decrypt(envelope, envelope.content);
@ -46,8 +47,6 @@ async function decryptForMediumGroup(
throw new Error(`Secret key is empty for group ${groupId}!`); throw new Error(`Secret key is empty for group ${groupId}!`);
} }
const { senderIdentity } = envelope;
const { const {
ciphertext: outerCiphertext, ciphertext: outerCiphertext,
ephemeralKey, ephemeralKey,
@ -64,15 +63,27 @@ async function decryptForMediumGroup(
outerCiphertext outerCiphertext
); );
const { ciphertext, keyIdx } = SignalService.MediumGroupCiphertext.decode( const {
source,
ciphertext,
keyIdx,
} = SignalService.MediumGroupCiphertext.decode(
new Uint8Array(mediumGroupCiphertext) new Uint8Array(mediumGroupCiphertext)
); );
const ourNumber = (await UserUtil.getCurrentDevicePubKey()) as string;
const sourceAsStr = StringUtils.decode(source, 'hex');
if (sourceAsStr === ourNumber) {
window.console.info(
'Dropping message from ourself after decryptForMediumGroup'
);
return;
}
const plaintext = await decryptWithSenderKey( const plaintext = await decryptWithSenderKey(
ciphertext, ciphertext,
keyIdx, keyIdx,
groupId, groupId,
senderIdentity sourceAsStr
); );
return plaintext; return plaintext;

View file

@ -4,6 +4,7 @@ import { UserUtil } from '../../util';
import { CipherTextObject } from '../../../libtextsecure/libsignal-protocol'; import { CipherTextObject } from '../../../libtextsecure/libsignal-protocol';
import { encryptWithSenderKey } from '../../session/medium_group/ratchet'; import { encryptWithSenderKey } from '../../session/medium_group/ratchet';
import { PubKey } from '../types'; import { PubKey } from '../types';
import { StringUtils } from '../utils';
/** /**
* Add padding to a message buffer * Add padding to a message buffer
@ -90,7 +91,7 @@ export async function encryptForMediumGroup(
// We should include ciphertext idx in the message // We should include ciphertext idx in the message
const content = SignalService.MediumGroupCiphertext.encode({ const content = SignalService.MediumGroupCiphertext.encode({
ciphertext, ciphertext,
source: ourKey, source: new Uint8Array(StringUtils.encode(ourKey, 'hex')),
keyIdx, keyIdx,
}).finish(); }).finish();

View file

@ -1,7 +1,6 @@
import { SignalService } from '../../../../../../protobuf';
import { ChatMessage } from '../ChatMessage'; import { ChatMessage } from '../ChatMessage';
import { PubKey } from '../../../../../types'; import { PubKey } from '../../../../../types';
import { MediumGroupMessage } from './MediumGroupMessage'; import { ClosedGroupChatMessage } from '../group/ClosedGroupChatMessage';
interface MediumGroupChatMessageParams { interface MediumGroupChatMessageParams {
identifier?: string; identifier?: string;
@ -9,21 +8,12 @@ interface MediumGroupChatMessageParams {
chatMessage: ChatMessage; chatMessage: ChatMessage;
} }
export class MediumGroupChatMessage extends MediumGroupMessage { export class MediumGroupChatMessage extends ClosedGroupChatMessage {
private readonly chatMessage: ChatMessage;
constructor(params: MediumGroupChatMessageParams) { constructor(params: MediumGroupChatMessageParams) {
super({ super({
timestamp: params.chatMessage.timestamp,
identifier: params.identifier ?? params.chatMessage.identifier, identifier: params.identifier ?? params.chatMessage.identifier,
groupId: params.groupId, groupId: params.groupId,
chatMessage: params.chatMessage,
}); });
this.chatMessage = params.chatMessage;
}
public dataProto(): SignalService.DataMessage {
const messageProto = this.chatMessage.dataProto();
return messageProto;
} }
} }

View file

@ -39,7 +39,12 @@ export async function send(
plainTextBuffer, plainTextBuffer,
encryption encryption
); );
const envelope = await buildEnvelope(envelopeType, timestamp, cipherText); const envelope = await buildEnvelope(
envelopeType,
device.key,
timestamp,
cipherText
);
const data = wrapEnvelope(envelope); const data = wrapEnvelope(envelope);
return pRetry( return pRetry(
@ -54,11 +59,15 @@ export async function send(
async function buildEnvelope( async function buildEnvelope(
type: SignalService.Envelope.Type, type: SignalService.Envelope.Type,
sskSource: string | undefined,
timestamp: number, timestamp: number,
content: Uint8Array content: Uint8Array
): Promise<SignalService.Envelope> { ): Promise<SignalService.Envelope> {
let source: string | undefined; let source: string | undefined;
if (type !== SignalService.Envelope.Type.UNIDENTIFIED_SENDER) {
if (type === SignalService.Envelope.Type.MEDIUM_GROUP_CIPHERTEXT) {
source = sskSource;
} else if (type !== SignalService.Envelope.Type.UNIDENTIFIED_SENDER) {
source = await UserUtil.getCurrentDevicePubKey(); source = await UserUtil.getCurrentDevicePubKey();
} }

View file

@ -12,7 +12,7 @@ import * as Ratchet from '../../../../session/medium_group/ratchet';
// tslint:disable-next-line: max-func-body-length // tslint:disable-next-line: max-func-body-length
describe('MessageEncrypter', () => { describe('MessageEncrypter', () => {
const sandbox = sinon.createSandbox(); const sandbox = sinon.createSandbox();
const ourNumber = 'ourNumber'; const ourNumber = '0123456789abcdef';
beforeEach(() => { beforeEach(() => {
TestUtils.stubWindow('libsignal', { TestUtils.stubWindow('libsignal', {

View file

@ -36,7 +36,7 @@ describe('MessageSender', () => {
}); });
describe('send', () => { describe('send', () => {
const ourNumber = 'ourNumber'; const ourNumber = '0123456789abcdef';
let lokiMessageAPISendStub: sinon.SinonStub< let lokiMessageAPISendStub: sinon.SinonStub<
[string, Uint8Array, number, number], [string, Uint8Array, number, number],
Promise<void> Promise<void>