/// <summary> /// Assumes no inital password /// </summary> /// <param name="fileName"></param> /// <param name="password"></param> /// <param name="encryption"></param> /// <param name="encryptionKeyLength"></param> /// <returns></returns> static public bool AddPasswordToZip(string fileName, string password, string encryption, string encryptionKeyLength) { if (VerifyPassword(fileName, password)) { return true; } using(var zip = new ZipWrapper()) { zip.OpenZip(fileName); zip.Encryption = 0; if (!string.IsNullOrEmpty(encryption)) // 'modern' zip encryption being used { try { zip.EncryptKeyLength = 128; if (!string.IsNullOrEmpty(encryptionKeyLength)) { zip.EncryptKeyLength = System.Convert.ToInt32(encryptionKeyLength); } zip.Encryption = System.Convert.ToInt32(encryption); } catch (FormatException) { zip.Encryption = 0; zip.EncryptKeyLength = 0; } } if (zip.Encryption == 0) // zip 2.0 encryption { zip.PasswordProtect = true; } zip.EncryptPassword = password; if (!zip.WriteZipAndClose()) { Logger.LogError(zip.LastErrorText); throw new Exception(String.Format("Failed adding password to zip {0}", fileName)); } return true; } }
/// <summary> /// Remove password from zip file /// </summary> /// <param name="fileName"></param> /// <param name="password"></param> /// <returns></returns> static public bool RemovePasswordFromZip(string fileName, string password) { // Poor mans version, extract entire zip and then read into a new one, but handles encrypted zips with empty folders in string tempDump = string.Empty; try { using (ZipWrapper zip = new ZipWrapper()) { zip.DecryptPassword = password; zip.OpenZip(fileName); tempDump = Path.Combine(Path.GetDirectoryName(fileName), Guid.NewGuid().ToString()); if (!zip.Extract(tempDump)) { Logger.LogError(zip.LastErrorText); throw new Exception(string.Format("Unable to extract {0] to {1}", fileName, tempDump)); } zip.CloseZip(); } System.IO.File.Delete(fileName); // Remove the original encrypted file // Now create a new zip without a password using (ZipWrapper zipDecrypted = new ZipWrapper()) { zipDecrypted.AppendFiles(tempDump, true); zipDecrypted.FileName = fileName; if (!zipDecrypted.WriteZipAndClose()) // Create a new decrypted zip { Logger.LogError(zipDecrypted.LastErrorText); throw new Exception("Failed trying to create decrypted version of: " + fileName); } } } finally { ForceDeleteDirectory(tempDump); } return true; //// Chilkat seems to have an issue with passworded zips containing empty folders, once password is removed(using below procedure that they outline in their samples //// http://www.example-code.com/csharp/zip_RemoveZipEncryption.asp) errors occur when trying to use the decrypted zip //// //// Also it seems to have issues with complex nesting, missing/not seeing files below the root after decryption //using (Chilkat.Zip zip = new Chilkat.Zip()) //{ // zip.UnlockComponent(Chilkat_Serial); // zip.DecryptPassword = password; // if (!zip.OpenZip(fileName)) // { // Logger.LogDebug("Unable to open: " + fileName); // Logger.LogDebug(zip.LastErrorText); // return false; // } // zip.Encryption = 0; // zip.PasswordProtect = false; // string tmpFile = Path.Combine(Path.GetDirectoryName(fileName), Guid.NewGuid().ToString() + ".zip"); // zip.FileName = tmpFile; // // From Chilkat:: // // Write the unencrypted .zip // // What happens during WriteZipAndClose? -- // // The encrypted entries from myEncrypted.zip are streamed in, // // decrypted, and then written out directly into unencrypted.zip // // In other words, internally the component is smart enough // // to stream the data from the existing .zip to the new .zip // // automatically, decrypting in the process.. // if (zip.WriteZipAndClose()) // { // Logger.LogInfo("Saved unpassworded zip to: " + tmpFile); // System.IO.File.Copy(tmpFile, fileName, true); // Logger.LogInfo("Copied: " + tmpFile + " back to: " + fileName); // System.IO.File.Delete(tmpFile); // return true; // } // else // { // Logger.LogDebug("Unable to decrypt: " + fileName); // Logger.LogDebug(zip.LastErrorText); // return false; // } //} }
public bool PackContainer(Collection<IContainer> fileList, FileData filedata, Dictionary<string, string> properties, string baseFileName, string sPassword) { filedata.Password = sPassword; string outputFileName = Path.GetTempFileName(); try { using (ZipWrapper zip = new ZipWrapper()) { zip.SetCompressionLevel(9); // max compression zip.FileName = outputFileName; zip.TempDir = Path.GetDirectoryName(outputFileName); // To zip using utf-8 filenames, set the OemCodePage = 65001 zip.OemCodePage = 65001; if (filedata.Password != null && 0 < filedata.Password.Length) { string sEncryption = string.Empty; string sEncryptionKeyLength = string.Empty; zip.Encryption = 0; if (properties.TryGetValue("Encryption", out sEncryption)) { try { zip.EncryptKeyLength = 128; if (properties.TryGetValue("EncryptionKeyLength", out sEncryptionKeyLength)) zip.EncryptKeyLength = System.Convert.ToInt32(sEncryptionKeyLength); zip.Encryption = System.Convert.ToInt32(sEncryption); } catch (FormatException) { zip.Encryption = 0; zip.EncryptKeyLength = 0; } } if (zip.Encryption == 0) zip.PasswordProtect = true; zip.SetPassword(filedata.Password); } // Get the folders in, first for (int i = 0; i < fileList.Count; ++i) { IFile zipEntry = fileList[i] as IFile; if (null == zipEntry) { Logger.LogError("Unable to convert IContainer to IFile file because underlying type was " + fileList[i].GetType()); continue; } if (zipEntry.FileType == FileType.Folder) // Just create the folder { zip.AppendOneFileOrDir(zipEntry.DisplayName, false); } } // And then the files for (int i = 0; i < fileList.Count; ++i) { IFile zipEntry = fileList[i] as IFile; if (null == zipEntry) { Logger.LogError("Unable to convert IContainer to IFile file because underlying type was " + fileList[i].GetType()); continue; } if (zipEntry.FileType == FileType.Folder) // Skip the folders as we have already created them. { continue; } // Which parts of the path do we NOT want to put into the zip folder structure string ignorePath = zipEntry.FileName.ToLower().Replace(zipEntry.DisplayName.ToLower(), ""); // This is needed if you right click on a unicode .docx file name -> Send to Mail Recipient // because outlook converts it into 8.3 file format filename so the display name is different from the file name. string displayName = Path.Combine(Path.GetDirectoryName(zipEntry.DisplayName), Path.GetFileName(zipEntry.FileName)); if (!ignorePath.EndsWith("\\")) { ignorePath = ignorePath.Substring(0, ignorePath.LastIndexOf("\\") + 1); } zip.AppendFromDir = ignorePath; zip.AppendOneFileOrDir(displayName, true /*We want to recreate folders within the zip files*/); } if (!zip.WriteZipAndClose()) { Logger.LogError(zip.LastErrorText); throw new Exception(String.Format("Failed trying pack container {0}, temp version of {1} ", outputFileName, baseFileName)); } // Now replace the orig zip with our new temp one System.IO.File.Copy(outputFileName, baseFileName, true); } filedata.BinaryFileData = new OptimizedBinaryData(outputFileName); return true; } catch (Exception ex) { Logger.LogError(ex.Message); throw ex; } finally { // Delete the temp zip we built System.IO.File.Delete(outputFileName); // Give the Chilkat zip object chance to finish with the files, otherwise we can get a locked file exception later when we try to delete the temp files System.GC.Collect(); System.GC.WaitForPendingFinalizers(); } }