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