Click here to Skip to main content
15,886,519 members
Articles / Programming Languages / C#
Article

An FTP secure client library for C#

Rate me:
Please Sign up or sign in to vote.
4.61/5 (34 votes)
10 Dec 2008CPOL2 min read 492K   15.8K   135   106
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

C#
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

C#
//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

C#
//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:

C#
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)


Written By
Architect
Belgium Belgium
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralRe: Index Out of bounds Pin
Ed Hellyer Evosis LLC26-Feb-09 7:06
Ed Hellyer Evosis LLC26-Feb-09 7:06 
GeneralRe: Index Out of bounds Pin
mulengak27-Mar-09 3:10
mulengak27-Mar-09 3:10 
QuestionThe requested name is valid, but no data of the requested type was found Pin
dsac11-Feb-09 6:10
dsac11-Feb-09 6:10 
AnswerRe: The requested name is valid, but no data of the requested type was found Pin
kadaoui el mehdi11-Feb-09 21:19
kadaoui el mehdi11-Feb-09 21:19 
GeneralRe: The requested name is valid, but no data of the requested type was found Pin
210jim5-Mar-09 7:19
210jim5-Mar-09 7:19 
QuestiondownlodSecure? Pin
JohnDoe177-Feb-09 6:48
JohnDoe177-Feb-09 6:48 
AnswerRe: downlodSecure? Pin
kadaoui el mehdi7-Feb-09 23:31
kadaoui el mehdi7-Feb-09 23:31 
GeneralRe: downlodSecure? Pin
René André18-Feb-10 1:01
René André18-Feb-10 1:01 
Try the following code:

///
/// Download a file to the Assembly's local directory,
/// keeping the same file name.
///
///
public void downloadSecure(string remFileName)
{
    downloadSecure(remFileName, "", false);
}

///
/// Download a remote file to the Assembly's local directory,
/// keeping the same file name, and set the resume flag.
///
///
///
public void downloadSecure(string remFileName, Boolean resume)
{
    downloadSecure(remFileName, "", resume);
}

///
/// Download a remote file to a local file name which can include
/// a path. The local file name will be created or overwritten,
/// but the path must exist.
///
///
///
public void downloadSecure(string remFileName, string locFileName)
{
    downloadSecure(remFileName, locFileName, false);
}

///
/// Download a remote file to a local file name which can include
/// a path, and set the resume flag. The local file name will be
/// created or overwritten, but the path must exist.
///
///
///
///
public void downloadSecure(string remFileName, string locFileName, Boolean resume)
{
    if (!logined)
    {
        login();
    }

    setBinaryMode(true);

    sendCommand("PBSZ 0");
    sendCommand("PROT P");
    sendCommand("PASV");

    if (retValue != 227)
    {
        throw new IOException(reply.Substring(4));
    }

    Console.WriteLine("Downloading file " + remFileName + " from " + remoteHost + "/" + remotePath);

    if (locFileName.Equals(""))
    {
        locFileName = remFileName;
    }

    if (!File.Exists(locFileName))
    {
        Stream st = File.Create(locFileName);
        st.Close();
    }

    FileStream output;
    if (resume)
    {
        output = new FileStream(locFileName, FileMode.Open);
    }
    else
    {
        output = new FileStream(locFileName, FileMode.Truncate);
    }

    Socket cSocket = createDataSocket();
    isUpload = false;
    this.getSslDataStream(cSocket);

    long offset = 0;

    if (resume)
    {

        offset = output.Length;

        if (offset > 0)
        {
            sendCommand("REST " + offset);
            if (retValue != 350)
            {
                //throw new IOException(reply.Substring(4));
                //Some servers may not support resuming.
                offset = 0;
            }
        }

        if (offset > 0)
        {
            if (debug)
            {
                Console.WriteLine("seeking to " + offset);
            }
            long npos = output.Seek(offset, SeekOrigin.Begin);
            Console.WriteLine("new pos=" + npos);
        }
    }

    sendCommand("RETR " + remFileName);
    stream2.AuthenticateAsClient(
        remoteHost,
        null,
        System.Security.Authentication.SslProtocols.Ssl3 |
        System.Security.Authentication.SslProtocols.Tls,
        true);

    if (stream2.IsAuthenticated)
    {
        if (!(retValue == 125 || retValue == 150))
        {
            throw new IOException(reply.Substring(4));
        }

        while (true)
        {

            bytes = stream2.Read(buffer, 0, buffer.Length);
            output.Write(buffer, 0, bytes);

            if (bytes <= 0)
            {
                break;
            }
        }
        output.Close();
    }
    if (cSocket.Connected)
    {
        cSocket.Close();
    }

    Console.WriteLine("");

    readReply();

    if (!(retValue == 226 || retValue == 250))
    {
        throw new IOException(reply.Substring(4));
    }

}


And don't forget to read the other posts containing
this.getSslDataStream(cSocket);


Chears
Generalprivate key issue Pin
flemingqin21-Jan-09 6:06
flemingqin21-Jan-09 6:06 
GeneralRe: private key issue Pin
kadaoui el mehdi21-Jan-09 21:13
kadaoui el mehdi21-Jan-09 21:13 
GeneralWorks like a charm Pin
TSNY20-Jan-09 5:04
TSNY20-Jan-09 5:04 
GeneralRe: Works like a charm Pin
kadaoui el mehdi21-Jan-09 21:09
kadaoui el mehdi21-Jan-09 21:09 
GeneralHangs Pin
Member 349382715-Dec-08 10:20
Member 349382715-Dec-08 10:20 
GeneralRe: Hangs [modified] Pin
kadaoui el mehdi15-Dec-08 21:07
kadaoui el mehdi15-Dec-08 21:07 
GeneralRe: Hangs Pin
kawie_45420-Apr-09 6:13
kawie_45420-Apr-09 6:13 
GeneralRe: Hangs Pin
brian64p27-Apr-09 3:18
brian64p27-Apr-09 3:18 
GeneralRe: Hangs [modified] Pin
sonnguyen7917-Jul-09 12:39
sonnguyen7917-Jul-09 12:39 
GeneralRe: Hangs Pin
freephone5-Jan-10 15:27
freephone5-Jan-10 15:27 

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

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