Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Cryptograhic error on FTP upload?

Status
Not open for further replies.

envisiondesign

Programmer
Jan 25, 2005
9
US
I am being asked to support an app written in C# that I know very little about. I believe it was intended for .NET 2.

This app creates a file(internal local server), encrypts it (GNUPG)(internal local server) and FTPs it to a server (external).

When we were with vendor A everything worked. That was until Oct 07

We have a new vendor now and when we run the app we get this error.

CryptographicException: Length of the data to decrypt is invalid.

The file gets created and encypted just fine (if we manually send it, they can read it fine) and if I comment out the part where the ftp "do upload" occurs I get no error.

Unfortunately, I have very little understanding of the details of what's going on at this level.

Thoughts?

If you choose not to decide you still have made a choice; choose life.
 
You're going to need to give a lot more information than that. And possibly some code, and what you are using to do the actual FTP'ing.

[small]----signature below----[/small]
Majority rule don't work in mental institutions

My Crummy Web Page
 
Here is the FTPLib.cs code. I think the failure is in the DoUpload portion.

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;

namespace FTPLib
{
public class FTP
{
#region Public Variables

/// <summary>
/// IP address or hostname to connect to
/// </summary>
public string server;
/// <summary>
/// Username to login as
/// </summary>
public string user;
/// <summary>
/// Password for account
/// </summary>
public string pass;
/// <summary>
/// Port number the FTP server is listening on
/// </summary>
public int port;
/// <summary>
/// The timeout (miliseconds) for waiting on data to arrive
/// </summary>
public int timeout;
/// <summary>
/// FTP log file directory
/// </summary>
public string logFileDirectory;
/// <summary>
/// FTP log file name
/// </summary>
public string logFile;

#endregion

#region Private Variables

private string messages; // server messages
private string responseStr; // server response if the user wants it.
private bool passive_mode; // #######################################
private long bytes_total; // upload/download info if the user wants it.
private long file_size; // gets set when an upload or download takes place
private Socket main_sock;
private IPEndPoint main_ipEndPoint;
private Socket listening_sock;
private Socket data_sock;
private IPEndPoint data_ipEndPoint;
private FileStream file;
private int response;
private string bucket;

#endregion

#region Constructors
/// <summary>
/// Constructor
/// </summary>
public FTP()
{
server = null;
user = null;
pass = null;
port = 21;
logFileDirectory = null;
logFile = null;
passive_mode = true; // #######################################
main_sock = null;
main_ipEndPoint = null;
listening_sock = null;
data_sock = null;
data_ipEndPoint = null;
file = null;
bucket = "";
bytes_total = 0;
timeout = 10000; // 10 seconds
messages = "";
}
#endregion

/// <summary>
/// Connection status to the server
/// </summary>
public bool IsConnected
{
get
{
if (main_sock != null)
return main_sock.Connected;
return false;
}
}
/// <summary>
/// Returns true if the message buffer has data in it
/// </summary>
public bool MessagesAvailable
{
get
{
if(messages.Length > 0)
return true;
return false;
}
}
/// <summary>
/// Server messages if any, buffer is cleared after you access this property
/// </summary>
public string Messages
{
get
{
string tmp = messages;
messages = "";
return tmp;
}
}
/// <summary>
/// The response string from the last issued command
/// </summary>
public string ResponseString
{
get
{
return responseStr;
}
}
/// <summary>
/// The total number of bytes sent/recieved in a transfer
/// </summary>
public long BytesTotal // #######################################
{
get
{
return bytes_total;
}
}
/// <summary>
/// The size of the file being downloaded/uploaded (Can possibly be 0 if no size is available)
/// </summary>
public long FileSize // #######################################
{
get
{
return file_size;
}
}
/// <summary>
/// True: Passive mode [default]
/// False: Active Mode
/// </summary>
public bool PassiveMode // #######################################
{
get
{
return passive_mode;
}
set
{
passive_mode = value;
}
}

private void Fail()
{
Disconnect();
throw new Exception(responseStr);
}
private void SetBinaryMode(bool mode)
{
if (mode)
SendCommand("TYPE I");
else
SendCommand("TYPE A");

ReadResponse();
if (response != 200)
Fail();
}
private void SendCommand(string command)
{
Byte[] cmd = Encoding.ASCII.GetBytes((command + "\r\n").ToCharArray());
//Byte[] cmd = Encoding.Unicode.GetBytes((command + "\r\n").ToCharArray());

#if (FTP_DEBUG)
if (command.Length > 3 && command.Substring(0, 4) == "PASS")
LogEvent("\rPASS xxx");
else
LogEvent("\r" + command);
#endif
main_sock.Send(cmd, cmd.Length, 0);
}
private void FillBucket()
{
Byte[] bytes = new Byte[512];
long bytesgot;
int msecs_passed = 0; // #######################################

while(main_sock.Available < 1)
{
System.Threading.Thread.Sleep(50);
msecs_passed += 50;
// this code is just a fail safe option
// so the code doesn't hang if there is
// no data comming.
if (msecs_passed > timeout)
{
Disconnect();
throw new Exception("Timed out waiting on server to respond.");
}
}

while(main_sock.Available > 0)
{
bytesgot = main_sock.Receive(bytes, 512, 0);
bucket += Encoding.ASCII.GetString(bytes, 0, (int)bytesgot);
// this may not be needed, gives any more data that hasn't arrived
// just yet a small chance to get there.
System.Threading.Thread.Sleep(50);
}
}
private string GetLineFromBucket()
{
int i;
string buf = "";

if ((i = bucket.IndexOf('\n')) < 0)
{
while(i < 0)
{
FillBucket();
i = bucket.IndexOf('\n');
}
}

buf = bucket.Substring(0, i);
bucket = bucket.Substring(i + 1);

return buf;
}
// Any time a command is sent, use ReadResponse() to get the response
// from the server. The variable responseStr holds the entire string and
// the variable response holds the response number.
private void ReadResponse()
{
string buf;
messages = "";

while(true)
{
//buf = GetLineFromBucket();
buf = GetLineFromBucket();

#if (FTP_DEBUG)
LogEvent(buf);
#endif
// the server will respond with "000-Foo bar" on multi line responses
// "000 Foo bar" would be the last line it sent for that response.
// Better example:
// "000-This is a multiline response"
// "000-Foo bar"
// "000 This is the end of the response"
if (Regex.Match(buf, "^[0-9]+ ").Success)
{
responseStr = buf;
response = int.Parse(buf.Substring(0, 3));
break;
}
else
messages += Regex.Replace(buf, "^[0-9]+-", "") + "\n";
}
}
// if you add code that needs a data socket, i.e. a PASV or PORT command required,
// call this function to do the dirty work. It sends the PASV or PORT command,
// parses out the port and ip info and opens the appropriate data socket
// for you. The socket variable is private Socket data_socket. Once you
// are done with it, be sure to call CloseDataSocket()
private void OpenDataSocket()
{
if (passive_mode) // #######################################
{
string[] pasv;
string server;
int port;

Connect();
SendCommand("PASV");
ReadResponse();
if (response != 227)
Fail();

try
{
int i1, i2;

i1 = responseStr.IndexOf('(') + 1;
i2 = responseStr.IndexOf(')') - i1;
pasv = responseStr.Substring(i1, i2).Split(',');
}
catch(Exception)
{
Disconnect();
throw new Exception("Malformed PASV response: " + responseStr);
}

if (pasv.Length < 6)
{
Disconnect();
throw new Exception("Malformed PASV response: " + responseStr);
}

server = String.Format("{0}.{1}.{2}.{3}", pasv[0], pasv[1], pasv[2], pasv[3]);
port = (int.Parse(pasv[4]) << 8) + int.Parse(pasv[5]);

try
{
#if (FTP_DEBUG)
LogEvent("Data socket: {0}:{1}" + server + " " + port);
#endif
CloseDataSocket();

#if (FTP_DEBUG)
LogEvent("Creating socket...");
#endif
data_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

#if (FTP_DEBUG)
LogEvent("Resolving host");
#endif

data_ipEndPoint = new IPEndPoint(Dns.GetHostByName(server).AddressList[0], port);


#if (FTP_DEBUG)
LogEvent("Connecting..");
#endif
data_sock.Connect(data_ipEndPoint);

#if (FTP_DEBUG)
LogEvent("Connected.");
#endif
}
catch(Exception ex)
{
throw new Exception("Failed to connect for data transfer: " + ex.Message);
}
}
else // #######################################
{
Connect();

try
{
#if (FTP_DEBUG)
LogEvent("Data socket (active mode)");
#endif
CloseDataSocket();

#if (FTP_DEBUG)
LogEvent("Creating listening socket...");
#endif
listening_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

#if (FTP_DEBUG)
LogEvent("Binding it to local address/port");
#endif
// for the PORT command we need to send our IP address; let's extract it
// from the LocalEndPoint of the main socket, that's already connected
string sLocAddr = main_sock.LocalEndPoint.ToString();
int ix = sLocAddr.IndexOf(':');
if (ix < 0)
{
throw new Exception("Failed to parse the local address: " + sLocAddr);
}
string sIPAddr = sLocAddr.Substring(0, ix);
// let the system automatically assign a port number (setting port = 0)
System.Net.IPEndPoint localEP = new IPEndPoint(IPAddress.Parse(sIPAddr), 0);

listening_sock.Bind(localEP);
sLocAddr = listening_sock.LocalEndPoint.ToString();
ix = sLocAddr.IndexOf(':');
if (ix < 0)
{
throw new Exception("Failed to parse the local address: " + sLocAddr);
}
int nPort = int.Parse(sLocAddr.Substring(ix + 1));
#if (FTP_DEBUG)
LogEvent("Listening on {0}:{1}" + sIPAddr + " " + nPort);
#endif
// start to listen for a connection request from the host (note that
// Listen is not blocking) and send the PORT command
listening_sock.Listen(1);
string sPortCmd = string.Format("PORT {0},{1},{2}",
sIPAddr.Replace('.', ','),
nPort / 256, nPort % 256);
SendCommand(sPortCmd);
ReadResponse();
if (response != 200)
Fail();
}
catch(Exception ex)
{
throw new Exception("Failed to connect for data transfer: " + ex.Message);
}
}
}
private void ConnectDataSocket() // #######################################
{
if (data_sock != null) // already connected (always so if passive mode)
return;

try
{
#if (FTP_DEBUG)
LogEvent("Accepting the data connection.");
#endif
data_sock = listening_sock.Accept(); // Accept is blocking
listening_sock.Close();
listening_sock = null;

if (data_sock == null)
{
throw new Exception("Winsock error: " +
Convert.ToString(System.Runtime.InteropServices.Marshal.GetLastWin32Error()) );
}
#if (FTP_DEBUG)
LogEvent("Connected.");
#endif
}
catch(Exception ex)
{
throw new Exception("Failed to connect for data transfer: " + ex.Message);
}
}
private void CloseDataSocket()
{
#if (FTP_DEBUG)
LogEvent("Attempting to close data channel socket...");
#endif
if (data_sock != null)
{
if (data_sock.Connected)
{
#if (FTP_DEBUG)
LogEvent("Closing data channel socket!");
#endif
data_sock.Close();
#if (FTP_DEBUG)
LogEvent("Data channel socket closed!");
#endif
}
data_sock = null;
}

data_ipEndPoint = null;
}
private void LogEvent(string message)
{
if (logFileDirectory == "" || logFile == "") return;
if (!Directory.Exists(logFileDirectory)) Directory.CreateDirectory(logFileDirectory);
TextWriter tw = new StreamWriter(logFileDirectory + logFile, true);
tw.WriteLine(message);
tw.Close();
}
/// <summary>
/// Connect to an ftp server
/// </summary>
private void Connect()
{
if (server == null)
{
throw new Exception("No server has been set.");
}
else if (user == null)
{
throw new Exception("No username has been set.");
}
else if (main_sock != null)
if (main_sock.Connected) return;

main_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
main_ipEndPoint = new IPEndPoint(Dns.GetHostByName(server).AddressList[0], port);

try
{
main_sock.Connect(main_ipEndPoint);
}
catch (Exception ex)
{
LogEvent(ex.Message);
throw new Exception(ex.Message);
}

ReadResponse();
if (response != 220)
Fail();

SendCommand("USER " + user);
ReadResponse();

switch (response)
{
case 331:
if (pass == null)
{
Disconnect();
throw new Exception("No password has been set.");
}
SendCommand("PASS " + pass);
ReadResponse();
if (response != 230)
Fail();
break;
case 230:
break;
}
return;
}

/// <summary>
/// Closes all connections to the ftp server
/// </summary>
public void Disconnect()
{
try
{
CloseDataSocket();

if (main_sock != null)
{
if (main_sock.Connected)
{
SendCommand("QUIT");
main_sock.Close();
}
main_sock = null;
}

if (file != null)
file.Close();

main_ipEndPoint = null;
file = null;
}
catch (Exception ex)
{
LogEvent(ex.Message);
throw ex;
}
}
/// <summary>
/// Connect to a ftp server
/// </summary>
/// <param name="server">IP or hostname of the server to connect to</param>
/// <param name="port">Port number the server is listening on</param>
/// <param name="user">Account name to login as</param>
/// <param name="pass">Password for the account specified</param>
/// <param name="logFileDirectory">FTP log file directory</param>
/// <param name="logFile">FTP log file name</param>
public void Connect(string server, int port, string user, string pass, string logFileDirectory, string logFile)
{
this.server = server;
this.user = user;
this.pass = pass;
this.port = port;
this.logFileDirectory = logFileDirectory;
this.logFile = logFile;

try
{
Connect();
}
catch (Exception ex)
{
LogEvent(ex.Message);
throw ex;
}
}

/// <summary>
/// Retrieves a list of files from the ftp server
/// </summary>
/// <returns>An ArrayList of files</returns>
public ArrayList List()
{
try
{
Byte[] bytes = new Byte[512];
string file_list = "";
long bytesgot = 0;
int msecs_passed = 0;
ArrayList list = new ArrayList();

Connect();
OpenDataSocket();
SendCommand("LIST");
ReadResponse();

//FILIPE MADUREIRA.
//Added response 125
switch (response)
{
case 125:
case 150:
break;
default:
CloseDataSocket();
throw new Exception(responseStr);
}
ConnectDataSocket(); // #######################################

while (data_sock.Available < 1)
{
System.Threading.Thread.Sleep(50);
msecs_passed += 50;
// this code is just a fail safe option
// so the code doesn't hang if there is
// no data comming.
if (msecs_passed > (timeout / 10))
{
//CloseDataSocket();
//throw new Exception("Timed out waiting on server to respond.");

//FILIPE MADUREIRA.
//If there are no files to list it gives timeout.
//So I wait less time and if no data is received, means that there are no files
break;//Maybe there are no files
}
}

while (data_sock.Available > 0)
{
bytesgot = data_sock.Receive(bytes, bytes.Length, 0);
file_list += Encoding.ASCII.GetString(bytes, 0, (int)bytesgot);
System.Threading.Thread.Sleep(50); // *shrug*, sometimes there is data comming but it isn't there yet.
}

CloseDataSocket();

ReadResponse();
if (response != 226)
throw new Exception(responseStr);

foreach (string f in file_list.Split('\n'))
{
if (f.Length > 0 && !Regex.Match(f, "^total").Success)
list.Add(f.Substring(0, f.Length - 1));
}

return list;
}
catch (Exception ex)
{
LogEvent(ex.Message);
throw ex;
}
}
/// <summary>
/// Gets a file list only
/// </summary>
/// <returns>ArrayList of files only</returns>
public ArrayList ListFiles()
{
ArrayList list = new ArrayList();
try
{
foreach (string f in List())
{
//FILIPE MADUREIRA
//In Windows servers it is identified by <DIR>
if ((f.Length > 0))
{
if ((f[0] != 'd') && (f.ToUpper().IndexOf("<DIR>") < 0))
list.Add(f);
}
}
return list;
}
catch (Exception ex)
{
LogEvent(ex.Message);
throw ex;
}
}
/// <summary>
/// Gets a directory list only
/// </summary>
/// <returns>ArrayList of directories only</returns>
public ArrayList ListDirectories()
{
ArrayList list = new ArrayList();
try
{
foreach (string f in List())
{
//FILIPE MADUREIRA
//In Windows servers it is identified by <DIR>
if (f.Length > 0)
{
if ((f[0] == 'd') || (f.ToUpper().IndexOf("<DIR>") >= 0))
list.Add(f);
}
}
return list;
}
catch (Exception ex)
{
LogEvent(ex.Message);
throw ex;
}
}
/// <summary>
/// Get the size of a file (Provided the ftp server supports it)
/// </summary>
/// <param name="filename">Name of file</param>
/// <returns>The size of the file specified by filename</returns>
public long GetFileSize(string filename)
{
Connect();
SendCommand("SIZE " + filename);
ReadResponse();

if (response != 213)
{
#if (FTP_DEBUG)
LogEvent("\r" + responseStr);
#endif
throw new Exception(responseStr);
}
return Int64.Parse(responseStr.Substring(4));
}
/// <summary>
/// Open an upload with resume support
/// </summary>
/// <param name="filename">Local file to upload (Can include path to file)</param>
/// <param name="remote_filename">Filename to store file as on ftp server</param>
/// <param name="resume">Attempt resume if exists</param>
public void OpenUpload(string filename, string remote_filename, bool resume)
{
try
{
Connect();
SetBinaryMode(true);
OpenDataSocket();

bytes_total = 0;

try
{
file = new FileStream(filename, FileMode.Open);
}
catch (Exception ex)
{
file = null;
throw new Exception(ex.Message);
}

file_size = file.Length;

if (resume)
{
long size = GetFileSize(remote_filename);
SendCommand("REST " + size);
ReadResponse();
if (response == 350)
file.Seek(size, SeekOrigin.Begin);
}

SendCommand("STOR " + remote_filename);
ReadResponse();

switch (response)
{
case 125:
case 150:
break;
default:
file.Close();
file = null;
throw new Exception(responseStr);
}
ConnectDataSocket(); // #######################################

return;
}
catch (Exception ex)
{
LogEvent(ex.Message);
throw ex;
}
}
/// <summary>
/// Upload the file, to be used in a loop until file is completely uploaded
/// </summary>
/// <returns>Bytes sent</returns>
public long DoUpload()
{
Byte[] bytes = new Byte[512];
long bytes_got;

try
{
bytes_got = file.Read(bytes, 0, bytes.Length);
bytes_total += bytes_got;
data_sock.Send(bytes, (int)bytes_got, 0);

if(bytes_got <= 0)
{
// the upload is complete or an error occured
file.Close();
file = null;

CloseDataSocket();
ReadResponse();
switch(response)
{
case 226:
case 250:
break;
default:
throw new Exception(responseStr);
}

SetBinaryMode(false);
}
}
catch(Exception ex)
{
file.Close();
file = null;
CloseDataSocket();
ReadResponse();
SetBinaryMode(false);

LogEvent(ex.Message);
throw ex;
}

return bytes_got;
}
}
}

If you choose not to decide you still have made a choice; choose life.
 
foreach (string f in file_list.Split('\n'))
{
if (f.Length > 0 && !Regex.Match(f, "^total").Success)
list.Add(f.Substring(0, f.Length - 1));
}

return list;
}
catch (Exception ex)
{
LogEvent(ex.Message);
throw ex;
}
}
/// <summary>
/// Gets a file list only
/// </summary>
/// <returns>ArrayList of files only</returns>
public ArrayList ListFiles()
{
ArrayList list = new ArrayList();
try
{
foreach (string f in List())
{
//FILIPE MADUREIRA
//In Windows servers it is identified by <DIR>
if ((f.Length > 0))
{
if ((f[0] != 'd') && (f.ToUpper().IndexOf("<DIR>") < 0))
list.Add(f);
}
}
return list;
}
catch (Exception ex)
{
LogEvent(ex.Message);
throw ex;
}
}
/// <summary>
/// Gets a directory list only
/// </summary>
/// <returns>ArrayList of directories only</returns>
public ArrayList ListDirectories()
{
ArrayList list = new ArrayList();
try
{
foreach (string f in List())
{
//FILIPE MADUREIRA
//In Windows servers it is identified by <DIR>
if (f.Length > 0)
{
if ((f[0] == 'd') || (f.ToUpper().IndexOf("<DIR>") >= 0))
list.Add(f);
}
}
return list;
}
catch (Exception ex)
{
LogEvent(ex.Message);
throw ex;
}
}
/// <summary>
/// Get the size of a file (Provided the ftp server supports it)
/// </summary>
/// <param name="filename">Name of file</param>
/// <returns>The size of the file specified by filename</returns>
public long GetFileSize(string filename)
{
Connect();
SendCommand("SIZE " + filename);
ReadResponse();

if (response != 213)
{
#if (FTP_DEBUG)
LogEvent("\r" + responseStr);
#endif
throw new Exception(responseStr);
}
return Int64.Parse(responseStr.Substring(4));
}
/// <summary>
/// Open an upload with resume support
/// </summary>
/// <param name="filename">Local file to upload (Can include path to file)</param>
/// <param name="remote_filename">Filename to store file as on ftp server</param>
/// <param name="resume">Attempt resume if exists</param>
public void OpenUpload(string filename, string remote_filename, bool resume)
{
try
{
Connect();
SetBinaryMode(true);
OpenDataSocket();

bytes_total = 0;

try
{
file = new FileStream(filename, FileMode.Open);
}
catch (Exception ex)
{
file = null;
throw new Exception(ex.Message);
}

file_size = file.Length;

if (resume)
{
long size = GetFileSize(remote_filename);
SendCommand("REST " + size);
ReadResponse();
if (response == 350)
file.Seek(size, SeekOrigin.Begin);
}

SendCommand("STOR " + remote_filename);
ReadResponse();

switch (response)
{
case 125:
case 150:
break;
default:
file.Close();
file = null;
throw new Exception(responseStr);
}
ConnectDataSocket(); // #######################################

return;
}
catch (Exception ex)
{
LogEvent(ex.Message);
throw ex;
}
}
/// <summary>
/// Upload the file, to be used in a loop until file is completely uploaded
/// </summary>
/// <returns>Bytes sent</returns>
public long DoUpload()
{
Byte[] bytes = new Byte[512];
long bytes_got;

try
{
bytes_got = file.Read(bytes, 0, bytes.Length);
bytes_total += bytes_got;
data_sock.Send(bytes, (int)bytes_got, 0);

if(bytes_got <= 0)
{
// the upload is complete or an error occured
file.Close();
file = null;

CloseDataSocket();
ReadResponse();
switch(response)
{
case 226:
case 250:
break;
default:
throw new Exception(responseStr);
}

SetBinaryMode(false);
}
}
catch(Exception ex)
{
file.Close();
file = null;
CloseDataSocket();
ReadResponse();
SetBinaryMode(false);

LogEvent(ex.Message);
throw ex;
}

return bytes_got;
}
}
}

If you choose not to decide you still have made a choice; choose life.
 
Hmmmmmm.... sadly, I've had the best luck with DOS Scripts and FTP.

Can you step through your code and identify which line is creating the error specifically? Can you post the error and stacktrace?

 
uploads in ftp usually fail because the mode is set to ascii when it should be binary.

if DoUpload() is supposed to be used in a loop, why does it SetBinaryMode(false)?


mr s. <;)

 
answer: because it very helpfully closes the connection if it runs out of data.

so that's not it.


mr s. <;)

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top