// Seal fulfills the crypto.AEAD interface func (c AesCbcHmac) Seal(dst, nonce, plaintext, data []byte) []byte { ctlen := len(plaintext) ciphertext := make([]byte, ctlen+c.Overhead())[:ctlen] copy(ciphertext, plaintext) ciphertext = padbuf.PadBuffer(ciphertext).Pad(c.blockCipher.BlockSize()) cbc := cipher.NewCBCEncrypter(c.blockCipher, nonce) cbc.CryptBlocks(ciphertext, ciphertext) authtag := c.ComputeAuthTag(data, nonce, ciphertext) retlen := len(dst) + len(ciphertext) + len(authtag) ret := ensureSize(dst, retlen) out := ret[len(dst):] n := copy(out, ciphertext) n += copy(out[n:], authtag) if debug.Enabled { debug.Printf("Seal: ciphertext = %x (%d)\n", ciphertext, len(ciphertext)) debug.Printf("Seal: authtag = %x (%d)\n", authtag, len(authtag)) debug.Printf("Seal: ret = %x (%d)\n", ret, len(ret)) } return ret }
// Open fulfills the crypto.AEAD interface func (c AesCbcHmac) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { if len(ciphertext) < c.keysize { return nil, errors.New("invalid ciphertext (too short)") } tagOffset := len(ciphertext) - c.tagsize if tagOffset%c.blockCipher.BlockSize() != 0 { return nil, fmt.Errorf( "invalid ciphertext (invalid length: %d %% %d != 0)", tagOffset, c.blockCipher.BlockSize(), ) } tag := ciphertext[tagOffset:] ciphertext = ciphertext[:tagOffset] expectedTag := c.ComputeAuthTag(data, nonce, ciphertext) if subtle.ConstantTimeCompare(expectedTag, tag) != 1 { if debug.Enabled { debug.Printf("provided tag = %x\n", tag) debug.Printf("expected tag = %x\n", expectedTag) } return nil, errors.New("invalid ciphertext (tag mismatch)") } cbc := cipher.NewCBCDecrypter(c.blockCipher, nonce) buf := make([]byte, tagOffset) cbc.CryptBlocks(buf, ciphertext) plaintext, err := padbuf.PadBuffer(buf).Unpad(c.blockCipher.BlockSize()) if err != nil { return nil, err } ret := ensureSize(dst, len(plaintext)) out := ret[len(dst):] copy(out, plaintext) return ret, nil }