Пример #1
0
        private static byte[] Sign(Smb2CryptoInfo cryptoInfo, Smb2SinglePacket original, Smb2Role role)
        {
            if (Smb2Utility.IsSmb2Family(cryptoInfo.Dialect))
            {
                // [MS-SMB2] 3.1.4.1
                // 3. If Connection.Dialect is "2.002" or "2.100", the sender MUST compute a 32-byte hash using HMAC-SHA256 over the entire message,
                HMACSHA256 hmacSha = new HMACSHA256(cryptoInfo.SigningKey);
                return(hmacSha.ComputeHash(original.ToBytes()));
            }
            else if (cryptoInfo.SigningId == SigningAlgorithm.AES_GMAC)
            {
                // [MS-SMB2] 3.1.4.1
                // 1. If Connection.Dialect belongs to the SMB 3.x dialect family and Connection.SigningAlgorithmId is AES-GMAC,
                // compute a 16-byte hash using the AES-GMAC over the entire message using nonce as specified
                var nonce = Smb2Utility.ComputeNonce(original, role);
                var(_, tag) = AesGmac.ComputeHash(cryptoInfo.SigningKey, nonce, original.ToBytes());

                return(tag);
            }
            else
            {
                // [MS-SMB2] 3.1.4.1
                // 2. If Connection.Dialect belongs to the SMB 3.x dialect family, the sender MUST compute a 16-byte hash using AES-128-CMAC over the entire message
                return(AesCmac128.ComputeHash(cryptoInfo.SigningKey, original.ToBytes()));
            }
        }
        /// <summary>
        /// Sign, compress and encrypt for Single or Compound packet.
        /// </summary>
        public static Smb2Packet SignCompressAndEncrypt(Smb2Packet originalPacket, Dictionary <ulong, Smb2CryptoInfo> cryptoInfoTable, Smb2CompressionInfo compressioninfo, Smb2Role role)
        {
            ulong sessionId;
            bool  isCompound        = false;
            bool  notEncryptNotSign = false;
            bool  notEncrypt        = false;
            var   compressedPacket  = originalPacket;

            if (originalPacket is Smb2SinglePacket)
            {
                Smb2SinglePacket singlePacket = originalPacket as Smb2SinglePacket;
                sessionId = singlePacket.Header.SessionId;
                // [MS-SMB2] Section 3.2.4.1.8, the request being sent is SMB2 NEGOTIATE,
                // or the request being sent is SMB2 SESSION_SETUP with the SMB2_SESSION_FLAG_BINDING bit set in the Flags field,
                // the client MUST NOT encrypt the message
                if (sessionId == 0 ||
                    (singlePacket.Header.Command == Smb2Command.NEGOTIATE && (singlePacket is Smb2NegotiateRequestPacket)))
                {
                    notEncryptNotSign = true;
                }
                else if ((singlePacket.Header.Command == Smb2Command.SESSION_SETUP && (singlePacket is Smb2SessionSetupRequestPacket) &&
                          (singlePacket as Smb2SessionSetupRequestPacket).PayLoad.Flags == SESSION_SETUP_Request_Flags.SESSION_FLAG_BINDING))
                {
                    notEncrypt = true;
                }
            }
            else if (originalPacket is Smb2CompoundPacket)
            {
                isCompound = true;
                // The subsequent request in compound packet should use the SessionId of the first request for encryption
                sessionId = (originalPacket as Smb2CompoundPacket).Packets[0].Header.SessionId;
            }
            else
            {
                throw new NotImplementedException(string.Format("Signing and encryption are not implemented for packet: {0}", originalPacket.ToString()));
            }

            if (sessionId == 0 || notEncryptNotSign || !cryptoInfoTable.ContainsKey(sessionId))
            {
                if (originalPacket is Smb2CompressiblePacket)
                {
                    compressedPacket = Smb2Compression.Compress(originalPacket as Smb2CompressiblePacket, compressioninfo, role);
                }
                return(compressedPacket);
            }

            Smb2CryptoInfo cryptoInfo = cryptoInfoTable[sessionId];

            #region Encrypt
            // Try to encrypt the message whenever the encryption is supported or not except for sesstion setup.
            // If it's not supported, do it for negative test.
            // For compound packet, the encryption is done for the entire message.
            if (!notEncrypt)
            {
                if (originalPacket is Smb2CompressiblePacket)
                {
                    compressedPacket = Smb2Compression.Compress(originalPacket as Smb2CompressiblePacket, compressioninfo, role);
                }
                var encryptedPacket = Encrypt(sessionId, cryptoInfo, role, compressedPacket, originalPacket);
                if (encryptedPacket != null)
                {
                    return(encryptedPacket);
                }
            }
            #endregion

            #region Sign
            if (cryptoInfo.EnableSessionSigning)
            {
                if (isCompound)
                {
                    // Calculate signature for every packet in the chain
                    foreach (Smb2SinglePacket packet in (originalPacket as Smb2CompoundPacket).Packets)
                    {
                        // If the packet is the first one in the chain or the unralated one, use its own SessionId for sign and encrypt
                        // If it's not the first one and it's the related one, use the SessionId of the first request for sign and encrypt
                        if (!packet.Header.Flags.HasFlag(Packet_Header_Flags_Values.FLAGS_RELATED_OPERATIONS))
                        {
                            sessionId  = packet.Header.SessionId;
                            cryptoInfo = cryptoInfoTable[sessionId];
                        }

                        packet.Header.Signature = Sign(cryptoInfo, packet.ToBytes());
                    }
                }
                else
                {
                    (originalPacket as Smb2SinglePacket).Header.Signature = Sign(cryptoInfo, originalPacket.ToBytes());
                }
            }
            #endregion
            if (originalPacket is Smb2CompressiblePacket)
            {
                compressedPacket = Smb2Compression.Compress(originalPacket as Smb2CompressiblePacket, compressioninfo, role);
            }
            return(compressedPacket);
        }