xref: /aosp_15_r20/external/tink/go/mac/subtle/cmac.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1*e7b1675dSTing-Kang Chang// Copyright 2020 Google LLC
2*e7b1675dSTing-Kang Chang//
3*e7b1675dSTing-Kang Chang// Licensed under the Apache License, Version 2.0 (the "License");
4*e7b1675dSTing-Kang Chang// you may not use this file except in compliance with the License.
5*e7b1675dSTing-Kang Chang// You may obtain a copy of the License at
6*e7b1675dSTing-Kang Chang//
7*e7b1675dSTing-Kang Chang//      http://www.apache.org/licenses/LICENSE-2.0
8*e7b1675dSTing-Kang Chang//
9*e7b1675dSTing-Kang Chang// Unless required by applicable law or agreed to in writing, software
10*e7b1675dSTing-Kang Chang// distributed under the License is distributed on an "AS IS" BASIS,
11*e7b1675dSTing-Kang Chang// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e7b1675dSTing-Kang Chang// See the License for the specific language governing permissions and
13*e7b1675dSTing-Kang Chang// limitations under the License.
14*e7b1675dSTing-Kang Chang//
15*e7b1675dSTing-Kang Chang////////////////////////////////////////////////////////////////////////////////
16*e7b1675dSTing-Kang Chang
17*e7b1675dSTing-Kang Changpackage subtle
18*e7b1675dSTing-Kang Chang
19*e7b1675dSTing-Kang Changimport (
20*e7b1675dSTing-Kang Chang	"crypto/subtle"
21*e7b1675dSTing-Kang Chang	"fmt"
22*e7b1675dSTing-Kang Chang
23*e7b1675dSTing-Kang Chang	subtleprf "github.com/google/tink/go/prf/subtle"
24*e7b1675dSTing-Kang Chang
25*e7b1675dSTing-Kang Chang	// Placeholder for internal crypto/subtle allowlist, please ignore.
26*e7b1675dSTing-Kang Chang)
27*e7b1675dSTing-Kang Chang
28*e7b1675dSTing-Kang Changconst (
29*e7b1675dSTing-Kang Chang	minCMACKeySizeInBytes         = 16
30*e7b1675dSTing-Kang Chang	recommendedCMACKeySizeInBytes = uint32(32)
31*e7b1675dSTing-Kang Chang	minTagLengthInBytes           = uint32(10)
32*e7b1675dSTing-Kang Chang	maxTagLengthInBytes           = uint32(16)
33*e7b1675dSTing-Kang Chang)
34*e7b1675dSTing-Kang Chang
35*e7b1675dSTing-Kang Chang// AESCMAC represents an AES-CMAC struct that implements the MAC interface.
36*e7b1675dSTing-Kang Changtype AESCMAC struct {
37*e7b1675dSTing-Kang Chang	prf       *subtleprf.AESCMACPRF
38*e7b1675dSTing-Kang Chang	tagLength uint32
39*e7b1675dSTing-Kang Chang}
40*e7b1675dSTing-Kang Chang
41*e7b1675dSTing-Kang Chang// NewAESCMAC creates a new AESCMAC object that implements the MAC interface.
42*e7b1675dSTing-Kang Changfunc NewAESCMAC(key []byte, tagLength uint32) (*AESCMAC, error) {
43*e7b1675dSTing-Kang Chang	if len(key) < minCMACKeySizeInBytes {
44*e7b1675dSTing-Kang Chang		return nil, fmt.Errorf("Only 256 but keys are allowed with AES-CMAC")
45*e7b1675dSTing-Kang Chang	}
46*e7b1675dSTing-Kang Chang	if tagLength < minTagLengthInBytes {
47*e7b1675dSTing-Kang Chang		return nil, fmt.Errorf("Tag length %d is shorter than minimum tag length %d", tagLength, minTagLengthInBytes)
48*e7b1675dSTing-Kang Chang	}
49*e7b1675dSTing-Kang Chang	if tagLength > maxTagLengthInBytes {
50*e7b1675dSTing-Kang Chang		return nil, fmt.Errorf("Tag length %d is longer than maximum tag length %d", tagLength, minTagLengthInBytes)
51*e7b1675dSTing-Kang Chang	}
52*e7b1675dSTing-Kang Chang	ac := &AESCMAC{}
53*e7b1675dSTing-Kang Chang	var err error
54*e7b1675dSTing-Kang Chang	ac.prf, err = subtleprf.NewAESCMACPRF(key)
55*e7b1675dSTing-Kang Chang	if err != nil {
56*e7b1675dSTing-Kang Chang		return nil, fmt.Errorf("Could not create AES-CMAC prf: %v", err)
57*e7b1675dSTing-Kang Chang	}
58*e7b1675dSTing-Kang Chang	ac.tagLength = tagLength
59*e7b1675dSTing-Kang Chang	return ac, nil
60*e7b1675dSTing-Kang Chang}
61*e7b1675dSTing-Kang Chang
62*e7b1675dSTing-Kang Chang// ComputeMAC computes message authentication code (MAC) for code data.
63*e7b1675dSTing-Kang Changfunc (a AESCMAC) ComputeMAC(data []byte) ([]byte, error) {
64*e7b1675dSTing-Kang Chang	return a.prf.ComputePRF(data, a.tagLength)
65*e7b1675dSTing-Kang Chang}
66*e7b1675dSTing-Kang Chang
67*e7b1675dSTing-Kang Chang// VerifyMAC returns nil if mac is a correct authentication code (MAC) for data,
68*e7b1675dSTing-Kang Chang// otherwise it returns an error.
69*e7b1675dSTing-Kang Changfunc (a AESCMAC) VerifyMAC(mac, data []byte) error {
70*e7b1675dSTing-Kang Chang	computed, err := a.prf.ComputePRF(data, a.tagLength)
71*e7b1675dSTing-Kang Chang	if err != nil {
72*e7b1675dSTing-Kang Chang		return fmt.Errorf("Could not compute MAC: %v", err)
73*e7b1675dSTing-Kang Chang	}
74*e7b1675dSTing-Kang Chang	if subtle.ConstantTimeCompare(mac, computed) != 1 {
75*e7b1675dSTing-Kang Chang		return fmt.Errorf("CMAC: Invalid MAC")
76*e7b1675dSTing-Kang Chang	}
77*e7b1675dSTing-Kang Chang	return nil
78*e7b1675dSTing-Kang Chang}
79*e7b1675dSTing-Kang Chang
80*e7b1675dSTing-Kang Chang// ValidateCMACParams validates the parameters for an AES-CMAC against the recommended parameters.
81*e7b1675dSTing-Kang Changfunc ValidateCMACParams(keySize, tagSize uint32) error {
82*e7b1675dSTing-Kang Chang	if keySize != recommendedCMACKeySizeInBytes {
83*e7b1675dSTing-Kang Chang		return fmt.Errorf("Only %d sized keys are allowed with Tink's AES-CMAC", recommendedCMACKeySizeInBytes)
84*e7b1675dSTing-Kang Chang	}
85*e7b1675dSTing-Kang Chang	if tagSize < minTagLengthInBytes {
86*e7b1675dSTing-Kang Chang		return fmt.Errorf("Tag size too short")
87*e7b1675dSTing-Kang Chang	}
88*e7b1675dSTing-Kang Chang	if tagSize > maxTagLengthInBytes {
89*e7b1675dSTing-Kang Chang		return fmt.Errorf("Tag size too long")
90*e7b1675dSTing-Kang Chang	}
91*e7b1675dSTing-Kang Chang	return nil
92*e7b1675dSTing-Kang Chang}
93