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/verity/encoder.go b/osbase/verity/encoder.go
index 5a968cd..6ba8b97 100644
--- a/osbase/verity/encoder.go
+++ b/osbase/verity/encoder.go
@@ -28,7 +28,6 @@
 
 import (
 	"bytes"
-	"crypto/rand"
 	"crypto/sha256"
 	"encoding/binary"
 	"encoding/hex"
@@ -93,19 +92,10 @@
 		version:       1,
 		hashType:      1,
 		algorithm:     [32]byte{'s', 'h', 'a', '2', '5', '6'},
-		saltSize:      64,
 		dataBlockSize: 4096,
 		hashBlockSize: 4096,
 	}
 
-	// Fill in the superblock UUID and cryptographic salt.
-	if _, err := rand.Read(sb.uuid[:]); err != nil {
-		return nil, fmt.Errorf("when generating UUID: %w", err)
-	}
-	if _, err := rand.Read(sb.saltBuffer[:]); err != nil {
-		return nil, fmt.Errorf("when generating salt: %w", err)
-	}
-
 	return &sb, nil
 }
 
@@ -308,6 +298,10 @@
 // VerityParameterList returns a list of Verity target parameters, ordered
 // as they would appear in a parameter string.
 func (t *MappingTable) VerityParameterList() []string {
+	salt := hex.EncodeToString(t.superblock.salt())
+	if salt == "" {
+		salt = "-"
+	}
 	return []string{
 		"1",
 		t.DataDevicePath,
@@ -318,7 +312,7 @@
 		strconv.FormatInt(t.HashStart, 10),
 		t.superblock.algorithmName(),
 		hex.EncodeToString(t.rootHash),
-		hex.EncodeToString(t.superblock.salt()),
+		salt,
 	}
 }
 
@@ -433,13 +427,14 @@
 // encoder will write to the given io.Writer object.
 // A verity superblock will be written, preceding the hash tree, if
 // writeSb is true.
-func NewEncoder(out io.Writer, dataBlockSize, hashBlockSize uint32, writeSb bool) (*encoder, error) {
+func NewEncoder(out io.Writer, dataBlockSize, hashBlockSize uint32, salt []byte, writeSb bool) (*encoder, error) {
 	sb, err := newSuperblock()
 	if err != nil {
 		return nil, fmt.Errorf("while creating a superblock: %w", err)
 	}
 	sb.dataBlockSize = dataBlockSize
 	sb.hashBlockSize = hashBlockSize
+	sb.saltSize = uint16(copy(sb.saltBuffer[:], salt))
 
 	e := encoder{
 		out:     out,
diff --git a/osbase/verity/encoder_test.go b/osbase/verity/encoder_test.go
index 012cb27..2c9c35b 100644
--- a/osbase/verity/encoder_test.go
+++ b/osbase/verity/encoder_test.go
@@ -93,7 +93,8 @@
 	// Create a Verity encoder, backed with hfd. Configure it to write the
 	// Verity superblock. Use 4096-byte blocks.
 	bs := uint32(4096)
-	verityEnc, err := NewEncoder(hfd, bs, bs, true)
+	salt := []byte("testsalt")
+	verityEnc, err := NewEncoder(hfd, bs, bs, salt, true)
 	require.NoError(t, err, "while creating a Verity encoder")
 
 	// Write pseudorandom data both to the Verity-protected data device, and