//--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\ #region --Misc Methods (Public)-- /// <summary> /// Encrypts the content of MESSAGE with the given SessionCipher and saves the result in BASE_64_PAYLOAD. /// </summary> /// <param name="omemoSession">A storage object containing all SessionCipher for the target OMEMO devices.</param> /// <param name="sourceDeviceId">The sender OMEMO device id.</param> public void encrypt(OmemoSession omemoSession, uint sourceDeviceId) { SOURCE_DEVICE_ID = sourceDeviceId; // 1. Generate a new AES-128 GCM key/iv: Aes128GcmCpp aes128Gcm = new Aes128GcmCpp(); aes128Gcm.generateKey(); aes128Gcm.generateIv(); // 2. Encrypt the message using the Aes128Gcm instance: byte[] encryptedData = aes128Gcm.encrypt(Encoding.UTF8.GetBytes(MESSAGE)); BASE_64_PAYLOAD = Convert.ToBase64String(encryptedData); BASE_64_IV = Convert.ToBase64String(aes128Gcm.iv); // 3. Concatenate key and authentication tag: byte[] keyAuthTag = new byte[aes128Gcm.authTag.Length + aes128Gcm.key.Length]; Buffer.BlockCopy(aes128Gcm.key, 0, keyAuthTag, 0, aes128Gcm.key.Length); Buffer.BlockCopy(aes128Gcm.authTag, 0, keyAuthTag, aes128Gcm.key.Length, aes128Gcm.authTag.Length); // 4. Encrypt the key/authTag pair with libsignal for each deviceId: KEYS = new List <OmemoKey>(); Logger.Debug("[OmemoMessageMessage]: Source device id: " + SOURCE_DEVICE_ID); Logger.Debug("[OmemoMessageMessage]: Encrypting for remote devices."); encryptForDevices(omemoSession.DEVICE_SESSIONS_REMOTE, keyAuthTag); Logger.Debug("[OmemoMessageMessage]: Encrypting for own devices."); encryptForDevices(omemoSession.DEVICE_SESSIONS_OWN, keyAuthTag); ENCRYPTED = true; }
public void Test_Aes128GcmCpp_Enc_Dec_Long_1() { Aes128GcmCpp aesEnc = new Aes128GcmCpp { key = CryptoUtils.hexStringToByteArray("feffe9928665731c6d6a8f9467308308"), iv = CryptoUtils.hexStringToByteArray("cafebabefacedbaddecaf888"), }; byte[] data = new byte[1024]; byte[] refCiphertext = CryptoUtils.hexStringToByteArray("9bb22ce7d9f372c1ee2b28722b25f206650d887c3936533a1b8d4e1ea39d2b5c3de91827c10e9a4f5240647ee5221f20aac9e6ccc0074ac0873b9ba85d908bd0dda867c4cef2b1f1b8a9ff49ca208b6116d8f4f1c3c9273f23d7581cc373e461f01e5cbfa52f40f2500c07c41f377171c1bdf4b560668370848aaa36061a9758fed6fdb1e83ba41f237936ab466025c0c0b6dc862245883a92d3f8d43b39a62b726d4616ada9e4b101479e81340226bf81bc7bc1a5c9372973ecbe829aff5720a4b304fe9a91a9aeafc4c4a1af5eaeb22e92be237a73b3174be2e5388099a53ab09d7ef18916daa6f7817d3345432a93b1903ad99767f610c691102a0a25a46c21610189f099a5ad44890c8c188325e881627a5b6c0c911b7ce3b3f079b7e8cd8e189b28c8158805633cdc448b78d4e4880b37f2faca7e34c4be2ff3c4bd00fdc0395cdc02eb5e727152559e4ac5c3d688b12ea339ffa46222a9ef2bf1d948bdd0c35db154b550cf88990d9d4391178999e106a4e4fc48e272d6b0b43959f6782f6850e533571e01122ae61ebc6fd34953c6a847b0d1fafde7e93821ea8bf98db5dc2b13aa9f1c5046682573e500c57058dfd21ec5c36cf627e8ffc8667fe774480c0f4b7b7843d336836f1ab5ac043f423e32ab5daea7d385e2668bc333b4e2aa3b7232ff62bcd61ec28af04842fd4642abb9900c416d6443132202bc59f9331ce3d98e9f56e59d0c43455c0653ec6de357e1ab3fde6145ea1caa313c3c005ddfa542359325a276018b4992d15799b3e53bffb4a7e2d4cdf0ded91f49072fdeb5a4383f6e6b3a6091172c5bb392151079ca31c0280bbeb191307f5ed753ee15113b73b1df4bb566cf5d6175ae83229ca55fc6bd0662b28848d7cbd9c987df339f193833640375523972bc8666b39f85d99bec505e8bb397cf08ea694f03b0883d60a1408b735d2fb0259ca8a3cf75eb6b6340600a83edd9aa2c20b6a2827e194d7a4e3b09d7267e739d9b89d00ead14c6888df05b72932ee8793ffaca64c9dd62ad7addfaff73ab1dd1dd7ff5bf006d4b25bf82f193449f20e04bb485a4bdfdf7b5fee4a812404bd6c87408275e41a5e09d24e29c3364016c6eec2e37fc316091b44886b73a888fc06eea87ee1c5bbdc82fc4f0cf303af81b5452c41f7ee8a2eb2c30c9d09a09735678109ae64ccc002b93f182cc858a08c4a144d5afabf1b7d4e47a232963719df669b50b3002f020e404cd7141c596e7804e7da133bf6a9030d584fb6f1e0b69137b1f9c0440f18e2dafab746ec3f976ebe07d426f54db3258aebdff22687fda41c7516162f533a316ef519706a76424b0884e2f8f8979cb305561bcf0b5f38ebaa74e8ea6c6692599ace5e1a190e073838952417b2a2434cf90f1d66b11d90b00a391f42c02d1261e19ab80d744fd1b402aa3a3d6f61492"); byte[] refAuthTag = CryptoUtils.hexStringToByteArray("5f4226cd3dbf20fdfbbd1947f6da4e82"); byte[] encData = aesEnc.encrypt(data); string s = CryptoUtils.byteArrayToHexString(aesEnc.authTag); Assert.IsTrue(encData.SequenceEqual(refCiphertext)); Assert.IsTrue(aesEnc.authTag.SequenceEqual(refAuthTag)); }
public void Test_Aes128GcmCpp_Enc_Dec_3() { // Test vectors from: https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=6b7b34330beaf7ff062d6a06b7733f069d77feaa Aes128GcmCpp aesEnc = new Aes128GcmCpp { key = CryptoUtils.hexStringToByteArray("feffe9928665731c6d6a8f9467308308"), iv = CryptoUtils.hexStringToByteArray("cafebabefacedbaddecaf888"), }; byte[] data = CryptoUtils.hexStringToByteArray("d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255"); byte[] refCiphertext = CryptoUtils.hexStringToByteArray("42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985"); byte[] refAuthTag = CryptoUtils.hexStringToByteArray("4d5c2af327cd64a62cf35abd2ba6fab4"); byte[] encData = aesEnc.encrypt(data); Assert.IsTrue(encData.SequenceEqual(refCiphertext)); Assert.IsTrue(aesEnc.authTag.SequenceEqual(refAuthTag)); }
public void Test_Aes128GcmCpp_Enc_Dec_2() { // Test vectors from: https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=6b7b34330beaf7ff062d6a06b7733f069d77feaa Aes128GcmCpp aesEnc = new Aes128GcmCpp { key = CryptoUtils.hexStringToByteArray("00000000000000000000000000000000"), iv = CryptoUtils.hexStringToByteArray("000000000000000000000000"), }; byte[] data = CryptoUtils.hexStringToByteArray("00000000000000000000000000000000"); byte[] refCiphertext = CryptoUtils.hexStringToByteArray("0388dace60b6a392f328c2b971b2fe78"); byte[] refAuthTag = CryptoUtils.hexStringToByteArray("ab6e47d42cec13bdf53a67b21257bddf"); byte[] encData = aesEnc.encrypt(data); Assert.IsTrue(encData.SequenceEqual(refCiphertext)); Assert.IsTrue(aesEnc.authTag.SequenceEqual(refAuthTag)); }
public void Test_Aes128GcmCpp_Enc_Dec_1() { for (int i = 0; i < 100; i++) { Aes128GcmCpp aesEnc = new Aes128GcmCpp(); aesEnc.generateKey(); aesEnc.generateIv(); Random r = new Random(); byte[] data = new byte[200]; r.NextBytes(data); byte[] dataEnc = aesEnc.encrypt(data); Aes128GcmCpp aesDec = new Aes128GcmCpp { authTag = aesEnc.authTag, iv = aesEnc.iv, key = aesEnc.key, }; byte[] dataDec = aesDec.decrypt(dataEnc); Assert.IsTrue(data.SequenceEqual(dataDec)); } }
/// <summary> /// Decrypts the content of BASE_64_PAYLOAD with the given SessionCipher and saves the result in MESSAGE. /// Sets ENCRYPTED to false. /// </summary> /// <param name="cipher">The SessionCipher for decrypting the content of BASE_64_PAYLOAD.</param> /// <param name="remoteAddress">The SignalProtocolAddress of the sender.</param> /// <param name="localeDeciceId">The local device id.</param> /// <param name="helper">The current OmemoHelper object of the current account. If null, won't remove used PreKey.</param> /// <returns>True on success.</returns> public async Task <bool> decryptAsync(SessionCipher cipher, SignalProtocolAddress remoteAddress, uint localeDeciceId, OmemoHelper helper) { try { // 1. Check if the message contains a key for the local device: OmemoKey key = getOmemoKey(localeDeciceId); if (key is null) { Logger.Info("Discarded received OMEMO message - doesn't contain device id!"); return(false); } // 2. Load the cipher: SignalProtocolAddress address = new SignalProtocolAddress(Utils.getBareJidFromFullJid(FROM), SOURCE_DEVICE_ID); byte[] encryptedKeyAuthTag = Convert.FromBase64String(key.BASE_64_KEY); byte[] decryptedKeyAuthTag = null; if (key.IS_PRE_KEY) { PreKeySignalMessage preKeySignalMessage = new PreKeySignalMessage(encryptedKeyAuthTag); decryptedKeyAuthTag = cipher.decrypt(preKeySignalMessage); if (!(helper is null)) { May <uint> preKey = preKeySignalMessage.getPreKeyId(); if (preKey.HasValue) { Logger.Info("Removing used PreKey."); await helper.removePreKeyAndRepublishAsync(preKey.ForceGetValue()); } else { Logger.Error("Failed to get value from PreKeySignalMessage."); } } } else { decryptedKeyAuthTag = cipher.decrypt(new SignalMessage(encryptedKeyAuthTag)); } // 3. Check if the cipher got loaded successfully: if (decryptedKeyAuthTag is null) { Logger.Info("Discarded received OMEMO message - failed to decrypt keyAuthTag is null!"); return(false); } // 4. Decrypt the payload: byte[] aesIv = Convert.FromBase64String(BASE_64_IV); byte[] aesKey = new byte[16]; byte[] aesAuthTag = new byte[decryptedKeyAuthTag.Length - aesKey.Length]; Buffer.BlockCopy(decryptedKeyAuthTag, 0, aesKey, 0, aesKey.Length); Buffer.BlockCopy(decryptedKeyAuthTag, aesKey.Length, aesAuthTag, 0, aesAuthTag.Length); Aes128GcmCpp aes128Gcm = new Aes128GcmCpp() { key = aesKey, authTag = aesAuthTag, iv = aesIv }; byte[] encryptedData = Convert.FromBase64String(BASE_64_PAYLOAD); byte[] decryptedData = aes128Gcm.decrypt(encryptedData); // 5. Convert decrypted data to Unicode string: MESSAGE = Encoding.UTF8.GetString(decryptedData); ENCRYPTED = false; return(true); } catch (Exception e) { Logger.Info("Discarded received OMEMO message - failed to decrypt with: " + e.Message); } return(false); }
public void Test_Omemo_Enc_Dec_1() { // Generate Alices keys: IdentityKeyPair aliceIdentKey = CryptoUtils.generateOmemoIdentityKeyPair(); IList <PreKeyRecord> alicePreKeys = CryptoUtils.generateOmemoPreKeys(); SignedPreKeyRecord aliceSignedPreKey = CryptoUtils.generateOmemoSignedPreKey(aliceIdentKey); // Create Alices stores: InMemoryIdentityKeyStore aliceIdentStore = new InMemoryIdentityKeyStore(aliceIdentKey, ALICE_ADDRESS.getDeviceId()); InMemoryPreKeyStore alicePreKeyStore = new InMemoryPreKeyStore(); foreach (PreKeyRecord key in alicePreKeys) { alicePreKeyStore.StorePreKey(key.getId(), key); } InMemorySignedPreKeyStore aliceSignedPreKeyStore = new InMemorySignedPreKeyStore(); aliceSignedPreKeyStore.StoreSignedPreKey(aliceSignedPreKey.getId(), aliceSignedPreKey); InMemorySessionStore aliceSessionStore = new InMemorySessionStore(); // Generate Bobs keys: IdentityKeyPair bobIdentKey = CryptoUtils.generateOmemoIdentityKeyPair(); IList <PreKeyRecord> bobPreKeys = CryptoUtils.generateOmemoPreKeys(); SignedPreKeyRecord bobSignedPreKey = CryptoUtils.generateOmemoSignedPreKey(bobIdentKey); // Create Bobs stores: InMemoryIdentityKeyStore bobIdentStore = new InMemoryIdentityKeyStore(bobIdentKey, BOB_ADDRESS.getDeviceId()); InMemoryPreKeyStore bobPreKeyStore = new InMemoryPreKeyStore(); foreach (PreKeyRecord key in bobPreKeys) { bobPreKeyStore.StorePreKey(key.getId(), key); } InMemorySignedPreKeyStore bobSignedPreKeyStore = new InMemorySignedPreKeyStore(); bobSignedPreKeyStore.StoreSignedPreKey(bobSignedPreKey.getId(), bobSignedPreKey); InMemorySessionStore bobSessionStore = new InMemorySessionStore(); //-----------------OMEOMO Session Building:----------------- MessageParser2 parser = new MessageParser2(); string deviceListMsg = getDeviceListMsg(); List <AbstractMessage> messages = parser.parseMessages(ref deviceListMsg); Assert.IsTrue(messages.Count == 1); Assert.IsTrue(messages[0] is OmemoDeviceListResultMessage); OmemoDeviceListResultMessage devList = messages[0] as OmemoDeviceListResultMessage; uint selectedBobDeviceId = devList.DEVICES.getRandomDeviceId(); Assert.IsTrue(selectedBobDeviceId == BOB_ADDRESS.getDeviceId()); // Alice builds a session to Bob: string bundleInfoMsg = getBundleInfoMsg(bobIdentKey, bobSignedPreKey, bobPreKeys); messages = parser.parseMessages(ref bundleInfoMsg); Assert.IsTrue(messages.Count == 1); Assert.IsTrue(messages[0] is OmemoBundleInformationResultMessage); OmemoBundleInformationResultMessage bundleInfo = messages[0] as OmemoBundleInformationResultMessage; Assert.IsTrue(bundleInfo.DEVICE_ID == BOB_ADDRESS.getDeviceId()); SessionBuilder sessionBuilder = new SessionBuilder(aliceSessionStore, alicePreKeyStore, aliceSignedPreKeyStore, aliceIdentStore, BOB_ADDRESS); PreKeyBundle bobPreKey = bundleInfo.BUNDLE_INFO.getRandomPreKey(bundleInfo.DEVICE_ID); sessionBuilder.process(bobPreKey); // Check if session exists: Assert.IsTrue(aliceSessionStore.ContainsSession(BOB_ADDRESS)); Assert.IsTrue(aliceSessionStore.LoadSession(BOB_ADDRESS).getSessionState().getSessionVersion() == 3); // Alice sends a message: string aliceOrigMsg = "$(rm -rvf .)"; // 1. Generate a new AES-128 GCM key/iv: Aes128GcmCpp aes128Gcm = new Aes128GcmCpp(); aes128Gcm.generateKey(); aes128Gcm.generateIv(); // 2. Encrypt the message using the Aes128Gcm instance: byte[] encryptedData = aes128Gcm.encrypt(Encoding.UTF8.GetBytes(aliceOrigMsg)); string base64Payload = Convert.ToBase64String(encryptedData); string base64IV = Convert.ToBase64String(aes128Gcm.iv); // 3. Concatenate key and authentication tag: byte[] keyAuthTag = new byte[aes128Gcm.authTag.Length + aes128Gcm.key.Length]; Buffer.BlockCopy(aes128Gcm.key, 0, keyAuthTag, 0, aes128Gcm.key.Length); Buffer.BlockCopy(aes128Gcm.authTag, 0, keyAuthTag, aes128Gcm.key.Length, aes128Gcm.authTag.Length); SessionCipher aliceSessionCipher = new SessionCipher(aliceSessionStore, alicePreKeyStore, aliceSignedPreKeyStore, aliceIdentStore, BOB_ADDRESS); CiphertextMessage ciphertextMessage = aliceSessionCipher.encrypt(keyAuthTag); OmemoKey omemoKey = new OmemoKey(BOB_ADDRESS.getDeviceId(), ciphertextMessage is PreKeySignalMessage, Convert.ToBase64String(ciphertextMessage.serialize())); Assert.IsTrue(string.Equals(Convert.ToBase64String(ciphertextMessage.serialize()), omemoKey.BASE_64_KEY)); //-------------------Decrypt Again:------------------- // 2. Load the cipher: SessionCipher cipher = new SessionCipher(bobSessionStore, bobPreKeyStore, bobSignedPreKeyStore, bobIdentStore, ALICE_ADDRESS); byte[] encryptedKeyAuthTag = Convert.FromBase64String(omemoKey.BASE_64_KEY); byte[] decryptedKeyAuthTag = null; if (omemoKey.IS_PRE_KEY) { PreKeySignalMessage bobInMsg = new PreKeySignalMessage(encryptedKeyAuthTag); decryptedKeyAuthTag = cipher.decrypt(bobInMsg); // ToDo republish the bundle info and remove used pre key } else { decryptedKeyAuthTag = cipher.decrypt(new SignalMessage(encryptedKeyAuthTag)); } // 3. Check if the cipher got loaded successfully: Assert.IsTrue(decryptedKeyAuthTag != null); // 4. Decrypt the payload: byte[] aesIv = Convert.FromBase64String(base64IV); byte[] aesKey = new byte[16]; byte[] aesAuthTag = new byte[decryptedKeyAuthTag.Length - aesKey.Length]; Buffer.BlockCopy(decryptedKeyAuthTag, 0, aesKey, 0, aesKey.Length); Buffer.BlockCopy(decryptedKeyAuthTag, aesKey.Length, aesAuthTag, 0, aesAuthTag.Length); aes128Gcm = new Aes128GcmCpp() { key = aesKey, authTag = aesAuthTag, iv = aesIv }; encryptedData = Convert.FromBase64String(base64Payload); byte[] bobData = aes128Gcm.decrypt(encryptedData); // 5. Convert decrypted data to Unicode string: string bobRecMsg = Encoding.UTF8.GetString(bobData); // Check if successfully send: Assert.AreEqual(aliceOrigMsg, bobRecMsg); Assert.IsTrue(bobSessionStore.ContainsSession(ALICE_ADDRESS)); }