public void Test_OmemoMessage() { Random rand = new Random(); byte[] sessionKey = new byte[32]; rand.NextBytes(sessionKey); IdentityKeyPairModel identityKey = KeyHelper.GenerateIdentityKeyPair(); SignedPreKeyModel signedPreKey = KeyHelper.GenerateSignedPreKey(0, identityKey.privKey); OmemoSessionModel refOmemoSession = new OmemoSessionModel(new Bundle() { identityKey = identityKey.pubKey, preKeys = KeyHelper.GeneratePreKeys(0, 10), preKeySignature = signedPreKey.signature, signedPreKey = signedPreKey.preKey.pubKey, signedPreKeyId = signedPreKey.preKey.keyId }, 0, KeyHelper.GenerateIdentityKeyPair()) { ek = KeyHelper.GenerateKeyPair().pubKey }; OmemoMessage refOmemoMessage = new OmemoMessage(refOmemoSession); byte[] data = refOmemoMessage.ToByteArray(); Assert.IsTrue(data.Length > 0); OmemoMessage omemoMessage = new OmemoMessage(data); Assert.IsTrue(omemoMessage.Equals(refOmemoMessage)); }
/// <summary> /// Decrypts the key and HMAC concatenation (<see cref="OmemoMessage.cipherText"/>) with the given <paramref name="mk"/> and returns the result. /// </summary> /// <param name="mk">The message key that should be used for decryption.</param> /// <param name="msg">The <see cref="OmemoMessage"/> containing the key and HMAC concatenation (<see cref="OmemoMessage.cipherText"/>).</param> /// <param name="msgHmac">The HMAC of the <paramref name="msg"/>.</param> /// <param name="assData">Encode(IK_A) || Encode(IK_B) => Concatenation of Alices and Bobs public part of their identity key.</param> /// <returns>key || HMAC</returns> private byte[] DecryptKeyHmacForDevice(byte[] mk, OmemoMessage msg, byte[] msgHmac, byte[] assData) { // 32 byte (256 bit) of salt. Initialized with 0s. byte[] hkdfOutput = CryptoUtils.HkdfSha256(mk, new byte[32], "OMEMO Message Key Material", 80); CryptoUtils.SplitKey(hkdfOutput, out byte[] encKey, out byte[] authKey, out byte[] iv); byte[] hmacInput = CryptoUtils.Concat(assData, msg.ToByteArray()); byte[] hmacResult = CryptoUtils.HmacSha256(authKey, hmacInput); byte[] hmacTruncated = CryptoUtils.Truncate(hmacResult, 16); // Debug trace output: Logger.Trace("[" + nameof(DecryptKeyHmacForDevice) + "] " + nameof(mk) + ": " + CryptoUtils.ToHexString(mk)); Logger.Trace("[" + nameof(DecryptKeyHmacForDevice) + "] " + nameof(msgHmac) + ": " + CryptoUtils.ToHexString(msgHmac)); Logger.Trace("[" + nameof(DecryptKeyHmacForDevice) + "] " + nameof(assData) + ": " + CryptoUtils.ToHexString(assData)); Logger.Trace("[" + nameof(DecryptKeyHmacForDevice) + "] " + nameof(hkdfOutput) + ": " + CryptoUtils.ToHexString(hkdfOutput)); Logger.Trace("[" + nameof(DecryptKeyHmacForDevice) + "] " + nameof(encKey) + ": " + CryptoUtils.ToHexString(encKey)); Logger.Trace("[" + nameof(DecryptKeyHmacForDevice) + "] " + nameof(authKey) + ": " + CryptoUtils.ToHexString(authKey)); Logger.Trace("[" + nameof(DecryptKeyHmacForDevice) + "] " + nameof(iv) + ": " + CryptoUtils.ToHexString(iv)); Logger.Trace("[" + nameof(DecryptKeyHmacForDevice) + "] " + nameof(hmacInput) + ": " + CryptoUtils.ToHexString(hmacInput)); Logger.Trace("[" + nameof(DecryptKeyHmacForDevice) + "] " + nameof(hmacResult) + ": " + CryptoUtils.ToHexString(hmacResult)); Logger.Trace("[" + nameof(DecryptKeyHmacForDevice) + "] " + nameof(hmacTruncated) + ": " + CryptoUtils.ToHexString(hmacTruncated)); if (!hmacTruncated.SequenceEqual(msgHmac)) { throw new OmemoException("Failed to decrypt. HMAC of OmemoMessage does not match."); } return(CryptoUtils.Aes256CbcDecrypt(encKey, iv, msg.cipherText)); }
/// <summary> /// Encrypts the given key and HMAC concatenation and returns the result. /// </summary> /// <param name="keyHmac">The key, HMAC concatenation result.</param> /// <param name="session">The <see cref="OmemoSessionModel"/> between the sender and receiver.</param> /// <param name="assData">Encode(IK_A) || Encode(IK_B) => Concatenation of Alices and Bobs public part of their identity key.</param> private OmemoAuthenticatedMessage EncryptKeyHmacForDevices(byte[] keyHmac, OmemoSessionModel session, byte[] assData) { byte[] mk = LibSignalUtils.KDF_CK(session.ckS, 0x01); session.ckS = LibSignalUtils.KDF_CK(session.ckS, 0x02); OmemoMessage omemoMessage = new OmemoMessage(session); ++session.nS; // 32 byte (256 bit) of salt. Initialized with 0s. byte[] hkdfOutput = CryptoUtils.HkdfSha256(mk, new byte[32], "OMEMO Message Key Material", 80); CryptoUtils.SplitKey(hkdfOutput, out byte[] encKey, out byte[] authKey, out byte[] iv); omemoMessage.cipherText = CryptoUtils.Aes256CbcEncrypt(encKey, iv, keyHmac); byte[] omemoMessageBytes = omemoMessage.ToByteArray(); byte[] hmacInput = CryptoUtils.Concat(assData, omemoMessageBytes); byte[] hmacResult = CryptoUtils.HmacSha256(authKey, hmacInput); byte[] hmacTruncated = CryptoUtils.Truncate(hmacResult, 16); return(new OmemoAuthenticatedMessage(hmacTruncated, omemoMessageBytes)); }
/// <summary> /// Encrypts the given key and HMAC concatenation and returns the result. /// </summary> /// <param name="keyHmac">The key, HMAC concatenation result.</param> /// <param name="session">The <see cref="OmemoSessionModel"/> between the sender and receiver.</param> /// <param name="assData">Encode(IK_A) || Encode(IK_B) => Concatenation of Alices and Bobs public part of their identity key.</param> private OmemoAuthenticatedMessage EncryptKeyHmacForDevices(byte[] keyHmac, OmemoSessionModel session, byte[] assData) { byte[] mk = LibSignalUtils.KDF_CK(session.ckS, 0x01); Logger.Trace("[" + nameof(EncryptKeyHmacForDevices) + "] " + nameof(session.ckS) + ": " + CryptoUtils.ToHexString(session.ckS)); session.ckS = LibSignalUtils.KDF_CK(session.ckS, 0x02); OmemoMessage omemoMessage = new OmemoMessage(session); ++session.nS; // 32 byte (256 bit) of salt. Initialized with 0s. byte[] hkdfOutput = CryptoUtils.HkdfSha256(mk, new byte[32], "OMEMO Message Key Material", 80); CryptoUtils.SplitKey(hkdfOutput, out byte[] encKey, out byte[] authKey, out byte[] iv); omemoMessage.cipherText = CryptoUtils.Aes256CbcEncrypt(encKey, iv, keyHmac); byte[] omemoMessageBytes = omemoMessage.ToByteArray(); byte[] hmacInput = CryptoUtils.Concat(assData, omemoMessageBytes); byte[] hmacResult = CryptoUtils.HmacSha256(authKey, hmacInput); byte[] hmacTruncated = CryptoUtils.Truncate(hmacResult, 16); // Update the session state: if (session.state == SessionState.RECEIVED) { session.state = SessionState.READY; } // Debug trace output: Logger.Trace("[" + nameof(EncryptKeyHmacForDevices) + "] " + nameof(mk) + ": " + CryptoUtils.ToHexString(mk)); Logger.Trace("[" + nameof(EncryptKeyHmacForDevices) + "] " + nameof(assData) + ": " + CryptoUtils.ToHexString(assData)); Logger.Trace("[" + nameof(EncryptKeyHmacForDevices) + "] " + nameof(hkdfOutput) + ": " + CryptoUtils.ToHexString(hkdfOutput)); Logger.Trace("[" + nameof(EncryptKeyHmacForDevices) + "] " + nameof(encKey) + ": " + CryptoUtils.ToHexString(encKey)); Logger.Trace("[" + nameof(EncryptKeyHmacForDevices) + "] " + nameof(authKey) + ": " + CryptoUtils.ToHexString(authKey)); Logger.Trace("[" + nameof(EncryptKeyHmacForDevices) + "] " + nameof(iv) + ": " + CryptoUtils.ToHexString(iv)); Logger.Trace("[" + nameof(EncryptKeyHmacForDevices) + "] " + nameof(hmacInput) + ": " + CryptoUtils.ToHexString(hmacInput)); Logger.Trace("[" + nameof(EncryptKeyHmacForDevices) + "] " + nameof(hmacResult) + ": " + CryptoUtils.ToHexString(hmacResult)); Logger.Trace("[" + nameof(EncryptKeyHmacForDevices) + "] " + nameof(hmacTruncated) + ": " + CryptoUtils.ToHexString(hmacTruncated)); Logger.Trace("[" + nameof(EncryptKeyHmacForDevices) + "] " + nameof(session.state) + ": " + session.state); return(new OmemoAuthenticatedMessage(hmacTruncated, omemoMessageBytes)); }