osbase/build/mkverity: make build reproducible

The verity encoder previously generated a random salt. To make the build
reproducible, the salt is now taken from a hash of the entire input
file.

I shortened the salt from 64 bytes to 16 bytes. This is enough for the
purpose of the salt, which is to make hash collisions not reusable
across images. A potential benefit of the 64 byte salt is that it fills
a sha256 block and thus the remaining data is aligned to that block
size. On the other hand, with a 16 byte salt, one fewer hash block is
needed because the sha256 length fits in the last partially filled
block.

The encoder also generated a random UUID, but this did not affect
reproducibility as we do not write the superblock. For now, I removed
the UUID generation as it is completely unused.

Now, the build of //metropolis/node:oci_image is reproducible on my
machine.

Change-Id: I756ca31d02e65c7d6ce7bbfd6749c835ab696f3f
Reviewed-on: https://review.monogon.dev/c/monogon/+/4418
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
Tested-by: Jenkins CI
diff --git a/osbase/build/mkverity/mkverity.go b/osbase/build/mkverity/mkverity.go
index 82db0da..f75845d 100644
--- a/osbase/build/mkverity/mkverity.go
+++ b/osbase/build/mkverity/mkverity.go
@@ -11,6 +11,7 @@
 package main
 
 import (
+	"crypto/sha256"
 	"flag"
 	"fmt"
 	"io"
@@ -55,20 +56,34 @@
 	}
 	defer outputImage.Close()
 
-	// Copy the input data into the output file, then rewind dataImage to be read
-	// again by the Verity encoder.
+	// Copy the input data into the output file, then rewind dataImage.
 	_, err = io.Copy(outputImage, dataImage)
 	if err != nil {
 		return nil, err
 	}
-	_, err = dataImage.Seek(0, os.SEEK_SET)
+	_, err = dataImage.Seek(0, io.SeekStart)
 	if err != nil {
 		return nil, err
 	}
 
+	// Hash the input data for use as the salt, then rewind dataImage. The purpose
+	// of the salt is to prevent reuse of collisions across different images. 16
+	// bytes is enough for this. We use a hash of the input instead of generating
+	// random bytes to make the build reproducible.
+	dataHash := sha256.New()
+	_, err = io.Copy(dataHash, dataImage)
+	if err != nil {
+		return nil, err
+	}
+	_, err = dataImage.Seek(0, io.SeekStart)
+	if err != nil {
+		return nil, err
+	}
+	salt := dataHash.Sum(nil)[:16]
+
 	// Write outputImage contents. Start with initializing a verity encoder,
-	// seting outputImage as its output.
-	v, err := verity.NewEncoder(outputImage, bs, bs, wsb)
+	// setting outputImage as its output.
+	v, err := verity.NewEncoder(outputImage, bs, bs, salt, wsb)
 	if err != nil {
 		return nil, fmt.Errorf("while initializing a verity encoder: %w", err)
 	}