diff --git a/pkg/api/entries.go b/pkg/api/entries.go
index d88770f63c241a302c27bcbd851bb98563dfdef3..a81da008f807a75ca45a4dfd2b4198126408b821 100644
--- a/pkg/api/entries.go
+++ b/pkg/api/entries.go
@@ -221,6 +221,7 @@ func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middl
 				log.RequestIDLogger(params.HTTPRequest).Infof("no attestation for %s", uuid)
 				return
 			}
+			// TODO stop using uuid and use attestation hash
 			if err := storeAttestation(context.Background(), uuid, attestation); err != nil {
 				log.RequestIDLogger(params.HTTPRequest).Errorf("error storing attestation: %s", err)
 			}
diff --git a/pkg/generated/models/intoto_v001_schema.go b/pkg/generated/models/intoto_v001_schema.go
index 58fc5fd5ddca3382ea3c3922535a6a6a27581bf0..e43e699f79af7e62e36ce48081927235bbed07b4 100644
--- a/pkg/generated/models/intoto_v001_schema.go
+++ b/pkg/generated/models/intoto_v001_schema.go
@@ -153,6 +153,9 @@ type IntotoV001SchemaContent struct {
 
 	// hash
 	Hash *IntotoV001SchemaContentHash `json:"hash,omitempty"`
+
+	// payload hash
+	PayloadHash *IntotoV001SchemaContentPayloadHash `json:"payloadHash,omitempty"`
 }
 
 // Validate validates this intoto v001 schema content
@@ -163,6 +166,10 @@ func (m *IntotoV001SchemaContent) Validate(formats strfmt.Registry) error {
 		res = append(res, err)
 	}
 
+	if err := m.validatePayloadHash(formats); err != nil {
+		res = append(res, err)
+	}
+
 	if len(res) > 0 {
 		return errors.CompositeValidationError(res...)
 	}
@@ -188,6 +195,25 @@ func (m *IntotoV001SchemaContent) validateHash(formats strfmt.Registry) error {
 	return nil
 }
 
+func (m *IntotoV001SchemaContent) validatePayloadHash(formats strfmt.Registry) error {
+	if swag.IsZero(m.PayloadHash) { // not required
+		return nil
+	}
+
+	if m.PayloadHash != nil {
+		if err := m.PayloadHash.Validate(formats); err != nil {
+			if ve, ok := err.(*errors.Validation); ok {
+				return ve.ValidateName("content" + "." + "payloadHash")
+			} else if ce, ok := err.(*errors.CompositeError); ok {
+				return ce.ValidateName("content" + "." + "payloadHash")
+			}
+			return err
+		}
+	}
+
+	return nil
+}
+
 // ContextValidate validate this intoto v001 schema content based on the context it is used
 func (m *IntotoV001SchemaContent) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
 	var res []error
@@ -196,6 +222,10 @@ func (m *IntotoV001SchemaContent) ContextValidate(ctx context.Context, formats s
 		res = append(res, err)
 	}
 
+	if err := m.contextValidatePayloadHash(ctx, formats); err != nil {
+		res = append(res, err)
+	}
+
 	if len(res) > 0 {
 		return errors.CompositeValidationError(res...)
 	}
@@ -218,6 +248,22 @@ func (m *IntotoV001SchemaContent) contextValidateHash(ctx context.Context, forma
 	return nil
 }
 
+func (m *IntotoV001SchemaContent) contextValidatePayloadHash(ctx context.Context, formats strfmt.Registry) error {
+
+	if m.PayloadHash != nil {
+		if err := m.PayloadHash.ContextValidate(ctx, formats); err != nil {
+			if ve, ok := err.(*errors.Validation); ok {
+				return ve.ValidateName("content" + "." + "payloadHash")
+			} else if ce, ok := err.(*errors.CompositeError); ok {
+				return ce.ValidateName("content" + "." + "payloadHash")
+			}
+			return err
+		}
+	}
+
+	return nil
+}
+
 // MarshalBinary interface implementation
 func (m *IntotoV001SchemaContent) MarshalBinary() ([]byte, error) {
 	if m == nil {
@@ -345,3 +391,113 @@ func (m *IntotoV001SchemaContentHash) UnmarshalBinary(b []byte) error {
 	*m = res
 	return nil
 }
+
+// IntotoV001SchemaContentPayloadHash Specifies the hash algorithm and value covering the payload within the DSSE envelope
+//
+// swagger:model IntotoV001SchemaContentPayloadHash
+type IntotoV001SchemaContentPayloadHash struct {
+
+	// The hashing function used to compute the hash value
+	// Required: true
+	// Enum: [sha256]
+	Algorithm *string `json:"algorithm"`
+
+	// The hash value for the envelope's payload
+	// Required: true
+	Value *string `json:"value"`
+}
+
+// Validate validates this intoto v001 schema content payload hash
+func (m *IntotoV001SchemaContentPayloadHash) Validate(formats strfmt.Registry) error {
+	var res []error
+
+	if err := m.validateAlgorithm(formats); err != nil {
+		res = append(res, err)
+	}
+
+	if err := m.validateValue(formats); err != nil {
+		res = append(res, err)
+	}
+
+	if len(res) > 0 {
+		return errors.CompositeValidationError(res...)
+	}
+	return nil
+}
+
+var intotoV001SchemaContentPayloadHashTypeAlgorithmPropEnum []interface{}
+
+func init() {
+	var res []string
+	if err := json.Unmarshal([]byte(`["sha256"]`), &res); err != nil {
+		panic(err)
+	}
+	for _, v := range res {
+		intotoV001SchemaContentPayloadHashTypeAlgorithmPropEnum = append(intotoV001SchemaContentPayloadHashTypeAlgorithmPropEnum, v)
+	}
+}
+
+const (
+
+	// IntotoV001SchemaContentPayloadHashAlgorithmSha256 captures enum value "sha256"
+	IntotoV001SchemaContentPayloadHashAlgorithmSha256 string = "sha256"
+)
+
+// prop value enum
+func (m *IntotoV001SchemaContentPayloadHash) validateAlgorithmEnum(path, location string, value string) error {
+	if err := validate.EnumCase(path, location, value, intotoV001SchemaContentPayloadHashTypeAlgorithmPropEnum, true); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (m *IntotoV001SchemaContentPayloadHash) validateAlgorithm(formats strfmt.Registry) error {
+
+	if err := validate.Required("content"+"."+"payloadHash"+"."+"algorithm", "body", m.Algorithm); err != nil {
+		return err
+	}
+
+	// value enum
+	if err := m.validateAlgorithmEnum("content"+"."+"payloadHash"+"."+"algorithm", "body", *m.Algorithm); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (m *IntotoV001SchemaContentPayloadHash) validateValue(formats strfmt.Registry) error {
+
+	if err := validate.Required("content"+"."+"payloadHash"+"."+"value", "body", m.Value); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// ContextValidate validate this intoto v001 schema content payload hash based on the context it is used
+func (m *IntotoV001SchemaContentPayloadHash) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
+	var res []error
+
+	if len(res) > 0 {
+		return errors.CompositeValidationError(res...)
+	}
+	return nil
+}
+
+// MarshalBinary interface implementation
+func (m *IntotoV001SchemaContentPayloadHash) MarshalBinary() ([]byte, error) {
+	if m == nil {
+		return nil, nil
+	}
+	return swag.WriteJSON(m)
+}
+
+// UnmarshalBinary interface implementation
+func (m *IntotoV001SchemaContentPayloadHash) UnmarshalBinary(b []byte) error {
+	var res IntotoV001SchemaContentPayloadHash
+	if err := swag.ReadJSON(b, &res); err != nil {
+		return err
+	}
+	*m = res
+	return nil
+}
diff --git a/pkg/types/intoto/v0.0.1/entry.go b/pkg/types/intoto/v0.0.1/entry.go
index 66cc065f3bf5ce0d9f359f58fe8f076cc4c0131c..fb4f230cc8cbd46f8b99e77aefea9e5b8bc9d731 100644
--- a/pkg/types/intoto/v0.0.1/entry.go
+++ b/pkg/types/intoto/v0.0.1/entry.go
@@ -23,7 +23,6 @@ import (
 	"encoding/base64"
 	"encoding/hex"
 	"encoding/json"
-	"errors"
 	"fmt"
 	"io/ioutil"
 	"path/filepath"
@@ -35,6 +34,8 @@ import (
 	"github.com/go-openapi/strfmt"
 	"github.com/go-openapi/swag"
 
+	"github.com/pkg/errors"
+
 	"github.com/sigstore/rekor/pkg/generated/models"
 	"github.com/sigstore/rekor/pkg/log"
 	"github.com/sigstore/rekor/pkg/pki"
@@ -150,6 +151,18 @@ func (v *V001Entry) Canonicalize(ctx context.Context) ([]byte, error) {
 			},
 		},
 	}
+	attestation := v.Attestation()
+	if attestation != nil {
+		decodedAttestation, err := base64.StdEncoding.DecodeString(string(attestation))
+		if err != nil {
+			return nil, errors.Wrap(err, "decoding attestation")
+		}
+		attH := sha256.Sum256(decodedAttestation)
+		canonicalEntry.Content.PayloadHash = &models.IntotoV001SchemaContentPayloadHash{
+			Algorithm: swag.String(models.IntotoV001SchemaContentHashAlgorithmSha256),
+			Value:     swag.String(hex.EncodeToString(attH[:])),
+		}
+	}
 
 	itObj := models.Intoto{}
 	itObj.APIVersion = swag.String(APIVERSION)
@@ -194,8 +207,9 @@ func (v *V001Entry) validate() error {
 }
 
 func (v *V001Entry) Attestation() []byte {
-	if len(v.env.Payload) > viper.GetInt("max_attestation_size") {
-		log.Logger.Infof("Skipping attestation storage, size %d is greater than max %d", len(v.env.Payload), viper.GetInt("max_attestation_size"))
+	storageSize := base64.StdEncoding.DecodedLen(len(v.env.Payload))
+	if storageSize > viper.GetInt("max_attestation_size") {
+		log.Logger.Infof("Skipping attestation storage, size %d is greater than max %d", storageSize, viper.GetInt("max_attestation_size"))
 		return nil
 	}
 	return []byte(v.env.Payload)
diff --git a/pkg/types/intoto/v0.0.1/intoto_v0_0_1_schema.json b/pkg/types/intoto/v0.0.1/intoto_v0_0_1_schema.json
index a8e8c054aa67ca9a2f6d88453d001849cc67a374..39117a66140b59251a0165eca5e02c704539f5af 100644
--- a/pkg/types/intoto/v0.0.1/intoto_v0_0_1_schema.json
+++ b/pkg/types/intoto/v0.0.1/intoto_v0_0_1_schema.json
@@ -34,6 +34,26 @@
                         "value"
                     ],
                     "readOnly": true
+                },
+                "payloadHash": {
+                    "description": "Specifies the hash algorithm and value covering the payload within the DSSE envelope",
+                    "type": "object",
+                    "properties": {
+                        "algorithm": {
+                            "description": "The hashing function used to compute the hash value",
+                            "type": "string",
+                            "enum": [ "sha256" ]
+                        },
+                        "value": {
+                            "description": "The hash value for the envelope's payload",
+                            "type": "string"
+                        }
+                    },
+                    "required": [
+                        "algorithm",
+                        "value"
+                    ],
+                    "readOnly": true
                 }
             }
         },
diff --git a/tests/e2e_test.go b/tests/e2e_test.go
index c96aa9df90525563d2b69a3956584d4290524b12..2f43e4965d789add6cb1c6521ed696804ac04d52 100644
--- a/tests/e2e_test.go
+++ b/tests/e2e_test.go
@@ -56,6 +56,7 @@ import (
 	"github.com/sigstore/rekor/pkg/generated/models"
 	"github.com/sigstore/rekor/pkg/sharding"
 	"github.com/sigstore/rekor/pkg/signer"
+	"github.com/sigstore/rekor/pkg/types"
 	rekord "github.com/sigstore/rekor/pkg/types/rekord/v0.0.1"
 	"github.com/sigstore/rekor/pkg/util"
 	"github.com/sigstore/sigstore/pkg/cryptoutils"
@@ -449,7 +450,7 @@ func TestIntoto(t *testing.T) {
 	if err := json.Unmarshal([]byte(out), &g); err != nil {
 		t.Fatal(err)
 	}
-	// The atteestation should be stored at /var/run/attestations/$uuid
+	// The attestation should be stored at /var/run/attestations/$uuid
 
 	got := in_toto.ProvenanceStatement{}
 	if err := json.Unmarshal(g.Attestation, &got); err != nil {
@@ -459,6 +460,25 @@ func TestIntoto(t *testing.T) {
 		t.Errorf("diff: %s", diff)
 	}
 
+	attHash := sha256.Sum256(g.Attestation)
+
+	intotoModel := &models.IntotoV001Schema{}
+	if err := types.DecodeEntry(g.Body.(map[string]interface{})["IntotoObj"], intotoModel); err != nil {
+		t.Errorf("could not convert body into intoto type: %v", err)
+	}
+	if intotoModel.Content == nil || intotoModel.Content.PayloadHash == nil {
+		t.Errorf("could not find hash over attestation %v", intotoModel)
+	}
+	recordedPayloadHash, err := hex.DecodeString(*intotoModel.Content.PayloadHash.Value)
+	if err != nil {
+		t.Errorf("error converting attestation hash to []byte: %v", err)
+	}
+
+	if !bytes.Equal(attHash[:], recordedPayloadHash) {
+		t.Fatal(fmt.Errorf("attestation hash %v doesnt match the payload we sent %v", hex.EncodeToString(attHash[:]),
+			*intotoModel.Content.PayloadHash.Value))
+	}
+
 	out = runCli(t, "upload", "--artifact", attestationPath, "--type", "intoto", "--public-key", pubKeyPath)
 	outputContains(t, out, "Entry already exists")