/// <summary>
        /// Covert to a byte array
        /// </summary>
        /// <returns>The byte array</returns>
        public override byte[] ToBytes()
        {
            byte[] messageData = TypeMarshal.ToBytes(this.Header);
            messageData = messageData.Concat(Smb2Utility.MarshalStructure(this.PayLoad)).ToArray();
            if (this.Buffer != null)
            {
                messageData = messageData.Concat(this.Buffer).ToArray();
            }

            if (NegotiateContext_PREAUTH != null)
            {
                // 8-byte align
                Smb2Utility.Align8(ref messageData);
                messageData = messageData.Concat(TypeMarshal.ToBytes <SMB2_PREAUTH_INTEGRITY_CAPABILITIES>(NegotiateContext_PREAUTH.Value)).ToArray();
            }

            if (NegotiateContext_ENCRYPTION != null)
            {
                // 8-byte align
                Smb2Utility.Align8(ref messageData);
                messageData = messageData.Concat(TypeMarshal.ToBytes <SMB2_ENCRYPTION_CAPABILITIES>(NegotiateContext_ENCRYPTION.Value)).ToArray();
            }

            if (NegotiateContext_COMPRESSION != null)
            {
                // 8-byte align
                Smb2Utility.Align8(ref messageData);
                messageData = messageData.Concat(TypeMarshal.ToBytes <SMB2_COMPRESSION_CAPABILITIES>(NegotiateContext_COMPRESSION.Value)).ToArray();
            }

            if (NegotiateContext_SIGNING != null)
            {
                // 8-byte align
                Smb2Utility.Align8(ref messageData);
                messageData = messageData.Concat(TypeMarshal.ToBytes <SMB2_SIGNING_CAPABILITIES>(NegotiateContext_SIGNING.Value)).ToArray();
            }

            if (NegotiateContext_RDMA != null)
            {
                // 8-byte align
                Smb2Utility.Align8(ref messageData);
                messageData = messageData.Concat(TypeMarshal.ToBytes <SMB2_RDMA_TRANSFORM_CAPABILITIES>(NegotiateContext_RDMA.Value)).ToArray();
            }

            return(messageData);
        }
Esempio n. 2
0
        public static byte[] Decrypt(byte[] bytes, Dictionary <ulong, Smb2CryptoInfo> cryptoInfoTable, Smb2Role role, out Transform_Header transformHeader)
        {
            var encryptedPacket = new Smb2EncryptedPacket();

            int consumedLen;
            int expectedLen;

            encryptedPacket.FromBytes(bytes, out consumedLen, out expectedLen);

            transformHeader = encryptedPacket.Header;

            // For client: If the Flags/EncryptionAlgorithm in the SMB2 TRANSFORM_HEADER is not 0x0001, the client MUST discard the message.
            // For server: If the Flags/EncryptionAlgorithm in the SMB2 TRANSFORM_HEADER is not 0x0001, the server MUST disconnect the connection.
            if (transformHeader.Flags != TransformHeaderFlags.Encrypted)
            {
                throw new InvalidOperationException(
                          String.Format(
                              "Flags/EncryptionAlgorithm field is invalid for encrypted message. Expected value 0x0001, actual {0}.",
                              (ushort)transformHeader.Flags
                              )
                          );
            }

            if (transformHeader.SessionId == 0 || !cryptoInfoTable.ContainsKey(transformHeader.SessionId))
            {
                throw new InvalidOperationException("Invalid SessionId in TRANSFORM_HEADER.");
            }

            Smb2CryptoInfo cryptoInfo = cryptoInfoTable[transformHeader.SessionId];

            using (var bcrypt = new BCryptAlgorithm("AES"))
            {
                int nonceLength       = 0;
                BCryptCipherMode mode = BCryptCipherMode.NotAvailable;
                GetCryptoParams(cryptoInfo, CryptoOperationType.Decrypt, out mode, out nonceLength);
                bcrypt.Mode = mode;
                bcrypt.Key  = role == Smb2Role.Server ? cryptoInfo.ServerInKey : cryptoInfo.ServerOutKey;
                // Auth data is Transform_Header start from Nonce, excluding ProtocolId and Signature.
                var authData = Smb2Utility.MarshalStructure(transformHeader).Skip((int)Marshal.OffsetOf <Transform_Header>("Nonce")).ToArray();
                return(bcrypt.Decrypt(encryptedPacket.EncryptdData, transformHeader.Nonce.ToByteArray().Take(nonceLength).ToArray(), authData, transformHeader.Signature));
            }
        }
        /// <summary>
        /// Covert to a byte array
        /// </summary>
        /// <returns>The byte array</returns>
        public override byte[] ToBytes()
        {
            byte[] messageData = TypeMarshal.ToBytes(this.Header);
            messageData = messageData.Concat(Smb2Utility.MarshalStructure(this.PayLoad)).ToArray();

            if (this.Dialects != null & this.Dialects.Length > 0)
            {
                messageData = messageData.Concat(Smb2Utility.MarshalStructArray(Dialects)).ToArray();
            }

            if (NegotiateContext_PREAUTH != null)
            {
                Smb2Utility.Align8(ref messageData);
                messageData = messageData.Concat(TypeMarshal.ToBytes <SMB2_PREAUTH_INTEGRITY_CAPABILITIES>(NegotiateContext_PREAUTH.Value)).ToArray();
            }

            if (NegotiateContext_ENCRYPTION != null)
            {
                Smb2Utility.Align8(ref messageData);
                messageData = messageData.Concat(TypeMarshal.ToBytes <SMB2_ENCRYPTION_CAPABILITIES>(NegotiateContext_ENCRYPTION.Value)).ToArray();
            }

            if (NegotiateContext_COMPRESSION != null)
            {
                Smb2Utility.Align8(ref messageData);
                messageData = messageData.Concat(TypeMarshal.ToBytes <SMB2_COMPRESSION_CAPABILITIES>(NegotiateContext_COMPRESSION.Value)).ToArray();
            }

            if (NegotiateContext_NETNAME != null)
            {
                Smb2Utility.Align8(ref messageData);
                messageData = messageData.Concat(NegotiateContext_NETNAME.Marshal()).ToArray();
            }

            return(messageData);
        }
        private static Smb2EncryptedPacket Encrypt(ulong sessionId, Smb2CryptoInfo cryptoInfo, Smb2Role role, Smb2Packet packet, Smb2Packet packetBeforCompression)
        {
            Packet_Header header;

            if (packetBeforCompression is Smb2SinglePacket)
            {
                header = (packetBeforCompression as Smb2SinglePacket).Header;
            }
            else if (packetBeforCompression is Smb2CompoundPacket)
            {
                header = (packetBeforCompression as Smb2CompoundPacket).Packets[0].Header;
            }
            else
            {
                throw new InvalidOperationException("Unsupported SMB2 packet type!");
            }

            // Encrypt all messages after session setup if global encryption enabled.
            // Encrypt all messages after tree connect if global encryption disabled but share encryption enabled.
            if ((cryptoInfo.EnableSessionEncryption ||
                 (cryptoInfo.EnableTreeEncryption.Contains(header.TreeId) &&
                  header.Command != Smb2Command.TREE_CONNECT
                 )
                 )
                )
            {
                byte[]           originalBinary  = packet.ToBytes();
                Transform_Header transformHeader = new Transform_Header
                {
                    ProtocolId          = Smb2Consts.ProtocolIdInTransformHeader,
                    OriginalMessageSize = (uint)originalBinary.Length,
                    SessionId           = sessionId,
                    Signature           = new byte[16]
                };

                if (cryptoInfo.Dialect == DialectRevision.Smb311)
                {
                    transformHeader.Flags = TransformHeaderFlags.Encrypted;
                }
                else
                {
                    transformHeader.EncryptionAlgorithm = EncryptionAlgorithm.ENCRYPTION_AES128_CCM;
                }

                byte[] encrypted = new byte[originalBinary.Length];
                byte[] tag       = new byte[16];
                byte[] key       = role == Smb2Role.Server ? cryptoInfo.ServerOutKey : cryptoInfo.ServerInKey;

                // The reserved field (5 bytes for CCM, 4 bytes for GCM) must be set to zero.
                byte[] nonce = new byte[16];

                if (cryptoInfo.CipherId == EncryptionAlgorithm.ENCRYPTION_AES128_CCM)
                {
                    int nonceLength = Smb2Consts.AES128CCM_Nonce_Length;
                    Buffer.BlockCopy(Guid.NewGuid().ToByteArray(), 0, nonce, 0, nonceLength);
                    transformHeader.Nonce = new Guid(nonce);

                    using (var cipher = new AesCcm(key))
                    {
                        cipher.Encrypt(
                            transformHeader.Nonce.ToByteArray().Take(nonceLength).ToArray(),
                            originalBinary,
                            encrypted,
                            tag,
                            // Use the fields including and after Nonce field as auth data
                            Smb2Utility.MarshalStructure(transformHeader).Skip(20).ToArray());
                    }
                }
                else if (cryptoInfo.CipherId == EncryptionAlgorithm.ENCRYPTION_AES128_GCM)
                {
                    int nonceLength = Smb2Consts.AES128GCM_Nonce_Length;
                    Buffer.BlockCopy(Guid.NewGuid().ToByteArray(), 0, nonce, 0, nonceLength);
                    transformHeader.Nonce = new Guid(nonce);

                    using (var cipher = new AesGcm(key))
                    {
                        cipher.Encrypt(
                            transformHeader.Nonce.ToByteArray().Take(nonceLength).ToArray(),
                            originalBinary,
                            encrypted,
                            tag,
                            // Use the fields including and after Nonce field as auth data
                            Smb2Utility.MarshalStructure(transformHeader).Skip(20).ToArray());
                    }
                }
                else
                {
                    throw new InvalidOperationException(String.Format(
                                                            "Invalid encryption algorithm is set in Smb2CryptoInfo when encrypting: {0}", cryptoInfo.CipherId));
                }

                transformHeader.Signature = tag;

                var encryptedPacket = new Smb2EncryptedPacket();
                encryptedPacket.Header       = transformHeader;
                encryptedPacket.EncryptdData = encrypted;

                return(encryptedPacket);
            }

            // Return null if the message is not required to be encrypted.
            return(null);
        }
        public static byte[] Decrypt(byte[] bytes, Dictionary <ulong, Smb2CryptoInfo> cryptoInfoTable, Smb2Role role, out Transform_Header transformHeader)
        {
            var encryptedPacket = new Smb2EncryptedPacket();

            int consumedLen;
            int expectedLen;

            encryptedPacket.FromBytes(bytes, out consumedLen, out expectedLen);

            transformHeader = encryptedPacket.Header;

            // For client: If the Flags/EncryptionAlgorithm in the SMB2 TRANSFORM_HEADER is not 0x0001, the client MUST discard the message.
            // For server: If the Flags/EncryptionAlgorithm in the SMB2 TRANSFORM_HEADER is not 0x0001, the server MUST disconnect the connection.
            if (transformHeader.Flags != TransformHeaderFlags.Encrypted)
            {
                throw new InvalidOperationException(
                          String.Format(
                              "Flags/EncryptionAlgorithm field is invalid for encrypted message. Expected value 0x0001, actual {0}.",
                              (ushort)transformHeader.Flags
                              )
                          );
            }

            if (transformHeader.SessionId == 0 || !cryptoInfoTable.ContainsKey(transformHeader.SessionId))
            {
                throw new InvalidOperationException("Invalid SessionId in TRANSFORM_HEADER.");
            }

            Smb2CryptoInfo cryptoInfo = cryptoInfoTable[transformHeader.SessionId];

            byte[] decrypted = new byte[encryptedPacket.EncryptdData.Length];
            byte[] key       = role == Smb2Role.Server ? cryptoInfo.ServerInKey : cryptoInfo.ServerOutKey;
            // Auth data is Transform_Header start from Nonce, excluding ProtocolId and Signature.
            var authData = Smb2Utility.MarshalStructure(transformHeader).Skip((int)Marshal.OffsetOf <Transform_Header>("Nonce")).ToArray();

            if (cryptoInfo.CipherId == EncryptionAlgorithm.ENCRYPTION_AES128_CCM)
            {
                int nonceLength = Smb2Consts.AES128CCM_Nonce_Length;
                using (var cipher = new AesCcm(key))
                {
                    cipher.Decrypt(
                        transformHeader.Nonce.ToByteArray().Take(nonceLength).ToArray(),
                        encryptedPacket.EncryptdData,
                        transformHeader.Signature,
                        decrypted,
                        authData);
                }
            }
            else if (cryptoInfo.CipherId == EncryptionAlgorithm.ENCRYPTION_AES128_GCM)
            {
                int nonceLength = Smb2Consts.AES128GCM_Nonce_Length;
                using (var cipher = new AesGcm(key))
                {
                    cipher.Decrypt(
                        transformHeader.Nonce.ToByteArray().Take(nonceLength).ToArray(),
                        encryptedPacket.EncryptdData,
                        transformHeader.Signature,
                        decrypted,
                        authData);
                }
            }
            else
            {
                throw new InvalidOperationException(String.Format(
                                                        "Invalid encryption algorithm is set in Smb2CryptoInfo when decrypting: {0}", cryptoInfo.CipherId));
            }

            return(decrypted);
        }
        private static byte[] Encrypt(ulong sessionId, Smb2CryptoInfo cryptoInfo, Smb2Role role, Smb2Packet originalPacket)
        {
            Packet_Header header;

            if (originalPacket is Smb2SinglePacket)
            {
                header = (originalPacket as Smb2SinglePacket).Header;
            }
            else
            {
                header = (originalPacket as Smb2CompoundPacket).Packets[0].Header;
            }

            // Encrypt all messages after session setup if global encryption enabled.
            // Encrypt all messages after tree connect if global encryption disabled but share encryption enabled.
            if ((cryptoInfo.EnableSessionEncryption ||
                 (cryptoInfo.EnableTreeEncryption.Contains(header.TreeId) &&
                  header.Command != Smb2Command.TREE_CONNECT
                 )
                 )
                )
            {
                using (var bcrypt = new BCryptAlgorithm("AES"))
                {
                    byte[]           originalBinary  = originalPacket.ToBytes();
                    Transform_Header transformHeader = new Transform_Header
                    {
                        ProtocolId          = Smb2Consts.ProtocolIdInTransformHeader,
                        OriginalMessageSize = (uint)originalBinary.Length,
                        SessionId           = sessionId,
                        Signature           = new byte[16]
                    };

                    if (cryptoInfo.Dialect == DialectRevision.Smb311)
                    {
                        transformHeader.Flags = TransformHeaderFlags.Encrypted;
                    }
                    else
                    {
                        transformHeader.EncryptionAlgorithm = EncryptionAlgorithm.ENCRYPTION_AES128_CCM;
                    }

                    byte[] tag;

                    int nonceLength       = 0;
                    BCryptCipherMode mode = BCryptCipherMode.NotAvailable;
                    GetCryptoParams(cryptoInfo, CryptoOperationType.Encrypt, out mode, out nonceLength);
                    bcrypt.Mode = mode;
                    bcrypt.Key  = role == Smb2Role.Server ? cryptoInfo.ServerOutKey : cryptoInfo.ServerInKey;
                    // The reserved field (5 bytes for CCM, 4 bytes for GCM) must be set to zero.
                    byte[] nonce = new byte[16];
                    Buffer.BlockCopy(Guid.NewGuid().ToByteArray(), 0, nonce, 0, nonceLength);
                    transformHeader.Nonce = new Guid(nonce);

                    byte[] output = bcrypt.Encrypt(
                        originalBinary,
                        transformHeader.Nonce.ToByteArray().Take(nonceLength).ToArray(),
                        // Use the fields including and after Nonce field as auth data
                        Smb2Utility.MarshalStructure(transformHeader).Skip(20).ToArray(),
                        // Signature is 16 bytes in length
                        16,
                        out tag);
                    transformHeader.Signature = tag;
                    return(Smb2Utility.MarshalStructure(transformHeader).Concat(output).ToArray());
                }
            }

            // Return null if the message is not required to be encrypted.
            return(null);
        }