diff options
-rw-r--r-- | cmd/verify.go | 30 | ||||
-rw-r--r-- | core/crypt.go | 10 | ||||
-rw-r--r-- | core/storage.go | 35 | ||||
-rw-r--r-- | fsverify-paper.md | 9 | ||||
-rw-r--r-- | part.fsverify | bin | 33081 -> 32967 bytes |
5 files changed, 47 insertions, 37 deletions
diff --git a/cmd/verify.go b/cmd/verify.go index 9c7947c..dc7a700 100644 --- a/cmd/verify.go +++ b/cmd/verify.go @@ -1,9 +1,11 @@ package cmd import ( + "bufio" "fmt" "github.com/axtloss/fsverify/core" "github.com/spf13/cobra" + "os" ) func NewVerifyCommand() *cobra.Command { @@ -19,20 +21,21 @@ func NewVerifyCommand() *cobra.Command { func ValidateCommand(_ *cobra.Command, args []string) error { - header, err := core.ReadHeader("./part.fsverify") - fmt.Println(header.MagicNumber) - fmt.Println(header.Signature) - fmt.Println(header.FilesystemSize) - fmt.Println(header.TableSize) + header, err := core.ReadHeader("/dev/sda") + fmt.Printf("Magic Number: %d\n", header.MagicNumber) + fmt.Printf("Signature: %s\n" + header.Signature) + fmt.Printf("FsSize: %d\n", header.FilesystemSize) + fmt.Printf("Table Size: %d\n", header.TableSize) + fmt.Printf("Table Size Unit: %d\n", header.TableUnit) if err != nil { return err } - dbfile, err := core.ReadDB("./part.fsverify") + dbfile, err := core.ReadDB("/dev/sda") if err != nil { return err } fmt.Println("DBFILE: ", dbfile) - db, err := core.OpenDB(dbfile) + db, err := core.OpenDB(dbfile, true) if err != nil { return err } @@ -42,5 +45,16 @@ func ValidateCommand(_ *cobra.Command, args []string) error { return err } fmt.Println(getnode) - return nil + + fmt.Println("----") + + disk, err := os.Open("./partition.raw") + reader := bufio.NewReader(disk) + part, err := core.ReadBlock(getnode, reader) + if err != nil { + return err + } + hash, err := core.CalculateBlockHash(part) + fmt.Println(hash) + return err } diff --git a/core/crypt.go b/core/crypt.go index 6de70e6..f741b8e 100644 --- a/core/crypt.go +++ b/core/crypt.go @@ -1,25 +1,25 @@ package core import ( + "bytes" "crypto/sha256" "fmt" "io" - "os" "strings" ) func calculateStringHash(a string) (string, error) { hash := sha256.New() hash.Write([]byte(a)) - hashInBytes := hash.Sum(nil)[:20] + hashInBytes := hash.Sum(nil)[:32] return strings.TrimSpace(fmt.Sprintf("%x", hashInBytes)), nil } -func calculateFileHash(file *os.File) (string, error) { +func CalculateBlockHash(block []byte) (string, error) { hash := sha256.New() - if _, err := io.Copy(hash, file); err != nil { + if _, err := io.Copy(hash, bytes.NewReader(block)); err != nil { return "", err } - hashInBytes := hash.Sum(nil)[:20] + hashInBytes := hash.Sum(nil)[:32] return strings.TrimSpace(fmt.Sprintf("%x", hashInBytes)), nil } diff --git a/core/storage.go b/core/storage.go index b3e1b53..363db0f 100644 --- a/core/storage.go +++ b/core/storage.go @@ -7,7 +7,6 @@ import ( "fmt" "io" "os" - "strings" bolt "go.etcd.io/bbolt" ) @@ -41,7 +40,8 @@ func ReadHeader(partition string) (Header, error) { header := Header{} reader := bufio.NewReader(part) MagicNumber := make([]byte, 2) - Signature := make([]byte, 302) + UntrustedHash := make([]byte, 100) + TrustedHash := make([]byte, 88) FileSystemSize := make([]byte, 4) TableSize := make([]byte, 4) TableUnit := make([]byte, 1) @@ -53,7 +53,11 @@ func ReadHeader(partition string) (Header, error) { } header.MagicNumber = int(MagicNum) - _, err = reader.Read(Signature) + _, err = reader.Read(UntrustedHash) + if err != nil { + return Header{}, err + } + _, err = reader.Read(TrustedHash) if err != nil { return Header{}, err } @@ -70,7 +74,7 @@ func ReadHeader(partition string) (Header, error) { return Header{}, err } - header.Signature = string(Signature) + header.Signature = fmt.Sprintf("untrusted comment: signature from minisign secret key\r\n%s\r\ntrusted comment: timestamp:0\tfile:fsverify\thashed\r\n%s\r\n", UntrustedHash, TrustedHash) header.FilesystemSize = int(binary.BigEndian.Uint16(FileSystemSize)) header.TableSize = int(binary.BigEndian.Uint32(TableSize)) switch TableUnit[0] { @@ -104,7 +108,7 @@ func ReadDB(partition string) (string, error) { defer part.Close() reader := bufio.NewReader(part) - _, err = reader.Read(make([]byte, 313)) + _, err = reader.Read(make([]byte, 199)) if err != nil { fmt.Println(err) return "", err @@ -135,12 +139,12 @@ func ReadDB(partition string) (string, error) { return temp + "/verify.db", nil } -func OpenDB(dbpath string) (*bolt.DB, error) { +func OpenDB(dbpath string, readonly bool) (*bolt.DB, error) { _, exist := os.Stat(dbpath) if os.IsNotExist(exist) { os.Create(dbpath) } - db, err := bolt.Open(dbpath, 0777, nil) + db, err := bolt.Open(dbpath, 0777, &bolt.Options{ReadOnly: readonly}) if err != nil { return nil, err } @@ -151,11 +155,13 @@ func AddNode(node Node, db *bolt.DB) error { var err error var deferDB bool if db == nil { - db, err = OpenDB("my.db") + db, err = OpenDB("my.db", false) if err != nil { return err } deferDB = true + } else if db.IsReadOnly() { + return fmt.Errorf("Error: database is opened read only, unable to add nodes") } err = db.Update(func(tx *bolt.Tx) error { nodes, err := tx.CreateBucketIfNotExists([]byte("Nodes")) @@ -180,7 +186,7 @@ func GetNode(checksum string, db *bolt.DB) (Node, error) { var err error var deferDB bool if db == nil { - db, err = OpenDB("my.db") + db, err = OpenDB("my.db", true) if err != nil { return Node{}, err } @@ -198,14 +204,3 @@ func GetNode(checksum string, db *bolt.DB) (Node, error) { } return node, err } - -func VerifyNode(node Node, nextNode Node) error { - nodeHash, err := calculateStringHash(fmt.Sprintf("%d%d%s%s", node.BlockStart, node.BlockEnd, node.BlockSum, node.PrevNodeSum)) - if err != nil { - return err - } - if strings.Compare(nodeHash, nextNode.PrevNodeSum) != 0 { - return fmt.Errorf("Node %s is not valid!", node.PrevNodeSum) - } - return nil -} diff --git a/fsverify-paper.md b/fsverify-paper.md index 82b9cf8..819c422 100644 --- a/fsverify-paper.md +++ b/fsverify-paper.md @@ -2,19 +2,20 @@ The FsVerify partition contains a header with the necessary metadata for the filesystem verification, and a bbolt database containing all File and Directory nodes to be checked. ## Partition Header -`<magic number> <signature> <filesystem size> <table size> <table unit>` +`<magic number> <untrusted signature hash> <trusted signature hash> <filesystem size> <table size> <table unit>` Field|Size|Purpose|Value -----|----|-------|----- magic number|2 bytes|sanity check|0xACAB -signature|302 bytes|minisign signature| +untrusted signature hash|100 bytes|untrusted signature from minisign +trusted signature hash|88 bytes|trusted signature from minisign filesystem size|4 bytes|size of the original filesystem in gb -table size|4 bytes| size of the table in \<table unit\> +table size|4 bytes| size of the table in <table unit\> table unit|1 byte|unit of the table size|0x0: bytes, 0x1: kilobytes, 0x2: megabytes, 0x3: gigabytes, 0x4: terabytes, 0x5: petabytes Due to the filesystem and table size field, which can go up to 0xFFFFFFFF (16777215), the maximum supported partition size and table size is 16777215gb (~16pb) -The entire Head should be a total of 312 bytes long, reaching from 0x0 to 0x138 +The entire Head should be a total of 199 bytes long, reaching from 0x0 to 0xC7 ## Partition Contents / Database The main database containing the checksums is a [bbolt](https://github.com/etcd-io/bbolt) datbase consisting of a single bucket called `Nodes` diff --git a/part.fsverify b/part.fsverify Binary files differindex 1890f21..bd59960 100644 --- a/part.fsverify +++ b/part.fsverify |