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); }