Repository: google/go-tpm
Pull request #92 (2019-04-18 18:03:16)

Replace global prefix size with U32Bytes and U16Bytes
Replace global prefix size with U32Bytes and U16Bytes
Modify tpm1.2 and tpm2.0 commands to use these types instead of []byte
@twitchy-jsonp did most of the heavy lifting rewriting tpmutil/encoding.go to use reflect.Value instead of {}interface.

twitchy-jsonp: These changes have been tested using a real TPM for `tpm2`, and tested as well as we can with a simulator on `tpm`. For tests that were already broken with `tpm`, we were able to verify that the same bytes were being emitted by go-tpm.

Patch:
diff --git a/tpm/commands.go b/tpm/commands.go
index 7177b7e..b9033d4 100644
--- a/tpm/commands.go
+++ b/tpm/commands.go
@@ -67,7 +67,7 @@ func osap(rw io.ReadWriter, osap *osapCommand) (*osapResponse, error) {
 }
 
 // seal performs a seal operation on the TPM.
-func seal(rw io.ReadWriter, sc *sealCommand, pcrs *pcrInfoLong, data []byte, ca *commandAuth) (*tpmStoredData, *responseAuth, uint32, error) {
+func seal(rw io.ReadWriter, sc *sealCommand, pcrs *pcrInfoLong, data tpmutil.U32Bytes, ca *commandAuth) (*tpmStoredData, *responseAuth, uint32, error) {
 	pcrsize := binary.Size(pcrs)
 	if pcrsize < 0 {
 		return nil, nil, 0, errors.New("couldn't compute the size of a pcrInfoLong")
@@ -91,7 +91,7 @@ func seal(rw io.ReadWriter, sc *sealCommand, pcrs *pcrInfoLong, data []byte, ca
 // unseal data sealed by the TPM.
 func unseal(rw io.ReadWriter, keyHandle tpmutil.Handle, sealed *tpmStoredData, ca1 *commandAuth, ca2 *commandAuth) ([]byte, *responseAuth, *responseAuth, uint32, error) {
 	in := []interface{}{keyHandle, sealed, ca1, ca2}
-	var outb []byte
+	var outb tpmutil.U32Bytes
 	var ra1 responseAuth
 	var ra2 responseAuth
 	out := []interface{}{&outb, &ra1, &ra2}
@@ -149,8 +149,8 @@ func getCapability(rw io.ReadWriter, cap, subcap uint32) ([]byte, error) {
 	if err != nil {
 		return nil, err
 	}
-	var b []byte
-	in := []interface{}{cap, subCapBytes}
+	var b tpmutil.U32Bytes
+	in := []interface{}{cap, tpmutil.U32Bytes(subCapBytes)}
 	out := []interface{}{&b}
 	if _, err := submitTPMRequest(rw, tagRQUCommand, ordGetCapability, in, out); err != nil {
 		return nil, err
@@ -159,7 +159,7 @@ func getCapability(rw io.ReadWriter, cap, subcap uint32) ([]byte, error) {
 }
 
 func nvReadValue(rw io.ReadWriter, index, offset, len uint32, ca *commandAuth) ([]byte, *responseAuth, uint32, error) {
-	var b []byte
+	var b tpmutil.U32Bytes
 	var ra responseAuth
 	in := []interface{}{index, offset, len, ca}
 	out := []interface{}{&b, &ra}
@@ -179,8 +179,8 @@ func quote2(rw io.ReadWriter, keyHandle tpmutil.Handle, hash [20]byte, pcrs *pcr
 	in := []interface{}{keyHandle, hash, pcrs, addVersion, ca}
 	var pcrShort pcrInfoShort
 	var capInfo capVersionInfo
-	var capBytes []byte
-	var sig []byte
+	var capBytes tpmutil.U32Bytes
+	var sig tpmutil.U32Bytes
 	var ra responseAuth
 	out := []interface{}{&pcrShort, &capBytes, &sig, &ra}
 	ret, err := submitTPMRequest(rw, tagRQUAuth1Command, ordQuote2, in, out)
@@ -189,17 +189,17 @@ func quote2(rw io.ReadWriter, keyHandle tpmutil.Handle, hash [20]byte, pcrs *pcr
 	}
 
 	// Deserialize the capInfo, if any.
-	if len(capBytes) == 0 {
+	if len([]byte(capBytes)) == 0 {
 		return &pcrShort, nil, capBytes, sig, &ra, ret, nil
 	}
 
 	size := binary.Size(capInfo.CapVersionFixed)
-	capInfo.VendorSpecific = make([]byte, len(capBytes)-size)
-	if _, err := tpmutil.Unpack(capBytes[:size], &capInfo.CapVersionFixed); err != nil {
+	capInfo.VendorSpecific = make([]byte, len([]byte(capBytes))-size)
+	if _, err := tpmutil.Unpack([]byte(capBytes)[:size], &capInfo.CapVersionFixed); err != nil {
 		return nil, nil, nil, nil, nil, 0, err
 	}
 
-	copy(capInfo.VendorSpecific, capBytes[size:])
+	copy(capInfo.VendorSpecific, []byte(capBytes)[size:])
 
 	return &pcrShort, &capInfo, capBytes, sig, &ra, ret, nil
 }
@@ -209,7 +209,7 @@ func quote2(rw io.ReadWriter, keyHandle tpmutil.Handle, hash [20]byte, pcrs *pcr
 func quote(rw io.ReadWriter, keyHandle tpmutil.Handle, hash [20]byte, pcrs *pcrSelection, ca *commandAuth) (*pcrComposite, []byte, *responseAuth, uint32, error) {
 	in := []interface{}{keyHandle, hash, pcrs, ca}
 	var pcrc pcrComposite
-	var sig []byte
+	var sig tpmutil.U32Bytes
 	var ra responseAuth
 	out := []interface{}{&pcrc, &sig, &ra}
 	ret, err := submitTPMRequest(rw, tagRQUAuth1Command, ordQuote, in, out)
@@ -225,7 +225,7 @@ func quote(rw io.ReadWriter, keyHandle tpmutil.Handle, hash [20]byte, pcrs *pcrS
 func makeIdentity(rw io.ReadWriter, encAuth digest, idDigest digest, k *key, ca1 *commandAuth, ca2 *commandAuth) (*key, []byte, *responseAuth, *responseAuth, uint32, error) {
 	in := []interface{}{encAuth, idDigest, k, ca1, ca2}
 	var aik key
-	var sig []byte
+	var sig tpmutil.U32Bytes
 	var ra1 responseAuth
 	var ra2 responseAuth
 	out := []interface{}{&aik, &sig, &ra1, &ra2}
@@ -239,7 +239,7 @@ func makeIdentity(rw io.ReadWriter, encAuth digest, idDigest digest, k *key, ca1
 
 // activateIdentity provides the TPM with an EK encrypted challenge and asks it to
 // decrypt the challenge and return the secret (symmetric key).
-func activateIdentity(rw io.ReadWriter, keyHandle tpmutil.Handle, blob []byte, ca1 *commandAuth, ca2 *commandAuth) (*symKey, *responseAuth, *responseAuth, uint32, error) {
+func activateIdentity(rw io.ReadWriter, keyHandle tpmutil.Handle, blob tpmutil.U32Bytes, ca1 *commandAuth, ca2 *commandAuth) (*symKey, *responseAuth, *responseAuth, uint32, error) {
 	in := []interface{}{keyHandle, blob, ca1, ca2}
 	var symkey symKey
 	var ra1 responseAuth
@@ -317,7 +317,7 @@ func ownerClear(rw io.ReadWriter, ca *commandAuth) (*responseAuth, uint32, error
 // owner auth. This operation can only be performed if there is no owner. The
 // TPM can be put into this state using TPM_OwnerClear. The encOwnerAuth and
 // encSRKAuth values must be encrypted using the endorsement key.
-func takeOwnership(rw io.ReadWriter, encOwnerAuth []byte, encSRKAuth []byte, srk *key, ca *commandAuth) (*key, *responseAuth, uint32, error) {
+func takeOwnership(rw io.ReadWriter, encOwnerAuth tpmutil.U32Bytes, encSRKAuth tpmutil.U32Bytes, srk *key, ca *commandAuth) (*key, *responseAuth, uint32, error) {
 	in := []interface{}{pidOwner, encOwnerAuth, encSRKAuth, srk, ca}
 	var k key
 	var ra responseAuth
@@ -344,9 +344,9 @@ func createWrapKey(rw io.ReadWriter, encUsageAuth digest, encMigrationAuth diges
 	return &k, &ra, ret, nil
 }
 
-func sign(rw io.ReadWriter, keyHandle tpmutil.Handle, data []byte, ca *commandAuth) ([]byte, *responseAuth, uint32, error) {
+func sign(rw io.ReadWriter, keyHandle tpmutil.Handle, data tpmutil.U32Bytes, ca *commandAuth) ([]byte, *responseAuth, uint32, error) {
 	in := []interface{}{keyHandle, data, ca}
-	var signature []byte
+	var signature tpmutil.U32Bytes
 	var ra responseAuth
 	out := []interface{}{&signature, &ra}
 	ret, err := submitTPMRequest(rw, tagRQUAuth1Command, ordSign, in, out)
diff --git a/tpm/constants.go b/tpm/constants.go
index 8dc8e4c..3b5b4f5 100644
--- a/tpm/constants.go
+++ b/tpm/constants.go
@@ -16,11 +16,6 @@ package tpm
 
 import "github.com/google/go-tpm/tpmutil"
 
-func init() {
-	// TPM 1.2 spec uses uint32 for length prefix of byte arrays.
-	tpmutil.UseTPM12LengthPrefixSize()
-}
-
 // Supported TPM commands.
 const (
 	tagPCRInfoLong     uint16 = 0x06
diff --git a/tpm/structures.go b/tpm/structures.go
index 4bb21f1..98be26f 100644
--- a/tpm/structures.go
+++ b/tpm/structures.go
@@ -17,7 +17,6 @@ package tpm
 import (
 	"crypto"
 	"crypto/rsa"
-	"encoding/binary"
 	"errors"
 	"fmt"
 	"io"
@@ -193,7 +192,7 @@ type keyParams struct {
 	AlgID     uint32
 	EncScheme uint16
 	SigScheme uint16
-	Params    []byte // Serialized rsaKeyParams or symmetricKeyParams.
+	Params    tpmutil.U32Bytes // Serialized rsaKeyParams or symmetricKeyParams.
 }
 
 // An rsaKeyParams encodes the length of the RSA prime in bits, the number of
@@ -202,13 +201,13 @@ type keyParams struct {
 type rsaKeyParams struct {
 	KeyLength uint32
 	NumPrimes uint32
-	Exponent  []byte
+	Exponent  tpmutil.U32Bytes
 }
 
 type symmetricKeyParams struct {
 	KeyLength uint32
 	BlockSize uint32
-	IV        []byte
+	IV        tpmutil.U32Bytes
 }
 
 // A key is a TPM representation of a key.
@@ -218,9 +217,9 @@ type key struct {
 	KeyFlags        uint32
 	AuthDataUsage   byte
 	AlgorithmParams keyParams
-	PCRInfo         []byte
-	PubKey          []byte
-	EncData         []byte
+	PCRInfo         tpmutil.U32Bytes
+	PubKey          tpmutil.U32Bytes
+	EncData         tpmutil.U32Bytes
 }
 
 // A key12 is a newer TPM representation of a key.
@@ -231,73 +230,29 @@ type key12 struct {
 	KeyFlags        uint32
 	AuthDataUsage   byte
 	AlgorithmParams keyParams
-	PCRInfo         []byte // This must be a serialization of a pcrInfoLong.
-	PubKey          []byte
-	EncData         []byte
+	PCRInfo         tpmutil.U32Bytes // This must be a serialization of a pcrInfoLong.
+	PubKey          tpmutil.U32Bytes
+	EncData         tpmutil.U32Bytes
 }
 
 // A pubKey represents a public key known to the TPM.
 type pubKey struct {
 	AlgorithmParams keyParams
-	Key             []byte
+	Key             tpmutil.U32Bytes
 }
 
 // A symKey is a TPM representation of a symmetric key.
 type symKey struct {
 	AlgID     uint32
 	EncScheme uint16
-	Key       []byte
-}
-
-// TPMMarshal will marshal the symKey into a byte Buffer as specified the TPM spec.
-func (k *symKey) TPMMarshal(out io.Writer) error {
-	if err := binary.Write(out, binary.BigEndian, &k.AlgID); err != nil {
-		return err
-	}
-	if err := binary.Write(out, binary.BigEndian, &k.EncScheme); err != nil {
-		return err
-	}
-	if err := binary.Write(out, binary.BigEndian, uint16(len(k.Key))); err != nil {
-		return err
-	}
-	if err := binary.Write(out, binary.BigEndian, k.Key); err != nil {
-		return err
-	}
-	return nil
-}
-
-// TPMUnmarshal will parse the byte Buffer and populate the symKey.
-func (k *symKey) TPMUnmarshal(in io.Reader) error {
-	if err := binary.Read(in, binary.BigEndian, &k.AlgID); err != nil {
-		return err
-	}
-	if err := binary.Read(in, binary.BigEndian, &k.EncScheme); err != nil {
-		return err
-	}
-	var size uint16
-	if err := binary.Read(in, binary.BigEndian, &size); err != nil {
-		return err
-	}
-	key := make([]byte, size)
-	if err := binary.Read(in, binary.BigEndian, &key); err != nil {
-		return err
-	}
-	k.Key = key
-	return nil
-}
-
-// TPMPackedSize will return the expected size in bytes of the marshaled symKey.
-func (k *symKey) TPMPackedSize() int {
-	// AlgID  + EncScheme + len(Key) + Key
-	// uint32 + uint16    + uint16   + BYTE[]
-	return binary.Size(k.AlgID) + binary.Size(k.EncScheme) + binary.Size(uint16(len(k.Key))) + binary.Size(k.Key)
+	Key       tpmutil.U16Bytes // TPM_SYMMETRIC_KEY uses a 16-bit header for Key data
 }
 
 // A tpmStoredData holds sealed data from the TPM.
 type tpmStoredData struct {
 	Version uint32
-	Info    []byte
-	Enc     []byte
+	Info    tpmutil.U32Bytes
+	Enc     tpmutil.U32Bytes
 }
 
 // String returns a string representation of a tpmStoredData.
@@ -323,7 +278,7 @@ type quoteInfo struct {
 // A pcrComposite stores a selection of PCRs with the selected PCR values.
 type pcrComposite struct {
 	Selection pcrSelection
-	Values    []byte
+	Values    tpmutil.U32Bytes
 }
 
 // convertPubKey converts a public key into TPM form. Currently, this function
diff --git a/tpm/tpm.go b/tpm/tpm.go
index 46ef7e7..2ab9dc5 100644
--- a/tpm/tpm.go
+++ b/tpm/tpm.go
@@ -93,7 +93,7 @@ func FetchPCRValues(rw io.ReadWriter, pcrVals []int) ([]byte, error) {
 
 // GetRandom gets random bytes from the TPM.
 func GetRandom(rw io.ReadWriter, size uint32) ([]byte, error) {
-	var b []byte
+	var b tpmutil.U32Bytes
 	in := []interface{}{size}
 	out := []interface{}{&b}
 	// There's no need to check the ret value here, since the err value
@@ -177,7 +177,7 @@ func Quote2(rw io.ReadWriter, handle tpmutil.Handle, data []byte, pcrVals []int,
 	}
 
 	// Check response authentication.
-	raIn := []interface{}{ret, ordQuote2, pcrShort, capBytes, sig}
+	raIn := []interface{}{ret, ordQuote2, pcrShort, tpmutil.U32Bytes(capBytes), tpmutil.U32Bytes(sig)}
 	if err := ra.verify(ca.NonceOdd, sharedSecret[:], raIn); err != nil {
 		return nil, err
 	}
@@ -353,7 +353,7 @@ func sealHelper(rw io.ReadWriter, pcrInfo *pcrInfoLong, data []byte, srkAuth []b
 	// digest = SHA1(ordSeal || encAuth || binary.Size(pcrInfo) || pcrInfo ||
 	//               len(data) || data)
 	//
-	authIn := []interface{}{ordSeal, sc.EncAuth, uint32(binary.Size(pcrInfo)), pcrInfo, data}
+	authIn := []interface{}{ordSeal, sc.EncAuth, uint32(binary.Size(pcrInfo)), pcrInfo, tpmutil.U32Bytes(data)}
 	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, sharedSecret[:], authIn)
 	if err != nil {
 		return nil, err
@@ -446,7 +446,7 @@ func Unseal(rw io.ReadWriter, sealed []byte, srkAuth []byte) ([]byte, error) {
 	}
 
 	// Check the response authentication.
-	raIn := []interface{}{ret, ordUnseal, unsealed}
+	raIn := []interface{}{ret, ordUnseal, tpmutil.U32Bytes(unsealed)}
 	if err := ra1.verify(ca1.NonceOdd, sharedSecret[:], raIn); err != nil {
 		return nil, err
 	}
@@ -488,7 +488,7 @@ func Quote(rw io.ReadWriter, handle tpmutil.Handle, data []byte, pcrNums []int,
 	}
 
 	// Check response authentication.
-	raIn := []interface{}{ret, ordQuote, pcrc, sig}
+	raIn := []interface{}{ret, ordQuote, pcrc, tpmutil.U32Bytes(sig)}
 	if err := ra.verify(ca.NonceOdd, sharedSecret[:], raIn); err != nil {
 		return nil, nil, err
 	}
@@ -607,7 +607,7 @@ func MakeIdentity(rw io.ReadWriter, srkAuth []byte, ownerAuth []byte, aikAuth []
 	}
 
 	// Check response authentication.
-	raIn := []interface{}{ret, ordMakeIdentity, k, sig}
+	raIn := []interface{}{ret, ordMakeIdentity, k, tpmutil.U32Bytes(sig)}
 	if err := ra1.verify(ca1.NonceOdd, sharedSecretSRK[:], raIn); err != nil {
 		return nil, err
 	}
@@ -679,7 +679,7 @@ func ActivateIdentity(rw io.ReadWriter, aikAuth []byte, ownerAuth []byte, aik tp
 	defer osaprOwn.Close(rw)
 	defer zeroBytes(sharedSecretOwn[:])
 
-	authIn := []interface{}{ordActivateIdentity, asym}
+	authIn := []interface{}{ordActivateIdentity, tpmutil.U32Bytes(asym)}
 	ca1, err := newCommandAuth(oiaprAIK.AuthHandle, oiaprAIK.NonceEven, aikAuth, authIn)
 	if err != nil {
 		return nil, fmt.Errorf("newCommandAuth failed: %v", err)
@@ -927,7 +927,7 @@ func NVReadValue(rw io.ReadWriter, index, offset, len uint32, ownAuth digest) ([
 	if err != nil {
 		return nil, fmt.Errorf("failed to read from NVRAM: %v", err)
 	}
-	raIn := []interface{}{ret, ordNVReadValue, data}
+	raIn := []interface{}{ret, ordNVReadValue, tpmutil.U32Bytes(data)}
 	if err := ra.verify(ca.NonceOdd, sharedSecretOwn[:], raIn); err != nil {
 		return nil, fmt.Errorf("failed to verify authenticity of response: %v", err)
 	}
@@ -1214,7 +1214,7 @@ func Sign(rw io.ReadWriter, keyAuth []byte, keyHandle tpmutil.Handle, hash crypt
 	defer osapr.Close(rw)
 	defer zeroBytes(sharedSecret[:])
 
-	authIn := []interface{}{ordSign, data}
+	authIn := []interface{}{ordSign, tpmutil.U32Bytes(data)}
 	ca, err := newCommandAuth(osapr.AuthHandle, osapr.NonceEven, sharedSecret[:], authIn)
 	if err != nil {
 		return nil, err
@@ -1225,7 +1225,7 @@ func Sign(rw io.ReadWriter, keyAuth []byte, keyHandle tpmutil.Handle, hash crypt
 		return nil, err
 	}
 
-	raIn := []interface{}{ret, ordSign, signature}
+	raIn := []interface{}{ret, ordSign, tpmutil.U32Bytes(signature)}
 	err = ra.verify(ca.NonceOdd, sharedSecret[:], raIn)
 	if err != nil {
 		return nil, err
diff --git a/tpm2/constants.go b/tpm2/constants.go
index ea954e7..268047d 100644
--- a/tpm2/constants.go
+++ b/tpm2/constants.go
@@ -25,10 +25,6 @@ import (
 	"github.com/google/go-tpm/tpmutil"
 )
 
-func init() {
-	tpmutil.UseTPM20LengthPrefixSize()
-}
-
 // MAX_DIGEST_BUFFER is the maximum size of []byte request or response fields.
 // Typically used for chunking of big blobs of data (such as for hashing or
 // encryption).
diff --git a/tpm2/credactivation/credential_activation.go b/tpm2/credactivation/credential_activation.go
index 61059b0..6ae3f5e 100644
--- a/tpm2/credactivation/credential_activation.go
+++ b/tpm2/credactivation/credential_activation.go
@@ -95,7 +95,7 @@ func generateRSA(aik *tpm2.HashValue, pub *rsa.PublicKey, symBlockSize int, secr
 	if err != nil {
 		return nil, nil, fmt.Errorf("symmetric cipher setup: %v", err)
 	}
-	cv, err := tpmutil.Pack(secret)
+	cv, err := tpmutil.Pack(tpmutil.U16Bytes(secret))
 	if err != nil {
 		return nil, nil, fmt.Errorf("generating cv (TPM2B_Digest): %v", err)
 	}
@@ -125,7 +125,7 @@ func generateRSA(aik *tpm2.HashValue, pub *rsa.PublicKey, symBlockSize int, secr
 	if err != nil {
 		return nil, nil, fmt.Errorf("encoding IDObject: %v", err)
 	}
-	packedEncSecret, err := tpmutil.Pack(encSecret)
+	packedEncSecret, err := tpmutil.Pack(tpmutil.U16Bytes(encSecret))
 	if err != nil {
 		return nil, nil, fmt.Errorf("packing encSecret: %v", err)
 	}
diff --git a/tpm2/structures.go b/tpm2/structures.go
index 3331e8f..8bde1a4 100644
--- a/tpm2/structures.go
+++ b/tpm2/structures.go
@@ -31,13 +31,13 @@ type NVPublic struct {
 	NVIndex    tpmutil.Handle
 	NameAlg    Algorithm
 	Attributes KeyProp
-	AuthPolicy []byte
+	AuthPolicy tpmutil.U16Bytes
 	DataSize   uint16
 }
 
 type tpmsSensitiveCreate struct {
-	UserAuth []byte
-	Data     []byte
+	UserAuth tpmutil.U16Bytes
+	Data     tpmutil.U16Bytes
 }
 
 // PCRSelection contains a slice of PCR indexes and a hash algorithm used in
@@ -58,7 +58,7 @@ type Public struct {
 	Type       Algorithm
 	NameAlg    Algorithm
 	Attributes KeyProp
-	AuthPolicy []byte
+	AuthPolicy tpmutil.U16Bytes
 
 	// If Type is AlgKeyedHash, then do not set these.
 	// Otherwise, only one of the Parameters fields should be set. When encoding/decoding,
@@ -161,7 +161,7 @@ type RSAParams struct {
 	// encoded bitstream, so Name digest calculations will be correct.
 	encodeDefaultExponentAsZero bool
 	Exponent                    uint32
-	ModulusRaw                  []byte
+	ModulusRaw                  tpmutil.U16Bytes
 	Modulus                     *big.Int
 }
 
@@ -194,7 +194,7 @@ func (p *RSAParams) encode() ([]byte, error) {
 	}
 	mod := p.ModulusRaw
 	if p.Modulus != nil {
-		mod = p.Modulus.Bytes()
+		mod = tpmutil.U16Bytes(p.Modulus.Bytes())
 	}
 	unique, err := tpmutil.Pack(mod)
 	if err != nil {
@@ -214,7 +214,7 @@ func decodeRSAParams(in *bytes.Buffer) (*RSAParams, error) {
 	if params.Sign, err = decodeSigScheme(in); err != nil {
 		return nil, fmt.Errorf("decoding Sign: %v", err)
 	}
-	var modBytes []byte
+	var modBytes tpmutil.U16Bytes
 	if err := tpmutil.UnpackBuf(in, &params.KeyBits, &params.Exponent, &modBytes); err != nil {
 		return nil, fmt.Errorf("decoding KeyBits, Exponent, Modulus: %v", err)
 	}
@@ -276,7 +276,8 @@ func (p *ECCParams) encode() ([]byte, error) {
 	if err != nil {
 		return nil, fmt.Errorf("encoding KDF: %v", err)
 	}
-	point, err := tpmutil.Pack(p.Point.x().Bytes(), p.Point.y().Bytes())
+	x, y := p.Point.x().Bytes(), p.Point.y().Bytes()
+	point, err := tpmutil.Pack(tpmutil.U16Bytes(x), tpmutil.U16Bytes(y))
 	if err != nil {
 		return nil, fmt.Errorf("encoding Point: %v", err)
 	}
@@ -299,7 +300,7 @@ func decodeECCParams(in *bytes.Buffer) (*ECCParams, error) {
 	if params.KDF, err = decodeKDFScheme(in); err != nil {
 		return nil, fmt.Errorf("decoding KDF: %v", err)
 	}
-	var x, y []byte
+	var x, y tpmutil.U16Bytes
 	if err := tpmutil.UnpackBuf(in, &x, &y); err != nil {
 		return nil, fmt.Errorf("decoding Point: %v", err)
 	}
@@ -311,7 +312,7 @@ func decodeECCParams(in *bytes.Buffer) (*ECCParams, error) {
 // SymCipherParams represents parameters of a symmetric block cipher TPM object.
 type SymCipherParams struct {
 	Symmetric *SymScheme
-	Unique    []byte
+	Unique    tpmutil.U16Bytes
 }
 
 func (p *SymCipherParams) encode() ([]byte, error) {
@@ -468,7 +469,7 @@ func DecodeSignature(in *bytes.Buffer) (*Signature, error) {
 		}
 	case AlgECDSA:
 		sig.ECC = new(SignatureECC)
-		var r, s []byte
+		var r, s tpmutil.U16Bytes
 		if err := tpmutil.UnpackBuf(in, &sig.ECC.HashAlg, &r, &s); err != nil {
 			return nil, fmt.Errorf("decoding ECC: %v", err)
 		}
@@ -483,7 +484,7 @@ func DecodeSignature(in *bytes.Buffer) (*Signature, error) {
 // SignatureRSA is an RSA-specific signature value.
 type SignatureRSA struct {
 	HashAlg   Algorithm
-	Signature []byte
+	Signature tpmutil.U16Bytes
 }
 
 // SignatureECC is an ECC-specific signature value.
@@ -496,9 +497,9 @@ type SignatureECC struct {
 // Private contains private section of a TPM key.
 type Private struct {
 	Type      Algorithm
-	AuthValue []byte
-	SeedValue []byte
-	Sensitive []byte
+	AuthValue tpmutil.U16Bytes
+	SeedValue tpmutil.U16Bytes
+	Sensitive tpmutil.U16Bytes
 }
 
 // Encode serializes a Private structure in TPM wire format.
@@ -519,7 +520,7 @@ type AttestationData struct {
 	Magic                uint32
 	Type                 tpmutil.Tag
 	QualifiedSigner      Name
-	ExtraData            []byte
+	ExtraData            tpmutil.U16Bytes
 	ClockInfo            ClockInfo
 	FirmwareVersion      uint64
 	AttestedCertifyInfo  *CertifyInfo
@@ -606,7 +607,7 @@ type CreationInfo struct {
 	// Most TPM2B_Digest structures contain a TPMU_HA structure
 	// and get parsed to HashValue. This is never the case for the
 	// digest in TPMS_CREATION_INFO.
-	OpaqueDigest []byte
+	OpaqueDigest tpmutil.U16Bytes
 }
 
 func decodeCreationInfo(in *bytes.Buffer) (*CreationInfo, error) {
@@ -678,7 +679,7 @@ func (ci CertifyInfo) encode() ([]byte, error) {
 // QuoteInfo represents a TPMS_QUOTE_INFO structure.
 type QuoteInfo struct {
 	PCRSelection PCRSelection
-	PCRDigest    []byte
+	PCRDigest    tpmutil.U16Bytes
 }
 
 func decodeQuoteInfo(in *bytes.Buffer) (*QuoteInfo, error) {
@@ -696,8 +697,8 @@ func decodeQuoteInfo(in *bytes.Buffer) (*QuoteInfo, error) {
 
 // IDObject represents an encrypted credential bound to a TPM object.
 type IDObject struct {
-	IntegrityHMAC []byte
-	EncIdentity   []byte
+	IntegrityHMAC tpmutil.U16Bytes
+	EncIdentity   tpmutil.RawBytes
 }
 
 // Encode packs the IDObject into a byte stream representing
@@ -705,23 +706,23 @@ type IDObject struct {
 func (o *IDObject) Encode() ([]byte, error) {
 	// encIdentity is packed raw, as the bytes representing the size
 	// of the credential value are present within the encrypted blob.
-	d, err := tpmutil.Pack(o.IntegrityHMAC, tpmutil.RawBytes(o.EncIdentity))
+	d, err := tpmutil.Pack(o.IntegrityHMAC, o.EncIdentity)
 	if err != nil {
 		return nil, fmt.Errorf("encoding IntegrityHMAC, EncIdentity: %v", err)
 	}
-	return tpmutil.Pack(d)
+	return tpmutil.Pack(tpmutil.U16Bytes(d))
 }
 
 // CreationData describes the attributes and environment for an object created
 // on the TPM. This structure encodes/decodes to/from TPMS_CREATION_DATA.
 type CreationData struct {
 	PCRSelection        PCRSelection
-	PCRDigest           []byte
+	PCRDigest           tpmutil.U16Bytes
 	Locality            byte
 	ParentNameAlg       Algorithm
 	ParentName          Name
 	ParentQualifiedName Name
-	OutsideInfo         []byte
+	OutsideInfo         tpmutil.U16Bytes
 }
 
 func (cd *CreationData) encode() ([]byte, error) {
@@ -789,7 +790,7 @@ type Name struct {
 }
 
 func decodeName(in *bytes.Buffer) (*Name, error) {
-	var nameBuf []byte
+	var nameBuf tpmutil.U16Bytes
 	if err := tpmutil.UnpackBuf(in, &nameBuf); err != nil {
 		return nil, err
 	}
@@ -828,7 +829,7 @@ func (n Name) encode() ([]byte, error) {
 	default:
 		// Name is empty, which is valid.
 	}
-	return tpmutil.Pack(buf)
+	return tpmutil.Pack(tpmutil.U16Bytes(buf))
 }
 
 // MatchesPublic compares Digest in Name against given Public structure. Note:
@@ -856,7 +857,7 @@ func (n Name) MatchesPublic(p Public) (bool, error) {
 // HashValue is an algorithm-specific hash value.
 type HashValue struct {
 	Alg   Algorithm
-	Value []byte
+	Value tpmutil.U16Bytes
 }
 
 func decodeHashValue(in *bytes.Buffer) (*HashValue, error) {
@@ -868,7 +869,7 @@ func decodeHashValue(in *bytes.Buffer) (*HashValue, error) {
 	if !ok {
 		return nil, fmt.Errorf("unsupported hash algorithm type 0x%x", hv.Alg)
 	}
-	hv.Value = make([]byte, hfn().Size())
+	hv.Value = make(tpmutil.U16Bytes, hfn().Size())
 	if _, err := in.Read(hv.Value); err != nil {
 		return nil, fmt.Errorf("decoding Value: %v", err)
 	}
@@ -911,7 +912,7 @@ type TaggedProperty struct {
 type Ticket struct {
 	Type      tpmutil.Tag
 	Hierarchy uint32
-	Digest    []byte
+	Digest    tpmutil.U16Bytes
 }
 
 func decodeTicket(in *bytes.Buffer) (*Ticket, error) {
@@ -926,7 +927,7 @@ func decodeTicket(in *bytes.Buffer) (*Ticket, error) {
 // which authorize the use of a given handle or parameter.
 type AuthCommand struct {
 	Session    tpmutil.Handle
-	Nonce      []byte
+	Nonce      tpmutil.U16Bytes
 	Attributes SessionAttributes
-	Auth       []byte
+	Auth       tpmutil.U16Bytes
 }
diff --git a/tpm2/tpm2.go b/tpm2/tpm2.go
index 91c8ab1..b34bfa4 100644
--- a/tpm2/tpm2.go
+++ b/tpm2/tpm2.go
@@ -36,7 +36,7 @@ func GetRandom(rw io.ReadWriter, size uint16) ([]byte, error) {
 		return nil, err
 	}
 
-	var randBytes []byte
+	var randBytes tpmutil.U16Bytes
 	if _, err := tpmutil.Unpack(resp, &randBytes); err != nil {
 		return nil, err
 	}
@@ -67,7 +67,7 @@ func encodeTPMLPCRSelection(sel PCRSelection) ([]byte, error) {
 	ts := tpmsPCRSelection{
 		Hash: sel.Hash,
 		Size: sizeOfPCRSelect,
-		PCRs: make([]byte, sizeOfPCRSelect),
+		PCRs: make(tpmutil.RawBytes, sizeOfPCRSelect),
 	}
 	// sel.PCRs parameter is indexes of PCRs, convert that to set bits.
 	for _, n := range sel.PCRs {
@@ -99,7 +99,7 @@ func decodeTPMLPCRSelection(buf *bytes.Buffer) (PCRSelection, error) {
 	if err := tpmutil.UnpackBuf(buf, &ts.Hash, &ts.Size); err != nil {
 		return sel, err
 	}
-	ts.PCRs = make([]byte, ts.Size)
+	ts.PCRs = make(tpmutil.RawBytes, ts.Size)
 	if _, err := buf.Read(ts.PCRs); err != nil {
 		return sel, err
 	}
@@ -139,7 +139,7 @@ func decodeReadPCRs(in []byte) (map[int][]byte, error) {
 
 	vals := make(map[int][]byte)
 	for _, pcr := range sel.PCRs {
-		var val []byte
+		var val tpmutil.U16Bytes
 		if err = tpmutil.UnpackBuf(buf, &val); err != nil {
 			return nil, fmt.Errorf("decoding TPML_DIGEST item: %v", err)
 		}
@@ -265,7 +265,7 @@ func GetCapability(rw io.ReadWriter, capa Capability, count, property uint32) (v
 }
 
 func encodeAuthArea(sections ...AuthCommand) ([]byte, error) {
-	var res []byte
+	var res tpmutil.RawBytes
 	for _, s := range sections {
 		buf, err := tpmutil.Pack(s)
 		if err != nil {
@@ -291,7 +291,7 @@ func encodePCREvent(pcr tpmutil.Handle, eventData []byte) ([]byte, error) {
 	if err != nil {
 		return nil, err
 	}
-	event, err := tpmutil.Pack(eventData)
+	event, err := tpmutil.Pack(tpmutil.U16Bytes(eventData))
 	if err != nil {
 		return nil, err
 	}
@@ -315,7 +315,7 @@ func encodeSensitiveArea(s tpmsSensitiveCreate) ([]byte, error) {
 		return nil, err
 	}
 	// TPM2B_SENSITIVE_CREATE
-	return tpmutil.Pack(buf)
+	return tpmutil.Pack(tpmutil.U16Bytes(buf))
 }
 
 // encodeCreate works for both TPM2_Create and TPM2_CreatePrimary.
@@ -343,11 +343,11 @@ func encodeCreateRawTemplate(owner tpmutil.Handle, sel PCRSelection, parentPassw
 	if err != nil {
 		return nil, err
 	}
-	publicBlob, err := tpmutil.Pack(inPublic)
+	publicBlob, err := tpmutil.Pack(tpmutil.U16Bytes(inPublic))
 	if err != nil {
 		return nil, err
 	}
-	outsideInfo, err := tpmutil.Pack([]byte(nil))
+	outsideInfo, err := tpmutil.Pack(tpmutil.U16Bytes(nil))
 	if err != nil {
 		return nil, err
 	}
@@ -365,7 +365,7 @@ func encodeCreateRawTemplate(owner tpmutil.Handle, sel PCRSelection, parentPassw
 	)
 }
 
-func decodeCreatePrimary(in []byte) (handle tpmutil.Handle, public, creationData, creationHash []byte, ticket *Ticket, creationName []byte, err error) {
+func decodeCreatePrimary(in []byte) (handle tpmutil.Handle, public, creationData, creationHash tpmutil.U16Bytes, ticket *Ticket, creationName tpmutil.U16Bytes, err error) {
 	var paramSize uint32
 
 	buf := bytes.NewBuffer(in)
@@ -449,9 +449,9 @@ func CreatePrimaryRawTemplate(rw io.ReadWriter, owner tpmutil.Handle, sel PCRSel
 
 func decodeReadPublic(in []byte) (Public, []byte, []byte, error) {
 	var resp struct {
-		Public        []byte
-		Name          []byte
-		QualifiedName []byte
+		Public        tpmutil.U16Bytes
+		Name          tpmutil.U16Bytes
+		QualifiedName tpmutil.U16Bytes
 	}
 	if _, err := tpmutil.Unpack(in, &resp); err != nil {
 		return Public{}, nil, nil, err
@@ -474,7 +474,7 @@ func ReadPublic(rw io.ReadWriter, handle tpmutil.Handle) (Public, []byte, []byte
 	return decodeReadPublic(resp)
 }
 
-func decodeCreate(in []byte) (handle tpmutil.Handle, private, public, creationData, creationHash []byte, creationTicket Ticket, err error) {
+func decodeCreate(in []byte) (handle tpmutil.Handle, private, public, creationData, creationHash tpmutil.U16Bytes, creationTicket Ticket, err error) {
 	buf := bytes.NewBuffer(in)
 
 	if err := tpmutil.UnpackBuf(buf, &handle, &private, &public, &creationData, &creationHash); err != nil {
@@ -527,12 +527,12 @@ func Seal(rw io.ReadWriter, parentHandle tpmutil.Handle, parentPassword, objectP
 	return private, public, nil
 }
 
-func encodeLoad(parentHandle tpmutil.Handle, parentAuth string, publicBlob, privateBlob []byte) ([]byte, error) {
+func encodeLoad(parentHandle tpmutil.Handle, parentAuth string, publicBlob, privateBlob tpmutil.U16Bytes) ([]byte, error) {
 	ah, err := tpmutil.Pack(parentHandle)
 	if err != nil {
 		return nil, err
 	}
-	auth, err := encodeAuthArea(AuthCommand{Session: HandlePasswordSession, Attributes: AttrContinueSession, Auth: []byte(parentAuth)})
+	auth, err := encodeAuthArea(AuthCommand{Session: HandlePasswordSession, Attributes: AttrContinueSession, Auth: tpmutil.U16Bytes(parentAuth)})
 	if err != nil {
 		return nil, err
 	}
@@ -546,7 +546,7 @@ func encodeLoad(parentHandle tpmutil.Handle, parentAuth string, publicBlob, priv
 func decodeLoad(in []byte) (tpmutil.Handle, []byte, error) {
 	var handle tpmutil.Handle
 	var paramSize uint32
-	var name []byte
+	var name tpmutil.U16Bytes
 
 	if _, err := tpmutil.Unpack(in, &handle, &paramSize, &name); err != nil {
 		return 0, nil, err
@@ -578,12 +578,12 @@ func encodeLoadExternal(pub Public, private Private, hierarchy tpmutil.Handle) (
 		return nil, err
 	}
 
-	return tpmutil.Pack(privateBlob, publicBlob, hierarchy)
+	return tpmutil.Pack(tpmutil.U16Bytes(privateBlob), tpmutil.U16Bytes(publicBlob), hierarchy)
 }
 
 func decodeLoadExternal(in []byte) (tpmutil.Handle, []byte, error) {
 	var handle tpmutil.Handle
-	var name []byte
+	var name tpmutil.U16Bytes
 
 	if _, err := tpmutil.Unpack(in, &handle, &name); err != nil {
 		return 0, nil, err
@@ -615,7 +615,7 @@ func PolicyPassword(rw io.ReadWriter, handle tpmutil.Handle) error {
 	return err
 }
 
-func encodePolicySecret(entityHandle tpmutil.Handle, entityAuth AuthCommand, policyHandle tpmutil.Handle, policyNonce, cpHash, policyRef []byte, expiry int32) ([]byte, error) {
+func encodePolicySecret(entityHandle tpmutil.Handle, entityAuth AuthCommand, policyHandle tpmutil.Handle, policyNonce, cpHash, policyRef tpmutil.U16Bytes, expiry int32) ([]byte, error) {
 	auth, err := encodeAuthArea(entityAuth)
 	if err != nil {
 		return nil, err
@@ -654,7 +654,7 @@ func PolicySecret(rw io.ReadWriter, entityHandle tpmutil.Handle, entityAuth Auth
 	return nil, nil
 }
 
-func encodePolicyPCR(session tpmutil.Handle, expectedDigest []byte, sel PCRSelection) ([]byte, error) {
+func encodePolicyPCR(session tpmutil.Handle, expectedDigest tpmutil.U16Bytes, sel PCRSelection) ([]byte, error) {
 	params, err := tpmutil.Pack(session, expectedDigest)
 	if err != nil {
 		return nil, err
@@ -683,12 +683,12 @@ func PolicyGetDigest(rw io.ReadWriter, handle tpmutil.Handle) ([]byte, error) {
 		return nil, err
 	}
 
-	var digest []byte
+	var digest tpmutil.U16Bytes
 	_, err = tpmutil.Unpack(resp, &digest)
 	return digest, err
 }
 
-func encodeStartAuthSession(tpmKey, bindKey tpmutil.Handle, nonceCaller, secret []byte, se SessionType, sym, hashAlg Algorithm) ([]byte, error) {
+func encodeStartAuthSession(tpmKey, bindKey tpmutil.Handle, nonceCaller, secret tpmutil.U16Bytes, se SessionType, sym, hashAlg Algorithm) ([]byte, error) {
 	ha, err := tpmutil.Pack(tpmKey, bindKey)
 	if err != nil {
 		return nil, err
@@ -702,7 +702,7 @@ func encodeStartAuthSession(tpmKey, bindKey tpmutil.Handle, nonceCaller, secret
 
 func decodeStartAuthSession(in []byte) (tpmutil.Handle, []byte, error) {
 	var handle tpmutil.Handle
-	var nonce []byte
+	var nonce tpmutil.U16Bytes
 	if _, err := tpmutil.Unpack(in, &handle, &nonce); err != nil {
 		return 0, nil, err
 	}
@@ -737,7 +737,7 @@ func encodeUnseal(sessionHandle, itemHandle tpmutil.Handle, password string) ([]
 
 func decodeUnseal(in []byte) ([]byte, error) {
 	var paramSize uint32
-	var unsealed []byte
+	var unsealed tpmutil.U16Bytes
 
 	if _, err := tpmutil.Unpack(in, &paramSize, &unsealed); err != nil {
 		return nil, err
@@ -763,7 +763,7 @@ func UnsealWithSession(rw io.ReadWriter, sessionHandle, itemHandle tpmutil.Handl
 	return decodeUnseal(resp)
 }
 
-func encodeQuote(signingHandle tpmutil.Handle, parentPassword, ownerPassword string, toQuote []byte, sel PCRSelection, sigAlg Algorithm) ([]byte, error) {
+func encodeQuote(signingHandle tpmutil.Handle, parentPassword, ownerPassword string, toQuote tpmutil.U16Bytes, sel PCRSelection, sigAlg Algorithm) ([]byte, error) {
 	ha, err := tpmutil.Pack(signingHandle)
 	if err != nil {
 		return nil, err
@@ -786,7 +786,7 @@ func encodeQuote(signingHandle tpmutil.Handle, parentPassword, ownerPassword str
 func decodeQuote(in []byte) ([]byte, *Signature, error) {
 	buf := bytes.NewBuffer(in)
 	var paramSize uint32
-	var attest []byte
+	var attest tpmutil.U16Bytes
 	if err := tpmutil.UnpackBuf(buf, &paramSize, &attest); err != nil {
 		return nil, nil, err
 	}
@@ -812,7 +812,7 @@ func Quote(rw io.ReadWriter, signingHandle tpmutil.Handle, parentPassword, owner
 	return decodeQuote(resp)
 }
 
-func encodeActivateCredential(auth []AuthCommand, activeHandle tpmutil.Handle, keyHandle tpmutil.Handle, credBlob, secret []byte) ([]byte, error) {
+func encodeActivateCredential(auth []AuthCommand, activeHandle tpmutil.Handle, keyHandle tpmutil.Handle, credBlob, secret tpmutil.U16Bytes) ([]byte, error) {
 	ha, err := tpmutil.Pack(activeHandle, keyHandle)
 	if err != nil {
 		return nil, err
@@ -830,7 +830,7 @@ func encodeActivateCredential(auth []AuthCommand, activeHandle tpmutil.Handle, k
 
 func decodeActivateCredential(in []byte) ([]byte, error) {
 	var paramSize uint32
-	var certInfo []byte
+	var certInfo tpmutil.U16Bytes
 
 	if _, err := tpmutil.Unpack(in, &paramSize, &certInfo); err != nil {
 		return nil, err
@@ -866,7 +866,7 @@ func ActivateCredentialUsingAuth(rw io.ReadWriter, auth []AuthCommand, activeHan
 	return decodeActivateCredential(resp)
 }
 
-func encodeMakeCredential(protectorHandle tpmutil.Handle, credential, activeName []byte) ([]byte, error) {
+func encodeMakeCredential(protectorHandle tpmutil.Handle, credential, activeName tpmutil.U16Bytes) ([]byte, error) {
 	ha, err := tpmutil.Pack(protectorHandle)
 	if err != nil {
 		return nil, err
@@ -879,8 +879,7 @@ func encodeMakeCredential(protectorHandle tpmutil.Handle, credential, activeName
 }
 
 func decodeMakeCredential(in []byte) ([]byte, []byte, error) {
-	var credBlob []byte
-	var encryptedSecret []byte
+	var credBlob, encryptedSecret tpmutil.U16Bytes
 
 	if _, err := tpmutil.Unpack(in, &credBlob, &encryptedSecret); err != nil {
 		return nil, nil, err
@@ -990,7 +989,7 @@ func NVUndefineSpace(rw io.ReadWriter, ownerAuth string, owner, index tpmutil.Ha
 	return err
 }
 
-func encodeDefineSpace(owner, handle tpmutil.Handle, ownerAuth, authVal string, attributes NVAttr, policy []byte, dataSize uint16) ([]byte, error) {
+func encodeDefineSpace(owner, handle tpmutil.Handle, ownerAuth, authVal string, attributes NVAttr, policy tpmutil.U16Bytes, dataSize uint16) ([]byte, error) {
 	ha, err := tpmutil.Pack(owner)
 	if err != nil {
 		return nil, err
@@ -1003,7 +1002,7 @@ func encodeDefineSpace(owner, handle tpmutil.Handle, ownerAuth, authVal string,
 	if err != nil {
 		return nil, err
 	}
-	params, err := tpmutil.Pack([]byte(authVal), publicInfo)
+	params, err := tpmutil.Pack(tpmutil.U16Bytes(authVal), tpmutil.U16Bytes(publicInfo))
 	if err != nil {
 		return nil, err
 	}
@@ -1020,7 +1019,7 @@ func NVDefineSpace(rw io.ReadWriter, owner, handle tpmutil.Handle, ownerAuth, au
 	return err
 }
 
-func encodeWriteNV(owner, handle tpmutil.Handle, authString string, data []byte, offset uint16) ([]byte, error) {
+func encodeWriteNV(owner, handle tpmutil.Handle, authString string, data tpmutil.U16Bytes, offset uint16) ([]byte, error) {
 	auth, err := encodeAuthArea(AuthCommand{Session: HandlePasswordSession, Attributes: AttrContinueSession, Auth: []byte(authString)})
 	if err != nil {
 		return nil, err
@@ -1037,7 +1036,7 @@ func encodeWriteNV(owner, handle tpmutil.Handle, authString string, data []byte,
 }
 
 // NVWrite writes data into the TPM's NV storage.
-func NVWrite(rw io.ReadWriter, owner, handle tpmutil.Handle, authString string, data []byte, offset uint16) error {
+func NVWrite(rw io.ReadWriter, owner, handle tpmutil.Handle, authString string, data tpmutil.U16Bytes, offset uint16) error {
 	cmd, err := encodeWriteNV(owner, handle, authString, data, offset)
 	if err != nil {
 		return err
@@ -1048,7 +1047,7 @@ func NVWrite(rw io.ReadWriter, owner, handle tpmutil.Handle, authString string,
 
 func decodeNVReadPublic(in []byte) (NVPublic, error) {
 	var pub NVPublic
-	var buf []byte
+	var buf tpmutil.U16Bytes
 	if _, err := tpmutil.Unpack(in, &buf); err != nil {
 		return pub, err
 	}
@@ -1068,7 +1067,7 @@ func NVReadPublic(rw io.ReadWriter, index tpmutil.Handle) (NVPublic, error) {
 
 func decodeNVRead(in []byte) ([]byte, error) {
 	var sessionAttributes uint32
-	var data []byte
+	var data tpmutil.U16Bytes
 	if _, err := tpmutil.Unpack(in, &sessionAttributes, &data); err != nil {
 		return nil, err
 	}
@@ -1151,13 +1150,13 @@ func NVReadEx(rw io.ReadWriter, index, authHandle tpmutil.Handle, password strin
 }
 
 // Hash computes a hash of data in buf using the TPM.
-func Hash(rw io.ReadWriter, alg Algorithm, buf []byte) ([]byte, error) {
+func Hash(rw io.ReadWriter, alg Algorithm, buf tpmutil.U16Bytes) ([]byte, error) {
 	resp, err := runCommand(rw, TagNoSessions, cmdHash, buf, alg, HandleNull)
 	if err != nil {
 		return nil, err
 	}
 
-	var digest []byte
+	var digest tpmutil.U16Bytes
 	if _, err = tpmutil.Unpack(resp, &digest); err != nil {
 		return nil, err
 	}
@@ -1176,7 +1175,7 @@ func Shutdown(rw io.ReadWriter, typ StartupType) error {
 	return err
 }
 
-func encodeSign(key tpmutil.Handle, password string, digest []byte, sigScheme *SigScheme) ([]byte, error) {
+func encodeSign(key tpmutil.Handle, password string, digest tpmutil.U16Bytes, sigScheme *SigScheme) ([]byte, error) {
 	ha, err := tpmutil.Pack(key)
 	if err != nil {
 		return nil, err
@@ -1197,7 +1196,7 @@ func encodeSign(key tpmutil.Handle, password string, digest []byte, sigScheme *S
 	if err != nil {
 		return nil, err
 	}
-	params, err := tpmutil.Pack(HandleNull, []byte(nil))
+	params, err := tpmutil.Pack(HandleNull, tpmutil.U16Bytes(nil))
 	if err != nil {
 		return nil, err
 	}
@@ -1228,7 +1227,7 @@ func Sign(rw io.ReadWriter, key tpmutil.Handle, password string, digest []byte,
 	return decodeSign(resp)
 }
 
-func encodeCertify(parentAuth, ownerAuth string, object, signer tpmutil.Handle, qualifyingData []byte) ([]byte, error) {
+func encodeCertify(parentAuth, ownerAuth string, object, signer tpmutil.Handle, qualifyingData tpmutil.U16Bytes) ([]byte, error) {
 	ha, err := tpmutil.Pack(object, signer)
 	if err != nil {
 		return nil, err
@@ -1250,7 +1249,7 @@ func encodeCertify(parentAuth, ownerAuth string, object, signer tpmutil.Handle,
 
 func decodeCertify(resp []byte) ([]byte, []byte, error) {
 	var paramSize uint32
-	var attest, signature []byte
+	var attest, signature tpmutil.U16Bytes
 	var sigAlg, hashAlg Algorithm
 	if _, err := tpmutil.Unpack(resp, &paramSize, &attest, &sigAlg, &hashAlg, &signature); err != nil {
 		return nil, nil, err
@@ -1273,7 +1272,7 @@ func Certify(rw io.ReadWriter, parentAuth, ownerAuth string, object, signer tpmu
 	return decodeCertify(resp)
 }
 
-func encodeCertifyCreation(objectAuth string, object, signer tpmutil.Handle, qualifyingData, creationHash []byte, scheme SigScheme, ticket *Ticket) ([]byte, error) {
+func encodeCertifyCreation(objectAuth string, object, signer tpmutil.Handle, qualifyingData, creationHash tpmutil.U16Bytes, scheme SigScheme, ticket *Ticket) ([]byte, error) {
 	handles, err := tpmutil.Pack(signer, object)
 	if err != nil {
 		return nil, err
@@ -1402,7 +1401,7 @@ func DecryptSymmetric(rw io.ReadWriteCloser, keyAuth string, key tpmutil.Handle,
 	return encryptDecryptSymmetric(rw, keyAuth, key, iv, data, true)
 }
 
-func encodeEncryptDecrypt(keyAuth string, key tpmutil.Handle, iv, data []byte, decrypt bool) ([]byte, error) {
+func encodeEncryptDecrypt(keyAuth string, key tpmutil.Handle, iv, data tpmutil.U16Bytes, decrypt bool) ([]byte, error) {
 	ha, err := tpmutil.Pack(key)
 	if err != nil {
 		return nil, err
@@ -1419,7 +1418,7 @@ func encodeEncryptDecrypt(keyAuth string, key tpmutil.Handle, iv, data []byte, d
 	return concat(ha, auth, params)
 }
 
-func encodeEncryptDecrypt2(keyAuth string, key tpmutil.Handle, iv, data []byte, decrypt bool) ([]byte, error) {
+func encodeEncryptDecrypt2(keyAuth string, key tpmutil.Handle, iv, data tpmutil.U16Bytes, decrypt bool) ([]byte, error) {
 	ha, err := tpmutil.Pack(key)
 	if err != nil {
 		return nil, err
@@ -1438,7 +1437,7 @@ func encodeEncryptDecrypt2(keyAuth string, key tpmutil.Handle, iv, data []byte,
 
 func decodeEncryptDecrypt(resp []byte) ([]byte, []byte, error) {
 	var paramSize uint32
-	var out, nextIV []byte
+	var out, nextIV tpmutil.U16Bytes
 	if _, err := tpmutil.Unpack(resp, &paramSize, &out, &nextIV); err != nil {
 		return nil, nil, err
 	}
@@ -1489,7 +1488,7 @@ func encryptDecryptSymmetric(rw io.ReadWriteCloser, keyAuth string, key tpmutil.
 	return out, nil
 }
 
-func encodeRSAEncrypt(key tpmutil.Handle, message []byte, scheme *AsymScheme, label string) ([]byte, error) {
+func encodeRSAEncrypt(key tpmutil.Handle, message tpmutil.U16Bytes, scheme *AsymScheme, label string) ([]byte, error) {
 	ha, err := tpmutil.Pack(key)
 	if err != nil {
 		return nil, err
@@ -1505,7 +1504,7 @@ func encodeRSAEncrypt(key tpmutil.Handle, message []byte, scheme *AsymScheme, la
 	if label != "" {
 		label += "\x00"
 	}
-	l, err := tpmutil.Pack([]byte(label))
+	l, err := tpmutil.Pack(tpmutil.U16Bytes(label))
 	if err != nil {
 		return nil, err
 	}
@@ -1513,7 +1512,7 @@ func encodeRSAEncrypt(key tpmutil.Handle, message []byte, scheme *AsymScheme, la
 }
 
 func decodeRSAEncrypt(resp []byte) ([]byte, error) {
-	var out []byte
+	var out tpmutil.U16Bytes
 	_, err := tpmutil.Unpack(resp, &out)
 	return out, err
 }
@@ -1534,7 +1533,7 @@ func RSAEncrypt(rw io.ReadWriter, key tpmutil.Handle, message []byte, scheme *As
 	return decodeRSAEncrypt(resp)
 }
 
-func encodeRSADecrypt(key tpmutil.Handle, password string, message []byte, scheme *AsymScheme, label string) ([]byte, error) {
+func encodeRSADecrypt(key tpmutil.Handle, password string, message tpmutil.U16Bytes, scheme *AsymScheme, label string) ([]byte, error) {
 	ha, err := tpmutil.Pack(key)
 	if err != nil {
 		return nil, err
@@ -1554,7 +1553,7 @@ func encodeRSADecrypt(key tpmutil.Handle, password string, message []byte, schem
 	if label != "" {
 		label += "\x00"
 	}
-	l, err := tpmutil.Pack([]byte(label))
+	l, err := tpmutil.Pack(tpmutil.U16Bytes(label))
 	if err != nil {
 		return nil, err
 	}
@@ -1562,7 +1561,7 @@ func encodeRSADecrypt(key tpmutil.Handle, password string, message []byte, schem
 }
 
 func decodeRSADecrypt(resp []byte) ([]byte, error) {
-	var out []byte
+	var out tpmutil.U16Bytes
 	var paramSize uint32
 	_, err := tpmutil.Unpack(resp, &paramSize, &out)
 	return out, err
diff --git a/tpmutil/encoding.go b/tpmutil/encoding.go
index 9457777..5983cc2 100644
--- a/tpmutil/encoding.go
+++ b/tpmutil/encoding.go
@@ -23,93 +23,28 @@ import (
 	"reflect"
 )
 
-// lengthPrefixSize is the size in bytes of length prefix for byte slices.
-//
-// In TPM 1.2 this is 4 bytes.
-// In TPM 2.0 this is 2 bytes.
-var lengthPrefixSize int
-
-const (
-	tpm12PrefixSize = 4
-	tpm20PrefixSize = 2
+var (
+	selfMarshalerType = reflect.TypeOf((*SelfMarshaler)(nil)).Elem()
+	handlesAreaType   = reflect.TypeOf((*[]Handle)(nil))
 )
 
-// UseTPM12LengthPrefixSize makes Pack/Unpack use TPM 1.2 encoding for byte
-// arrays.
-func UseTPM12LengthPrefixSize() {
-	lengthPrefixSize = tpm12PrefixSize
-}
-
-// UseTPM20LengthPrefixSize makes Pack/Unpack use TPM 2.0 encoding for byte
-// arrays.
-func UseTPM20LengthPrefixSize() {
-	lengthPrefixSize = tpm20PrefixSize
-}
-
-// packedSize computes the size of a sequence of types that can be passed to
-// binary.Read or binary.Write.
-func packedSize(elts ...interface{}) (int, error) {
-	var size int
-	for _, e := range elts {
-		marshaler, ok := e.(SelfMarshaler)
-		if ok {
-			size += marshaler.TPMPackedSize()
-			continue
-		}
-		v := reflect.ValueOf(e)
-		switch v.Kind() {
-		case reflect.Ptr:
-			s, err := packedSize(reflect.Indirect(v).Interface())
-			if err != nil {
-				return 0, err
-			}
-
-			size += s
-		case reflect.Struct:
-			for i := 0; i < v.NumField(); i++ {
-				s, err := packedSize(v.Field(i).Interface())
-				if err != nil {
-					return 0, err
-				}
-
-				size += s
-			}
-		case reflect.Slice:
-			switch s := e.(type) {
-			case []byte:
-				size += lengthPrefixSize + len(s)
-			case RawBytes:
-				size += len(s)
-			default:
-				return 0, fmt.Errorf("encoding of %T is not supported, only []byte and RawBytes slices are", e)
-			}
-		default:
-			s := binary.Size(e)
-			if s < 0 {
-				return 0, fmt.Errorf("can't calculate size of type %T", e)
-			}
-
-			size += s
-		}
-	}
-
-	return size, nil
-}
-
 // packWithHeader takes a header and a sequence of elements that are either of
 // fixed length or slices of fixed-length types and packs them into a single
 // byte array using binary.Write. It updates the CommandHeader to have the right
 // length.
 func packWithHeader(ch commandHeader, cmd ...interface{}) ([]byte, error) {
 	hdrSize := binary.Size(ch)
-	bodySize, err := packedSize(cmd...)
+	body, err := Pack(cmd...)
 	if err != nil {
-		return nil, fmt.Errorf("couldn't compute packed size for message body: %v", err)
+		return nil, fmt.Errorf("couldn't pack message body: %v", err)
 	}
+	bodySize := len(body)
 	ch.Size = uint32(hdrSize + bodySize)
-	in := []interface{}{ch}
-	in = append(in, cmd...)
-	return Pack(in...)
+	header, err := Pack(ch)
+	if err != nil {
+		return nil, fmt.Errorf("couldn't pack message header: %v", err)
+	}
+	return append(header, body...), nil
 }
 
 // Pack encodes a set of elements into a single byte array, using
@@ -120,81 +55,99 @@ func packWithHeader(ch commandHeader, cmd ...interface{}) ([]byte, error) {
 // prepended length, to match how the TPM encodes variable-length arrays. If
 // you wish to add a byte slice without length prefix, use RawBytes.
 func Pack(elts ...interface{}) ([]byte, error) {
-	if lengthPrefixSize == 0 {
-		return nil, errors.New("lengthPrefixSize must be initialized")
-	}
-
 	buf := new(bytes.Buffer)
 	if err := packType(buf, elts...); err != nil {
 		return nil, err
 	}
-
 	return buf.Bytes(), nil
 }
 
-// packType recursively packs types the same way that encoding/binary does
-// under binary.BigEndian, but with one difference: it packs a byte slice as a
-// lengthPrefixSize size followed by the bytes. The function unpackType
-// performs the inverse operation of unpacking slices stored in this manner and
-// using encoding/binary for everything else.
-func packType(buf io.Writer, elts ...interface{}) error {
-	for _, e := range elts {
-		marshaler, ok := e.(SelfMarshaler)
-		if ok {
-			if err := marshaler.TPMMarshal(buf); err != nil {
-				return err
-			}
-			continue
+// tryMarshal attempts to use a TPMMarshal() method defined on the type
+// to pack v into buf. True is returned if the method exists and the
+// marshal was attempted.
+func tryMarshal(buf io.Writer, v reflect.Value) (bool, error) {
+	t := v.Type()
+	if t.Implements(selfMarshalerType) {
+		if v.Kind() == reflect.Ptr && v.IsNil() {
+			return true, fmt.Errorf("cannot call TPMMarshal on a nil pointer of type %T", v)
 		}
-		v := reflect.ValueOf(e)
-		switch v.Kind() {
-		case reflect.Ptr:
-			if err := packType(buf, reflect.Indirect(v).Interface()); err != nil {
-				return err
-			}
-		case reflect.Struct:
-			// TODO(awly): Currently packType cannot handle non-struct fields that implement SelfMarshaler
-			for i := 0; i < v.NumField(); i++ {
-				if err := packType(buf, v.Field(i).Interface()); err != nil {
-					return err
-				}
-			}
-		case reflect.Slice:
-			switch s := e.(type) {
-			case []byte:
-				switch lengthPrefixSize {
-				case tpm20PrefixSize:
-					if err := binary.Write(buf, binary.BigEndian, uint16(len(s))); err != nil {
-						return err
-					}
-				case tpm12PrefixSize:
-					if err := binary.Write(buf, binary.BigEndian, uint32(len(s))); err != nil {
-						return err
-					}
-				default:
-					return fmt.Errorf("lengthPrefixSize is %d, must be either 2 or 4", lengthPrefixSize)
-				}
-				if err := binary.Write(buf, binary.BigEndian, s); err != nil {
-					return err
-				}
-			case RawBytes:
-				if err := binary.Write(buf, binary.BigEndian, s); err != nil {
-					return err
-				}
-			default:
-				return fmt.Errorf("only []byte and RawBytes slices are supported, got %T", e)
-			}
-		default:
-			if err := binary.Write(buf, binary.BigEndian, e); err != nil {
+		return true, v.Interface().(SelfMarshaler).TPMMarshal(buf)
+	}
+
+	// We might have a non-pointer struct field, but we dont have a
+	// pointer with which to implement the interface.
+	// If the pointer of the type implements the interface, we should be
+	// able to construct a value to call TPMMarshal() with.
+	// TODO(awly): Try and avoid blowing away private data by using Addr() instead of Set()
+	if reflect.PtrTo(t).Implements(selfMarshalerType) {
+		tmp := reflect.New(t)
+		tmp.Elem().Set(v)
+		return true, tmp.Interface().(SelfMarshaler).TPMMarshal(buf)
+	}
+
+	return false, nil
+}
+
+func packValue(buf io.Writer, v reflect.Value) error {
+	if v.Type() == handlesAreaType {
+		v = v.Convert(reflect.TypeOf((*handleList)(nil)))
+	}
+	if canMarshal, err := tryMarshal(buf, v); canMarshal {
+		return err
+	}
+
+	switch v.Kind() {
+	case reflect.Ptr:
+		if v.IsNil() {
+			return fmt.Errorf("cannot pack nil %s", v.Type().String())
+		}
+		return packValue(buf, v.Elem())
+	case reflect.Struct:
+		for i := 0; i < v.NumField(); i++ {
+			f := v.Field(i)
+			if err := packValue(buf, f); err != nil {
 				return err
 			}
 		}
+	default:
+		return binary.Write(buf, binary.BigEndian, v.Interface())
+	}
+	return nil
+}
 
+func packType(buf io.Writer, elts ...interface{}) error {
+	for _, e := range elts {
+		if err := packValue(buf, reflect.ValueOf(e)); err != nil {
+			return err
+		}
 	}
 
 	return nil
 }
 
+// tryUnmarshal attempts to use TPMUnmarshal() to perform the
+// unpack, if the given value implements SelfMarshaler.
+// True is returned if v implements SelfMarshaler & TPMUnmarshal
+// was called, along with an error returned from TPMUnmarshal.
+func tryUnmarshal(buf io.Reader, v reflect.Value) (bool, error) {
+	t := v.Type()
+	if t.Implements(selfMarshalerType) {
+		if v.Kind() == reflect.Ptr && v.IsNil() {
+			return true, fmt.Errorf("cannot call TPMUnmarshal on a nil pointer")
+		}
+		return true, v.Interface().(SelfMarshaler).TPMUnmarshal(buf)
+	}
+
+	// We might have a non-pointer struct field, which is addressable,
+	// If the pointer of the type implements the interface, and the
+	// value is addressable, we should be able to call TPMUnmarshal().
+	if v.CanAddr() && reflect.PtrTo(t).Implements(selfMarshalerType) {
+		return true, v.Addr().Interface().(SelfMarshaler).TPMUnmarshal(buf)
+	}
+
+	return false, nil
+}
+
 // Unpack is a convenience wrapper around UnpackBuf. Unpack returns the number
 // of bytes read from b to fill elts and error, if any.
 func Unpack(b []byte, elts ...interface{}) (int, error) {
@@ -204,6 +157,37 @@ func Unpack(b []byte, elts ...interface{}) (int, error) {
 	return read, err
 }
 
+func unpackValue(buf io.Reader, v reflect.Value) error {
+	if v.Type() == handlesAreaType {
+		v = v.Convert(reflect.TypeOf((*handleList)(nil)))
+	}
+	if didUnmarshal, err := tryUnmarshal(buf, v); didUnmarshal {
+		return err
+	}
+
+	switch v.Kind() {
+	case reflect.Ptr:
+		if v.IsNil() {
+			return fmt.Errorf("cannot unpack nil %s", v.Type().String())
+		}
+		return unpackValue(buf, v.Elem())
+	case reflect.Struct:
+		for i := 0; i < v.NumField(); i++ {
+			f := v.Field(i)
+			if err := unpackValue(buf, f); err != nil {
+				return err
+			}
+		}
+		return nil
+	default:
+		// binary.Read can only set pointer values, so we need to take the address.
+		if !v.CanAddr() {
+			return fmt.Errorf("cannot unpack unaddressable leaf type %q", v.Type().String())
+		}
+		return binary.Read(buf, binary.BigEndian, v.Addr().Interface())
+	}
+}
+
 // UnpackBuf recursively unpacks types from a reader just as encoding/binary
 // does under binary.BigEndian, but with one difference: it unpacks a byte
 // slice by first reading an integer with lengthPrefixSize bytes, then reading
@@ -212,95 +196,16 @@ func Unpack(b []byte, elts ...interface{}) (int, error) {
 func UnpackBuf(buf io.Reader, elts ...interface{}) error {
 	for _, e := range elts {
 		v := reflect.ValueOf(e)
-		k := v.Kind()
-		if k != reflect.Ptr {
-			return fmt.Errorf("all values passed to Unpack must be pointers, got %v", k)
+		if v.Kind() != reflect.Ptr {
+			return fmt.Errorf("non-pointer value %q passed to UnpackBuf", v.Type().String())
 		}
-
 		if v.IsNil() {
-			return errors.New("can't fill a nil pointer")
+			return errors.New("nil pointer passed to UnpackBuf")
 		}
 
-		marshaler, ok := e.(SelfMarshaler)
-		if ok {
-			if err := marshaler.TPMUnmarshal(buf); err != nil {
-				return err
-			}
-			continue
-		}
-		iv := reflect.Indirect(v)
-		switch iv.Kind() {
-		case reflect.Struct:
-			// Decompose the struct and copy over the values.
-			for i := 0; i < iv.NumField(); i++ {
-				if err := UnpackBuf(buf, iv.Field(i).Addr().Interface()); err != nil {
-					return err
-				}
-			}
-		case reflect.Slice:
-			var size int
-			_, isHandles := e.(*[]Handle)
-
-			switch {
-			// []Handle always uses 2-byte length, even with TPM 1.2.
-			case isHandles:
-				var tmpSize uint16
-				if err := binary.Read(buf, binary.BigEndian, &tmpSize); err != nil {
-					return err
-				}
-				size = int(tmpSize)
-			// TPM 2.0
-			case lengthPrefixSize == tpm20PrefixSize:
-				var tmpSize uint16
-				if err := binary.Read(buf, binary.BigEndian, &tmpSize); err != nil {
-					return err
-				}
-				size = int(tmpSize)
-			// TPM 1.2
-			case lengthPrefixSize == tpm12PrefixSize:
-				var tmpSize uint32
-				if err := binary.Read(buf, binary.BigEndian, &tmpSize); err != nil {
-					return err
-				}
-				size = int(tmpSize)
-			default:
-				return fmt.Errorf("lengthPrefixSize is %d, must be either 2 or 4", lengthPrefixSize)
-			}
-
-			// A zero size is used by the TPM to signal that certain elements
-			// are not present.
-			if size == 0 {
-				continue
-			}
-
-			// Make len(e) match size exactly.
-			switch b := e.(type) {
-			case *[]byte:
-				if len(*b) >= size {
-					*b = (*b)[:size]
-				} else {
-					*b = append(*b, make([]byte, size-len(*b))...)
-				}
-			case *[]Handle:
-				if len(*b) >= size {
-					*b = (*b)[:size]
-				} else {
-					*b = append(*b, make([]Handle, size-len(*b))...)
-				}
-			default:
-				return fmt.Errorf("can't fill pointer to %T, only []byte or []Handle slices", e)
-			}
-
-			if err := binary.Read(buf, binary.BigEndian, e); err != nil {
-				return err
-			}
-		default:
-			if err := binary.Read(buf, binary.BigEndian, e); err != nil {
-				return err
-			}
+		if err := unpackValue(buf, v); err != nil {
+			return err
 		}
-
 	}
-
 	return nil
 }
diff --git a/tpmutil/run.go b/tpmutil/run.go
index 641febe..21a9c66 100644
--- a/tpmutil/run.go
+++ b/tpmutil/run.go
@@ -13,10 +13,6 @@
 // limitations under the License.
 
 // Package tpmutil provides common utility functions for both TPM 1.2 and TPM 2.0 devices.
-//
-// Users should call either UseTPM12LengthPrefixSize or
-// UseTPM20LengthPrefixSize before using this package, depending on their type
-// of TPM device.
 package tpmutil
 
 import (
diff --git a/tpmutil/structures.go b/tpmutil/structures.go
index 8e71f52..c67b51a 100644
--- a/tpmutil/structures.go
+++ b/tpmutil/structures.go
@@ -14,13 +14,103 @@
 
 package tpmutil
 
-import "io"
+import (
+	"encoding/binary"
+	"fmt"
+	"io"
+)
 
 // RawBytes is for Pack and RunCommand arguments that are already encoded.
 // Compared to []byte, RawBytes will not be prepended with slice length during
 // encoding.
 type RawBytes []byte
 
+// U16Bytes is a byte slice with a 16-bit header
+type U16Bytes []byte
+
+// TPMMarshal packs U16Bytes
+func (b *U16Bytes) TPMMarshal(out io.Writer) error {
+	size := uint16(len([]byte(*b)))
+	if err := binary.Write(out, binary.BigEndian, size); err != nil {
+		return err
+	}
+
+	n, err := out.Write(*b)
+	if err != nil {
+		return err
+	}
+	if n != int(size) {
+		return fmt.Errorf("unable to write all contents of U16Bytes")
+	}
+	return nil
+}
+
+// TPMUnmarshal unpacks a U16Bytes
+func (b *U16Bytes) TPMUnmarshal(in io.Reader) error {
+	var tmpSize uint16
+	if err := binary.Read(in, binary.BigEndian, &tmpSize); err != nil {
+		return err
+	}
+	size := int(tmpSize)
+	if len(*b) >= size {
+		*b = (*b)[:size]
+	} else {
+		*b = append(*b, make([]byte, size-len(*b))...)
+	}
+
+	n, err := in.Read(*b)
+	if err != nil {
+		return err
+	}
+	if n != size {
+		return fmt.Errorf("unable to read all contents in to U16Bytes")
+	}
+	return nil
+}
+
+// U32Bytes is a byte slice with a 32-bit header
+type U32Bytes []byte
+
+// TPMMarshal packs U32Bytes
+func (b *U32Bytes) TPMMarshal(out io.Writer) error {
+	size := uint32(len([]byte(*b)))
+	if err := binary.Write(out, binary.BigEndian, size); err != nil {
+		return err
+	}
+
+	n, err := out.Write(*b)
+	if err != nil {
+		return err
+	}
+	if n != int(size) {
+		return fmt.Errorf("unable to write all contents of U32Bytes")
+	}
+	return nil
+}
+
+// TPMUnmarshal unpacks a U32Bytes
+func (b *U32Bytes) TPMUnmarshal(in io.Reader) error {
+	var tmpSize uint32
+	if err := binary.Read(in, binary.BigEndian, &tmpSize); err != nil {
+		return err
+	}
+	size := int(tmpSize)
+	if len(*b) >= size {
+		*b = (*b)[:size]
+	} else {
+		*b = append(*b, make([]byte, size-len(*b))...)
+	}
+
+	n, err := in.Read(*b)
+	if err != nil {
+		return err
+	}
+	if n != size {
+		return fmt.Errorf("unable to read all contents in to U32Bytes")
+	}
+	return nil
+}
+
 // Tag is a command tag.
 type Tag uint16
 
@@ -51,10 +141,31 @@ type responseHeader struct {
 // A Handle is a reference to a TPM object.
 type Handle uint32
 
+type handleList []Handle
+
+func (l *handleList) TPMMarshal(out io.Writer) error {
+	return fmt.Errorf("TPMMarhsal on []Handle is not supported yet")
+}
+
+func (l *handleList) TPMUnmarshal(in io.Reader) error {
+	var numHandles uint16
+	if err := binary.Read(in, binary.BigEndian, &numHandles); err != nil {
+		return err
+	}
+
+	// Make len(e) match size exactly.
+	size := int(numHandles)
+	if len(*l) >= size {
+		*l = (*l)[:size]
+	} else {
+		*l = append(*l, make([]Handle, size-len(*l))...)
+	}
+	return binary.Read(in, binary.BigEndian, *l)
+}
+
 // SelfMarshaler allows custom types to override default encoding/decoding
 // behavior in Pack, Unpack and UnpackBuf.
 type SelfMarshaler interface {
 	TPMMarshal(out io.Writer) error
 	TPMUnmarshal(in io.Reader) error
-	TPMPackedSize() int
 }


Test patch:
diff --git a/tpm/tpm_test.go b/tpm/tpm_test.go
index 3ef08b4..fdfb18e 100644
--- a/tpm/tpm_test.go
+++ b/tpm/tpm_test.go
@@ -216,13 +216,13 @@ func TestResizeableSlice(t *testing.T) {
 		t.Fatal("Couldn't read random bytes into the byte array")
 	}
 
-	bb, err := tpmutil.Pack(ra, b)
+	bb, err := tpmutil.Pack(ra, tpmutil.U32Bytes(b))
 	if err != nil {
 		t.Fatal("Couldn't pack the bytes:", err)
 	}
 
 	var ra2 responseAuth
-	var b2 []byte
+	var b2 tpmutil.U32Bytes
 	if _, err := tpmutil.Unpack(bb, &ra2, &b2); err != nil {
 		t.Fatal("Couldn't unpack the resizeable values:", err)
 	}
diff --git a/tpm2/tpm2_test.go b/tpm2/tpm2_test.go
index 14020ac..41f322a 100644
--- a/tpm2/tpm2_test.go
+++ b/tpm2/tpm2_test.go
@@ -242,10 +242,10 @@ func TestCombinedEndorsementTest(t *testing.T) {
 		{Session: HandlePasswordSession, Attributes: AttrContinueSession, Auth: []byte(emptyPassword)},
 	}, keyHandle, parentHandle, credBlob, encryptedSecret0)
 	if err == nil {
-		t.Fatal("ActivateCredentialUsingAuth: error == nil, expected response status 0x98e (authorization failure)")
+		t.Fatal("ActivateCredentialUsingAuth: error == nil, expected authorization failure")
 	}
-	if !strings.Contains(err.Error(), "0x98e") {
-		t.Errorf("ActivateCredentialUsingAuth: error = %v, expected response status 0x98e (authorization failure)", err)
+	if !strings.Contains(err.Error(), "the authorization HMAC check failed") {
+		t.Errorf("ActivateCredentialUsingAuth: error = %v, expected authorization failure", err)
 	}
 
 	_, err = ActivateCredentialUsingAuth(rw, []AuthCommand{
diff --git a/tpmutil/encoding_test.go b/tpmutil/encoding_test.go
index 9efe315..4cf4aa1 100644
--- a/tpmutil/encoding_test.go
+++ b/tpmutil/encoding_test.go
@@ -22,10 +22,6 @@ import (
 	"testing"
 )
 
-func init() {
-	UseTPM12LengthPrefixSize()
-}
-
 type invalidPacked struct {
 	A []int
 	B uint32
@@ -59,15 +55,6 @@ func testEncodingInvalidSlices(t *testing.T, f func(io.Writer, interface{}) erro
 	}
 }
 
-func TestEncodingPackedSizeInvalid(t *testing.T) {
-	f := func(w io.Writer, i interface{}) error {
-		_, err := packedSize(i)
-		return err
-	}
-
-	testEncodingInvalidSlices(t, f)
-}
-
 func TestEncodingPackTypeInvalid(t *testing.T) {
 	f := func(w io.Writer, i interface{}) error {
 		return packType(w, i)
@@ -88,28 +75,7 @@ type nestedPacked struct {
 
 type nestedSlice struct {
 	A uint32
-	S []byte
-}
-
-func TestEncodingPackedSize(t *testing.T) {
-	buf := make([]byte, 10)
-	tests := []struct {
-		in   interface{}
-		want int
-	}{
-		{uint32(3), 4},
-		{buf, 14},
-		{&buf, 14},
-		{simplePacked{137, 138}, 8},
-		{nestedPacked{simplePacked{137, 138}, 139}, 12},
-		{nestedSlice{137, buf}, 18},
-		{[]byte(nil), 4},
-	}
-	for _, tt := range tests {
-		if s, err := packedSize(tt.in); err != nil || s != tt.want {
-			t.Errorf("packedSize(%#v): %d, want %d", tt.in, s, tt.want)
-		}
-	}
+	S U32Bytes
 }
 
 func TestEncodingPackType(t *testing.T) {
@@ -132,12 +98,15 @@ func TestEncodingPackType(t *testing.T) {
 }
 
 func TestEncodingPackTypeWriteFail(t *testing.T) {
+	u32WithOneByte := U32Bytes([]byte{1})
+	u32Empty := U32Bytes([]byte(nil))
+
 	tests := []struct {
 		limit int
 		in    interface{}
 	}{
-		{4, []byte{1}},
-		{3, []byte(nil)},
+		{4, &u32WithOneByte},
+		{3, &u32Empty},
 	}
 	for _, tt := range tests {
 		if err := packType(&limitedDiscard{tt.limit}, tt.in); err == nil {
@@ -223,11 +192,11 @@ func TestEncodingInvalidUnpack(t *testing.T) {
 		t.Fatal("UnpackBuf incorrectly deserialized into a non pointer")
 	}
 
-	var b []byte
+	var b U32Bytes
 	var empty []byte
 	emptyBuf := bytes.NewBuffer(empty)
 	if err := UnpackBuf(emptyBuf, &b); err == nil {
-		t.Fatal("UnpackBuf incorrectly deserialized an empty byte array into a byte slice")
+		t.Fatal("UnpackBuf incorrectly deserialized an empty byte array into U32Bytes")
 	}
 
 	// Try to deserialize a byte array that has a length but not enough bytes.
@@ -247,9 +216,37 @@ func TestEncodingInvalidUnpack(t *testing.T) {
 
 }
 
+func TestSelfMarshaler(t *testing.T) {
+	var empty16 U16Bytes
+	var empty32 U32Bytes
+	subTests := []struct {
+		encoded []byte
+		decoded interface{}
+	}{
+		{[]byte{0, 0}, &empty16},
+		{[]byte{0, 1, 137}, &empty16},
+		{[]byte{0, 0, 0, 0}, &empty32},
+		{[]byte{0, 0, 0, 1, 137}, &empty32},
+	}
+	for _, st := range subTests {
+		t.Logf("Attempting to Marshal/Unmarshal %#v into %T", st.encoded, st.decoded)
+		buffer := bytes.NewBuffer(st.encoded)
+		if err := UnpackBuf(buffer, st.decoded); err != nil {
+			t.Fatalf("UnpackBuf failed: %v", err)
+		}
+		packed, err := Pack(st.decoded)
+		if err != nil {
+			t.Fatalf("Pack failed: %v", err)
+		}
+		if !bytes.Equal(packed, st.encoded) {
+			t.Fatalf("Pack failed: got %#v, want: %#v", packed, st.encoded)
+		}
+	}
+}
+
 func TestEncodingUnpack(t *testing.T) {
 	// Deserialize the empty byte array.
-	var b []byte
+	var b U32Bytes
 	// The slice ui represents uint32(0), which is the length of an empty byte array.
 	ui := []byte{0, 0, 0, 0}
 	uiBuf := bytes.NewBuffer(ui)
@@ -264,7 +261,7 @@ func TestEncodingUnpack(t *testing.T) {
 		t.Fatal("UnpackBuf failed to unpack a byte array with a single value in it")
 	}
 
-	if !bytes.Equal(b, []byte{137}) {
+	if !bytes.Equal([]byte(b), []byte{137}) {
 		t.Fatal("UnpackBuf unpacked a small byte array incorrectly")
 	}
 
@@ -301,7 +298,7 @@ func TestEncodingUnpack(t *testing.T) {
 	}
 
 	ns := nestedSlice{137, b}
-	bns, err := Pack(ns)
+	bns, err := Pack(&ns)
 	if err != nil {
 		t.Fatal("Couldn't pack a struct with a nested byte slice:", err)
 	}
@@ -310,6 +307,8 @@ func TestEncodingUnpack(t *testing.T) {
 		t.Fatal("Couldn't unpacked a struct with a nested slice:", err)
 	}
 	if ns.A != ns2.A || !bytes.Equal(ns.S, ns2.S) {
+		t.Logf("orginal = %+v", ns)
+		t.Logf("decoded = %+v", ns2)
 		t.Fatal("Unpacked struct with nested slice didn't match the original")
 	}
 
@@ -349,3 +348,19 @@ func TestPartialUnpack(t *testing.T) {
 		t.Errorf("sum of bytes read doesn't ad up to total packed size: got %d+%d=%d, want %d", read1, read2, read1+read2, len(buf))
 	}
 }
+
+func TestUnpackHandlesArea(t *testing.T) {
+	buf := []byte{
+		0, 2,
+		0, 0, 0, 1,
+		0, 0, 5, 57,
+	}
+	var out []Handle
+
+	if _, err := Unpack(buf, &out); err != nil {
+		t.Fatalf("Unpack(%v, %T) failed: %v", buf, &out, err)
+	}
+	if want := []Handle{1, 1337}; !reflect.DeepEqual(out, want) {
+		t.Errorf("Unpack(%v, %T): %T = %v, want %v", buf, &out, out, out, want)
+	}
+}