示例#1
0
文件: upgrade.go 项目: tudalex/mig
// verifyChecksum computes the hash of a file and compares it
// to a checksum. If comparison fails, it returns an error.
func verifyChecksum(fd *os.File, checksum string) (err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("verifyChecksum() -> %v", e)
		}
	}()
	var h hash.Hash
	h = sha256.New()
	buf := make([]byte, 4096)
	var offset int64 = 0
	for {
		block, err := fd.ReadAt(buf, offset)
		if err != nil && err != io.EOF {
			panic(err)
		}
		if block == 0 {
			break
		}
		h.Write(buf[:block])
		offset += int64(block)
	}
	hexhash := fmt.Sprintf("%x", h.Sum(nil))
	if hexhash != checksum {
		return fmt.Errorf("Checksum validation failed. Got '%s', Expected '%s'.",
			hexhash, checksum)
	}
	return
}
示例#2
0
// Iterated writes to out the result of computing the Iterated and Salted S2K
// function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase,
// salt and iteration count.
func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) {
	combined := make([]byte, len(in)+len(salt))
	copy(combined, salt)
	copy(combined[len(salt):], in)

	if count < len(combined) {
		count = len(combined)
	}

	done := 0
	var digest []byte
	for i := 0; done < len(out); i++ {
		h.Reset()
		for j := 0; j < i; j++ {
			h.Write(zero[:])
		}
		written := 0
		for written < count {
			if written+len(combined) > count {
				todo := count - written
				h.Write(combined[:todo])
				written = count
			} else {
				h.Write(combined)
				written += len(combined)
			}
		}
		digest = h.Sum(digest[:0])
		n := copy(out[done:], digest)
		done += n
	}
}
示例#3
0
// RefFromHash returns a blobref representing the given hash.
// It panics if the hash isn't of a known type.
func RefFromHash(h hash.Hash) Ref {
	meta, ok := metaFromType[reflect.TypeOf(h)]
	if !ok {
		panic(fmt.Sprintf("Currently-unsupported hash type %T", h))
	}
	return Ref{meta.ctor(h.Sum(nil))}
}
示例#4
0
// Returns true if the provided message is unsigned or has a valid signature
// from one of the provided signers.
func authenticateMessage(signers map[string]Signer, header *Header, msg []byte) bool {
	digest := header.GetHmac()
	if digest != nil {
		var key string
		signer := fmt.Sprintf("%s_%d", header.GetHmacSigner(),
			header.GetHmacKeyVersion())
		if s, ok := signers[signer]; ok {
			key = s.HmacKey
		} else {
			return false
		}

		var hm hash.Hash
		switch header.GetHmacHashFunction() {
		case Header_MD5:
			hm = hmac.New(md5.New, []byte(key))
		case Header_SHA1:
			hm = hmac.New(sha1.New, []byte(key))
		}
		hm.Write(msg)
		expectedDigest := hm.Sum(nil)
		if subtle.ConstantTimeCompare(digest, expectedDigest) != 1 {
			return false
		}
	}
	return true
}
示例#5
0
func LoadPost(ctx *web.Context, val string) {
	username := ctx.Params["username"]
	password := ctx.Params["password"]

	salt := strconv.Itoa64(time.Nanoseconds()) + username

	var h hash.Hash = sha256.New()
	h.Write([]byte(password + salt))

	s, _err := conn.Prepare("INSERT INTO users VALUES(NULL, ?, ?, ?)")
	utils.ReportErr(_err)

	s.Exec(username, string(h.Sum()), salt)
	s.Finalize()
	conn.Close()
	sidebar := utils.Loadmustache("admin.mustache", &map[string]string{})

	//TESTING, REMOVE LATER
	script := "<script type=\"text/javascript\" src=\"../inc/adminref.js\"></script>"
	content := "Welcome to the admin panel, use the control box on your right to control the site content"
	//ENDTESTING

	mapping := map[string]string{"css": "../inc/site.css",
		"title":   "Proggin: Admin panel",
		"sidebar": sidebar,
		"content": content,
		"script":  script}

	output := utils.Loadmustache("frame.mustache", &mapping)
	ctx.WriteString(output)
}
示例#6
0
func (c *Client) PutObject(name, bucket string, md5 hash.Hash, size int64, body io.Reader) error {
	req := newReq("http://" + bucket + ".s3.amazonaws.com/" + name)
	req.Method = "PUT"
	req.ContentLength = size
	if md5 != nil {
		b64 := new(bytes.Buffer)
		encoder := base64.NewEncoder(base64.StdEncoding, b64)
		encoder.Write(md5.Sum(nil))
		encoder.Close()
		req.Header.Set("Content-MD5", b64.String())
	}
	c.Auth.SignRequest(req)
	req.Body = ioutil.NopCloser(body)

	res, err := c.httpClient().Do(req)
	if res != nil && res.Body != nil {
		defer res.Body.Close()
	}
	if err != nil {
		return err
	}
	if res.StatusCode != 200 {
		res.Write(os.Stderr)
		return fmt.Errorf("Got response code %d from s3", res.StatusCode)
	}
	return nil
}
示例#7
0
func finishEAX(tag []byte, cmac hash.Hash) {
	// Finish CMAC #2 and xor into tag.
	sum := cmac.Sum()
	for i := range tag {
		tag[i] ^= sum[i]
	}
}
示例#8
0
文件: main.go 项目: dullgiulio/empa
func filehash(h hash.Hash, r io.Reader) ([]byte, error) {
	defer h.Reset()
	if _, err := io.Copy(h, r); err != nil {
		return nil, err
	}
	return h.Sum(nil), nil
}
示例#9
0
func TestKeccak(t *testing.T) {
	for i := range tests {
		var h hash.Hash

		switch tests[i].length {
		case 28:
			h = New224()
		case 32:
			h = New256()
		case 48:
			h = New384()
		case 64:
			h = New512()
		default:
			panic("invalid testcase")
		}

		h.Write(tests[i].input)

		d := h.Sum(nil)
		if !bytes.Equal(d, tests[i].output) {
			t.Errorf("testcase %d: expected %x got %x", i, tests[i].output, d)
		}
	}
}
示例#10
0
文件: mdr_hash.go 项目: hotei/mdr
// Compute md5 for given file
// Test is Test_005
func FileMD5(fname string) (string, error) {
	//fmt.Printf("Computing digest for %s\n",fname)
	const NBUF = 1 << 20 // 20 -> 1 MB
	file, err := os.OpenFile(fname, os.O_RDONLY, 0666)
	if file == nil {
		fmt.Printf("!Err--> mdr.FileMD5() can't open file %s as readonly; err=%v\n", fname, err)
		return "", err
	}
	defer file.Close()
	buf := make([]byte, NBUF)
	var h hash.Hash = md5.New()
	for {
		numRead, err := file.Read(buf)
		if (err == io.EOF) && (numRead == 0) {
			break
		} // end of file reached
		if (err != nil) || (numRead < 0) {
			fmt.Fprintf(os.Stderr, "!Err--> mdr.FileMD5: error reading from %s: %v\n", fname, err)
			return "", err
		}
		//		fmt.Printf("read(%d) bytes\n",numRead)
		h.Write(buf[0:numRead])
	}
	digest := h.Sum(nil)
	rv := DigestToString(digest)
	//fmt.Printf("%s digest ->%s\n",fname,rv)
	return string(rv), nil
}
示例#11
0
文件: hooks.go 项目: judwhite/ghapi
func checkMAC(mac hash.Hash, message, messageMAC []byte) bool {
	if _, err := mac.Write(message); err != nil {
		return false
	}
	expectedMAC := mac.Sum(nil)
	return hmac.Equal(messageMAC, expectedMAC)
}
示例#12
0
文件: mdr_hash.go 项目: hotei/mdr
func BufSHA256(buf []byte) string {
	var h hash.Hash = sha256.New()
	h.Write(buf[:])
	digest := h.Sum(nil)
	//fmt.Printf("%s digest ->%s\n",fname,rv)
	return DigestToString(digest)
}
示例#13
0
// Initialize manifest from BLOB
func (s *Manifest) ParseBlob(in io.Reader, chunkSize int64) (err error) {
	var chunkHasher hash.Hash
	var w io.Writer
	var chunk Chunk
	hasher := sha3.New256()
	var written int64

	for {
		chunk = Chunk{
			Offset: s.Size,
		}
		chunkHasher = sha3.New256()
		w = io.MultiWriter(hasher, chunkHasher)
		written, err = io.CopyN(w, in, chunkSize)
		s.Size += written
		chunk.Size = written
		chunk.ID = ID(hex.EncodeToString(chunkHasher.Sum(nil)))
		s.Chunks = append(s.Chunks, chunk)

		if err == io.EOF {
			err = nil
			break
		} else if err != nil {
			return
		}
	}
	s.ID = ID(hex.EncodeToString(hasher.Sum(nil)))
	return
}
示例#14
0
文件: sshkey.go 项目: postfix/sshkey
// Return the fingerprint of the key in a raw format.
func Fingerprint(pub *SSHPublicKey, hashalgo crypto.Hash) (fpr []byte, err error) {
	var h hash.Hash

	// The default algorithm for OpenSSH appears to be MD5.
	if hashalgo == 0 {
		hashalgo = crypto.MD5
	}

	switch hashalgo {
	case crypto.MD5:
		h = md5.New()
	case crypto.SHA1:
		h = sha1.New()
	case crypto.SHA256:
		h = sha256.New()
	default:
		return nil, ErrInvalidDigest
	}

	blob, err := publicToBlob(pub)
	if err != nil {
		return nil, err
	}
	h.Write(blob)

	return h.Sum(nil), nil
}
//TODO: test and add to tests
//RIPEMD-160 operation for bitcoin address hashing
func Ripemd(b []byte) []byte {
	//ripemd hashing of the sha hash
	var h hash.Hash = ripemd160.New()
	h.Write(b)

	return h.Sum(nil) //return
}
示例#16
0
文件: client.go 项目: simonz05/util
func (c *Client) PutObject(name, bucket string, md5 hash.Hash, size int64, body io.Reader) error {
	req := newReq("http://" + bucket + "." + c.hostname() + "/" + name)
	req.Method = "PUT"
	req.ContentLength = size
	if md5 != nil {
		b64 := new(bytes.Buffer)
		encoder := base64.NewEncoder(base64.StdEncoding, b64)
		encoder.Write(md5.Sum(nil))
		encoder.Close()
		req.Header.Set("Content-MD5", b64.String())
	}
	if c.DefaultACL != "" {
		req.Header.Set("x-amz-acl", c.DefaultACL)
	}
	contentType := mime.TypeByExtension(path.Ext(name))
	if contentType == "" {
		contentType = "application/octet-stream"
	}
	req.Header.Set("Content-Type", contentType)
	c.Auth.SignRequest(req)
	req.Body = ioutil.NopCloser(body)

	res, err := c.httpClient().Do(req)
	if res != nil && res.Body != nil {
		defer httputil.CloseBody(res.Body)
	}
	if err != nil {
		return err
	}
	if res.StatusCode != http.StatusOK {
		res.Write(os.Stderr)
		return fmt.Errorf("Got response code %d from s3", res.StatusCode)
	}
	return nil
}
示例#17
0
文件: sha1.go 项目: dulumao/ant
func SHA1(s string) (r string) {
	var h hash.Hash
	h = sha1.New()
	io.WriteString(h, s)
	r = hex.EncodeToString(h.Sum(nil))
	return
}
示例#18
0
// Verifies the image package integrity after it is downloaded
func (img *Image) verify() error {
	// Makes sure the file cursor is positioned at the beginning of the file
	_, err := img.file.Seek(0, 0)
	if err != nil {
		return err
	}

	log.Printf("[DEBUG] Verifying image checksum...")
	var hasher hash.Hash

	switch img.ChecksumType {
	case "md5":
		hasher = md5.New()
	case "sha1":
		hasher = sha1.New()
	case "sha256":
		hasher = sha256.New()
	case "sha512":
		hasher = sha512.New()
	default:
		return fmt.Errorf("[ERROR] Crypto algorithm no supported: %s", img.ChecksumType)
	}
	_, err = io.Copy(hasher, img.file)
	if err != nil {
		return err
	}

	result := fmt.Sprintf("%x", hasher.Sum(nil))

	if result != img.Checksum {
		return fmt.Errorf("[ERROR] Checksum does not match\n Result: %s\n Expected: %s", result, img.Checksum)
	}

	return nil
}
示例#19
0
文件: sqs_test.go 项目: DataDog/goamz
func (s *S) TestSendMessageWithAttributes(c *C) {
	testServer.PrepareResponse(200, nil, TestSendMessageXmlOK)

	q := &Queue{s.sqs, testServer.URL + "/123456789012/testQueue/"}
	attrs := map[string]string{
		"test_attribute_name_1": "test_attribute_value_1",
	}
	resp, err := q.SendMessageWithAttributes("This is a test message", attrs)
	req := testServer.WaitRequest()

	c.Assert(req.Method, Equals, "GET")
	c.Assert(req.URL.Path, Equals, "/123456789012/testQueue/")
	c.Assert(req.Header["Date"], Not(Equals), "")

	var attrsHash = md5.New()
	attrsHash.Write(encodeMessageAttribute("test_attribute_name_1"))
	attrsHash.Write(encodeMessageAttribute("String"))
	attrsHash.Write([]byte{1})
	attrsHash.Write(encodeMessageAttribute("test_attribute_value_1"))
	c.Assert(resp.MD5OfMessageAttributes, Equals, fmt.Sprintf("%x", attrsHash.Sum(nil)))

	msg := "This is a test message"
	var h hash.Hash = md5.New()
	h.Write([]byte(msg))
	c.Assert(resp.MD5, Equals, fmt.Sprintf("%x", h.Sum(nil)))
	c.Assert(resp.Id, Equals, "5fea7756-0ea4-451a-a703-a558b933e274")
	c.Assert(err, IsNil)
}
示例#20
0
// DeriveConcatKDF implements NIST SP 800-56A Concatenation Key Derivation Function. Derives
// key material of keydatalen bits size given Z (sharedSecret), OtherInfo (AlgorithmID |
// PartyUInfo | PartyVInfo | SuppPubInfo | SuppPrivInfo) and hash function
func DeriveConcatKDF(keydatalen int, sharedSecret, algId, partyUInfo, partyVInfo, suppPubInfo, suppPrivInfo []byte, h hash.Hash) []byte {

	otherInfo := arrays.Concat(algId, partyUInfo, partyVInfo, suppPubInfo, suppPrivInfo)

	keyLenBytes := keydatalen >> 3

	reps := int(math.Ceil(float64(keyLenBytes) / float64(h.Size())))

	if reps > MaxInt {
		panic("kdf.DeriveConcatKDF: too much iterations (more than 2^32-1).")
	}

	dk := make([]byte, 0, keyLenBytes)

	for counter := 1; counter <= reps; counter++ {
		h.Reset()

		counterBytes := arrays.UInt32ToBytes(uint32(counter))

		h.Write(counterBytes)
		h.Write(sharedSecret)
		h.Write(otherInfo)

		dk = h.Sum(dk)
	}

	return dk[:keyLenBytes]
}
示例#21
0
// Checksum returns the checksum of some data, using a specified algorithm.
// It only returns an error when an invalid algorithm is used. The valid ones
// are MD5, SHA1, SHA224, SHA256, SHA384, SHA512, SHA3224, SHA3256, SHA3384,
// and SHA3512.
func Checksum(algorithm string, data []byte) (checksum string, err error) {
	// default
	var hasher hash.Hash
	switch strings.ToUpper(algorithm) {
	case "MD5":
		hasher = md5.New()
	case "SHA1":
		hasher = sha1.New()
	case "SHA224":
		hasher = sha256.New224()
	case "SHA256":
		hasher = sha256.New()
	case "SHA384":
		hasher = sha512.New384()
	case "SHA512":
		hasher = sha512.New()
	case "SHA3224":
		hasher = sha3.New224()
	case "SHA3256":
		hasher = sha3.New256()
	case "SHA3384":
		hasher = sha3.New384()
	case "SHA3512":
		hasher = sha3.New512()
	default:
		msg := "Invalid algorithm parameter passed go Checksum: %s"
		return checksum, fmt.Errorf(msg, algorithm)
	}
	hasher.Write(data)
	str := hex.EncodeToString(hasher.Sum(nil))
	return str, nil
}
示例#22
0
func (c *Client) PutObject(key, bucket string, md5 hash.Hash, size int64, body io.Reader) error {
	req := newReq(c.keyURL(bucket, key))
	req.Method = "PUT"
	req.ContentLength = size
	if md5 != nil {
		b64 := new(bytes.Buffer)
		encoder := base64.NewEncoder(base64.StdEncoding, b64)
		encoder.Write(md5.Sum(nil))
		encoder.Close()
		req.Header.Set("Content-MD5", b64.String())
	}
	c.Auth.SignRequest(req)
	req.Body = ioutil.NopCloser(body)

	res, err := c.transport().RoundTrip(req)
	if res != nil && res.Body != nil {
		defer httputil.CloseBody(res.Body)
	}
	if err != nil {
		return err
	}
	if res.StatusCode != http.StatusOK {
		// res.Write(os.Stderr)
		return fmt.Errorf("Got response code %d from s3", res.StatusCode)
	}
	return nil
}
示例#23
0
文件: inputs.go 项目: hellcoderz/heka
func authenticateMessage(signers map[string]Signer, header *Header,
	pack *PipelinePack) bool {
	digest := header.GetHmac()
	if digest != nil {
		var key string
		signer := fmt.Sprintf("%s_%d", header.GetHmacSigner(),
			header.GetHmacKeyVersion())
		if s, ok := signers[signer]; ok {
			key = s.HmacKey
		} else {
			return false
		}

		var hm hash.Hash
		switch header.GetHmacHashFunction() {
		case Header_MD5:
			hm = hmac.New(md5.New, []byte(key))
		case Header_SHA1:
			hm = hmac.New(sha1.New, []byte(key))
		}
		hm.Write(pack.MsgBytes)
		expectedDigest := hm.Sum(nil)
		if bytes.Compare(digest, expectedDigest) != 0 {
			return false
		}
		pack.Signer = header.GetHmacSigner()
	}
	return true
}
示例#24
0
// MakeSignature returns a auth_v4 signature from the `string to sign` variable.
// May be useful for creating v4 requests for services other than DynamoDB.
func MakeSignature(string2sign, zone, service, secret string) string {
	kCredentials, _ := cacheable_hmacs(zone, service, secret)
	var kSigning_hmac_sha256 hash.Hash = hmac.New(sha256.New, kCredentials)
	kSigning_hmac_sha256.Write([]byte(string2sign))
	kSigning := kSigning_hmac_sha256.Sum(nil)
	return hex.EncodeToString(kSigning)
}
示例#25
0
文件: tsig.go 项目: avalanche123/dns
// TsigVerify verifies the TSIG on a message.
// If the signature does not validate err contains the
// error, otherwise it is nil.
func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
	rawsecret, err := packBase64([]byte(secret))
	if err != nil {
		return err
	}
	// Srtip the TSIG from the incoming msg
	stripped, tsig, err := stripTsig(msg)
	if err != nil {
		return err
	}

	buf := tsigBuffer(stripped, tsig, requestMAC, timersOnly)

	ti := uint64(time.Now().Unix()) - tsig.TimeSigned
	if uint64(tsig.Fudge) < ti {
		return ErrTime
	}

	var h hash.Hash
	switch tsig.Algorithm {
	case HmacMD5:
		h = hmac.New(md5.New, []byte(rawsecret))
	case HmacSHA1:
		h = hmac.New(sha1.New, []byte(rawsecret))
	case HmacSHA256:
		h = hmac.New(sha256.New, []byte(rawsecret))
	default:
		return ErrKeyAlg
	}
	io.WriteString(h, string(buf))
	if strings.ToUpper(hex.EncodeToString(h.Sum(nil))) != strings.ToUpper(tsig.MAC) {
		return ErrSig
	}
	return nil
}
示例#26
0
// VerifySignature returns nil iff sig is a valid signature, made by this
// public key, of the data hashed into signed. signed is mutated by this call.
func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err os.Error) {
	if !pk.CanSign() {
		return error.InvalidArgumentError("public key cannot generate signatures")
	}

	signed.Write(sig.HashSuffix)
	hashBytes := signed.Sum()

	if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
		return error.SignatureError("hash tag doesn't match")
	}

	if pk.PubKeyAlgo != sig.PubKeyAlgo {
		return error.InvalidArgumentError("public key and signature use different algorithms")
	}

	switch pk.PubKeyAlgo {
	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
		rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey)
		err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature)
		if err != nil {
			return error.SignatureError("RSA verification failure")
		}
		return nil
	case PubKeyAlgoDSA:
		dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey)
		if !dsa.Verify(dsaPublicKey, hashBytes, sig.DSASigR, sig.DSASigS) {
			return error.SignatureError("DSA verification failure")
		}
		return nil
	default:
		panic("shouldn't happen")
	}
	panic("unreachable")
}
示例#27
0
// writeEncodedData -
func (b bucket) writeEncodedData(k, m uint8, writers []io.WriteCloser, objectData io.Reader, sumMD5, sum512 hash.Hash) (int, int, error) {
	chunks := split.Stream(objectData, 10*1024*1024)
	encoder, err := newEncoder(k, m, "Cauchy")
	if err != nil {
		return 0, 0, iodine.New(err, nil)
	}
	chunkCount := 0
	totalLength := 0
	for chunk := range chunks {
		if chunk.Err == nil {
			totalLength = totalLength + len(chunk.Data)
			encodedBlocks, _ := encoder.Encode(chunk.Data)
			sumMD5.Write(chunk.Data)
			sum512.Write(chunk.Data)
			for blockIndex, block := range encodedBlocks {
				_, err := io.Copy(writers[blockIndex], bytes.NewBuffer(block))
				if err != nil {
					return 0, 0, iodine.New(err, nil)
				}
			}
		}
		chunkCount = chunkCount + 1
	}
	return chunkCount, totalLength, nil
}
示例#28
0
文件: reader.go 项目: pnelson/archive
func generateChecksum(h hash.Hash, b *[]byte) string {
	_, err := h.Write(*b)
	if err != nil {
		return ""
	}
	return fmt.Sprintf("%x", h.Sum(nil))
}
// VerifySignatureV3 returns nil iff sig is a valid signature, made by this
// public key, of the data hashed into signed. signed is mutated by this call.
func (pk *PublicKeyV3) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err error) {
	if !pk.CanSign() {
		return errors.InvalidArgumentError("public key cannot generate signatures")
	}

	suffix := make([]byte, 5)
	suffix[0] = byte(sig.SigType)
	binary.BigEndian.PutUint32(suffix[1:], uint32(sig.CreationTime.Unix()))
	signed.Write(suffix)
	hashBytes := signed.Sum(nil)

	if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
		return errors.SignatureError("hash tag doesn't match")
	}

	if pk.PubKeyAlgo != sig.PubKeyAlgo {
		return errors.InvalidArgumentError("public key and signature use different algorithms")
	}

	switch pk.PubKeyAlgo {
	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
		if err = rsa.VerifyPKCS1v15(pk.PublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes); err != nil {
			return errors.SignatureError("RSA verification failure")
		}
		return
	default:
		// V3 public keys only support RSA.
		panic("shouldn't happen")
	}
	panic("unreachable")
}
示例#30
0
// decode uses the given block cipher (in CTR mode) to decrypt the
// data, and validate the hash.  If hash validation fails, an error is
// returned.
func decode(block cipher.Block, hmac hash.Hash, ciphertext []byte) ([]byte, error) {
	if len(ciphertext) < 2*block.BlockSize()+hmac.Size() {
		return nil, LenError
	}

	receivedHmac := ciphertext[len(ciphertext)-hmac.Size():]
	ciphertext = ciphertext[:len(ciphertext)-hmac.Size()]

	hmac.Write(ciphertext)
	if subtle.ConstantTimeCompare(hmac.Sum(nil), receivedHmac) != 1 {
		return nil, HashError
	}

	// split the iv and session bytes
	iv := ciphertext[len(ciphertext)-block.BlockSize():]
	session := ciphertext[:len(ciphertext)-block.BlockSize()]

	stream := cipher.NewCTR(block, iv)
	stream.XORKeyStream(session, session)

	// skip past the iv
	session = session[block.BlockSize():]

	return session, nil
}