C#
C++/CLI
public int GetIsclCommunicationBlockLength()
public:
int GetIsclCommunicationBlockLength();
The communication block length agreed upon during mutual authentication.
Using a block size that is too small or too big could impact performance.
This is a comprehensive sample that shows how to use DICOM Secure communication using ISCL.
using Leadtools;
using Leadtools.Dicom;
[StructLayout(LayoutKind.Sequential)]
public struct MSG
{
public IntPtr hwnd;
public uint message;
public IntPtr wParam;
public IntPtr lParam;
public uint time;
public System.Drawing.Point p;
}
public enum WaitReturn
{
Complete,
Timeout,
}
class Utils
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool PeekMessage(out MSG lpMsg, IntPtr hWnd,
uint wMsgFilterMin, uint wMsgFilterMax,
uint wRemoveMsg);
[DllImport("user32.dll")]
static extern bool TranslateMessage([In] ref MSG lpMsg);
[DllImport("user32.dll")]
static extern IntPtr DispatchMessage([In] ref MSG lpmsg);
const uint PM_REMOVE = 1;
public static WaitReturn WaitForComplete(double mill, WaitHandle wh)
{
TimeSpan goal = new TimeSpan(DateTime.Now.AddMilliseconds(mill).Ticks);
do
{
MSG msg = new MSG();
if (PeekMessage(out msg, IntPtr.Zero, 0, 0, PM_REMOVE))
{
TranslateMessage(ref msg);
DispatchMessage(ref msg);
}
if (wh.WaitOne(new TimeSpan(0, 0, 0), false))
{
return WaitReturn.Complete;
}
if (goal.CompareTo(new TimeSpan(DateTime.Now.Ticks)) < 0)
{
return WaitReturn.Timeout;
}
} while (true);
}
public static void SetupISCL(DicomNet net, string authData)
{
net.SetIsclMutualAuthenticationAlgorithm(DicomIsclMutualAuthenticationMode.ThreePFourW);
net.SetIsclMutualAuthenticationKey(1, 11619789628100321);
net.SetIsclMutualAuthenticationKey(2, 34217865672122111);
net.SetIsclMutualAuthenticationKey(3, 1605935625518899689);
net.SetIsclMutualAuthenticationKey(4, 138217077775855676);
net.SetIsclMutualAuthenticationKey(5, 9117318694593010212);
net.SetIsclMutualAuthenticationKey(6, 3485297985488245687);
net.SetIsclMutualAuthenticationKey(7, 1533287511573403981);
net.SetIsclMutualAuthenticationKey(8, 5604839976916070822);
net.SetIsclIndexForMutualAuthentication(1);
net.SetIsclDefaultEncryptionMode(DicomIsclEncryptionMethodType.DesCbc);
net.SetIsclDefaultSigningMode(DicomIsclSigningMethodType.Md5);
net.SetIsclEncryptionKey(1, 8079278526052745737);
net.SetIsclEncryptionKey(2, 1312864321990916052);
net.SetIsclEncryptionKey(3, 7190959962252002117);
net.SetIsclEncryptionKey(4, 3619524191167482890);
net.SetIsclEncryptionKey(5, 3466658849848898336);
net.SetIsclEncryptionKey(6, 8474124475946342520);
net.SetIsclEncryptionKey(7, 7725464453540259890);
net.SetIsclEncryptionKey(8, 4320705344832296668);
net.SetIsclEncryptionKeyIndex(1);
net.SetIsclMaxMessageLength(1024000);
net.SetIsclMaxCommunicationBlockLength(8129);
byte[] data = new ASCIIEncoding().GetBytes(authData);
net.SetIsclAuthenticationData(data, data.GetLength(0));
}
}
//
// Secure client (ISCL)
//
public class Client : DicomNet
{
readonly AutoResetEvent waitEvent = new AutoResetEvent(false);
public Client()
: base(null, DicomNetSecurityMode.Iscl)
{
const string authData = "LEAD client ISCL";
Utils.SetupISCL(this, authData);
}
public bool Wait()
{
WaitReturn ret = Utils.WaitForComplete((2 * 60) * 1000, waitEvent);
return (ret == WaitReturn.Complete);
}
protected override void OnConnect(DicomExceptionCode error)
{
waitEvent.Set();
}
protected override void OnSecureLinkReady(DicomExceptionCode error)
{
Console.WriteLine("Iscl Peer Encryption is : {0}", GetIsclPeerEncryption());
Console.WriteLine("Iscl Peer Mac : {0}", GetIsclPeerMac());
Console.WriteLine("Iscl Communication Block Length is : {0}", GetIsclCommunicationBlockLength());
Console.WriteLine("Iscl Index For Encryption : {0}", GetIsclIndexForEncryption());
Console.WriteLine("Is Iscl Queue Empty : {0}", IsIsclQueueEmpty());
Console.WriteLine("Iscl Index For Mutual Authentication : {0}", GetIsclIndexForMutualAuthentication());
Console.WriteLine("Iscl Status is : {0}", GetIsclStatus());
//We can also call GetIsclPeerAuthenticationData() to Get the Peer Authentication Data
waitEvent.Set();
}
protected override bool GetChallengeIscl(ref long challenge, long parameter)
{
challenge = 0x0123456789ABCDE1;
return true;
}
protected override bool InternalAuthenticateIscl(long challenge, ref long response, long parameter)
{
response = challenge + 1;
return true;
}
protected override bool ExternalAuthenticateIscl(long challenge, long response, long parameter)
{
if (response == (challenge + 1))
return true;
return false;
}
protected override void OnReceiveAssociateAccept(DicomAssociate association)
{
waitEvent.Set();
}
protected override void OnReceiveReleaseResponse()
{
waitEvent.Set();
}
protected override void OnReceiveCEchoResponse(byte presentationID, int messageID, string affectedClass, DicomCommandStatusType status)
{
Debug.Assert(presentationID == 1, "Presentation id should be 1");
Debug.Assert(messageID == 1, "Message ID should be 1");
Debug.Assert(affectedClass == DicomUidType.VerificationClass, "Affected class should be " + DicomUidType.VerificationClass);
waitEvent.Set();
}
};
//
// Secure server client (ISCL)
//
public class ServerConnection : DicomNet
{
public ServerConnection()
: base(null, DicomNetSecurityMode.Iscl)
{
const string authData = "LEAD ServerConnection ISCL";
Utils.SetupISCL(this, authData);
}
protected override bool GetChallengeIscl(ref long challenge, long parameter)
{
challenge = 0x0123456789ABCDE1;
return true;
}
protected override bool InternalAuthenticateIscl(long challenge, ref long response, long parameter)
{
response = challenge + 1;
return true;
}
protected override bool ExternalAuthenticateIscl(long challenge, long response, long parameter)
{
if (response == challenge + 1)
return true;
return false;
}
protected override void OnReceiveAssociateRequest(DicomAssociate association)
{
DicomAssociate retAssociation = new DicomAssociate(false);
Debug.Assert(association.Called == "ServerTest", "Called AETitle should be ServerTest");
Debug.Assert(association.Calling == "ClientTest", "Calling AETitle should be ClientTest");
Debug.Assert(association.ImplementClass == "1.2.840.114257.1", "Implementation class should be 1.2.840.114257.1");
Debug.Assert(association.ImplementationVersionName == "1", "Implementation version should be 1");
Debug.Assert(association.MaxLength == 0x100000, "Max length should be 0x100000");
Debug.Assert(association.GetAbstract(1) == DicomUidType.VerificationClass, "Presentation index 1 should be " + DicomUidType.VerificationClass);
Debug.Assert(association.GetTransfer(1, 0) == DicomUidType.ImplicitVRLittleEndian, "Abstract Syntax (1,0) should be " + DicomUidType.ImplicitVRLittleEndian);
//
// Build our Association Accept
//
retAssociation.Called = association.Called;
retAssociation.Calling = association.Calling;
retAssociation.ImplementClass = association.ImplementClass;
retAssociation.ImplementationVersionName = association.ImplementationVersionName;
for (int x = 0; x < association.PresentationContextCount; x++)
{
byte id = association.GetPresentationContextID(x);
string abSyntax = association.GetAbstract(id);
string trSyntax = DicomUidType.ImplicitVRLittleEndian;
retAssociation.AddPresentationContext(id, 0, abSyntax);
if (association.GetTransferCount(id) > 0)
{
trSyntax = association.GetTransfer(id, 0);
}
retAssociation.AddTransfer(id, trSyntax);
}
SendAssociateAccept(retAssociation);
}
protected override void OnReceiveReleaseRequest()
{
SendReleaseResponse();
}
protected override void OnReceiveCEchoRequest(byte presentationID, int messageID, string affectedClass)
{
Debug.Assert(presentationID == 1, "Presentation id should be 1");
Debug.Assert(messageID == 1, "Message ID should be 1");
Debug.Assert(affectedClass == DicomUidType.VerificationClass, "Affected class should be " + DicomUidType.VerificationClass);
SendCEchoResponse(presentationID, messageID, DicomUidType.VerificationClass, DicomCommandStatusType.Success);
}
};
public class Server : DicomNet
{
readonly AutoResetEvent waitEvent = new AutoResetEvent(false);
public Server()
: base(null, DicomNetSecurityMode.None)
{
}
protected override void OnAccept(DicomExceptionCode error)
{
ServerConnection client = new ServerConnection();
Accept(client);
}
}
public void ISCLSecuritySample()
{
DicomEngine.Startup();
DicomNet.Startup();
using (Server server = new Server())
{
using (Client client = new Client())
{
server.Listen("127.0.0.1", 106, 1); // start server
client.Connect("", 1006, "127.0.0.1", 106); // connect to secure server
if (!client.Wait()) // wait for connection to finish
{
Debug.Fail("Connection timed out");
}
Debug.Assert(client.IsConnected(), "Client not connected");
//
// Wait for authenication
//
if (!client.Wait())
{
Debug.Fail("Connection timed out waiting for authenication");
}
// If secure link is established you can now do your regular
// dicom communications.
//
// Send associate request
//
DicomAssociate associate = new DicomAssociate(true);
associate.Called = "ServerTest";
associate.Calling = "ClientTest";
associate.ImplementClass = "1.2.840.114257.1";
associate.ImplementationVersionName = "1";
associate.MaxLength = 0x100000;
associate.AddPresentationContext(1, 0, DicomUidType.VerificationClass);
associate.AddTransfer(1, DicomUidType.ImplicitVRLittleEndian);
client.SendAssociateRequest(associate);
if (!client.Wait()) // wait for connection to finish
{
Debug.Fail("SendAssociateRequest timed out");
}
//
// Send Echo Request
//
byte pid = client.Association.FindAbstract(DicomUidType.VerificationClass);
client.SendCEchoRequest(pid, 1, DicomUidType.VerificationClass);
if (!client.Wait()) // wait for connection to finish
{
Debug.Fail("SendCEchoRequest timed out");
}
//
// SendReleaseRequest
//
client.SendReleaseRequest();
if (!client.Wait()) // wait for connection to finish
{
Debug.Fail("SendReleaseRequest timed out");
}
client.CloseForced(true);
}
server.CloseForced(true);
}
DicomEngine.Shutdown();
DicomNet.Shutdown();
}