• R/O
  • HTTP
  • SSH
  • HTTPS

excelize: 提交

Go language library for reading and writing Microsoft Excel™ (XLAM / XLSM / XLSX / XLTM / XLTX) spreadsheets


Commit MetaInfo

修订版cfa2d603ddb0fac50ca1af3fe1d28fe17a65a6f3 (tree)
时间2022-08-20 16:51:03
作者Sangua633 <76948439+Sangua633@user...>
CommiterGitHub

Log Message

Support encrypt workbook with password #199 (#1324)

更改概述

差异

--- a/crypt.go
+++ b/crypt.go
@@ -25,7 +25,9 @@ import (
2525 "encoding/xml"
2626 "hash"
2727 "math"
28+ "path/filepath"
2829 "reflect"
30+ "sort"
2931 "strings"
3032
3133 "github.com/richardlehane/mscfb"
@@ -37,6 +39,10 @@ import (
3739 var (
3840 blockKey = []byte{0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6} // Block keys used for encryption
3941 oleIdentifier = []byte{0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1}
42+ headerCLSID = make([]byte, 16)
43+ difSect = -4
44+ endOfChain = -2
45+ fatSect = -3
4046 iterCount = 50000
4147 packageEncryptionChunkSize = 4096
4248 packageOffset = 8 // First 8 bytes are the size of the stream
@@ -150,7 +156,7 @@ func Decrypt(raw []byte, opt *Options) (packageBuf []byte, err error) {
150156 }
151157
152158 // Encrypt API encrypt data with the password.
153-func Encrypt(raw []byte, opt *Options) (packageBuf []byte, err error) {
159+func Encrypt(raw []byte, opt *Options) ([]byte, error) {
154160 encryptor := encryption{
155161 EncryptedVerifierHashInput: make([]byte, 16),
156162 EncryptedVerifierHashValue: make([]byte, 32),
@@ -169,9 +175,13 @@ func Encrypt(raw []byte, opt *Options) (packageBuf []byte, err error) {
169175 binary.LittleEndian.PutUint64(encryptedPackage, uint64(len(raw)))
170176 encryptedPackage = append(encryptedPackage, encryptor.encrypt(raw)...)
171177 // Create a new CFB
172- compoundFile := cfb{}
173- packageBuf = compoundFile.Writer(encryptionInfoBuffer, encryptedPackage)
174- return packageBuf, nil
178+ compoundFile := &cfb{
179+ paths: []string{"Root Entry/"},
180+ sectors: []sector{{name: "Root Entry", typeID: 5}},
181+ }
182+ compoundFile.put("EncryptionInfo", encryptionInfoBuffer)
183+ compoundFile.put("EncryptedPackage", encryptedPackage)
184+ return compoundFile.write(), nil
175185 }
176186
177187 // extractPart extract data from storage by specified part name.
@@ -618,6 +628,15 @@ func genISOPasswdHash(passwd, hashAlgorithm, salt string, spinCount int) (hashVa
618628 type cfb struct {
619629 stream []byte
620630 position int
631+ paths []string
632+ sectors []sector
633+}
634+
635+// sector structure used for FAT, directory, miniFAT, and miniStream sectors.
636+type sector struct {
637+ clsID, content []byte
638+ name string
639+ C, L, R, color, size, start, state, typeID int
621640 }
622641
623642 // writeBytes write bytes in the stream by a given value with an offset.
@@ -666,415 +685,156 @@ func (c *cfb) writeStrings(value string) {
666685 c.writeBytes(buffer)
667686 }
668687
669-// writeVersionStream provides a function to write compound file version
670-// stream.
671-func (c *cfb) writeVersionStream() []byte {
672- var storage cfb
673- storage.writeUint32(0x3c)
674- storage.writeStrings("Microsoft.Container.DataSpaces")
675- storage.writeUint32(0x01)
676- storage.writeUint32(0x01)
677- storage.writeUint32(0x01)
678- return storage.stream
679-}
680-
681-// writeDataSpaceMapStream provides a function to write compound file
682-// DataSpaceMap stream.
683-func (c *cfb) writeDataSpaceMapStream() []byte {
684- var storage cfb
685- storage.writeUint32(0x08)
686- storage.writeUint32(0x01)
687- storage.writeUint32(0x68)
688- storage.writeUint32(0x01)
689- storage.writeUint32(0x00)
690- storage.writeUint32(0x20)
691- storage.writeStrings("EncryptedPackage")
692- storage.writeUint32(0x32)
693- storage.writeStrings("StrongEncryptionDataSpace")
694- storage.writeUint16(0x00)
695- return storage.stream
696-}
697-
698-// writeStrongEncryptionDataSpaceStream provides a function to write compound
699-// file StrongEncryptionDataSpace stream.
700-func (c *cfb) writeStrongEncryptionDataSpaceStream() []byte {
701- var storage cfb
702- storage.writeUint32(0x08)
703- storage.writeUint32(0x01)
704- storage.writeUint32(0x32)
705- storage.writeStrings("StrongEncryptionTransform")
706- storage.writeUint16(0x00)
707- return storage.stream
708-}
709-
710-// writePrimaryStream provides a function to write compound file Primary
711-// stream.
712-func (c *cfb) writePrimaryStream() []byte {
713- var storage cfb
714- storage.writeUint32(0x6C)
715- storage.writeUint32(0x01)
716- storage.writeUint32(0x4C)
717- storage.writeStrings("{FF9A3F03-56EF-4613-BDD5-5A41C1D07246}")
718- storage.writeUint32(0x4E)
719- storage.writeUint16(0x00)
720- storage.writeUint32(0x01)
721- storage.writeUint32(0x01)
722- storage.writeUint32(0x01)
723- storage.writeStrings("AES128")
724- storage.writeUint32(0x00)
725- storage.writeUint32(0x04)
726- return storage.stream
727-}
728-
729-// writeFileStream provides a function to write encrypted package in compound
730-// file by a given buffer and the short sector allocation table.
731-func (c *cfb) writeFileStream(encryptionInfoBuffer []byte, SSAT []int) ([]byte, []int) {
732- var (
733- storage cfb
734- miniProperties int
735- stream = make([]byte, 0x100)
736- )
737- if encryptionInfoBuffer != nil {
738- copy(stream, encryptionInfoBuffer)
739- }
740- storage.writeBytes(stream)
741- streamBlocks := len(stream) / 64
742- if len(stream)%64 > 0 {
743- streamBlocks++
744- }
745- for i := 1; i < streamBlocks; i++ {
746- SSAT = append(SSAT, i)
747- }
748- SSAT = append(SSAT, -2)
749- miniProperties += streamBlocks
750- versionStream := make([]byte, 0x80)
751- version := c.writeVersionStream()
752- copy(versionStream, version)
753- storage.writeBytes(versionStream)
754- versionBlocks := len(versionStream) / 64
755- if len(versionStream)%64 > 0 {
756- versionBlocks++
757- }
758- for i := 1; i < versionBlocks; i++ {
759- SSAT = append(SSAT, i+miniProperties)
760- }
761- SSAT = append(SSAT, -2)
762- miniProperties += versionBlocks
763- dataSpaceMap := make([]byte, 0x80)
764- dataStream := c.writeDataSpaceMapStream()
765- copy(dataSpaceMap, dataStream)
766- storage.writeBytes(dataSpaceMap)
767- dataSpaceMapBlocks := len(dataSpaceMap) / 64
768- if len(dataSpaceMap)%64 > 0 {
769- dataSpaceMapBlocks++
770- }
771- for i := 1; i < dataSpaceMapBlocks; i++ {
772- SSAT = append(SSAT, i+miniProperties)
773- }
774- SSAT = append(SSAT, -2)
775- miniProperties += dataSpaceMapBlocks
776- dataSpaceStream := c.writeStrongEncryptionDataSpaceStream()
777- storage.writeBytes(dataSpaceStream)
778- dataSpaceStreamBlocks := len(dataSpaceStream) / 64
779- if len(dataSpaceStream)%64 > 0 {
780- dataSpaceStreamBlocks++
781- }
782- for i := 1; i < dataSpaceStreamBlocks; i++ {
783- SSAT = append(SSAT, i+miniProperties)
784- }
785- SSAT = append(SSAT, -2)
786- miniProperties += dataSpaceStreamBlocks
787- primaryStream := make([]byte, 0x1C0)
788- primary := c.writePrimaryStream()
789- copy(primaryStream, primary)
790- storage.writeBytes(primaryStream)
791- primaryBlocks := len(primary) / 64
792- if len(primary)%64 > 0 {
793- primaryBlocks++
794- }
795- for i := 1; i < primaryBlocks; i++ {
796- SSAT = append(SSAT, i+miniProperties)
797- }
798- SSAT = append(SSAT, -2)
799- if len(SSAT) < 128 {
800- for i := len(SSAT); i < 128; i++ {
801- SSAT = append(SSAT, -1)
688+// put provides a function to add an entry to compound file by given entry name
689+// and raw bytes.
690+func (c *cfb) put(name string, content []byte) {
691+ path := c.paths[0]
692+ if len(path) <= len(name) && name[:len(path)] == path {
693+ path = name
694+ } else {
695+ if len(path) > 0 && string(path[len(path)-1]) != "/" {
696+ path += "/"
697+ }
698+ path = strings.ReplaceAll(path+name, "//", "/")
699+ }
700+ file := sector{name: path, typeID: 2, content: content, size: len(content)}
701+ c.sectors = append(c.sectors, file)
702+ c.paths = append(c.paths, path)
703+}
704+
705+// compare provides a function to compare object path, each set of sibling
706+// objects in one level of the containment hierarchy (all child objects under
707+// a storage object) is represented as a red-black tree. The parent object of
708+// this set of siblings will have a pointer to the top of this tree.
709+func (c *cfb) compare(left, right string) int {
710+ L, R, i, j := strings.Split(left, "/"), strings.Split(right, "/"), 0, 0
711+ for Z := int(math.Min(float64(len(L)), float64(len(R)))); i < Z; i++ {
712+ if j = len(L[i]) - len(R[i]); j != 0 {
713+ return j
714+ }
715+ if L[i] != R[i] {
716+ if L[i] < R[i] {
717+ return -1
718+ }
719+ return 1
802720 }
803721 }
804- storage.position = 0
805- return storage.stream, SSAT
806-}
807-
808-// writeRootEntry provides a function to write compound file root directory
809-// entry. The first entry in the first sector of the directory chain
810-// (also referred to as the first element of the directory array, or stream
811-// ID #0) is known as the root directory entry, and it is reserved for two
812-// purposes. First, it provides a root parent for all objects that are
813-// stationed at the root of the compound file. Second, its function is
814-// overloaded to store the size and starting sector for the mini stream.
815-func (c *cfb) writeRootEntry(customSectID int) []byte {
816- storage := cfb{stream: make([]byte, 128)}
817- storage.writeStrings("Root Entry")
818- storage.position = 0x40
819- storage.writeUint16(0x16)
820- storage.writeBytes([]byte{5, 0})
821- storage.writeUint32(-1)
822- storage.writeUint32(-1)
823- storage.writeUint32(1)
824- storage.position = 0x64
825- storage.writeUint32(0)
826- storage.writeUint32(0)
827- storage.writeUint32(0)
828- storage.writeUint32(0)
829- storage.writeUint32(customSectID)
830- storage.writeUint32(0x340)
831- return storage.stream
832-}
833-
834-// writeEncryptionInfo provides a function to write compound file
835-// writeEncryptionInfo stream. The writeEncryptionInfo stream contains
836-// detailed information that is used to initialize the cryptography used to
837-// encrypt the EncryptedPackage stream.
838-func (c *cfb) writeEncryptionInfo() []byte {
839- storage := cfb{stream: make([]byte, 128)}
840- storage.writeStrings("EncryptionInfo")
841- storage.position = 0x40
842- storage.writeUint16(0x1E)
843- storage.writeBytes([]byte{2, 1})
844- storage.writeUint32(0x03)
845- storage.writeUint32(0x02)
846- storage.writeUint32(-1)
847- storage.position = 0x64
848- storage.writeUint32(0)
849- storage.writeUint32(0)
850- storage.writeUint32(0)
851- storage.writeUint32(0)
852- storage.writeUint32(0)
853- storage.writeUint32(0xF8)
854- return storage.stream
855-}
856-
857-// writeEncryptedPackage provides a function to write compound file
858-// writeEncryptedPackage stream. The writeEncryptedPackage stream is an
859-// encrypted stream of bytes containing the entire ECMA-376 source file in
860-// compressed form.
861-func (c *cfb) writeEncryptedPackage(propertyCount, size int) []byte {
862- storage := cfb{stream: make([]byte, 128)}
863- storage.writeStrings("EncryptedPackage")
864- storage.position = 0x40
865- storage.writeUint16(0x22)
866- storage.writeBytes([]byte{2, 0})
867- storage.writeUint32(-1)
868- storage.writeUint32(-1)
869- storage.writeUint32(-1)
870- storage.position = 0x64
871- storage.writeUint32(0)
872- storage.writeUint32(0)
873- storage.writeUint32(0)
874- storage.writeUint32(0)
875- storage.writeUint32(propertyCount)
876- storage.writeUint32(size)
877- return storage.stream
878-}
879-
880-// writeDataSpaces provides a function to write compound file writeDataSpaces
881-// stream. The data spaces structure consists of a set of interrelated
882-// storages and streams in an OLE compound file.
883-func (c *cfb) writeDataSpaces() []byte {
884- storage := cfb{stream: make([]byte, 128)}
885- storage.writeUint16(0x06)
886- storage.position = 0x40
887- storage.writeUint16(0x18)
888- storage.writeBytes([]byte{1, 0})
889- storage.writeUint32(-1)
890- storage.writeUint32(-1)
891- storage.writeUint32(5)
892- storage.position = 0x64
893- storage.writeUint32(0)
894- storage.writeUint32(0)
895- storage.writeUint32(0)
896- storage.writeUint32(0)
897- storage.writeUint32(0)
898- storage.writeUint32(0)
899- return storage.stream
900-}
901-
902-// writeVersion provides a function to write compound file version. The
903-// writeVersion structure specifies the version of a product or feature. It
904-// contains a major and a minor version number.
905-func (c *cfb) writeVersion() []byte {
906- storage := cfb{stream: make([]byte, 128)}
907- storage.writeStrings("Version")
908- storage.position = 0x40
909- storage.writeUint16(0x10)
910- storage.writeBytes([]byte{2, 1})
911- storage.writeUint32(-1)
912- storage.writeUint32(-1)
913- storage.writeUint32(-1)
914- storage.position = 0x64
915- storage.writeUint32(0)
916- storage.writeUint32(0)
917- storage.writeUint32(0)
918- storage.writeUint32(0)
919- storage.writeUint32(4)
920- storage.writeUint32(76)
921- return storage.stream
922-}
923-
924-// writeDataSpaceMap provides a function to write compound file
925-// writeDataSpaceMap stream. The writeDataSpaceMap structure associates
926-// protected content with data space definitions. The data space definition,
927-// in turn, describes the series of transforms that MUST be applied to that
928-// protected content to restore it to its original form. By using a map to
929-// associate data space definitions with content, a single data space
930-// definition can be used to define the transforms applied to more than one
931-// piece of protected content. However, a given piece of protected content can
932-// be referenced only by a single data space definition.
933-func (c *cfb) writeDataSpaceMap() []byte {
934- storage := cfb{stream: make([]byte, 128)}
935- storage.writeStrings("DataSpaceMap")
936- storage.position = 0x40
937- storage.writeUint16(0x1A)
938- storage.writeBytes([]byte{2, 1})
939- storage.writeUint32(0x04)
940- storage.writeUint32(0x06)
941- storage.writeUint32(-1)
942- storage.position = 0x64
943- storage.writeUint32(0)
944- storage.writeUint32(0)
945- storage.writeUint32(0)
946- storage.writeUint32(0)
947- storage.writeUint32(6)
948- storage.writeUint32(112)
949- return storage.stream
950-}
951-
952-// writeDataSpaceInfo provides a function to write compound file
953-// writeDataSpaceInfo storage. The writeDataSpaceInfo is a storage containing
954-// the data space definitions used in the file. This storage must contain one
955-// or more streams, each of which contains a DataSpaceDefinition structure.
956-// The storage must contain exactly one stream for each DataSpaceMapEntry
957-// structure in the DataSpaceMap stream. The name of each stream must be equal
958-// to the DataSpaceName field of exactly one DataSpaceMapEntry structure
959-// contained in the DataSpaceMap stream.
960-func (c *cfb) writeDataSpaceInfo() []byte {
961- storage := cfb{stream: make([]byte, 128)}
962- storage.writeStrings("DataSpaceInfo")
963- storage.position = 0x40
964- storage.writeUint16(0x1C)
965- storage.writeBytes([]byte{1, 1})
966- storage.writeUint32(-1)
967- storage.writeUint32(8)
968- storage.writeUint32(7)
969- storage.position = 0x64
970- storage.writeUint32(0)
971- storage.writeUint32(0)
972- storage.writeUint32(0)
973- storage.writeUint32(0)
974- storage.writeUint32(0)
975- storage.writeUint32(0)
976- return storage.stream
977-}
978-
979-// writeStrongEncryptionDataSpace provides a function to write compound file
980-// writeStrongEncryptionDataSpace stream.
981-func (c *cfb) writeStrongEncryptionDataSpace() []byte {
982- storage := cfb{stream: make([]byte, 128)}
983- storage.writeStrings("StrongEncryptionDataSpace")
984- storage.position = 0x40
985- storage.writeUint16(0x34)
986- storage.writeBytes([]byte{2, 1})
987- storage.writeUint32(-1)
988- storage.writeUint32(-1)
989- storage.writeUint32(-1)
990- storage.position = 0x64
991- storage.writeUint32(0)
992- storage.writeUint32(0)
993- storage.writeUint32(0)
994- storage.writeUint32(0)
995- storage.writeUint32(8)
996- storage.writeUint32(64)
997- return storage.stream
998-}
999-
1000-// writeTransformInfo provides a function to write compound file
1001-// writeTransformInfo storage. writeTransformInfo is a storage containing
1002-// definitions for the transforms used in the data space definitions stored in
1003-// the DataSpaceInfo storage. The stream contains zero or more definitions for
1004-// the possible transforms that can be applied to the data in content
1005-// streams.
1006-func (c *cfb) writeTransformInfo() []byte {
1007- storage := cfb{stream: make([]byte, 128)}
1008- storage.writeStrings("TransformInfo")
1009- storage.position = 0x40
1010- storage.writeUint16(0x1C)
1011- storage.writeBytes([]byte{1, 0})
1012- storage.writeUint32(-1)
1013- storage.writeUint32(-1)
1014- storage.writeUint32(9)
1015- storage.position = 0x64
1016- storage.writeUint32(0)
1017- storage.writeUint32(0)
1018- storage.writeUint32(0)
1019- storage.writeUint32(0)
1020- storage.writeUint32(0)
1021- storage.writeUint32(0)
1022- return storage.stream
722+ return len(L) - len(R)
1023723 }
1024724
1025-// writeStrongEncryptionTransform provides a function to write compound file
1026-// writeStrongEncryptionTransform storage.
1027-func (c *cfb) writeStrongEncryptionTransform() []byte {
1028- storage := cfb{stream: make([]byte, 128)}
1029- storage.writeStrings("StrongEncryptionTransform")
1030- storage.position = 0x40
1031- storage.writeUint16(0x34)
1032- storage.writeBytes([]byte{1})
1033- storage.writeBytes([]byte{1})
1034- storage.writeUint32(-1)
1035- storage.writeUint32(-1)
1036- storage.writeUint32(0x0A)
1037- storage.position = 0x64
1038- storage.writeUint32(0)
1039- storage.writeUint32(0)
1040- storage.writeUint32(0)
1041- storage.writeUint32(0)
1042- storage.writeUint32(0)
1043- storage.writeUint32(0)
1044- return storage.stream
725+// prepare provides a function to prepare object before write stream.
726+func (c *cfb) prepare() {
727+ type object struct {
728+ path string
729+ sector sector
730+ }
731+ var objects []object
732+ for i := 0; i < len(c.paths); i++ {
733+ if c.sectors[i].typeID == 0 {
734+ continue
735+ }
736+ objects = append(objects, object{path: c.paths[i], sector: c.sectors[i]})
737+ }
738+ sort.Slice(objects, func(i, j int) bool {
739+ return c.compare(objects[i].path, objects[j].path) == 0
740+ })
741+ c.paths, c.sectors = []string{}, []sector{}
742+ for i := 0; i < len(objects); i++ {
743+ c.paths = append(c.paths, objects[i].path)
744+ c.sectors = append(c.sectors, objects[i].sector)
745+ }
746+ for i := 0; i < len(objects); i++ {
747+ sector, path := &c.sectors[i], c.paths[i]
748+ sector.name, sector.color = filepath.Base(path), 1
749+ sector.L, sector.R, sector.C = -1, -1, -1
750+ sector.size, sector.start = len(sector.content), 0
751+ if len(sector.clsID) == 0 {
752+ sector.clsID = headerCLSID
753+ }
754+ if i == 0 {
755+ sector.C = -1
756+ if len(objects) > 1 {
757+ sector.C = 1
758+ }
759+ sector.size, sector.typeID = 0, 5
760+ } else {
761+ if len(c.paths) > i+1 && filepath.Dir(c.paths[i+1]) == filepath.Dir(path) {
762+ sector.R = i + 1
763+ }
764+ sector.typeID = 2
765+ }
766+ }
1045767 }
1046768
1047-// writePrimary provides a function to write compound file writePrimary stream.
1048-func (c *cfb) writePrimary() []byte {
1049- storage := cfb{stream: make([]byte, 128)}
1050- storage.writeUint16(0x06)
1051- storage.writeStrings("Primary")
1052- storage.position = 0x40
1053- storage.writeUint16(0x12)
1054- storage.writeBytes([]byte{2, 1})
1055- storage.writeUint32(-1)
1056- storage.writeUint32(-1)
1057- storage.writeUint32(-1)
1058- storage.position = 0x64
1059- storage.writeUint32(0)
1060- storage.writeUint32(0)
1061- storage.writeUint32(0)
1062- storage.writeUint32(0)
1063- storage.writeUint32(9)
1064- storage.writeUint32(208)
1065- return storage.stream
769+// locate provides a function to locate sectors location and size of the
770+// compound file.
771+func (c *cfb) locate() []int {
772+ var miniStreamSectorSize, FATSectorSize int
773+ for i := 0; i < len(c.sectors); i++ {
774+ sector := c.sectors[i]
775+ if len(sector.content) == 0 {
776+ continue
777+ }
778+ size := len(sector.content)
779+ if size > 0 {
780+ if size < 0x1000 {
781+ miniStreamSectorSize += (size + 0x3F) >> 6
782+ } else {
783+ FATSectorSize += (size + 0x01FF) >> 9
784+ }
785+ }
786+ }
787+ directorySectors := (len(c.paths) + 3) >> 2
788+ miniStreamSectors := (miniStreamSectorSize + 7) >> 3
789+ miniFATSectors := (miniStreamSectorSize + 0x7F) >> 7
790+ sectors := miniStreamSectors + FATSectorSize + directorySectors + miniFATSectors
791+ FATSectors := (sectors + 0x7F) >> 7
792+ DIFATSectors := 0
793+ if FATSectors > 109 {
794+ DIFATSectors = int(math.Ceil((float64(FATSectors) - 109) / 0x7F))
795+ }
796+ for ((sectors + FATSectors + DIFATSectors + 0x7F) >> 7) > FATSectors {
797+ FATSectors++
798+ if FATSectors <= 109 {
799+ DIFATSectors = 0
800+ } else {
801+ DIFATSectors = int(math.Ceil((float64(FATSectors) - 109) / 0x7F))
802+ }
803+ }
804+ location := []int{1, DIFATSectors, FATSectors, miniFATSectors, directorySectors, FATSectorSize, miniStreamSectorSize, 0}
805+ c.sectors[0].size = miniStreamSectorSize << 6
806+ c.sectors[0].start = location[0] + location[1] + location[2] + location[3] + location[4] + location[5]
807+ location[7] = c.sectors[0].start + ((location[6] + 7) >> 3)
808+ return location
1066809 }
1067810
1068-// writeNoneDir provides a function to write compound file writeNoneDir stream.
1069-func (c *cfb) writeNoneDir() []byte {
1070- storage := cfb{stream: make([]byte, 128)}
1071- storage.position = 0x40
1072- storage.writeUint16(0x00)
1073- storage.writeUint16(0x00)
1074- storage.writeUint32(-1)
1075- storage.writeUint32(-1)
1076- storage.writeUint32(-1)
1077- return storage.stream
811+// writeMSAT provides a function to write compound file master sector allocation
812+// table.
813+func (c *cfb) writeMSAT(location []int) {
814+ var i, offset int
815+ for i = 0; i < 109; i++ {
816+ if i < location[2] {
817+ c.writeUint32(location[1] + i)
818+ } else {
819+ c.writeUint32(-1)
820+ }
821+ }
822+ if location[1] != 0 {
823+ for offset = 0; offset < location[1]; offset++ {
824+ for ; i < 236+offset*127; i++ {
825+ if i < location[2] {
826+ c.writeUint32(location[1] + i)
827+ } else {
828+ c.writeUint32(-1)
829+ }
830+ }
831+ if offset == location[1]-1 {
832+ c.writeUint32(endOfChain)
833+ } else {
834+ c.writeUint32(offset + 1)
835+ }
836+ }
837+ }
1078838 }
1079839
1080840 // writeDirectoryEntry provides a function to write compound file directory
@@ -1083,189 +843,175 @@ func (c *cfb) writeNoneDir() []byte {
1083843 // within a compound file is represented by a single directory entry. The
1084844 // space for the directory sectors that are holding the array is allocated
1085845 // from the FAT.
1086-func (c *cfb) writeDirectoryEntry(propertyCount, customSectID, size int) []byte {
1087- var storage cfb
1088- if size < 0 {
1089- size = 0
1090- }
1091- for _, entry := range [][]byte{
1092- c.writeRootEntry(customSectID),
1093- c.writeEncryptionInfo(),
1094- c.writeEncryptedPackage(propertyCount, size),
1095- c.writeDataSpaces(),
1096- c.writeVersion(),
1097- c.writeDataSpaceMap(),
1098- c.writeDataSpaceInfo(),
1099- c.writeStrongEncryptionDataSpace(),
1100- c.writeTransformInfo(),
1101- c.writeStrongEncryptionTransform(),
1102- c.writePrimary(),
1103- c.writeNoneDir(),
1104- } {
1105- storage.writeBytes(entry)
1106- }
1107- return storage.stream
1108-}
1109-
1110-// writeMSAT provides a function to write compound file master sector allocation
1111-// table.
1112-func (c *cfb) writeMSAT(MSATBlocks, SATBlocks int, MSAT []int) []int {
1113- if MSATBlocks > 0 {
1114- cnt, MSATIdx := MSATBlocks*128+109, 0
1115- for i := 0; i < cnt; i++ {
1116- if i < SATBlocks {
1117- bufferSize := i - 109
1118- if bufferSize > 0 && bufferSize%0x80 == 0 {
1119- MSATIdx++
1120- MSAT = append(MSAT, MSATIdx)
1121- }
1122- MSAT = append(MSAT, i+MSATBlocks)
1123- continue
1124- }
1125- MSAT = append(MSAT, -1)
846+func (c *cfb) writeDirectoryEntry(location []int) {
847+ var sector sector
848+ var j, sectorSize int
849+ for i := 0; i < location[4]<<2; i++ {
850+ var path string
851+ if i < len(c.paths) {
852+ path = c.paths[i]
1126853 }
1127- return MSAT
1128- }
1129- for i := 0; i < 109; i++ {
1130- if i < SATBlocks {
1131- MSAT = append(MSAT, i)
854+ if i >= len(c.paths) || len(path) == 0 {
855+ for j = 0; j < 17; j++ {
856+ c.writeUint32(0)
857+ }
858+ for j = 0; j < 3; j++ {
859+ c.writeUint32(-1)
860+ }
861+ for j = 0; j < 12; j++ {
862+ c.writeUint32(0)
863+ }
1132864 continue
1133865 }
1134- MSAT = append(MSAT, -1)
1135- }
1136- return MSAT
1137-}
1138-
1139-// writeSAT provides a function to write compound file sector allocation
1140-// table.
1141-func (c *cfb) writeSAT(MSATBlocks, SATBlocks, SSATBlocks, directoryBlocks, fileBlocks, streamBlocks int, SAT []int) (int, []int) {
1142- var blocks int
1143- if SATBlocks > 0 {
1144- for i := 1; i <= MSATBlocks; i++ {
1145- SAT = append(SAT, -4)
866+ sector = c.sectors[i]
867+ if i == 0 {
868+ if sector.size > 0 {
869+ sector.start = sector.start - 1
870+ } else {
871+ sector.start = endOfChain
872+ }
1146873 }
1147- blocks = MSATBlocks
1148- for i := 1; i <= SATBlocks; i++ {
1149- SAT = append(SAT, -3)
874+ name := sector.name
875+ sectorSize = 2 * (len(name) + 1)
876+ c.writeStrings(name)
877+ c.position += 64 - 2*(len(name))
878+ c.writeUint16(sectorSize)
879+ c.writeBytes([]byte(string(rune(sector.typeID))))
880+ c.writeBytes([]byte(string(rune(sector.color))))
881+ c.writeUint32(sector.L)
882+ c.writeUint32(sector.R)
883+ c.writeUint32(sector.C)
884+ if len(sector.clsID) == 0 {
885+ for j = 0; j < 4; j++ {
886+ c.writeUint32(0)
887+ }
888+ } else {
889+ c.writeBytes(sector.clsID)
1150890 }
1151- blocks += SATBlocks
1152- for i := 1; i < SSATBlocks; i++ {
1153- SAT = append(SAT, i)
891+ c.writeUint32(sector.state)
892+ c.writeUint32(0)
893+ c.writeUint32(0)
894+ c.writeUint32(0)
895+ c.writeUint32(0)
896+ c.writeUint32(sector.start)
897+ c.writeUint32(sector.size)
898+ c.writeUint32(0)
899+ }
900+}
901+
902+// writeSectorChains provides a function to write compound file sector chains.
903+func (c *cfb) writeSectorChains(location []int) sector {
904+ var i, j, offset, sectorSize int
905+ writeSectorChain := func(head, offset int) int {
906+ for offset += head; i < offset-1; i++ {
907+ c.writeUint32(i + 1)
1154908 }
1155- SAT = append(SAT, -2)
1156- blocks += SSATBlocks
1157- for i := 1; i < directoryBlocks; i++ {
1158- SAT = append(SAT, i+blocks)
909+ if head != 0 {
910+ i++
911+ c.writeUint32(endOfChain)
1159912 }
1160- SAT = append(SAT, -2)
1161- blocks += directoryBlocks
1162- for i := 1; i < fileBlocks; i++ {
1163- SAT = append(SAT, i+blocks)
913+ return offset
914+ }
915+ for offset += location[1]; i < offset; i++ {
916+ c.writeUint32(difSect)
917+ }
918+ for offset += location[2]; i < offset; i++ {
919+ c.writeUint32(fatSect)
920+ }
921+ offset = writeSectorChain(location[3], offset)
922+ offset = writeSectorChain(location[4], offset)
923+ sector := c.sectors[0]
924+ for ; j < len(c.sectors); j++ {
925+ if sector = c.sectors[j]; len(sector.content) == 0 {
926+ continue
1164927 }
1165- SAT = append(SAT, -2)
1166- blocks += fileBlocks
1167- for i := 1; i < streamBlocks; i++ {
1168- SAT = append(SAT, i+blocks)
928+ if sectorSize = len(sector.content); sectorSize < 0x1000 {
929+ continue
1169930 }
1170- SAT = append(SAT, -2)
931+ c.sectors[j].start = offset
932+ offset = writeSectorChain((sectorSize+0x01FF)>>9, offset)
1171933 }
1172- return blocks, SAT
1173-}
1174-
1175-// Writer provides a function to create compound file with given info stream
1176-// and package stream.
1177-//
1178-// MSAT - The master sector allocation table
1179-// SSAT - The short sector allocation table
1180-// SAT - The sector allocation table
1181-func (c *cfb) Writer(encryptionInfoBuffer, encryptedPackage []byte) []byte {
1182- var (
1183- storage cfb
1184- MSAT, SAT, SSAT []int
1185- directoryBlocks, fileBlocks, SSATBlocks = 3, 2, 1
1186- size = int(math.Max(float64(len(encryptedPackage)), float64(packageEncryptionChunkSize)))
1187- streamBlocks = len(encryptedPackage) / 0x200
1188- )
1189- if len(encryptedPackage)%0x200 > 0 {
1190- streamBlocks++
1191- }
1192- propertyBlocks := directoryBlocks + fileBlocks + SSATBlocks
1193- blockSize := (streamBlocks + propertyBlocks) * 4
1194- SATBlocks := blockSize / 0x200
1195- if blockSize%0x200 > 0 {
1196- SATBlocks++
1197- }
1198- MSATBlocks, blocksChanged := 0, true
1199- for blocksChanged {
1200- var SATCap, MSATCap int
1201- blocksChanged = false
1202- blockSize = (streamBlocks + propertyBlocks + SATBlocks + MSATBlocks) * 4
1203- SATCap = blockSize / 0x200
1204- if blockSize%0x200 > 0 {
1205- SATCap++
934+ writeSectorChain((location[6]+7)>>3, offset)
935+ for c.position&0x1FF != 0 {
936+ c.writeUint32(endOfChain)
937+ }
938+ i, offset = 0, 0
939+ for j = 0; j < len(c.sectors); j++ {
940+ if sector = c.sectors[j]; len(sector.content) == 0 {
941+ continue
1206942 }
1207- if SATCap > SATBlocks {
1208- SATBlocks, blocksChanged = SATCap, true
943+ if sectorSize = len(sector.content); sectorSize == 0 || sectorSize >= 0x1000 {
1209944 continue
1210945 }
1211- if SATBlocks > 109 {
1212- blockRemains := (SATBlocks - 109) * 4
1213- blockBuffer := blockRemains % 0x200
1214- MSATCap = blockRemains / 0x200
1215- if blockBuffer > 0 {
1216- MSATCap++
1217- }
1218- if blockBuffer+(4*MSATCap) > 0x200 {
1219- MSATCap++
946+ sector.start = offset
947+ offset = writeSectorChain((sectorSize+0x3F)>>6, offset)
948+ }
949+ for c.position&0x1FF != 0 {
950+ c.writeUint32(endOfChain)
951+ }
952+ return sector
953+}
954+
955+// write provides a function to create compound file package stream.
956+func (c *cfb) write() []byte {
957+ c.prepare()
958+ location := c.locate()
959+ c.stream = make([]byte, location[7]<<9)
960+ var i, j int
961+ for i = 0; i < 8; i++ {
962+ c.writeBytes([]byte{oleIdentifier[i]})
963+ }
964+ c.writeBytes(make([]byte, 16))
965+ c.writeUint16(0x003E)
966+ c.writeUint16(0x0003)
967+ c.writeUint16(0xFFFE)
968+ c.writeUint16(0x0009)
969+ c.writeUint16(0x0006)
970+ c.writeBytes(make([]byte, 10))
971+ c.writeUint32(location[2])
972+ c.writeUint32(location[0] + location[1] + location[2] + location[3] - 1)
973+ c.writeUint32(0)
974+ c.writeUint32(1 << 12)
975+ if location[3] != 0 {
976+ c.writeUint32(location[0] + location[1] + location[2] - 1)
977+ } else {
978+ c.writeUint32(endOfChain)
979+ }
980+ c.writeUint32(location[3])
981+ if location[1] != 0 {
982+ c.writeUint32(location[0] - 1)
983+ } else {
984+ c.writeUint32(endOfChain)
985+ }
986+ c.writeUint32(location[1])
987+ c.writeMSAT(location)
988+ sector := c.writeSectorChains(location)
989+ c.writeDirectoryEntry(location)
990+ for i = 1; i < len(c.sectors); i++ {
991+ sector = c.sectors[i]
992+ if sector.size >= 0x1000 {
993+ c.position = (sector.start + 1) << 9
994+ for j = 0; j < sector.size; j++ {
995+ c.writeBytes([]byte{sector.content[j]})
1220996 }
1221- if MSATCap > MSATBlocks {
1222- MSATBlocks, blocksChanged = MSATCap, true
997+ for ; j&0x1FF != 0; j++ {
998+ c.writeBytes([]byte{0})
1223999 }
12241000 }
12251001 }
1226- MSAT = c.writeMSAT(MSATBlocks, SATBlocks, MSAT)
1227- blocks, SAT := c.writeSAT(MSATBlocks, SATBlocks, SSATBlocks, directoryBlocks, fileBlocks, streamBlocks, SAT)
1228- for i := 0; i < 8; i++ {
1229- storage.writeBytes([]byte{oleIdentifier[i]})
1230- }
1231- storage.writeBytes(make([]byte, 16))
1232- storage.writeUint16(0x003E)
1233- storage.writeUint16(0x0003)
1234- storage.writeUint16(-2)
1235- storage.writeUint16(9)
1236- storage.writeUint32(6)
1237- storage.writeUint32(0)
1238- storage.writeUint32(0)
1239- storage.writeUint32(SATBlocks)
1240- storage.writeUint32(MSATBlocks + SATBlocks + SSATBlocks)
1241- storage.writeUint32(0)
1242- storage.writeUint32(0x00001000)
1243- storage.writeUint32(SATBlocks + MSATBlocks)
1244- storage.writeUint32(SSATBlocks)
1245- if MSATBlocks > 0 {
1246- storage.writeUint32(0)
1247- storage.writeUint32(MSATBlocks)
1248- } else {
1249- storage.writeUint32(-2)
1250- storage.writeUint32(0)
1251- }
1252- for _, block := range MSAT {
1253- storage.writeUint32(block)
1254- }
1255- for i := 0; i < SATBlocks*128; i++ {
1256- if i < len(SAT) {
1257- storage.writeUint32(SAT[i])
1258- continue
1002+ for i = 1; i < len(c.sectors); i++ {
1003+ sector = c.sectors[i]
1004+ if sector.size > 0 && sector.size < 0x1000 {
1005+ for j = 0; j < sector.size; j++ {
1006+ c.writeBytes([]byte{sector.content[j]})
1007+ }
1008+ for ; j&0x3F != 0; j++ {
1009+ c.writeBytes([]byte{0})
1010+ }
12591011 }
1260- storage.writeUint32(-1)
12611012 }
1262- fileStream, SSATStream := c.writeFileStream(encryptionInfoBuffer, SSAT)
1263- for _, block := range SSATStream {
1264- storage.writeUint32(block)
1013+ for c.position < len(c.stream) {
1014+ c.writeBytes([]byte{0})
12651015 }
1266- directoryEntry := c.writeDirectoryEntry(blocks, blocks-fileBlocks, size)
1267- storage.writeBytes(directoryEntry)
1268- storage.writeBytes(fileStream)
1269- storage.writeBytes(encryptedPackage)
1270- return storage.stream
1016+ return c.stream
12711017 }
--- a/crypt_test.go
+++ b/crypt_test.go
@@ -59,11 +59,6 @@ func TestEncryptionMechanism(t *testing.T) {
5959 assert.EqualError(t, err, ErrUnknownEncryptMechanism.Error())
6060 }
6161
62-func TestEncryptionWriteDirectoryEntry(t *testing.T) {
63- cfb := cfb{}
64- assert.Equal(t, 1536, len(cfb.writeDirectoryEntry(0, 0, -1)))
65-}
66-
6762 func TestHashing(t *testing.T) {
6863 assert.Equal(t, hashing("unsupportedHashAlgorithm", []byte{}), []byte(nil))
6964 }
Show on old repository browser