2011-04-25 12 views

Respuesta

9

Aquí es una versión cruda de una contraseña DETECTER hice. No necesita abrir ningún objeto de Office.

public static bool IsPassworded(string file) { 
     var bytes = File.ReadAllBytes(file); 
     return IsPassworded(bytes); 
     return false; 
    } 
    public static bool IsPassworded(byte[] bytes) { 
     var prefix = Encoding.Default.GetString(bytes.Take(2).ToArray()); 
     if (prefix == "PK") { 
      //ZIP and not password protected 
      return false; 
     } 
     if (prefix == "ÐÏ") { 
      //Office format. 

      //Flagged with password 
      if (bytes.Skip(0x20c).Take(1).ToArray()[0] == 0x2f) return true; //XLS 2003 
      if (bytes.Skip(0x214).Take(1).ToArray()[0] == 0x2f) return true; //XLS 2005 
      if (bytes.Skip(0x20B).Take(1).ToArray()[0] == 0x13) return true; //DOC 2005 

      if (bytes.Length < 2000) return false; //Guessing false 
      var start = Encoding.Default.GetString(bytes.Take(2000).ToArray()); //DOC/XLS 2007+ 
      start = start.Replace("\0", " "); 
      if (start.Contains("E n c r y p t e d P a c k a g e")) return true; 
      return false; 
     } 

     //Unknown. 
     return false; 
    } 

Puede que no sea 100%. Las banderas que encontré al comparar varios documentos de Excel y Word con y sin contraseña. Para agregar para PowerPoint solo haz lo mismo.

+0

Niza. @ Wolf5 +1 –

+0

genial. ¿esto solo funciona para documentos de oficina? ¿Qué hay de los PDF? – echo

+0

El código anterior es solo para documentos de oficina (Microsoft). Los PDF son un producto de Adobe y probablemente tengan una forma diferente de hacerlo. Pero podría ser tan fácil como comparar un documento PDF antes y después de que se lo haya pasado por alto para encontrar una bandera (posición) que indique que ha sido cedido. Luego solo crea un código que reaccione al valor en esa ubicación. – Wolf5

9

He creado un método de utilidad que intenta detectar si un documento de oficina determinado está protegido por una contraseña o no. Aquí está la lista de ventajas:

  • compatible con Word, Excel y PowerPoint, tanto legado (doc, xls, ppt) y la nueva versión OpenXml (docx, xlsx, pptx)
  • no depende de COM o cualquier otra biblioteca
  • requiere solo sistema, espacios de nombres System.IO y System.Text
  • de detección (aspectos legado .doc, .ppt y .xls) formatos muy rápidos y fiables
  • bajo uso de memoria (máximo 64 KB)

Aquí está el código, espero que alguien le resultará útil:

public static class MsOfficeHelper 
{ 
    /// <summary> 
    /// Detects if a given office document is protected by a password or not. 
    /// Supported formats: Word, Excel and PowerPoint (both legacy and OpenXml). 
    /// </summary> 
    /// <param name="fileName">Path to an office document.</param> 
    /// <returns>True if document is protected by a password, false otherwise.</returns> 
    public static bool IsPasswordProtected(string fileName) 
    { 
     using (var stream = File.OpenRead(fileName)) 
      return IsPasswordProtected(stream); 
    } 

    /// <summary> 
    /// Detects if a given office document is protected by a password or not. 
    /// Supported formats: Word, Excel and PowerPoint (both legacy and OpenXml). 
    /// </summary> 
    /// <param name="stream">Office document stream.</param> 
    /// <returns>True if document is protected by a password, false otherwise.</returns> 
    public static bool IsPasswordProtected(Stream stream) 
    { 
     // minimum file size for office file is 4k 
     if (stream.Length < 4096) 
      return false; 

     // read file header 
     stream.Seek(0, SeekOrigin.Begin); 
     var compObjHeader = new byte[0x20]; 
     ReadFromStream(stream, compObjHeader); 

     // check if we have plain zip file 
     if (compObjHeader[0] == 'P' && compObjHeader[1] == 'K') 
     { 
      // this is a plain OpenXml document (not encrypted) 
      return false; 
     } 

     // check compound object magic bytes 
     if (compObjHeader[0] != 0xD0 || compObjHeader[1] != 0xCF) 
     { 
      // unknown document format 
      return false; 
     } 

     int sectionSizePower = compObjHeader[0x1E]; 
     if (sectionSizePower < 8 || sectionSizePower > 16) 
     { 
      // invalid section size 
      return false; 
     } 
     int sectionSize = 2 << (sectionSizePower - 1); 

     const int defaultScanLength = 32768; 
     long scanLength = Math.Min(defaultScanLength, stream.Length); 

     // read header part for scan 
     stream.Seek(0, SeekOrigin.Begin); 
     var header = new byte[scanLength]; 
     ReadFromStream(stream, header); 

     // check if we detected password protection 
     if (ScanForPassword(stream, header, sectionSize)) 
      return true; 

     // if not, try to scan footer as well 

     // read footer part for scan 
     stream.Seek(-scanLength, SeekOrigin.End); 
     var footer = new byte[scanLength]; 
     ReadFromStream(stream, footer); 

     // finally return the result 
     return ScanForPassword(stream, footer, sectionSize); 
    } 

    static void ReadFromStream(Stream stream, byte[] buffer) 
    { 
     int bytesRead, count = buffer.Length; 
     while (count > 0 && (bytesRead = stream.Read(buffer, 0, count)) > 0) 
      count -= bytesRead; 
     if (count > 0) throw new EndOfStreamException(); 
    } 

    static bool ScanForPassword(Stream stream, byte[] buffer, int sectionSize) 
    { 
     const string afterNamePadding = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 

     try 
     { 
      string bufferString = Encoding.ASCII.GetString(buffer, 0, buffer.Length); 

      // try to detect password protection used in new OpenXml documents 
      // by searching for "EncryptedPackage" or "EncryptedSummary" streams 
      const string encryptedPackageName = "E\0n\0c\0r\0y\0p\0t\0e\0d\0P\0a\0c\0k\0a\0g\0e" + afterNamePadding; 
      const string encryptedSummaryName = "E\0n\0c\0r\0y\0p\0t\0e\0d\0S\0u\0m\0m\0a\0r\0y" + afterNamePadding; 
      if (bufferString.Contains(encryptedPackageName) || 
       bufferString.Contains(encryptedSummaryName)) 
       return true; 

      // try to detect password protection for legacy Office documents 
      const int coBaseOffset = 0x200; 
      const int sectionIdOffset = 0x74; 

      // check for Word header 
      const string wordDocumentName = "W\0o\0r\0d\0D\0o\0c\0u\0m\0e\0n\0t" + afterNamePadding; 
      int headerOffset = bufferString.IndexOf(wordDocumentName, StringComparison.InvariantCulture); 
      int sectionId; 
      if (headerOffset >= 0) 
      { 
       sectionId = BitConverter.ToInt32(buffer, headerOffset + sectionIdOffset); 
       int sectionOffset = coBaseOffset + sectionId * sectionSize; 
       const int fibScanSize = 0x10; 
       if (sectionOffset < 0 || sectionOffset + fibScanSize > stream.Length) 
        return false; // invalid document 
       var fibHeader = new byte[fibScanSize]; 
       stream.Seek(sectionOffset, SeekOrigin.Begin); 
       ReadFromStream(stream, fibHeader); 
       short properties = BitConverter.ToInt16(fibHeader, 0x0A); 
       // check for fEncrypted FIB bit 
       const short fEncryptedBit = 0x0100; 
       return (properties & fEncryptedBit) == fEncryptedBit; 
      } 

      // check for Excel header 
      const string workbookName = "W\0o\0r\0k\0b\0o\0o\0k" + afterNamePadding; 
      headerOffset = bufferString.IndexOf(workbookName, StringComparison.InvariantCulture); 
      if (headerOffset >= 0) 
      { 
       sectionId = BitConverter.ToInt32(buffer, headerOffset + sectionIdOffset); 
       int sectionOffset = coBaseOffset + sectionId * sectionSize; 
       const int streamScanSize = 0x100; 
       if (sectionOffset < 0 || sectionOffset + streamScanSize > stream.Length) 
        return false; // invalid document 
       var workbookStream = new byte[streamScanSize]; 
       stream.Seek(sectionOffset, SeekOrigin.Begin); 
       ReadFromStream(stream, workbookStream); 
       short record = BitConverter.ToInt16(workbookStream, 0); 
       short recordSize = BitConverter.ToInt16(workbookStream, sizeof(short)); 
       const short bofMagic = 0x0809; 
       const short eofMagic = 0x000A; 
       const short filePassMagic = 0x002F; 
       if (record != bofMagic) 
        return false; // invalid BOF 
       // scan for FILEPASS record until the end of the buffer 
       int offset = sizeof(short) * 2 + recordSize; 
       int recordsLeft = 16; // simple infinite loop check just in case 
       do 
       { 
        record = BitConverter.ToInt16(workbookStream, offset); 
        if (record == filePassMagic) 
         return true; 
        recordSize = BitConverter.ToInt16(workbookStream, sizeof(short) + offset); 
        offset += sizeof(short) * 2 + recordSize; 
        recordsLeft--; 
       } while (record != eofMagic && recordsLeft > 0); 
      } 

      // check for PowerPoint user header 
      const string currentUserName = "C\0u\0r\0r\0e\0n\0t\0 \0U\0s\0e\0r" + afterNamePadding; 
      headerOffset = bufferString.IndexOf(currentUserName, StringComparison.InvariantCulture); 
      if (headerOffset >= 0) 
      { 
       sectionId = BitConverter.ToInt32(buffer, headerOffset + sectionIdOffset); 
       int sectionOffset = coBaseOffset + sectionId * sectionSize; 
       const int userAtomScanSize = 0x10; 
       if (sectionOffset < 0 || sectionOffset + userAtomScanSize > stream.Length) 
        return false; // invalid document 
       var userAtom = new byte[userAtomScanSize]; 
       stream.Seek(sectionOffset, SeekOrigin.Begin); 
       ReadFromStream(stream, userAtom); 
       const int headerTokenOffset = 0x0C; 
       uint headerToken = BitConverter.ToUInt32(userAtom, headerTokenOffset); 
       // check for headerToken 
       const uint encryptedToken = 0xF3D1C4DF; 
       return headerToken == encryptedToken; 
      } 
     } 
     catch (Exception ex) 
     { 
      // BitConverter exceptions may be related to document format problems 
      // so we just treat them as "password not detected" result 
      if (ex is ArgumentException) 
       return false; 
      // respect all the rest exceptions 
      throw; 
     } 

     return false; 
    } 
} 
+1

¡Es una buena espeleología! – jschroedl

+0

¡Buen trabajo! Confirmó que funciona en word, excel para los formatos 2013 y 97. –

+0

Parece que no puede detectarlo correctamente para 97 versiones de Powerpoint. Si estás intentando fallar en lugar de colgar. Sugiero pasar la contraseña inmediatamente después de la ruta de archivo en abierto como tal. @ "c: \ path \ to \ file.ppt" + ":: BadPassword ::" –

Cuestiones relacionadas