internal void EncryptAndSign(byte[] inputNullable, int id, EncryptedFieldIds fieldId, out byte[] encrypted, out byte[] hmac) { if (inputNullable == null) { encrypted = null; hmac = null; return; } if (inputNullable.Length > 65535) { throw new ArgumentException(nameof(inputNullable)); } GetIVandKeys(id, fieldId, out var iv, out var aesKey, out var hmacKey); // encode length of input and add padding, to make it good for AES BinaryProcedures.CreateBinaryWriter(out var ms, out var w); w.Write((ushort)inputNullable.Length); w.Write(inputNullable); var bytesInLastBlock = (int)ms.Position % CryptoLibraries.AesBlockSize; if (bytesInLastBlock != 0) { var bytesRemainingTillFullAesBlock = CryptoLibraries.AesBlockSize - bytesInLastBlock; w.Write(_cryptoLibrary.GetRandomBytes(bytesRemainingTillFullAesBlock)); } var inputWithPadding = ms.ToArray(); encrypted = new byte[inputWithPadding.Length]; _cryptoLibrary.ProcessAesCbcBlocks(true, aesKey, iv, inputWithPadding, encrypted); hmac = _cryptoLibrary.GetSha256HMAC(hmacKey, encrypted); }
/// <param name="ack1SdIsReady"> /// =true for SD in ACK2 /// =false for SD in ACK1 (since the SessionDescription is not initialized yet) /// </param> internal byte[] Encrypt(ICryptoLibrary cryptoLibrary, InviteRequestPacket req, InviteAck1Packet ack1, InviteSession session, bool ack1SdIsReady ) { BinaryProcedures.CreateBinaryWriter(out var ms, out var w); w.Write(Flags); UserCertificate.Encode(w, false); BinaryProcedures.EncodeIPEndPoint(w, DirectChannelEndPoint); NatBehaviour.Encode(w); DirectChannelToken32.Encode(w); w.Write((byte)SessionType); UserCertificateSignature.Encode(w); var bytesInLastBlock = (int)ms.Position % CryptoLibraries.AesBlockSize; if (bytesInLastBlock != 0) { var bytesRemainingTillFullAesBlock = CryptoLibraries.AesBlockSize - bytesInLastBlock; w.Write(cryptoLibrary.GetRandomBytes(bytesRemainingTillFullAesBlock)); } var plainTextSdData = ms.ToArray(); var encryptedSdData = new byte[plainTextSdData.Length]; #region key, iv BinaryProcedures.CreateBinaryWriter(out var ms2, out var w2); req.GetSharedSignedFields(w2); ack1.GetSharedSignedFields(w2, ack1SdIsReady); var iv = cryptoLibrary.GetHashSHA256(ms2.ToArray()).Take(16).ToArray(); ms2.Write(session.SharedInviteAckDhSecret, 0, session.SharedInviteAckDhSecret.Length); var aesKey = cryptoLibrary.GetHashSHA256(ms2.ToArray()); // here SHA256 is used as KDF, together with common fields from packets, including both ECDH public keys and timestamp #endregion cryptoLibrary.ProcessAesCbcBlocks(true, aesKey, iv, plainTextSdData, encryptedSdData); return(encryptedSdData); }
internal byte[] EncryptIke1Data(ICryptoLibrary cryptoLibrary, Ike1Data ike1Data) { if (Status != MessageSessionStatusCode.inProgress) { throw new InvalidOperationException(); } var decryptedMessageData = MessageEncoderDecoder.EncodeIke1DataWithPadding(cryptoLibrary, ike1Data); var encryptedMessageData = new byte[decryptedMessageData.Length]; cryptoLibrary.ProcessAesCbcBlocks(true, _aesKey, _iv, decryptedMessageData, encryptedMessageData); Status = MessageSessionStatusCode.encryptionDecryptionCompleted; return(encryptedMessageData); }
internal byte[] EncryptShortSingleMessage(ICryptoLibrary cryptoLibrary, string messageText) { if (Status != MessageSessionStatusCode.inProgress) { throw new InvalidOperationException(); } var decryptedMessageData = MessageEncoderDecoder.EncodePlainTextMessageWithPadding_plainTextUtf8_256(cryptoLibrary, messageText); var encryptedMessageData = new byte[decryptedMessageData.Length]; cryptoLibrary.ProcessAesCbcBlocks(true, _aesKey, _iv, decryptedMessageData, encryptedMessageData); Status = MessageSessionStatusCode.encryptionDecryptionCompleted; return(encryptedMessageData); }
/// <param name="receivedFromUser">comes from local contact book. is null if it is contact invitation</param> internal static InviteSessionDescription Decrypt_Verify(ICryptoLibrary cryptoLibrary, byte[] encryptedSdData, InviteRequestPacket req, InviteAck1Packet ack1, bool ack1SdIsReady, InviteSession session, UserId receivedFromUserNullable, DateTime localTimeNowUtc ) { #region key, iv BinaryProcedures.CreateBinaryWriter(out var ms2, out var w2); req.GetSharedSignedFields(w2); ack1.GetSharedSignedFields(w2, ack1SdIsReady); var iv = cryptoLibrary.GetHashSHA256(ms2.ToArray()).Take(16).ToArray(); ms2.Write(session.SharedInviteAckDhSecret, 0, session.SharedInviteAckDhSecret.Length); var aesKey = cryptoLibrary.GetHashSHA256(ms2.ToArray()); // here SHA256 is used as KDF, together with common fields from packets, including both ECDH public keys and timestamp #endregion // decrypt var plainTextSdData = new byte[encryptedSdData.Length]; cryptoLibrary.ProcessAesCbcBlocks(false, aesKey, iv, encryptedSdData, plainTextSdData); var r = new InviteSessionDescription(); var reader = BinaryProcedures.CreateBinaryReader(plainTextSdData, 0); r.Flags = reader.ReadByte(); if ((r.Flags & FlagsMask_MustBeZero) != 0) { throw new NotImplementedException(); } r.UserCertificate = UserCertificate.Decode_AssertIsValidNow(reader, cryptoLibrary, receivedFromUserNullable, localTimeNowUtc); r.DirectChannelEndPoint = BinaryProcedures.DecodeIPEndPoint(reader); r.NatBehaviour = NatBehaviourModel.Decode(reader); r.DirectChannelToken32 = DirectChannelToken32.Decode(reader); r.SessionType = (SessionType)reader.ReadByte(); r.UserCertificateSignature = UserCertificateSignature.DecodeAndVerify(reader, cryptoLibrary, w => { req.GetSharedSignedFields(w); ack1.GetSharedSignedFields(w, ack1SdIsReady); r.WriteSignedFields(w); }, r.UserCertificate); return(r); }