Click here to Skip to main content
11,639,922 members (66,086 online)
Click here to Skip to main content

An FTP secure client library for C#

, 10 Dec 2008 CPOL 231K 9.4K 124
Rate this:
Please Sign up or sign in to vote.
How to implement an FTP secure connection with an SSL stream class.

Introduction

The purpose of this article is to create a C # FTP client in Secure mode, so if you don’t have much knowledge of FTPS, I advise you to take a look at this: FTPS.

In the .NET Framework, to upload a file in FTPS mode, we generally use the FtpWebRequest class, but you can not send commands with « quote » arguments, and even if you search on the web, you will not find a concrete example of a secured C# FTP client.

It’s for those reasons I decided to create this article.

SSL Stream?

To send a socket in Secure Socket Layer (SSL) mode, we use the class System.Net.Security.SslStream.

Provides a stream used for client-server communication that uses the Secure Socket Layer (SSL) security protocol to authenticate the server and optionally the client”.

For more information, refer to MSDN.

Using the Code

1. Pre-Authenticate

FTPFactory ftp = new FTPFactory();
ftp.setDebug(true);
ftp.setRemoteHost(Settings.Default.TargetFtpSource);

//Connect to SSL Port (990)
ftp.setRemotePort(990);
ftp.loginWithoutUser();

//Send "AUTH SSL" Command
string cmd = "AUTH SSL";
ftp.sendCommand(cmd);

Before connecting to the FTP server in SSL mode, you have to define the 990 SSL port and send the « AUTH SSL » command authentication using SSL.

WelcomeFTPSecure.JPG

2. Create SSL Stream

//Create SSL Stream
ftp.getSslStream();
ftp.setUseStream(true);
//Login to FTP Secure
ftp.setRemoteUser(Settings.Default.TargetFtpSecureUser);
ftp.setRemotePass(Settings.Default.TargetFtpSecurePass);
ftp.login();

ftp.getSslStream() creates an SSL stream from client socket which will be used for exchange between the client and the server FTPS. Then, you have to enter a login and password to authenticate on the FTPS server.

Note: if the SSL stream is well established, then I display all the information about the server certificate.

CertificatInfos.JPG

3. Upload File

//Set ASCII Mode
ftp.setBinaryMode(false);

//Send Arguments if you want
//cmd = "site arg1 arg2";
//ftp.sendCommand(cmd);

//Upload file
ftp.uploadSecure(@"Filepath", false);

ftp.close();

Before uploading a file, you have to specify the mode: ftp.setBinaryMode(bool value).

  • value is false --> ASCII mode
  • value is true --> Binary mode

By default, it’s binary. Now, you upload the file using:

ftp.uploadSecure(@"Filepath", false)

Note: you can upload in non secured mode using ftp.upload().

Points of Interest

I learned how an SSL stream and the RAW FTP communication works between a client and an FTP server. Searching on the web, I found many who were stuck on the issue of SSL communication with an FTP server, so I hope this article will be of great help.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

kadaoui el mehdi
Architect
Belgium Belgium
in 2005, I started my career. Net and I could improve in this technology through the project WinFroms. Net 2.0 / MVC2 for "Nestle".

After obtaining my diploma MASTER "MBDS" from the University of Nice Sophia Anti-police, I left to Belguim to work as Expert .Net Analyst Developer.

Currently I specialize in architecture Asp.net to the lowest level.

Meanwhile I remain very active in the community. Net, I created the 1st community. Net Morocco "on Facebook and LinkedIn and twitter, called "Morocco .Net User Group (MONUG)"

You may also be interested in...

Comments and Discussions

 
Question_sslStream.AuthenticateAsClient hangout Pin
Member 1096598014-Mar-15 7:07
memberMember 1096598014-Mar-15 7:07 
QuestionException Pin
MehraRaj25-Dec-14 18:01
memberMehraRaj25-Dec-14 18:01 
GeneralBeware and use with caution Pin
Seva Zaslavsky11-Jul-14 2:03
memberSeva Zaslavsky11-Jul-14 2:03 
GeneralRe: Beware and use with caution Pin
Antonio Ripa1-Aug-14 11:05
memberAntonio Ripa1-Aug-14 11:05 
SuggestionAnother library to try if you have problems with this one.... Pin
gmagana29-Jan-14 13:37
membergmagana29-Jan-14 13:37 
QuestionAplication freezing after login method Pin
Member 194843914-Jan-14 8:45
memberMember 194843914-Jan-14 8:45 
Questionsftp Pin
King Ravi Kumar14-May-13 2:13
memberKing Ravi Kumar14-May-13 2:13 
QuestionDoes anyone have an implemenation example ? Pin
Member 979519322-Mar-13 8:24
memberMember 979519322-Mar-13 8:24 
QuestionAn unknown, invalid, or unsupported option or level was specified in a getsockopt or setsockopt call Pin
Member 982113318-Feb-13 8:26
memberMember 982113318-Feb-13 8:26 
QuestionHow to run this program. Pin
Member 982113318-Feb-13 8:05
memberMember 982113318-Feb-13 8:05 
QuestionFTPS - Connecting to the server through proxy Pin
Member 251419017-Jan-13 21:19
memberMember 251419017-Jan-13 21:19 
QuestionWhy is the SslStream object stuff commented out? Is this truly FTP over SSL without that? Pin
andegre16-Aug-12 8:31
memberandegre16-Aug-12 8:31 
QuestionDir not working with secure Pin
Big D30-May-12 7:47
memberBig D30-May-12 7:47 
AnswerAre you having issues uploading and downloading files? Pin
Member 76555695-Apr-12 11:09
memberMember 76555695-Apr-12 11:09 
The IBM FTP server I was using this class to access was freezing when trying to upload or download files. It froze on the _sslStream.AuthenticateAsClient function. The issue turned out to be the sequence of commands sent to the server. On the IBM FTP server you have to send the RETR/STOR commands first thing after creating the data transfer socket before you call the function to create the secure stream. I've edited the class a bit, but here are the revised upload and download functions I use that work with the IBM FTP server:

NOTE: The functionality to resume has been removed because our server doesn't support it. Also, you may notice the outDelegate. This is the function used to output. You can set it to any function that returns void and takes a string (Ex: Console.WriteLine).

        /// <summary>
        /// Upload a file to the server
        /// </summary>
        /// <param name="fileName">The file name (including path) of the local file to upload</param>
        /// <returns>True if successful, False otherwise</returns>
        public bool Upload(string fileName)
        {
            // If we aren't logged in already
            if (!loggedIn)
            {
                Login(); // Login
            }
 
            // Create the data socket and attempt to connect
            Socket cSocket = createDataSocket();
            isData = true;
 
            if (outDelegate != null)
            {
                outDelegate("Data Socket Connected: " + cSocket.Connected.ToString());
                if (appendNewLines)
                    outDelegate("\n");
            }
 
            // Send the store command to the server
            sendCommand("STOR " + Path.GetFileName(fileName));
 
            if (!(retValue == 125 || retValue == 150))
            {
                if (outDelegate != null)
                {
                    outDelegate("Error: Bad response from server during upload: " + reply);
                    if (appendNewLines)
                        outDelegate("\n");
                }
                return false;
            }
 
            // If we were able to secure the stream
            if (getSslStream(cSocket))
            {
                // Id the data socket is connected
                if (cSocket.Connected)
                {
                    byte[] bufferFile = null;
                    try
                    {
                        // Open the local file for reading
                        FileStream input = File.OpenRead(fileName);
                        if (outDelegate != null)
                        {
                            outDelegate("Uploading file " + fileName + " to " + remoteDir);
                            if (appendNewLines)
                                outDelegate("\n");
                        }
 
                        while (true)
                        {
                            bufferFile = new byte[BLOCK_SIZE];
 
                            int bytes = input.Read(bufferFile, 0, bufferFile.Length); // Fill the buffer with the file
                            dataStream.Write(bufferFile, 0, bufferFile.Length); // Write the buffer to the server using the secure stream

                            // If we read less bytes than the file had left, we reached the end of the file
                            if (bytes < bufferFile.Length)
                            {
                                break;
                            }
                        }
 
                        // Close the local file
                        input.Close();
 
                        if (outDelegate != null)
                        {
                            outDelegate("File successfully uploaded");
                            if (appendNewLines)
                                outDelegate("\n");
                        }
                    }
                    catch (Exception ex)
                    {
                        if (outDelegate != null)
                        {
                            outDelegate("Error uploading file: " + ex.Message);
                            if (appendNewLines)
                                outDelegate("\n");
                        }
                        return false;
                    }
                }
 
                // Close the secure stream
                dataStream.Close();
            }
 
            // If the socket is still connected, close it
            if (cSocket.Connected)
            {
                cSocket.Close();
            }
 
            // Read and check the reply
            readReply();
            if (!(retValue == 226 || retValue == 250))
            {
                if (outDelegate != null)
                {
                    outDelegate("Error: Bad response from server during upload: " + reply);
                    if (appendNewLines)
                        outDelegate("\n");
                }
                return false;
            }
 
            isData = false;
            return true;
        }
 
        /// <summary>
        /// Downloads a file from the server
        /// </summary>
        /// <param name="remFileName">Filename of the file on the server</param>
        /// <param name="locFileName">Filename (with path) of the local file</param>
        /// <returns>True if successful, False otherwise</returns>
        public bool Download(string remFileName, string locFileName = null)
        {
            // If we aren't logged in, do so now
            if (!loggedIn)
            {
                Login();
            }
 
            isData = true;
 
            // If the local file isn't set, default it to be the same name as the server's file name
            if (locFileName == null || locFileName.Equals(""))
            {
                locFileName = remFileName;
            }
 
            try
            {
                // Create or open the local file for writing
                FileStream output = new FileStream(locFileName, FileMode.OpenOrCreate, FileAccess.Write);
 
                // Create the data socket
                Socket cSocket = createDataSocket();
 
                // Send the retrieve command to the server
                sendCommand("RETR " + remFileName);
 
                if (!(retValue == 150 || retValue == 125))
                {
                    if (outDelegate != null)
                    {
                        outDelegate("Error: Bad response from server during download: " + reply);
                        if (appendNewLines)
                            outDelegate("\n");
                    }
                    return false;
                }
 
                // Secure the stream
                this.getSslStream(cSocket);
 
                if (cSocket.Connected)
                {
                    if (outDelegate != null)
                    {
                        outDelegate("Downloading file " + remFileName + " from " + remoteHost);
                        if (appendNewLines)
                            outDelegate("\n");
                    }
 
                    byte[] downBuffer = new byte[1024];
                    int len;
                    // Read the file from the server and write it to the local file
                    while ((len = dataStream.Read(downBuffer, 0, downBuffer.Length)) > 0)
                    {
                        output.Write(downBuffer, 0, len);
                    }
 
                    dataStream.Close();
                }
 
                // Close everything
                output.Close();
                if (cSocket.Connected)
                {
                    cSocket.Close();
                }
 
                // Read the reply
                readReply();
                if (!(retValue == 226 || retValue == 250))
                {
                    if (outDelegate != null)
                    {
                        outDelegate("Error: Bad response from server during download: " + reply);
                        if (appendNewLines)
                            outDelegate("\n");
                    }
                    return false;
                }
            }
            catch (Exception ex)
            {
                if (outDelegate != null)
                {
                    outDelegate("Error downloading file: " + ex.Message);
                    if (appendNewLines)
                        outDelegate("\n");
                }
                return false;
            }
 
            if (outDelegate != null)
            {
                outDelegate("Download Complete");
                if (appendNewLines)
                    outDelegate("\n");
            }
 
            isData = false;
            return true;
        }

GeneralRe: Are you having issues uploading and downloading files? Pin
gmagana29-Jan-14 11:26
membergmagana29-Jan-14 11:26 
QuestionIndex and length must refer to a location within the string.\r\nParameter name: length Pin
Member 84911326-Mar-12 21:56
memberMember 84911326-Mar-12 21:56 
QuestionNo port 990 Pin
Member 855570311-Jan-12 7:02
memberMember 855570311-Jan-12 7:02 
AnswerRe: No port 990 Pin
bob mourning2-Mar-12 2:49
memberbob mourning2-Mar-12 2:49 
Questionneeds your helps Pin
Jacob P Yamarthi18-Oct-11 21:53
memberJacob P Yamarthi18-Oct-11 21:53 
AnswerRe: needs your helps Pin
Member 76555695-Apr-12 10:57
memberMember 76555695-Apr-12 10:57 
GeneralRe: needs your helps Pin
volax12-Feb-13 5:39
membervolax12-Feb-13 5:39 
QuestionUpload File - Nothing Happens Pin
Sergio Marchetti22-Aug-11 12:04
memberSergio Marchetti22-Aug-11 12:04 
AnswerRe: Upload File - Nothing Happens Pin
Member 76555695-Apr-12 10:56
memberMember 76555695-Apr-12 10:56 
QuestionCannot Upload File Pin
luis hernandez11-Aug-11 9:20
memberluis hernandez11-Aug-11 9:20 
AnswerRe: Cannot Upload File Pin
Member 76555695-Apr-12 10:56
memberMember 76555695-Apr-12 10:56 
QuestionError: A non-blocking socket operation could not be completed immediately Pin
bigMoey27-Jun-11 18:29
memberbigMoey27-Jun-11 18:29 
GeneralI can not run this project. Pin
wertyk12-May-11 3:16
memberwertyk12-May-11 3:16 
GeneralRe: I can not run this project. Pin
kadaoui el mehdi12-May-11 6:24
memberkadaoui el mehdi12-May-11 6:24 
GeneralRe: I can not run this project. Pin
wertyk12-May-11 20:25
memberwertyk12-May-11 20:25 
GeneralRe: I can not run this project. Pin
kadaoui el mehdi12-May-11 21:58
memberkadaoui el mehdi12-May-11 21:58 
QuestionError on ftp.loginWihtoutUser Pin
jayson pryde28-Oct-10 11:45
memberjayson pryde28-Oct-10 11:45 
AnswerRe: Error on ftp.loginWihtoutUser Pin
gyingLiow9-Apr-13 20:15
membergyingLiow9-Apr-13 20:15 
GeneralOriginal FTPFactory.cs written by Jaimon Mathew. Pin
JulianPo23-Nov-09 5:40
memberJulianPo23-Nov-09 5:40 
General"An existing connection was forcibly closed by the remote host." [modified] Pin
Hoang dinh Trung18-Nov-09 21:43
memberHoang dinh Trung18-Nov-09 21:43 
GeneralRe: "An existing connection was forcibly closed by the remote host." Pin
kadaoui el mehdi19-Nov-09 1:06
memberkadaoui el mehdi19-Nov-09 1:06 
GeneralRe: "An existing connection was forcibly closed by the remote host." Pin
Hoang dinh Trung19-Nov-09 19:37
memberHoang dinh Trung19-Nov-09 19:37 
GeneralRe: "An existing connection was forcibly closed by the remote host." Pin
kadaoui el mehdi19-Nov-09 20:43
memberkadaoui el mehdi19-Nov-09 20:43 
GeneralRe: "An existing connection was forcibly closed by the remote host." Pin
Hoang dinh Trung21-Nov-09 4:21
memberHoang dinh Trung21-Nov-09 4:21 
GeneralRe: "An existing connection was forcibly closed by the remote host." Pin
kadaoui el mehdi24-Nov-09 21:02
memberkadaoui el mehdi24-Nov-09 21:02 
GeneralRe: "An existing connection was forcibly closed by the remote host." Pin
mdbaskaran30-Dec-09 9:55
membermdbaskaran30-Dec-09 9:55 
GeneralRe: "An existing connection was forcibly closed by the remote host." Pin
SonnyDude13-Jul-10 21:11
memberSonnyDude13-Jul-10 21:11 
GeneralGetting a file listing returning odd characters Pin
hankgrav16-Nov-09 7:40
memberhankgrav16-Nov-09 7:40 
GeneralRe: Getting a file listing returning odd characters Pin
kadaoui el mehdi16-Nov-09 9:20
memberkadaoui el mehdi16-Nov-09 9:20 
GeneralRe: Getting a file listing returning odd characters Pin
hankgrav16-Nov-09 9:26
memberhankgrav16-Nov-09 9:26 
GeneralRe: Getting a file listing returning odd characters Pin
kadaoui el mehdi16-Nov-09 9:47
memberkadaoui el mehdi16-Nov-09 9:47 
GeneralRe: Getting a file listing returning odd characters Pin
hankgrav16-Nov-09 9:56
memberhankgrav16-Nov-09 9:56 
GeneralRe: Getting a file listing returning odd characters Pin
kadaoui el mehdi19-Nov-09 1:11
memberkadaoui el mehdi19-Nov-09 1:11 
GeneralRe: Getting a file listing returning odd characters Pin
Member 1044694019-Jan-14 23:57
memberMember 1044694019-Jan-14 23:57 
GeneralDuring PASV I get: 500 You need to use a client supporting PRET (PRE Transfer) to use PASV Pin
AndreasLink14-Nov-09 3:56
memberAndreasLink14-Nov-09 3:56 
GeneralRe: During PASV I get: 500 You need to use a client supporting PRET (PRE Transfer) to use PASV Pin
AndreasLink14-Nov-09 4:23
memberAndreasLink14-Nov-09 4:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.150731.1 | Last Updated 10 Dec 2008
Article Copyright 2008 by kadaoui el mehdi
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid