Related
I try upload a file to an FTP-server with C#. The file is uploaded but with zero bytes.
private void button2_Click(object sender, EventArgs e)
{
var dirPath = #"C:/Documents and Settings/sander.GD/Bureaublad/test/";
ftp ftpClient = new ftp("ftp://example.com/", "username", "password");
string[] files = Directory.GetFiles(dirPath,"*.*");
var uploadPath = "/httpdocs/album";
foreach (string file in files)
{
ftpClient.createDirectory("/test");
ftpClient.upload(uploadPath + "/" + Path.GetFileName(file), file);
}
if (string.IsNullOrEmpty(txtnaam.Text))
{
MessageBox.Show("Gelieve uw naam in te geven !");
}
}
The existing answers are valid, but why re-invent the wheel and bother with lower level WebRequest types while WebClient already implements FTP uploading neatly:
using (var client = new WebClient())
{
client.Credentials = new NetworkCredential(ftpUsername, ftpPassword);
client.UploadFile("ftp://host/path.zip", WebRequestMethods.Ftp.UploadFile, localFile);
}
Easiest way
The most trivial way to upload a file to an FTP server using .NET framework is using WebClient.UploadFile method:
WebClient client = new WebClient();
client.Credentials = new NetworkCredential("username", "password");
var url = "ftp://ftp.example.com/remote/path/file.zip";
client.UploadFile(url, #"C:\local\path\file.zip");
Advanced options
If you need a greater control, that WebClient does not offer (like TLS/SSL encryption, ascii/text transfer mode, active mode, transfer resuming, progress monitoring, etc), use FtpWebRequest. Easy way is to just copy a FileStream to an FTP stream using Stream.CopyTo:
var url = "ftp://ftp.example.com/remote/path/file.zip";
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(url);
request.Credentials = new NetworkCredential("username", "password");
request.Method = WebRequestMethods.Ftp.UploadFile;
using (Stream fileStream = File.OpenRead(#"C:\local\path\file.zip"))
using (Stream ftpStream = request.GetRequestStream())
{
fileStream.CopyTo(ftpStream);
}
Progress monitoring
If you need to monitor an upload progress, you have to copy the contents by chunks yourself:
var url = "ftp://ftp.example.com/remote/path/file.zip";
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(url);
request.Credentials = new NetworkCredential("username", "password");
request.Method = WebRequestMethods.Ftp.UploadFile;
using (Stream fileStream = File.OpenRead(#"C:\local\path\file.zip"))
using (Stream ftpStream = request.GetRequestStream())
{
byte[] buffer = new byte[10240];
int read;
while ((read = fileStream.Read(buffer, 0, buffer.Length)) > 0)
{
ftpStream.Write(buffer, 0, read);
Console.WriteLine("Uploaded {0} bytes", fileStream.Position);
}
}
For GUI progress (WinForms ProgressBar), see C# example at:
How can we show progress bar for upload with FtpWebRequest
Uploading folder
If you want to upload all files from a folder, see
Upload directory of files to FTP server using WebClient.
For a recursive upload, see
Recursive upload to FTP server in C#
.NET 5 Guide
async Task<FtpStatusCode> FtpFileUploadAsync(string ftpUrl, string userName, string password, string filePath)
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpUrl);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(userName, password);
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
using (Stream requestStream = request.GetRequestStream())
{
await fileStream.CopyToAsync(requestStream);
}
using (FtpWebResponse response = (FtpWebResponse)await request.GetResponseAsync())
{
return response.StatusCode;
}
}
.NET Framework
public void UploadFtpFile(string folderName, string fileName)
{
FtpWebRequest request;
string folderName;
string fileName;
string absoluteFileName = Path.GetFileName(fileName);
request = WebRequest.Create(new Uri(string.Format(#"ftp://{0}/{1}/{2}", "127.0.0.1", folderName, absoluteFileName))) as FtpWebRequest;
request.Method = WebRequestMethods.Ftp.UploadFile;
request.UseBinary = 1;
request.UsePassive = 1;
request.KeepAlive = 1;
request.Credentials = new NetworkCredential(user, pass);
request.ConnectionGroupName = "group";
using (FileStream fs = File.OpenRead(fileName))
{
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
fs.Close();
Stream requestStream = request.GetRequestStream();
requestStream.Write(buffer, 0, buffer.Length);
requestStream.Flush();
requestStream.Close();
}
}
How to use
UploadFtpFile("testFolder", "E:\\filesToUpload\\test.img");
use this in your foreach
and you only need to create folder one time
to create a folder
request = WebRequest.Create(new Uri(string.Format(#"ftp://{0}/{1}/", "127.0.0.1", "testFolder"))) as FtpWebRequest;
request.Method = WebRequestMethods.Ftp.MakeDirectory;
FtpWebResponse ftpResponse = (FtpWebResponse)request.GetResponse();
The following works for me:
public virtual void Send(string fileName, byte[] file)
{
ByteArrayToFile(fileName, file);
var request = (FtpWebRequest) WebRequest.Create(new Uri(ServerUrl + fileName));
request.Method = WebRequestMethods.Ftp.UploadFile;
request.UsePassive = false;
request.Credentials = new NetworkCredential(UserName, Password);
request.ContentLength = file.Length;
var requestStream = request.GetRequestStream();
requestStream.Write(file, 0, file.Length);
requestStream.Close();
var response = (FtpWebResponse) request.GetResponse();
if (response != null)
response.Close();
}
You can't read send the file parameter in your code as it is only the filename.
Use the following:
byte[] bytes = File.ReadAllBytes(dir + file);
To get the file so you can pass it to the Send method.
public static void UploadFileToFtp(string url, string filePath, string username, string password)
{
var fileName = Path.GetFileName(filePath);
var request = (FtpWebRequest)WebRequest.Create(url + fileName);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = false;
using (var fileStream = File.OpenRead(filePath))
{
using (var requestStream = request.GetRequestStream())
{
fileStream.CopyTo(requestStream);
requestStream.Close();
}
}
var response = (FtpWebResponse)request.GetResponse();
Console.WriteLine("Upload done: {0}", response.StatusDescription);
response.Close();
}
In the first example must change those to:
requestStream.Flush();
requestStream.Close();
First flush and after that close.
This works for me,this method will SFTP a file to a location within your network.
It uses SSH.NET.2013.4.7 library.One can just download it for free.
//Secure FTP
public void SecureFTPUploadFile(string destinationHost,int port,string username,string password,string source,string destination)
{
ConnectionInfo ConnNfo = new ConnectionInfo(destinationHost, port, username, new PasswordAuthenticationMethod(username, password));
var temp = destination.Split('/');
string destinationFileName = temp[temp.Count() - 1];
string parentDirectory = destination.Remove(destination.Length - (destinationFileName.Length + 1), destinationFileName.Length + 1);
using (var sshclient = new SshClient(ConnNfo))
{
sshclient.Connect();
using (var cmd = sshclient.CreateCommand("mkdir -p " + parentDirectory + " && chmod +rw " + parentDirectory))
{
cmd.Execute();
}
sshclient.Disconnect();
}
using (var sftp = new SftpClient(ConnNfo))
{
sftp.Connect();
sftp.ChangeDirectory(parentDirectory);
using (var uplfileStream = System.IO.File.OpenRead(source))
{
sftp.UploadFile(uplfileStream, destinationFileName, true);
}
sftp.Disconnect();
}
}
publish date: 06/26/2018
https://learn.microsoft.com/en-us/dotnet/framework/network-programming/how-to-upload-files-with-ftp
using System;
using System.IO;
using System.Net;
using System.Text;
namespace Examples.System.Net
{
public class WebRequestGetExample
{
public static void Main ()
{
// Get the object used to communicate with the server.
FtpWebRequest request =
(FtpWebRequest)WebRequest.Create("ftp://www.contoso.com/test.htm");
request.Method = WebRequestMethods.Ftp.UploadFile;
// This example assumes the FTP site uses anonymous logon.
request.Credentials = new NetworkCredential("anonymous",
"janeDoe#contoso.com");
// Copy the contents of the file to the request stream.
byte[] fileContents;
using (StreamReader sourceStream = new StreamReader("testfile.txt"))
{
fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
}
request.ContentLength = fileContents.Length;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(fileContents, 0, fileContents.Length);
}
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
{
Console.WriteLine($"Upload File Complete, status
{response.StatusDescription}");
}
}
}
}
Best way I've found is FluentFtp
You can find the repo here:
https://github.com/robinrodricks/FluentFTP
and the quickstart example here:
https://github.com/robinrodricks/FluentFTP/wiki/Quick-Start-Example.
And actually the WebRequest class recommended by a few people here, is not recommended by Microsoft anymore, check out this page:
https://learn.microsoft.com/en-us/dotnet/api/system.net.webrequest?view=net-5.0
// create an FTP client and specify the host, username and password
// (delete the credentials to use the "anonymous" account)
FtpClient client = new FtpClient("123.123.123.123", "david", "pass123");
// connect to the server and automatically detect working FTP settings
client.AutoConnect();
// upload a file and retry 3 times before giving up
client.RetryAttempts = 3;
client.UploadFile(#"C:\MyVideo.mp4", "/htdocs/big.txt",
FtpRemoteExists.Overwrite, false, FtpVerify.Retry);
// disconnect! good bye!
client.Disconnect();
I have observed that -
FtpwebRequest is missing.
As the target is FTP, so the NetworkCredential required.
I have prepared a method that works like this, you can replace the value of the variable ftpurl with the parameter TargetDestinationPath. I had tested this method on winforms application :
private void UploadProfileImage(string TargetFileName, string TargetDestinationPath, string FiletoUpload)
{
//Get the Image Destination path
string imageName = TargetFileName; //you can comment this
string imgPath = TargetDestinationPath;
string ftpurl = "ftp://downloads.abc.com/downloads.abc.com/MobileApps/SystemImages/ProfileImages/" + imgPath;
string ftpusername = krayknot_DAL.clsGlobal.FTPUsername;
string ftppassword = krayknot_DAL.clsGlobal.FTPPassword;
string fileurl = FiletoUpload;
FtpWebRequest ftpClient = (FtpWebRequest)FtpWebRequest.Create(ftpurl);
ftpClient.Credentials = new System.Net.NetworkCredential(ftpusername, ftppassword);
ftpClient.Method = System.Net.WebRequestMethods.Ftp.UploadFile;
ftpClient.UseBinary = true;
ftpClient.KeepAlive = true;
System.IO.FileInfo fi = new System.IO.FileInfo(fileurl);
ftpClient.ContentLength = fi.Length;
byte[] buffer = new byte[4097];
int bytes = 0;
int total_bytes = (int)fi.Length;
System.IO.FileStream fs = fi.OpenRead();
System.IO.Stream rs = ftpClient.GetRequestStream();
while (total_bytes > 0)
{
bytes = fs.Read(buffer, 0, buffer.Length);
rs.Write(buffer, 0, bytes);
total_bytes = total_bytes - bytes;
}
//fs.Flush();
fs.Close();
rs.Close();
FtpWebResponse uploadResponse = (FtpWebResponse)ftpClient.GetResponse();
string value = uploadResponse.StatusDescription;
uploadResponse.Close();
}
Let me know in case of any issue, or here is one more link that can help you:
https://msdn.microsoft.com/en-us/library/ms229715(v=vs.110).aspx
I had my code to retrieve logged user details , every thing is OK but
i cannot retrieve the user image .
DirectorySearcher searcher = new DirectorySearcher();
searcher.SearchScope = SearchScope.Subtree;
searcher.Filter = string.Format(CultureInfo.InvariantCulture, "(sAMAccountName={0})", Environment.UserName);
//SearchResult findUser = searcher.FindOne();
foreach (SearchResult findUser in searcher.FindAll())
{
if (findUser != null)
{
DirectoryEntry user = findUser.GetDirectoryEntry();
string userName = user.Properties["displayName"].Value.ToString();
string departement = user.Properties["Department"].Value.ToString();
string title = user.Properties["title"].Value.ToString();
string[] rt = new string[] { Login, userName, Email, Mobile };
Lbl_User.Text = userName;
Lbl_Administrative.Text = departement;
Lbl_Position.Text = title;
}
}
I've just taken your code and made a method out of it just to retrieve the image. You would need to refactor it, to either get only the byte[] or thw whole image.
//add this
using System.Drawing;
static Image GetPhotoFromAD(string userName)
{
DirectorySearcher searcher = new DirectorySearcher();
searcher.SearchScope = SearchScope.Subtree;
searcher.Filter = string.Format(CultureInfo.InvariantCulture, "(sAMAccountName={0})", userName);
//SearchResult findUser = searcher.FindOne();
foreach (SearchResult findUser in searcher.FindAll())
{
if (findUser != null)
{
byte[] photodata = findUser.Properties["jpegPhoto"].Value as byte[];
using (MemoryStream str = new MemoryStream(photodata))
{
return Bitmap.FromStream(str);
}
}
}
}
If you only want the raw data, the important bit is byte[] photodata = user.Properties["jpegPhoto"].Value as byte[];
The binary image should be stored in property called thumbnailPhoto.
var photo = user.Properties["thumbnailPhoto"];
if (photo != null) {
byte[] buffer = (byte[])photo.Value;
//var bitmap = new Bitmap(new MemoryStream(buffer, false));
//bitmap.Save(#"c:\test.bmp");
}
Now, given the fact that you tagged question as asp.net you'll have to write generic handler (.ashx) for retrieving the image. This handler should write content of
photo.Value
into response output stream and set content type to image/bmp
In your control/page just reference the handler like
<img src="/GenericHandler.ashx" alt="My image" />
I'm using this tutorial https://web.archive.org/web/20211020001747/https://www.4guysfromrolla.com/articles/030211-1.aspx that’s uses a PDF template, lets the user input fields using textbox's. The file downloads onto the client’s pc but I would like to save a copy of the file into a sql database also or just save the file in the database instead of both.
protected void btnGeneratePDF_Click(object sender, EventArgs e)
{
var pdfPath = Path.Combine(Server.MapPath("~/PDFTemplates/fw9.pdf"));
// Get the form fields for this PDF and fill them in!
var formFieldMap = PDFHelper.GetFormFieldNames(pdfPath);
formFieldMap["topmostSubform[0].Page1[0].f1_01_0_[0]"] = txtName.Text;
formFieldMap["topmostSubform[0].Page1[0].f1_02_0_[0]"] = txtBusinessName.Text;
if (rblTaxClassification.SelectedValue != null)
{
var formFieldName = string.Format("topmostSubform[0].Page1[0].c1_01[{0}]", rblTaxClassification.SelectedIndex);
formFieldMap[formFieldName] = (rblTaxClassification.SelectedIndex + 1).ToString();
}
if (chkExemptPayee.Checked)
formFieldMap["topmostSubform[0].Page1[0].c1_01[7]"] = "8";
formFieldMap["topmostSubform[0].Page1[0].f1_04_0_[0]"] = txtAddress.Text;
formFieldMap["topmostSubform[0].Page1[0].f1_05_0_[0]"] = txtCityStateZIP.Text;
formFieldMap["topmostSubform[0].Page1[0].f1_07_0_[0]"] = txtAccountNumbers.Text;
// Requester's name and address (hard-coded)
formFieldMap["topmostSubform[0].Page1[0].f1_06_0_[0]"] = "Acme Website\n123 Anywhere Lane\nSpringfield, USA";
// SSN
if (!string.IsNullOrEmpty(txtSSN1.Text))
{
formFieldMap["topmostSubform[0].Page1[0].social[0].TextField1[0]"] = txtSSN1.Text;
formFieldMap["topmostSubform[0].Page1[0].social[0].TextField2[0]"] = txtSSN2.Text;
formFieldMap["topmostSubform[0].Page1[0].social[0].TextField2[1]"] = txtSSN3.Text;
}
else if (!string.IsNullOrEmpty(txtEIN1.Text))
{
formFieldMap["topmostSubform[0].Page1[0].social[0].TextField2[2]"] = txtEIN1.Text;
formFieldMap["topmostSubform[0].Page1[0].social[0].TextField2[3]"] = txtEIN2.Text;
}
var pdfContents = PDFHelper.GeneratePDF(pdfPath, formFieldMap);
PDFHelper.ReturnPDF(pdfContents, "Completed-W9.pdf");
FileStream fs = new FileStream(pdfPath, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
Byte[] bytes = br.ReadBytes((Int32)fs.Length);
br.Close();
fs.Close();
//insert the file into database
string strQuery = "insert into tblFiles(Name, ContentType, Data) values (#Name, #ContentType, #Data)";
SqlCommand cmd = new SqlCommand(strQuery);
cmd.Parameters.Add("#Name", SqlDbType.VarChar).Value = "Completed-W9132.pdf";
cmd.Parameters.Add("#ContentType", SqlDbType.VarChar).Value = "application/pdf";
cmd.Parameters.Add("#Data", SqlDbType.Binary).Value = bytes;
InsertUpdateData(cmd);
App_code/pdfHelper.cs
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Web;
using System.IO;
using iTextSharp.text.pdf;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
public class PDFHelper
{
public static Dictionary<string, string> GetFormFieldNames(string pdfPath)
{
var fields = new Dictionary<string, string>();
var reader = new PdfReader(pdfPath);
foreach (DictionaryEntry entry in reader.AcroFields.Fields)
fields.Add(entry.Key.ToString(), string.Empty);
reader.Close();
return fields;
}
public static byte[] GeneratePDF(string pdfPath, Dictionary<string, string> formFieldMap)
{
var output = new MemoryStream();
var reader = new PdfReader(pdfPath);
var stamper = new PdfStamper(reader, output);
var formFields = stamper.AcroFields;
foreach (var fieldName in formFieldMap.Keys)
formFields.SetField(fieldName, formFieldMap[fieldName]);
stamper.FormFlattening = true;
stamper.Close();
reader.Close();
return output.ToArray();
}
// See http://stackoverflow.com/questions/4491156/get-the-export-value-of-a-checkbox-using-itextsharp/
public static string GetExportValue(AcroFields.Item item)
{
var valueDict = item.GetValue(0);
var appearanceDict = valueDict.GetAsDict(PdfName.AP);
if (appearanceDict != null)
{
var normalAppearances = appearanceDict.GetAsDict(PdfName.N);
// /D is for the "down" appearances.
// if there are normal appearances, one key will be "Off", and the other
// will be the export value... there should only be two.
if (normalAppearances != null)
{
foreach (var curKey in normalAppearances.Keys)
if (!PdfName.OFF.Equals(curKey))
return curKey.ToString().Substring(1); // string will have a leading '/' character, so remove it!
}
}
// if that doesn't work, there might be an /AS key, whose value is a name with
// the export value, again with a leading '/', so remove it!
var curVal = valueDict.GetAsName(PdfName.AS);
if (curVal != null)
return curVal.ToString().Substring(1);
else
return string.Empty;
}
public static void ReturnPDF(byte[] contents)
{
ReturnPDF(contents, null);
}
public static void ReturnPDF(byte[] contents, string attachmentFilename)
{
var response = HttpContext.Current.Response;
if (!string.IsNullOrEmpty(attachmentFilename))
response.AddHeader("Content-Disposition", "attachment; filename=" + attachmentFilename);
response.ContentType = "application/pdf";
response.BinaryWrite(contents);
response.End();
}
}
The parts of the tutorial you're looking for in that case are right here:
Response.ContentType = "application/pdf";
Response.BinaryWrite(output.ToArray());
When saving a "file" to a database you essentially care about two (maybe three) things:
The byte array of the file contents
The type of the file
(Maybe a name for the file)
Since the tutorial concludes with two of these things (above), the type and the data, you can store these two things into your database however you need to store them. This depends on the database you're using, how you access that database, etc. Essentially to store these two things you just need a text column (varchar?) and a binary (or "blob") column (varbinary?).
The only difference is that instead of setting the type as a header in an HTTP response and writing the bytes to that HTTP response, you're using both of them as values in your database. Everything else is the same.
Currently i am doing a little project, the user registration password field is encrypted in the database, therefore I need to authenticate users using md5 algorithm also but my code is not working, whenever i try to input the correct password(unencrypted) it enters but later out i figured out that any password I type, the system will accept it even it doesn't matches in the database.
Can you help me? Here is my code:
protected void btnSubmit_Click(object sender, EventArgs e)
{
string pAssword = txtPassword.Text;
MD5CryptoServiceProvider encryptor = new MD5CryptoServiceProvider();
byte[] encryptedValue;
UTF8Encoding encoder = new UTF8Encoding();
encryptedValue = encryptor.ComputeHash(encoder.GetBytes(pAssword));
DataSet ds = new DataSet();
ds = (startWebService.getAllUsers());
if (ds.Tables[0].Rows.Count > 0)
{
foreach (DataRow dRow in ds.Tables[0].Rows)
{
string userName = dRow["UserName"].ToString();
string passWord = dRow["Password"].ToString();
string acctNo = dRow["AccountNumber"].ToString();
if (userName == txtUsername.Text.ToString() && acctNo == txtAcctNo.Text.ToString() && passWord == encryptedValue.ToString() )
{
FormsAuthentication.RedirectFromLoginPage(txtUsername.Text.ToString(), false);
lblError.Text = "You got it!";
Response.Redirect("MyAccount.aspx");
}
else
{
this.lblError.ForeColor = System.Drawing.Color.Red;
this.lblError.Text = "Either you have been type an incorrect network credentials or you have reached the maximum login attempts for your account.Please try again or contact the system administrator.";
startWebService.updateFailedLogin(txtAcctNo.Text.ToString(), txtUsername.Text.ToString());
}
}
}
}
my web services:
private DataSet GetDataSet(string strSPROC)
{
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = strSPROC;
conn.Open();
SqlDataAdapter myDataAdapter = new SqlDataAdapter();
myDataAdapter.SelectCommand = cmd;
DataSet dsMT = new DataSet();
myDataAdapter.Fill(dsMT);
return dsMT;
conn.Close();
}
[WebMethod]
public DataSet getAllUsers()
{
return GetDataSet("ELMS_ALLINTERNETUSERS");
}
Please help me, I have to correct this in a way that the system will accepts the correct equivalent of encrypted text for example I type: spain = wdhs3x9029 but i tried to type philippines , it accepts also.
There is a nice built-in method for hashing passwords (you can use MD5 with it):
string encryptedValue = FormsAuthentication.HashPasswordForStoringInConfigFile(pAssword, "MD5");
You can read more about this method here. If you need to reinvent the wheel, then I suggest you change your method of getting hash as string to something more like this:
MD5CryptoServiceProvider encryptor = new MD5CryptoServiceProvider();
UTF8Encoding encoder = new UTF8Encoding();
byte[] encryptedValueBytes = encryptor.ComputeHash(encoder.GetBytes(pAssword));
StringBuilder encryptedValueBuilder = new StringBuilder();
for (int i = 0; i < encryptedValueBytes.Length; i++)
{
encryptedValueBuilder.Append(data[i].ToString("x2"));
}
string encryptedValue = encryptedValueBuilder.ToString();
instead of simple .ToString() on byte array.
I need advice. I zip and crypt SOAP message on web service and client side.
Client is winforms app.
If I only crypt SOAP message, it works good.
If I only zip SOAP message it also works good.
I use SOAP extension on crypt and zip SOAP.
I use AES - Advanced Encryption Standard - Rijndael and on compresion I use SharpZipLib from http://sourceforge.net/projects/sharpdevelop/.
The problem is I send dataset on client.
Firstly I zip and secondly encrypt SOAP on web service side.
Send on client.
On client side I load XML from stream. But it finish with this error :
Data at the root level is invalid. Line 1, position 2234.
Here is the code, where I load XML from stream:
var doc = new XmlDocument();
using (var reader = new XmlTextReader(inputStream))
{
doc.Load(reader);
}
Any advice ? Thank you...
Here are methods on web service side which zip and crypt SOAP :
//encrypt string
private static string EncryptString(string #string, string initialVector, string salt, string password,
string hashAlgorithm, int keySize, int passwordIterations)
{
byte[] initialVectorBytes = Encoding.ASCII.GetBytes(initialVector);
byte[] saltValueBytes = Encoding.ASCII.GetBytes(salt);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(#string);
var derivedPassword = new PasswordDeriveBytes(password, saltValueBytes, hashAlgorithm, passwordIterations);
byte[] keyBytes = derivedPassword.GetBytes(keySize / 8);
var symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initialVectorBytes);
using (var memStream = new MemoryStream())
{
var cryptoStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write);
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
var serializer = new XmlSerializer(typeof(byte[]));
var sb = new StringBuilder();
TextWriter writer = new StringWriter(sb);
serializer.Serialize(writer, memStream.ToArray());
writer.Flush();
var doc = new XmlDocument();
doc.LoadXml(sb.ToString());
if (doc.DocumentElement != null) return doc.DocumentElement.InnerXml;
}
return "";
}
//zip string
private static byte[] ZipArray(string stringToZip)
{
byte[] inputByteArray = Encoding.UTF8.GetBytes(stringToZip);
var ms = new MemoryStream();
// SharpZipLib.Zip,
var zipOut = new ZipOutputStream(ms);
var zipEntry = new ZipEntry("ZippedFile");
zipOut.PutNextEntry(zipEntry);
zipOut.SetLevel(7);
zipOut.Write(inputByteArray, 0, inputByteArray.Length);
zipOut.Finish();
zipOut.Close();
return ms.ToArray();
}
//zip and encrypt SOAP
public virtual Stream OutSoap(string[] soapElement, Stream inputStream)
{
#region Load XML from SOAP
var doc = new XmlDocument();
using (XmlReader reader = XmlReader.Create(inputStream))
{
doc.Load(reader);
}
var nsMan = new XmlNamespaceManager(doc.NameTable);
nsMan.AddNamespace("soap",
"http://schemas.xmlsoap.org/soap/envelope/");
#endregion Load XML from SOAP
#region Zip SOAP
XmlNode bodyNode = doc.SelectSingleNode(#"//soap:Body", nsMan);
bodyNode = bodyNode.FirstChild.FirstChild;
while (bodyNode != null)
{
if (bodyNode.InnerXml.Length > 0)
{
// Zip
byte[] outData = ZipArray(bodyNode.InnerXml);
bodyNode.InnerXml = Convert.ToBase64String(outData);
}
bodyNode = bodyNode.NextSibling;
}
#endregion Zip SOAP
#region Crypt SOAP
foreach (string xPathQuery in soapElement)
{
XmlNodeList nodesToEncrypt = doc.SelectNodes(xPathQuery, nsMan);
if (nodesToEncrypt != null)
foreach (XmlNode nodeToEncrypt in nodesToEncrypt)
{
//Encrypt
nodeToEncrypt.InnerXml = EncryptString(nodeToEncrypt.InnerXml,
user.IV, user.Salt, user.Password, user.HashType,
user.KeySize, user.PasswordIterations);
}
}
#endregion Crypt SOAP
inputStream.Position = 0;
var settings = new XmlWriterSettings { Encoding = Encoding.UTF8 };
using (XmlWriter writer = XmlWriter.Create(inputStream, settings))
{
doc.WriteTo(writer);
return inputStream;
}
}
Here is a code on client side which decrypt and uzip SOAP :
//decrypt string
private static string DecryptString(string #string, string initialVector, string salt, string password,
string hashAlgorithm, int keySize, int passwordIterations)
{
byte[] initialVectorBytes = Encoding.ASCII.GetBytes(initialVector);
byte[] saltValueBytes = Encoding.ASCII.GetBytes(salt);
byte[] cipherTextBytes = Convert.FromBase64String(#string);
var derivedPassword = new PasswordDeriveBytes(password, saltValueBytes, hashAlgorithm, passwordIterations);
byte[] keyBytes = derivedPassword.GetBytes(keySize / 8);
var symmetricKey = new RijndaelManaged { Mode = CipherMode.CBC };
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initialVectorBytes);
using (var memStream = new MemoryStream(cipherTextBytes))
{
var cryptoStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Read);
var plainTextBytes = new byte[cipherTextBytes.Length];
int byteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
return Encoding.UTF8.GetString(plainTextBytes, 0, byteCount);
}
}
//unzip string
private static byte[] UnzipArray(string stringToUnzip)
{
byte[] inputByteArray = Convert.FromBase64String(stringToUnzip);
var ms = new MemoryStream(inputByteArray);
var ret = new MemoryStream();
// SharpZipLib.Zip
var zipIn = new ZipInputStream(ms);
var theEntry = zipIn.GetNextEntry();
var buffer = new Byte[2048];
int size = 2048;
while (true)
{
size = zipIn.Read(buffer, 0, buffer.Length);
if (size > 0)
{
ret.Write(buffer, 0, size);
}
else
{
break;
}
}
return ret.ToArray();
}
public virtual Stream InSoap(Stream inputStream, string[] soapElement)
{
#region Load XML from SOAP
var doc = new XmlDocument();
using (var reader = new XmlTextReader(inputStream))
{
doc.Load(reader);
}
var nsMan = new XmlNamespaceManager(doc.NameTable);
nsMan.AddNamespace("soap",
"http://schemas.xmlsoap.org/soap/envelope/");
#endregion Load XML from SOAP
#region Decrypt SOAP
foreach (string xPathQuery in soapElement)
{
XmlNodeList nodesToEncrypt = doc.SelectNodes(xPathQuery, nsMan);
if (nodesToEncrypt != null)
foreach (XmlNode nodeToEncrypt in nodesToEncrypt)
{
nodeToEncrypt.InnerXml = DecryptString(nodeToEncrypt.InnerXml, saltPhrase, passwordPhrase, initialVector,
hashAlgorithm, passwordIterations, keySize);
}
}
#endregion Decrypt SOAP
#region UnZip SOAP
XmlNode node = doc.SelectSingleNode("//soap:Body", nsMan);
node = node.FirstChild.FirstChild;
while (node != null)
{
if (node.InnerXml.Length > 0)
{
byte[] outData = UnzipArray(node.InnerXml);
string sTmp = Encoding.UTF8.GetString(outData);
node.InnerXml = sTmp;
}
node = node.NextSibling;
}
#endregion UnZip SOAP
var retStream = new MemoryStream();
doc.Save(retStream);
return retStream;
}
strong text
I'm not sure why your unencrypted xml won't parse, but I think you're first step should be to dump the decrypted data to the terminal to see exactly what text you're getting back. Perhaps the process corrupts your data somehow, or you have an encoding issue.
Alternatively, you could configure your server to use https and gzip compression to achieve the same goal. You won't loose any security with this approach and this is by far the more standard way to do things. You can also have a look at MS's support for the WS-Security standard