Esempio n. 1
0
        Compressed DecryptCommon(CipherV2 cipherV2, KeyMaterial64 keyMaterial64, LongRunningOperationContext context)
        {
            if (context == null)
            {
                context = new LongRunningOperation(progress => { }, () => { }).Context;
            }

            Guard.NotNull(new object[] { cipherV2, keyMaterial64 });
            EnsurePlatform();

            InputDerivedKey32 inputDerivedKey = cipherV2.RoundsExponent.Value == RoundsExponent.DontMakeRounds
                ? CreateDerivedKeyWithSHA256(cipherV2.IV16, keyMaterial64)
                : CreatePasswordDerivedKeyWithBCrypt(cipherV2.IV16, keyMaterial64, cipherV2.RoundsExponent, context);

            XDSSecAPIInternal.IVCache ivCache = cipherV2.RoundsExponent.Value == RoundsExponent.DontMakeRounds
                ? null
                : this._internal.CreateIVTable(cipherV2.IV16, cipherV2.RoundsExponent.Value);

            RandomKey32 randomKey = this._internal.AESDecryptRandomKeyWithPasswordDerivedKey(cipherV2, inputDerivedKey, ivCache, context);

            MAC16 decryptedMAC = this._internal.AESDecryptMAC(cipherV2, randomKey, ivCache, context);

            MAC16 actualMAC = CreateMAC(cipherV2, context);

            if (!actualMAC.GetBytes().SequenceEqual(decryptedMAC.GetBytes()))
            {
                throw new Exception(LocalizableStrings.MsgPasswordError);
            }

            PaddedData paddedData = this._internal.AESDecryptMessage(cipherV2, cipherV2.IV16, randomKey, ivCache, context);

            Compressed compressed = this._internal.RemovePadding(paddedData);

            return(compressed);
        }
Esempio n. 2
0
        void SaveFileToDownloads(Message message)
        {
            var fileName  = message.ThreadText.Split(',').First().Trim();
            var appDir    = App.ServiceProvider.Get <ICancellation>().DataDirRoot.Parent;
            var exportDir = Path.Combine(appDir.FullName, "temp");

            if (!Directory.Exists(exportDir))
            {
                Directory.CreateDirectory(exportDir);
            }

            var xdsSec = App.ServiceProvider.Get <IXDSSecService>();



            var decryptionkey  = new KeyMaterial64(xdsSec.DefaultDecrypt(message.EncryptedE2EEncryptionKey, xdsSec.SymmetricKeyRepository.GetMasterRandomKey()));
            var plaintextBytes = xdsSec.DefaultDecrypt(message.ImageCipher, decryptionkey);

            var pathAndFileName = Path.Combine(exportDir, fileName);

            File.WriteAllBytes(pathAndFileName, plaintextBytes);


            MessageBox.Query("File decrypted",
                             $"The file was decrypted and saved as {Path.Combine(exportDir, fileName)}. We'll try to delete it when you quit the app!", Strings.Ok);
        }
Esempio n. 3
0
        InputDerivedKey32 CreateDerivedKeyWithSHA256(IV16 iv, KeyMaterial64 keyMaterial64)
        {
            var keyMaterial = ByteArrays.Concatenate(iv.GetBytes(), keyMaterial64.GetBytes());
            var derivedKey  = this._platform.ComputeSHA256(keyMaterial);

            return(new InputDerivedKey32(derivedKey));
        }
Esempio n. 4
0
        public TLSEnvelope TLSServerEncryptRequest(byte[] clearPacket, string recipientId)
        {
            byte[] authSecret = GetAuthSecret(recipientId);

            DynamicSecret dynamicSecret = GetDynamicSecretForEncryption(recipientId);

            Debug.WriteLine($"{this.ServerId}: TLSEncrypt: DynamicPublicKeyID: {dynamicSecret.DynamicPublicKeyId}, PrivateKeyHint: {dynamicSecret.PrivateKeyHint}.");

            // Concatenate = 'TLSAuthMode.Combined'
            byte[] symmetricKeyMaterial64 = ByteArrays.Concatenate(dynamicSecret.DynamicSharedSecret, authSecret);

            var lro        = new LongRunningOperation(progress => { }, () => { });
            var clearBytes = new Clearbytes(clearPacket);
            var sha512PW64 = new KeyMaterial64(symmetricKeyMaterial64);
            var method     = new RoundsExponent(0xff);

            var encryptResponse = this.ixdsCryptoService.BinaryEncrypt(clearBytes, sha512PW64, method, lro.Context);

            if (!encryptResponse.IsSuccess)
            {
                throw new Exception(encryptResponse.Error);
            }

            var encodeResponse = this.ixdsCryptoService.BinaryEncodeXDSSec(encryptResponse.Result, lro.Context);

            if (!encodeResponse.IsSuccess)
            {
                throw new Exception(encodeResponse.Error);
            }

            var tlsEnvelope = new TLSEnvelope(dynamicSecret.PrivateKeyHint, dynamicSecret.DynamicPublicKeyId, dynamicSecret.DynamicPublicKey, encodeResponse.Result);

            return(tlsEnvelope);
        }
Esempio n. 5
0
        InputDerivedKey32 CreatePasswordDerivedKeyWithBCrypt(IV16 iv, KeyMaterial64 keyMaterial64, RoundsExponent roundsExponent,
                                                             LongRunningOperationContext context)
        {
            var leftSHA512  = new byte[32];
            var rightSHA512 = new byte[32];

            Buffer.BlockCopy(keyMaterial64.GetBytes(), 0, leftSHA512, 0, 32);
            Buffer.BlockCopy(keyMaterial64.GetBytes(), 32, rightSHA512, 0, 32);

            context.EncryptionProgress.Message = LocalizableStrings.MsgProcessingKey;

            // Compute the left side on a ThreadPool thread
            var task = Task.Run(() => BCrypt.CreateHash(iv, leftSHA512, roundsExponent.Value, context));

            // Compute the right side after dispatching the work for the right side
            BCrypt24 rightBCrypt = BCrypt.CreateHash(iv, rightSHA512, roundsExponent.Value, context);

            // Wait for the left side result
            task.Wait(context.CancellationToken);

            // Use the results
            var combinedHashes = ByteArrays.Concatenate(keyMaterial64.GetBytes(), task.Result.GetBytes(), rightBCrypt.GetBytes());

            Debug.Assert(combinedHashes.Length == 64 + 24 + 24);

            var condensedHash = this._platform.ComputeSHA256(combinedHashes);

            return(new InputDerivedKey32(condensedHash));
        }
Esempio n. 6
0
        KeyMaterial64 CreateKeyMaterialFromPassphrase(string passphrase)
        {
            NormalizedPassword normalizedPassword = this.xdsCryptoService.NormalizePassword(passphrase).Result;
            KeyMaterial64      hashedPassword     = this.xdsCryptoService.HashPassword(normalizedPassword).Result;

            return(hashedPassword);
        }
Esempio n. 7
0
 public void ClearMasterRandomKey()
 {
     if (this._masterRandomKey != null)
     {
         this._masterRandomKey.GetBytes().FillWithZeros();
     }
     this._masterRandomKey = null;
 }
Esempio n. 8
0
 public void SetMasterRandomKey(KeyMaterial64 masterRandomKey)
 {
     if (masterRandomKey == null)
     {
         throw new ArgumentNullException(nameof(masterRandomKey));
     }
     this._masterRandomKey = masterRandomKey;
 }
Esempio n. 9
0
        async Task EncryptAndSaveDeviceVaultKeyAsync(KeyMaterial64 masterRandomKey, KeyMaterial64 masterPassphraseKeyMaterial, LongRunningOperationContext context)
        {
            context.EncryptionProgress.Message = "Encrypting master random key";
            context.EncryptionProgress.Report(context.EncryptionProgress);
            CipherV2 encryptedMasterRandomKey = this.xdsCryptoService.BinaryEncrypt(new Clearbytes(masterRandomKey.GetBytes()), masterPassphraseKeyMaterial, new RoundsExponent(10), context).Result;

            byte[] encryptedMasterRandomKeyBytes = this.xdsCryptoService.BinaryEncodeXDSSec(encryptedMasterRandomKey, context).Result;
            await this.repo.WriteSpecialFile(MasterKeyFilename, encryptedMasterRandomKeyBytes);
        }
Esempio n. 10
0
        public byte[] DefaultEncrypt(byte[] plaintextBytes, KeyMaterial64 keyMaterial64)
        {
            var binaryEncryptResponse = BinaryEncrypt(new Clearbytes(plaintextBytes), keyMaterial64, new RoundsExponent(RoundsExponent.DontMakeRounds), null);

            if (binaryEncryptResponse.IsSuccess)
            {
                return(XDSSecFormatter.CreateBinary(binaryEncryptResponse.Result));
            }
            throw new Exception(binaryEncryptResponse.Error);
        }
Esempio n. 11
0
        public static byte[] EncryptWithPassphrase(string passphrase, byte[] bytesToEncryt)
        {
            var context = GetContext();
            NormalizedPassword normalizedPassword           = Instance().NormalizePassword(passphrase).Result;
            KeyMaterial64      passwordDerivedkeyMaterial64 = Instance().HashPassword(normalizedPassword).Result;
            CipherV2           cipherV2 = Instance().BinaryEncrypt(new Clearbytes(bytesToEncryt), passwordDerivedkeyMaterial64, new RoundsExponent(RoundsExponent.DontMakeRounds), context).Result;
            var cipherV2Bytes           = Instance().BinaryEncodeXDSSec(cipherV2, context).Result;

            return(cipherV2Bytes);
        }
Esempio n. 12
0
        /// <summary>
        /// Loads the key file and tries to decrypt the master random key. Only if successful, it also sets the decrypted master random key in SymmetricKeyRepository.
        /// Then, Response.Success is true. Therefore, this method can also be used to check if the master password is correct. If it is incorrect, the method does nothing and
        /// Response.Success is false.
        /// </summary>
        /// <param name="unprunedUtf16LeMasterPassword">the master password</param>
        /// <param name="context">Progress object</param>
        public async Task TryLoadDecryptAndSetMasterRandomKeyAsync(string unprunedUtf16LeMasterPassword, LongRunningOperationContext context)
        {
            KeyMaterial64 masterPasswordHash = CreateKeyMaterialFromPassphrase(unprunedUtf16LeMasterPassword);

            byte[] encryptedRandomMasterKey = await this.repo.LoadSpecialFile(MasterKeyFilename);

            byte[] decryptedMasterRandomKey = this.xdsCryptoService.DefaultDecrypt(encryptedRandomMasterKey, masterPasswordHash, context);

            this.xdsCryptoService.SymmetricKeyRepository.SetDeviceVaultRandomKey(new KeyMaterial64(decryptedMasterRandomKey));
        }
Esempio n. 13
0
        public byte[] DefaultDecrypt(byte[] cipherTextBytes, KeyMaterial64 keyMaterial64, LongRunningOperationContext context = null)
        {
            CipherV2 cipherV2 = XDSSecFormatter.DissectXDSSecBytes(cipherTextBytes, context);
            var      binaryDecryptResponse = BinaryDecrypt(cipherV2, keyMaterial64, context);

            if (!binaryDecryptResponse.IsSuccess)
            {
                throw new Exception(binaryDecryptResponse.Error);
            }
            return(binaryDecryptResponse.Result.GetBytes());
        }
Esempio n. 14
0
        void EncryptWithStrategy(Message message, KeyMaterial64 keyMaterial, RoundsExponent roundsExponent, KeyMaterial64 initialMetadataKeyMaterial)
        {
            XMessageMetaData messageMetadata = new XMessageMetaData {
                MessageType = message.MessageType
            };

            switch (message.MessageType)
            {
            case MessageType.Text:
                message.TextCipher = EncryptTextToBytes(message.ThreadText, keyMaterial, roundsExponent);
                messageMetadata.SenderLocalMessageId = int.Parse(message.Id);
                break;

            case MessageType.Media:
                message.ImageCipher = this.ixdsCryptoService.DefaultEncrypt(message.ThreadMedia, keyMaterial);
                messageMetadata.SenderLocalMessageId = int.Parse(message.Id);
                break;

            case MessageType.TextAndMedia:
            case MessageType.File:
                message.TextCipher  = EncryptTextToBytes(message.ThreadText, keyMaterial, roundsExponent);
                message.ImageCipher = this.ixdsCryptoService.DefaultEncrypt(message.ThreadMedia, keyMaterial);
                messageMetadata.SenderLocalMessageId = int.Parse(message.Id);
                break;

            case MessageType.DeliveryReceipt:
            case MessageType.ReadReceipt:
                messageMetadata.SenderLocalMessageId = int.Parse(message.SenderLocalMessageId);
                break;

            default:
                throw new Exception("Invalid MessageType");
            }

            if (initialMetadataKeyMaterial != null)             // initialMetadataKeyMaterial is only for resend requests
            {
                messageMetadata.SenderPublicKey = this.profileViewModel.PublicKey;
                message.MetaCipher = this.ixdsCryptoService.DefaultEncrypt(messageMetadata.SerializeCore(), initialMetadataKeyMaterial);
            }
            else
            {
                messageMetadata.SenderPublicKey = this.ixdsCryptoService.GetRandom(32).Result.X;
                message.MetaCipher = this.ixdsCryptoService.DefaultEncrypt(messageMetadata.SerializeCore(), keyMaterial);
            }

            if (!message.MessageType.IsReceipt())
            {
                message.EncryptedE2EEncryptionKey = this.ixdsCryptoService.DefaultEncrypt(keyMaterial.GetBytes(), this.ixdsCryptoService.SymmetricKeyRepository.GetMasterRandomKey());
            }
        }
Esempio n. 15
0
        public static byte[] DecryptWithPassphrase(string passphrase, byte[] bytesToDecrypt)
        {
            var context = GetContext();
            NormalizedPassword normalizedPassword           = Instance().NormalizePassword(passphrase).Result;
            KeyMaterial64      passwordDerivedkeyMaterial64 = Instance().HashPassword(normalizedPassword).Result;
            CipherV2           cipherV2 = Instance().BinaryDecodeXDSSec(bytesToDecrypt, context).Result;
            var response = Instance().BinaryDecrypt(cipherV2, passwordDerivedkeyMaterial64, context);

            if (response.IsSuccess)
            {
                return(response.Result.GetBytes());
            }
            return(null);
        }
Esempio n. 16
0
        byte[] EncryptTextToBytes(string clearText, KeyMaterial64 keyMaterial64, RoundsExponent roundsExponent)
        {
            var encryptResponse = this.ixdsCryptoService.Encrypt(new Cleartext(clearText), keyMaterial64, roundsExponent, null);

            if (!encryptResponse.IsSuccess)
            {
                throw new InvalidOperationException(encryptResponse.Error);
            }
            var encodeResponse = this.ixdsCryptoService.BinaryEncodeXDSSec(encryptResponse.Result, null);

            if (!encodeResponse.IsSuccess)
            {
                throw new InvalidOperationException(encodeResponse.Error);
            }
            return(encodeResponse.Result);
        }
Esempio n. 17
0
        /// <summary>
        /// Creates, encrypts and saves the master random key during the onboarding process.
        /// </summary>
        /// <param name="newMasterPassphrase">The newly chosen master passphrase.</param>
        /// <param name="masterKey">The master random key material, including collected user random.</param>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task InitDeviceVaultKeyAsync(string newMasterPassphrase, byte[] masterKey, LongRunningOperationContext context)
        {
            KeyMaterial64 masterPassphraseKeyMaterial = CreateKeyMaterialFromPassphrase(newMasterPassphrase);

            byte[] deviceVaultKey = new byte[64];
            Buffer.BlockCopy(masterKey, 64, deviceVaultKey, 0, 64);               // use the second part, so that we do not use the wallet seed material.
            deviceVaultKey = this.xdsCryptoService.ComputeSHA512(deviceVaultKey); // hash it, because we have a new specific purpose and do not want key reuse.

            KeyMaterial64 deviceVaultKeyMaterial = new KeyMaterial64(deviceVaultKey);

            this.xdsCryptoService.SymmetricKeyRepository.SetDeviceVaultRandomKey(deviceVaultKeyMaterial);
            await Task.Run(async() =>
            {
                await EncryptAndSaveDeviceVaultKeyAsync(deviceVaultKeyMaterial, masterPassphraseKeyMaterial, context);
            });
        }
Esempio n. 18
0
        /// <summary>
        /// Changes the master password by encrypting the master random key with a new password and updating the key file.
        /// </summary>
        /// <param name="currentMasterPassword">The current master password.</param>
        /// <param name="futureMasterPassword">The future master password.</param>
        /// <returns></returns>
        public async Task ChangeMasterPasswordAsync(string currentMasterPassword, string futureMasterPassword)
        {
            // Verify the user knows the current master password
            await TryLoadDecryptAndSetMasterRandomKeyAsync(currentMasterPassword, null);

            KeyMaterial64 futureMasterPasswordHash = CreateKeyMaterialFromPassphrase(futureMasterPassword);

            // get the current master random key in plaintext
            KeyMaterial64 currentPlaintextMasterRandomKey = this.xdsCryptoService.SymmetricKeyRepository.GetMasterRandomKey();

            // encrypt the current master random key for saving in the key file and write the file.
            CipherV2 encryptedMasterRandomKey = this.xdsCryptoService.BinaryEncrypt(new Clearbytes(currentPlaintextMasterRandomKey.GetBytes()), futureMasterPasswordHash, new RoundsExponent(10), null).Result;

            byte[] encryptedMasterRandomKeyBytes = this.xdsCryptoService.BinaryEncodeXDSSec(encryptedMasterRandomKey, null).Result;
            await this.repo.WriteSpecialFile(MasterKeyFilename, encryptedMasterRandomKeyBytes);
        }
Esempio n. 19
0
        public TLSEnvelope TLSServerEncryptRequestAnonymous(byte[] clearPacket, byte[] dynamicPublicKey, long dynamicPublicKeyID)
        {
            byte[] authSecret = new byte[32]; // we cannot create an authSecret based on the client's public key when we don't know who the client is.

            // we use the dynamicPublicKey and the server private key.
            var dynamicSharedSecret = this.ixdsCryptoService.CalculateAndHashSharedSecret(this._serverPrivateKey, dynamicPublicKey);

            // the hint to the clients privk for pubkey he sent
            long privateKeyHint = dynamicPublicKeyID;

            // and now we create a dynamic public key, just to fit the protocol, but not intended for use.
            var random          = this.ixdsCryptoService.GetRandom(32).Result.X;
            var throwAwayPubKey = this.ixdsCryptoService.GenerateCurve25519KeyPairExact(random).Result.PublicKey;
            // and a fake id
            long fakeDynamicPublicKeyID = 9999; // use a realistic value, not 9999!

            Debug.WriteLine($"{this.ServerId}: TLSServerEncryptRequestAnonymous: FakeDynamicPublicKeyID: {fakeDynamicPublicKeyID}, PrivateKeyHint: {privateKeyHint}.");

            // Concatenate = 'TLSAuthMode.Dynamic' - THIS is anothe case!
            byte[] symmetricKeyMaterial64 = ByteArrays.Concatenate(dynamicSharedSecret, authSecret);

            // same as normally
            var lro        = new LongRunningOperation(progress => { }, () => { });
            var clearBytes = new Clearbytes(clearPacket);
            var sha512PW64 = new KeyMaterial64(symmetricKeyMaterial64);
            var method     = new RoundsExponent(0xff);

            var encryptResponse = this.ixdsCryptoService.BinaryEncrypt(clearBytes, sha512PW64, method, lro.Context);

            if (!encryptResponse.IsSuccess)
            {
                throw new Exception(encryptResponse.Error);
            }

            var encodeResponse = this.ixdsCryptoService.BinaryEncodeXDSSec(encryptResponse.Result, lro.Context);

            if (!encodeResponse.IsSuccess)
            {
                throw new Exception(encodeResponse.Error);
            }

            var tlsEnvelope = new TLSEnvelope(privateKeyHint, fakeDynamicPublicKeyID, throwAwayPubKey, encodeResponse.Result);

            return(tlsEnvelope);
        }
Esempio n. 20
0
        // same in ChatWorker
        string DecryptBytesToText(byte[] cipherBytes, KeyMaterial64 keyMaterial64)
        {
            var decodeResponse = this.ixdsCryptoService.BinaryDecodeXDSSec(cipherBytes, null);

            if (!decodeResponse.IsSuccess)
            {
                throw new Exception(decodeResponse.Error);
            }
            var decrpytResponse = this.ixdsCryptoService.Decrypt(decodeResponse.Result, keyMaterial64, null);

            if (!decrpytResponse.IsSuccess)
            {
                throw new Exception(decrpytResponse.Error);
            }
            Cleartext cleartext = decrpytResponse.Result;

            return(cleartext.Text);
        }
Esempio n. 21
0
        public Response <Clearbytes> BinaryDecrypt(CipherV2 cipherV2, KeyMaterial64 keyMaterial64, LongRunningOperationContext context)
        {
            var response = new Response <Clearbytes>();

            try
            {
                Compressed compressed = DecryptCommon(cipherV2, keyMaterial64, context);

                Clearbytes cleartext = this._internal.DecompressBytes(compressed);

                response.Result = cleartext;
                response.SetSuccess();
            }
            catch (Exception e)
            {
                response.SetError(e);
            }
            return(response);
        }
Esempio n. 22
0
        public Response <CipherV2> BinaryEncrypt(Clearbytes clearBytes, KeyMaterial64 keyMaterial64, RoundsExponent roundsExponent, LongRunningOperationContext context)
        {
            var response = new Response <CipherV2>();

            try
            {
                Guard.NotNull(new object[] { clearBytes, keyMaterial64, roundsExponent });
                EnsurePlatform();

                Compressed compressed = this._internal.CompressBytes(clearBytes);

                var cipherV2 = EncryptCommon(keyMaterial64, roundsExponent, context, compressed);
                response.Result = cipherV2;
                response.SetSuccess();
            }
            catch (Exception e)
            {
                response.SetError(e);
            }
            return(response);
        }
Esempio n. 23
0
        public async Task <TLSEnvelope> EncryptRequest(byte[] clearPacket)
        {
            await this._publicMemberLock.WaitAsync();

            try
            {
                DynamicSecret dynamicSecret = GetDynamicSecretForEncryption();
                Debug.WriteLine(
                    $"{this.MyId}: TLSEncrypt: DynamicPublicKeyID: {dynamicSecret.DynamicPublicKeyId}, PrivateKeyHint: {dynamicSecret.PrivateKeyHint}.");

                byte[] authSecret = this._server.AuthSecret;

                var securable = ByteArrays.Concatenate(authSecret, this._myIdBytes, clearPacket);
                var symmetricKeyMaterial64 = ByteArrays.Concatenate(dynamicSecret.DynamicSharedSecret, new byte[32]);

                var lro           = new LongRunningOperation(progress => { }, () => { });
                var clearBytes    = new Clearbytes(securable);
                var keyMaterial64 = new KeyMaterial64(symmetricKeyMaterial64);
                var method        = new RoundsExponent(0xff);

                var encryptResponse = this._visualCrypt2Service.BinaryEncrypt(clearBytes, keyMaterial64, method, lro.Context);
                if (!encryptResponse.IsSuccess)
                {
                    throw new Exception(encryptResponse.Error);
                }

                var encodeResponse = this._visualCrypt2Service.BinaryEncodeVisualCrypt(encryptResponse.Result, lro.Context);
                if (!encodeResponse.IsSuccess)
                {
                    throw new Exception(encodeResponse.Error);
                }

                return(new TLSEnvelope(dynamicSecret.PrivateKeyHint, dynamicSecret.DynamicPublicKeyId,
                                       dynamicSecret.DynamicPublicKey, encodeResponse.Result));
            }
            finally
            {
                this._publicMemberLock.Release();
            }
        }
Esempio n. 24
0
        void DecryptToCache(Message message, KeyMaterial64 keyMaterial64)
        {
            switch (message.MessageType)
            {
            case MessageType.Text:
            case MessageType.File:
                message.ThreadText = DecryptBytesToText(message.TextCipher, keyMaterial64);
                break;

            case MessageType.Media:
                message.ThreadMedia = this.ixdsCryptoService.DefaultDecrypt(message.ImageCipher, keyMaterial64);
                break;

            case MessageType.TextAndMedia:
                message.ThreadText  = DecryptBytesToText(message.TextCipher, keyMaterial64);
                message.ThreadMedia = this.ixdsCryptoService.DefaultDecrypt(message.ImageCipher, keyMaterial64);
                break;

            default:
                throw new Exception("Invalid MessageType.");
            }
        }
Esempio n. 25
0
        /// <summary>
        /// Fully decrypts a message of all types, both control and content messages (including images), if an end-to-en-encryption key can be determined.
        /// </summary>
        async Task <Message> TryDecryptMessageToFindSenderEnryptDecryptionKeyAndSaveIt(XMessage xmessage)
        {
            try
            {
                IReadOnlyList <Identity> contacts = await this.repo.GetAllContacts();

                var decryptedMessage = new Message
                {
                    // XMessage fields
                    RecipientId = "1", // drop my Id

                    TextCipher  = xmessage.TextCipher,
                    ImageCipher = xmessage.ImageCipher,

                    DynamicPublicKey   = xmessage.DynamicPublicKey,
                    DynamicPublicKeyId = xmessage.DynamicPublicKeyId,
                    PrivateKeyHint     = xmessage.PrivateKeyHint,

                    LocalMessageState = LocalMessageState.JustReceived,
                    SendMessageState  = SendMessageState.None,
                    Side = MessageSide.You,

                    // This is what we try to decrypt here
                    MessageType = MessageType.None,
                    SenderId    = null,
                };


                Response <CipherV2> decodeMetaResponse = this.ixdsCryptoService.BinaryDecodeXDSSec(xmessage.MetaCipher, null);
                if (!decodeMetaResponse.IsSuccess)
                {
                    return(null); // garbled, no chance, ignore!
                }
                foreach (Identity identity in contacts)
                {
                    GetE2EDecryptionKeyResult getE2EDecryptionKeyResult = await this.e2eRatchet.GetEndToEndDecryptionKeyAsync(identity.Id, xmessage.DynamicPublicKey, xmessage.PrivateKeyHint);

                    if (getE2EDecryptionKeyResult.E2EDecryptionKeyType == E2EDecryptionKeyType.UnavailableDynamicPrivateKey)
                    {
                        continue; // there was a privateKeyHint != 0 in the message, but the dynamic private key was not in the ratchet for user in the loop
                    }
                    KeyMaterial64 keyMaterial64 = getE2EDecryptionKeyResult.E2EDecryptionKeyMaterial;

                    var decryptMetaResponse = this.ixdsCryptoService.BinaryDecrypt(decodeMetaResponse.Result, keyMaterial64, null);
                    if (!decryptMetaResponse.IsSuccess)
                    {
                        continue;
                    }

                    await this.e2eRatchet.SaveIncomingDynamicPublicKeyOnSuccessfulDecryptionAsync(identity.Id, xmessage.DynamicPublicKey,
                                                                                                  xmessage.DynamicPublicKeyId);

                    XMessageMetaData metadata = decryptMetaResponse.Result.GetBytes().DeserializeMessageMetadata();

                    decryptedMessage.SenderId             = identity.Id;
                    decryptedMessage.MessageType          = metadata.MessageType;
                    decryptedMessage.SenderLocalMessageId = metadata.SenderLocalMessageId.ToString();


                    if (decryptedMessage.MessageType.IsReceipt())
                    {
                        return(decryptedMessage);
                    }

                    if (decryptedMessage.MessageType.IsContent())
                    {
                        if (decryptedMessage.MessageType == MessageType.Text || decryptedMessage.MessageType == MessageType.TextAndMedia || decryptedMessage.MessageType == MessageType.File)
                        {
                            // if the message has text, decrypt all text
                            var decodeTextResponse = this.ixdsCryptoService.BinaryDecodeXDSSec(xmessage.TextCipher, null);
                            if (!decodeTextResponse.IsSuccess)
                            {
                                return(null); // something is wrong, should have worked
                            }
                            var decrpytTextResponse = this.ixdsCryptoService.Decrypt(decodeTextResponse.Result, keyMaterial64, null);
                            if (!decrpytTextResponse.IsSuccess)
                            {
                                return(null); // something is wrong, should have worked
                            }
                            decryptedMessage.ThreadText = decrpytTextResponse.Result.Text;
                        }

                        if (decryptedMessage.MessageType == MessageType.Media || decryptedMessage.MessageType == MessageType.TextAndMedia || decryptedMessage.MessageType == MessageType.File)
                        {
                            // if the message has image content, decrypt the image content
                            var decodeImageResponse = this.ixdsCryptoService.BinaryDecodeXDSSec(xmessage.ImageCipher, null);
                            if (!decodeImageResponse.IsSuccess)
                            {
                                return(null); // something is wrong, should have worked
                            }
                            var decrpytImageResponse = this.ixdsCryptoService.BinaryDecrypt(decodeImageResponse.Result, keyMaterial64, null);
                            if (!decrpytImageResponse.IsSuccess)
                            {
                                return(null); // something is wrong, should have worked
                            }
                            decryptedMessage.ThreadMedia = decrpytImageResponse.Result.GetBytes();
                        }

                        decryptedMessage.EncryptedE2EEncryptionKey = this.ixdsCryptoService.DefaultEncrypt(keyMaterial64.GetBytes(), this.ixdsCryptoService.SymmetricKeyRepository.GetMasterRandomKey());
                        decryptedMessage.LocalMessageState         = LocalMessageState.Integrated;
                        await this.repo.AddMessage(decryptedMessage);
                    }
                    else
                    {
                        throw new Exception($"Invalid MessageType {decryptedMessage.MessageType}");
                    }

                    return(decryptedMessage);
                } // foreach



                // If we are here, assume it's a new contact's message or RESENT message:
                CipherV2      encryptedMetaData          = decodeMetaResponse.Result;
                KeyMaterial64 initialKey                 = this.e2eRatchet.GetInitialE2EDecryptionKey(xmessage.DynamicPublicKey);
                var           decryptInitialMetaResponse = this.ixdsCryptoService.BinaryDecrypt(encryptedMetaData, initialKey, null);
                if (decryptInitialMetaResponse.IsSuccess)
                {
                    XMessageMetaData initialMessageMetadata =
                        decryptInitialMetaResponse.Result.GetBytes().DeserializeMessageMetadata();
                    var incomingPublicKey = initialMessageMetadata.SenderPublicKey;

                    // If we received several resent messages, the first from that incoming contact has already produced that contact:
                    var  contact           = contacts.SingleOrDefault(c => ByteArrays.AreAllBytesEqual(c.StaticPublicKey, incomingPublicKey));
                    bool isIncomingContact = false;

                    if (contact == null)
                    {
                        // Create new contact and save it to make the ratchet work normally
                        isIncomingContact = true;
                        var date            = DateTime.UtcNow;
                        var incomingContact = new Identity
                        {
                            Id = Guid.NewGuid().ToString(),
                            StaticPublicKey = incomingPublicKey,
                            ContactState    = ContactState.Valid,
                            Name            = "Anonymous",
                            FirstSeenUtc    = date,
                            LastSeenUtc     = date
                        };

                        await this.repo.AddContact(incomingContact);

                        contact = incomingContact;
                    }



                    await this.e2eRatchet.SaveIncomingDynamicPublicKeyOnSuccessfulDecryptionAsync(contact.Id, xmessage.DynamicPublicKey,
                                                                                                  xmessage.DynamicPublicKeyId);

                    // add metadata to message
                    decryptedMessage.SenderId             = contact.Id;
                    decryptedMessage.MessageType          = initialMessageMetadata.MessageType;
                    decryptedMessage.SenderLocalMessageId = initialMessageMetadata.SenderLocalMessageId.ToString();

                    if (decryptedMessage.MessageType.IsContent())
                    {
                        var success = true;

                        GetE2EDecryptionKeyResult getE2EDecryptionKeyResult = await this.e2eRatchet.GetEndToEndDecryptionKeyAsync(contact.Id, xmessage.DynamicPublicKey, xmessage.PrivateKeyHint);

                        KeyMaterial64 keyMaterial64 = getE2EDecryptionKeyResult.E2EDecryptionKeyMaterial;
                        await this.e2eRatchet.GetEndToEndDecryptionKeyAsync(contact.Id, xmessage.DynamicPublicKey, xmessage.PrivateKeyHint);

                        if (decryptedMessage.MessageType == MessageType.Text || decryptedMessage.MessageType == MessageType.TextAndMedia)
                        {
                            // if the message has text, decrypt all text
                            var decodeTextResponse = this.ixdsCryptoService.BinaryDecodeXDSSec(xmessage.TextCipher, null);
                            if (!decodeTextResponse.IsSuccess)
                            {
                                success = false; // something is wrong, should have worked
                            }
                            else
                            {
                                var decrpytTextResponse = this.ixdsCryptoService.Decrypt(decodeTextResponse.Result, keyMaterial64, null);
                                if (!decrpytTextResponse.IsSuccess)
                                {
                                    success = false; // something is wrong, should have worked
                                }
                                else
                                {
                                    decryptedMessage.ThreadText = decrpytTextResponse.Result.Text;
                                }
                            }
                        }

                        if (decryptedMessage.MessageType == MessageType.Media || decryptedMessage.MessageType == MessageType.TextAndMedia)
                        {
                            // if the message has image content, decrypt the image content
                            var decodeImageResponse = this.ixdsCryptoService.BinaryDecodeXDSSec(xmessage.ImageCipher, null);
                            if (!decodeImageResponse.IsSuccess)
                            {
                                success = false; // something is wrong, should have worked
                            }
                            else
                            {
                                var decrpytImageResponse = this.ixdsCryptoService.BinaryDecrypt(decodeImageResponse.Result, keyMaterial64, null);
                                if (!decrpytImageResponse.IsSuccess)
                                {
                                    success = false; // something is wrong, should have worked
                                }
                                else
                                {
                                    decryptedMessage.ThreadMedia = decrpytImageResponse.Result.GetBytes();
                                }
                            }
                        }

                        if (success)
                        {
                            decryptedMessage.EncryptedE2EEncryptionKey = this.ixdsCryptoService.DefaultEncrypt(keyMaterial64.GetBytes(), this.ixdsCryptoService.SymmetricKeyRepository.GetMasterRandomKey());
                            decryptedMessage.LocalMessageState         = LocalMessageState.Integrated;
                            await this.contactListManager.ChatWorker_ContactUpdateReceived(null, contact.Id);

                            await this.repo.AddMessage(decryptedMessage);

                            return(decryptedMessage);
                        }
                        else
                        {
                            if (isIncomingContact)
                            {
                                await this.repo.DeleteContacts(new[] { contact.Id }); // delete the just incoming contact if the was an error anyway.
                            }

                            return(null);
                        }
                    }
                    else
                    {
                        return(null);
                    }
                }

                // nope, resend request (I hope we don't loop here!)
                string networkPayloadHash = NetworkPayloadHash.ComputeAsGuidString(xmessage.SerializedPayload);
                if (!this._resendsRequested.Contains(networkPayloadHash))
                {
                    var response = await this.chatClient.UploadResendRequest(new XResendRequest { Id = networkPayloadHash, RecipientId = null });

                    if (response.IsSuccess)
                    {
                        this._resendsRequested.Add(networkPayloadHash);
                    }
                }
            }
            catch (Exception e)
            {
                this.logger.LogError(e.Message);
            }

            return(null);
        }
Esempio n. 26
0
        CipherV2 EncryptCommon(KeyMaterial64 keyMaterial64, RoundsExponent roundsExponent, LongRunningOperationContext context,
                               Compressed compressed)
        {
            if (context == null)
            {
                context = new LongRunningOperation(progress => { }, () => { }).Context;
            }

            if (this._log)
            {
                Debug.WriteLine("KeyMaterial64:");
                Debug.WriteLine(keyMaterial64.GetBytes().ToHexView(false));
            }

            if (this._log)
            {
                Debug.WriteLine("Compressed:");
                Debug.WriteLine(compressed.GetBytes().ToHexView(false));
            }

            PaddedData paddedData = this._internal.ApplyRandomPadding(compressed);

            if (this._log)
            {
                Debug.WriteLine("PaddedData:");
                Debug.WriteLine(paddedData.GetBytes().ToHexView(false));

                Debug.WriteLine("PlainTextPadding:");
                Debug.WriteLine(paddedData.PlaintextPadding);
            }

            IV16 iv = new IV16(this._platform.GenerateRandomBytes(16));

            if (this._log)
            {
                Debug.WriteLine("IV16:");
                Debug.WriteLine(iv.GetBytes().ToHexView(false));
            }

            InputDerivedKey32 inputDerivedKey = roundsExponent.Value == RoundsExponent.DontMakeRounds
                ? CreateDerivedKeyWithSHA256(iv, keyMaterial64)
                : CreatePasswordDerivedKeyWithBCrypt(iv, keyMaterial64, roundsExponent, context);

            if (this._log)
            {
                Debug.WriteLine("InputDerivedKey32:");
                Debug.WriteLine(inputDerivedKey.GetBytes().ToHexView(false));
            }

            RandomKey32 randomKey = new RandomKey32(this._platform.GenerateRandomBytes(32));

            if (this._log)
            {
                Debug.WriteLine("RandomKey32:");
                Debug.WriteLine(randomKey.GetBytes().ToHexView(false));
            }

            XDSSecAPIInternal.IVCache ivCache = roundsExponent.Value == RoundsExponent.DontMakeRounds
                ? null
                : this._internal.CreateIVTable(iv, roundsExponent.Value);

            var cipherV2 = new CipherV2 {
                RoundsExponent = roundsExponent, IV16 = iv
            };

            this._internal.AESEncryptRandomKeyWithInputDerivedKey(inputDerivedKey, randomKey, cipherV2, ivCache, context);
            if (this._log)
            {
                Debug.WriteLine("RandomKeyCipher32:");
                Debug.WriteLine(cipherV2.RandomKeyCipher32.GetBytes().ToHexView(false));
            }

            this._internal.AESEncryptMessageWithRandomKey(paddedData, randomKey, cipherV2, ivCache, context);
            if (this._log)
            {
                Debug.WriteLine("MessageCipher:");
                Debug.WriteLine(cipherV2.MessageCipher.GetBytes().ToHexView(false));
            }

            MAC16 mac = CreateMAC(cipherV2, context);

            if (this._log)
            {
                Debug.WriteLine("MAC16:");
                Debug.WriteLine(mac.GetBytes().ToHexView(false));
            }

            this._internal.AESEncryptMACWithRandomKey(cipherV2, mac, randomKey, ivCache, context);
            if (this._log)
            {
                Debug.WriteLine("MACCipher16:");
                Debug.WriteLine(cipherV2.MACCipher16.GetBytes().ToHexView(false));
            }
            return(cipherV2);
        }
Esempio n. 27
0
        public async Task <Response> DecryptCipherTextInVisibleBubble(Message message)
        {
            var response = new Response();

            try
            {
                if (message.ThreadText != null && message.MessageType == MessageType.Text)                 // TODO: do this properly ....nothing to do, already decrypted
                {
                    response.SetSuccess();
                    return(response);
                }

                KeyMaterial64 decryptionkey;
                if (message.LocalMessageState == LocalMessageState.JustReceived)                 // this is an incoming message
                {
                    GetE2EDecryptionKeyResult getE2EDecryptionKeyResult = await this.e2ERatchet.GetEndToEndDecryptionKeyAsync(message.SenderId, message.DynamicPublicKey, message.PrivateKeyHint);

                    if (getE2EDecryptionKeyResult.E2EDecryptionKeyType != E2EDecryptionKeyType.UnavailableDynamicPrivateKey)
                    {
                        decryptionkey = getE2EDecryptionKeyResult.E2EDecryptionKeyMaterial;
                    }
                    else
                    {
                        message.LocalMessageState = LocalMessageState.RatchetMismatchError;
                        // When adding a contact and sending the first message to him, the contact can immediately read the message,
                        // because the message is encrypted with the static public key of that contact.
                        // But when one side deletes the contact, and the contact sends a message again, that's not possible,
                        // because the sender dosn't know he would need to use only the static public key.
                        // Instead, he's also use the last dynamic key, expecting the other side has matching material.
                        // Then, we land here. A recovery would require that we ask the other side to resend the message.
                        // Instead, just a delivery receipt is sent automatically, which repairs the ratchet.
                        // The problem is, the other side does not know
                        message.LocalMessageState = LocalMessageState.RatchetMismatchError;                         // create anothe enum member for this case?
                        await this.repo.UpdateMessage(message);

                        response.SetError(nameof(LocalMessageState.RatchetMismatchError));
                        return(response);
                    }

                    await Task.Run(() => DecryptToCache(message, decryptionkey));

                    await this.e2ERatchet.SaveIncomingDynamicPublicKeyOnSuccessfulDecryptionAsync(message.SenderId, message.DynamicPublicKey, message.DynamicPublicKeyId);

                    message.EncryptedE2EEncryptionKey = this.ixdsCryptoService.DefaultEncrypt(decryptionkey.GetBytes(), this.ixdsCryptoService.SymmetricKeyRepository.GetMasterRandomKey());
                    message.LocalMessageState         = LocalMessageState.Integrated;

                    Debug.Assert(message.MessageType != MessageType.ReadReceipt && message.MessageType != MessageType.DeliveryReceipt);

                    await this.repo.UpdateMessage(message);

                    await this.ChatWorker.SendReceipt(message, MessageType.ReadReceipt);
                }
                else                 // this is a message we have stored locally
                {
                    if (message.EncryptedE2EEncryptionKey == null)
                    {
                        message.LocalMessageState = LocalMessageState.LocalDecryptionError;
                    }
                    else
                    {
                        decryptionkey = new KeyMaterial64(this.ixdsCryptoService.DefaultDecrypt(message.EncryptedE2EEncryptionKey, this.ixdsCryptoService.SymmetricKeyRepository.GetMasterRandomKey()));
                        await Task.Run(() => DecryptToCache(message, decryptionkey));
                    }
                    // should we check that a read receipt has really been sent and retry till we are sure?
                }
                response.SetSuccess();
            }
            catch (Exception e)
            {
                response.SetError(e.Message);
                this.logger.LogError(e.Message);
            }
            return(response);
        }