mirror of
https://github.com/TalAloni/SMBLibrary.git
synced 2025-07-21 16:55:54 +02:00
Client: Added SMB 3.0 support
This commit is contained in:
parent
d0b721d621
commit
1636079cc2
2 changed files with 53 additions and 10 deletions
|
@ -44,6 +44,10 @@ namespace SMBLibrary.Client
|
|||
private uint m_messageID = 0;
|
||||
private SMB2Dialect m_dialect;
|
||||
private bool m_signingRequired;
|
||||
private byte[] m_signingKey;
|
||||
private bool m_encryptSessionData;
|
||||
private byte[] m_encryptionKey;
|
||||
private byte[] m_decryptionKey;
|
||||
private uint m_maxTransactSize;
|
||||
private uint m_maxReadSize;
|
||||
private uint m_maxWriteSize;
|
||||
|
@ -155,10 +159,12 @@ namespace SMBLibrary.Client
|
|||
{
|
||||
NegotiateRequest request = new NegotiateRequest();
|
||||
request.SecurityMode = SecurityMode.SigningEnabled;
|
||||
request.Capabilities = Capabilities.Encryption;
|
||||
request.ClientGuid = Guid.NewGuid();
|
||||
request.ClientStartTime = DateTime.Now;
|
||||
request.Dialects.Add(SMB2Dialect.SMB202);
|
||||
request.Dialects.Add(SMB2Dialect.SMB210);
|
||||
request.Dialects.Add(SMB2Dialect.SMB300);
|
||||
|
||||
TrySendCommand(request);
|
||||
NegotiateResponse response = WaitForCommand(SMB2CommandName.Negotiate) as NegotiateResponse;
|
||||
|
@ -217,6 +223,13 @@ namespace SMBLibrary.Client
|
|||
if (response != null)
|
||||
{
|
||||
m_isLoggedIn = (response.Header.Status == NTStatus.STATUS_SUCCESS);
|
||||
m_signingKey = SMB2Cryptography.GenerateSigningKey(m_sessionKey, m_dialect, null);
|
||||
if (m_dialect == SMB2Dialect.SMB300)
|
||||
{
|
||||
m_encryptSessionData = (((SessionSetupResponse)response).SessionFlags & SessionFlags.EncryptData) > 0;
|
||||
m_encryptionKey = SMB2Cryptography.GenerateClientEncryptionKey(m_sessionKey, SMB2Dialect.SMB300, null);
|
||||
m_decryptionKey = SMB2Cryptography.GenerateClientDecryptionKey(m_sessionKey, SMB2Dialect.SMB300, null);
|
||||
}
|
||||
return response.Header.Status;
|
||||
}
|
||||
}
|
||||
|
@ -283,7 +296,8 @@ namespace SMBLibrary.Client
|
|||
status = response.Header.Status;
|
||||
if (response.Header.Status == NTStatus.STATUS_SUCCESS && response is TreeConnectResponse)
|
||||
{
|
||||
return new SMB2FileStore(this, response.Header.TreeID);
|
||||
bool encryptShareData = (((TreeConnectResponse)response).ShareFlags & ShareFlags.EncryptData) > 0;
|
||||
return new SMB2FileStore(this, response.Header.TreeID, m_encryptSessionData || encryptShareData);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -377,10 +391,22 @@ namespace SMBLibrary.Client
|
|||
{
|
||||
if (packet is SessionMessagePacket)
|
||||
{
|
||||
byte[] messageBytes;
|
||||
if (m_dialect == SMB2Dialect.SMB300 && SMB2TransformHeader.IsTransformHeader(packet.Trailer, 0))
|
||||
{
|
||||
SMB2TransformHeader transformHeader = new SMB2TransformHeader(packet.Trailer, 0);
|
||||
byte[] encryptedMessage = ByteReader.ReadBytes(packet.Trailer, SMB2TransformHeader.Length, (int)transformHeader.OriginalMessageSize);
|
||||
messageBytes = SMB2Cryptography.DecryptMessage(m_decryptionKey, transformHeader, encryptedMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
messageBytes = packet.Trailer;
|
||||
}
|
||||
|
||||
SMB2Command command;
|
||||
try
|
||||
{
|
||||
command = SMB2Command.ReadResponse(packet.Trailer, 0);
|
||||
command = SMB2Command.ReadResponse(messageBytes, 0);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -487,6 +513,11 @@ namespace SMBLibrary.Client
|
|||
}
|
||||
|
||||
internal void TrySendCommand(SMB2Command request)
|
||||
{
|
||||
TrySendCommand(request, m_encryptSessionData);
|
||||
}
|
||||
|
||||
internal void TrySendCommand(SMB2Command request, bool encryptData)
|
||||
{
|
||||
if (m_dialect == SMB2Dialect.SMB202 || m_transport == SMBTransportType.NetBiosOverTCP)
|
||||
{
|
||||
|
@ -516,19 +547,21 @@ namespace SMBLibrary.Client
|
|||
|
||||
request.Header.MessageID = m_messageID;
|
||||
request.Header.SessionID = m_sessionID;
|
||||
if (m_signingRequired)
|
||||
// [MS-SMB2] If the client encrypts the message [..] then the client MUST set the Signature field of the SMB2 header to zero
|
||||
if (m_signingRequired && !encryptData)
|
||||
{
|
||||
request.Header.IsSigned = (m_sessionID != 0 && (request.CommandName == SMB2CommandName.TreeConnect || request.Header.TreeID != 0));
|
||||
request.Header.IsSigned = (m_sessionID != 0 && ((request.CommandName == SMB2CommandName.TreeConnect || request.Header.TreeID != 0) ||
|
||||
(m_dialect == SMB2Dialect.SMB300 && request.CommandName == SMB2CommandName.Logoff)));
|
||||
if (request.Header.IsSigned)
|
||||
{
|
||||
request.Header.Signature = new byte[16]; // Request could be reused
|
||||
byte[] buffer = request.GetBytes();
|
||||
byte[] signature = SMB2Cryptography.CalculateSignature(m_sessionKey, m_dialect, buffer, 0, buffer.Length);
|
||||
byte[] signature = SMB2Cryptography.CalculateSignature(m_signingKey, m_dialect, buffer, 0, buffer.Length);
|
||||
// [MS-SMB2] The first 16 bytes of the hash MUST be copied into the 16-byte signature field of the SMB2 Header.
|
||||
request.Header.Signature = ByteReader.ReadBytes(signature, 0, 16);
|
||||
}
|
||||
}
|
||||
TrySendCommand(m_clientSocket, request);
|
||||
TrySendCommand(m_clientSocket, request, encryptData ? m_encryptionKey : null);
|
||||
if (m_dialect == SMB2Dialect.SMB202 || m_transport == SMBTransportType.NetBiosOverTCP)
|
||||
{
|
||||
m_messageID++;
|
||||
|
@ -563,10 +596,18 @@ namespace SMBLibrary.Client
|
|||
}
|
||||
}
|
||||
|
||||
public static void TrySendCommand(Socket socket, SMB2Command request)
|
||||
public static void TrySendCommand(Socket socket, SMB2Command request, byte[] encryptionKey)
|
||||
{
|
||||
SessionMessagePacket packet = new SessionMessagePacket();
|
||||
packet.Trailer = request.GetBytes();
|
||||
if (encryptionKey != null)
|
||||
{
|
||||
byte[] requestBytes = request.GetBytes();
|
||||
packet.Trailer = SMB2Cryptography.TransformMessage(encryptionKey, requestBytes, request.Header.SessionID);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet.Trailer = request.GetBytes();
|
||||
}
|
||||
TrySendPacket(socket, packet);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,11 +17,13 @@ namespace SMBLibrary.Client
|
|||
|
||||
private SMB2Client m_client;
|
||||
private uint m_treeID;
|
||||
private bool m_encryptShareData;
|
||||
|
||||
public SMB2FileStore(SMB2Client client, uint treeID)
|
||||
public SMB2FileStore(SMB2Client client, uint treeID, bool encryptShareData)
|
||||
{
|
||||
m_client = client;
|
||||
m_treeID = treeID;
|
||||
m_encryptShareData = encryptShareData;
|
||||
}
|
||||
|
||||
public NTStatus CreateFile(out object handle, out FileStatus fileStatus, string path, AccessMask desiredAccess, FileAttributes fileAttributes, ShareAccess shareAccess, CreateDisposition createDisposition, CreateOptions createOptions, SecurityContext securityContext)
|
||||
|
@ -320,7 +322,7 @@ namespace SMBLibrary.Client
|
|||
private void TrySendCommand(SMB2Command request)
|
||||
{
|
||||
request.Header.TreeID = m_treeID;
|
||||
m_client.TrySendCommand(request);
|
||||
m_client.TrySendCommand(request, m_encryptShareData);
|
||||
}
|
||||
|
||||
public uint MaxReadSize
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue