xref: /aosp_15_r20/external/tink/go/prf/subtle/aes_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/aes"
21*e7b1675dSTing-Kang Chang	"crypto/cipher"
22*e7b1675dSTing-Kang Chang	"crypto/subtle"
23*e7b1675dSTing-Kang Chang	"fmt"
24*e7b1675dSTing-Kang Chang
25*e7b1675dSTing-Kang Chang	// Placeholder for internal crypto/cipher allowlist, please ignore.
26*e7b1675dSTing-Kang Chang	// Placeholder for internal crypto/subtle allowlist, please ignore.
27*e7b1675dSTing-Kang Chang)
28*e7b1675dSTing-Kang Chang
29*e7b1675dSTing-Kang Changconst (
30*e7b1675dSTing-Kang Chang	mul                = 0x87
31*e7b1675dSTing-Kang Chang	pad                = byte(0x80)
32*e7b1675dSTing-Kang Chang	recommendedKeySize = uint32(32)
33*e7b1675dSTing-Kang Chang)
34*e7b1675dSTing-Kang Chang
35*e7b1675dSTing-Kang Chang// AESCMACPRF is a type that can be used to compute several CMACs with the same key material.
36*e7b1675dSTing-Kang Changtype AESCMACPRF struct {
37*e7b1675dSTing-Kang Chang	bc               cipher.Block
38*e7b1675dSTing-Kang Chang	subkey1, subkey2 []byte
39*e7b1675dSTing-Kang Chang}
40*e7b1675dSTing-Kang Chang
41*e7b1675dSTing-Kang Chang// NewAESCMACPRF creates a new AESCMACPRF object and initializes it with the correct key material.
42*e7b1675dSTing-Kang Changfunc NewAESCMACPRF(key []byte) (*AESCMACPRF, error) {
43*e7b1675dSTing-Kang Chang	aesCmac := &AESCMACPRF{}
44*e7b1675dSTing-Kang Chang	var err error
45*e7b1675dSTing-Kang Chang	aesCmac.bc, err = aes.NewCipher(key)
46*e7b1675dSTing-Kang Chang	if err != nil {
47*e7b1675dSTing-Kang Chang		return nil, fmt.Errorf("Could not obtain cipher: %v", err)
48*e7b1675dSTing-Kang Chang	}
49*e7b1675dSTing-Kang Chang	bs := aesCmac.bc.BlockSize()
50*e7b1675dSTing-Kang Chang	zeroBlock := make([]byte, bs)
51*e7b1675dSTing-Kang Chang
52*e7b1675dSTing-Kang Chang	// Generate Subkeys
53*e7b1675dSTing-Kang Chang	aesCmac.subkey1 = make([]byte, bs)
54*e7b1675dSTing-Kang Chang	aesCmac.subkey2 = make([]byte, bs)
55*e7b1675dSTing-Kang Chang	aesCmac.bc.Encrypt(aesCmac.subkey1, zeroBlock)
56*e7b1675dSTing-Kang Chang	mulByX(aesCmac.subkey1)
57*e7b1675dSTing-Kang Chang	copy(aesCmac.subkey2, aesCmac.subkey1)
58*e7b1675dSTing-Kang Chang	mulByX(aesCmac.subkey2)
59*e7b1675dSTing-Kang Chang	return aesCmac, nil
60*e7b1675dSTing-Kang Chang}
61*e7b1675dSTing-Kang Chang
62*e7b1675dSTing-Kang Chang// ValidateAESCMACPRFParams checks that the key is the recommended size for AES-CMAC.
63*e7b1675dSTing-Kang Changfunc ValidateAESCMACPRFParams(keySize uint32) error {
64*e7b1675dSTing-Kang Chang	if keySize != recommendedKeySize {
65*e7b1675dSTing-Kang Chang		return fmt.Errorf("Recommended key size for AES-CMAC is %d, but %d given", recommendedKeySize, keySize)
66*e7b1675dSTing-Kang Chang	}
67*e7b1675dSTing-Kang Chang	return nil
68*e7b1675dSTing-Kang Chang}
69*e7b1675dSTing-Kang Chang
70*e7b1675dSTing-Kang Chang// ComputePRF computes the AES-CMAC for the given key and data, returning outputLength bytes.
71*e7b1675dSTing-Kang Chang// The timing of this function will only depend on len(data), and not leak any additional information about the key or the data.
72*e7b1675dSTing-Kang Changfunc (a AESCMACPRF) ComputePRF(data []byte, outputLength uint32) ([]byte, error) {
73*e7b1675dSTing-Kang Chang	// Setup
74*e7b1675dSTing-Kang Chang	bs := a.bc.BlockSize()
75*e7b1675dSTing-Kang Chang	if outputLength > uint32(bs) {
76*e7b1675dSTing-Kang Chang		return nil, fmt.Errorf("outputLength must be between 0 and %d", bs)
77*e7b1675dSTing-Kang Chang	}
78*e7b1675dSTing-Kang Chang
79*e7b1675dSTing-Kang Chang	// Pad
80*e7b1675dSTing-Kang Chang	flag := false
81*e7b1675dSTing-Kang Chang	n := len(data)/bs + 1
82*e7b1675dSTing-Kang Chang	// if only depends on len(data).
83*e7b1675dSTing-Kang Chang	if len(data) > 0 && len(data)%bs == 0 {
84*e7b1675dSTing-Kang Chang		n--
85*e7b1675dSTing-Kang Chang		flag = true
86*e7b1675dSTing-Kang Chang	}
87*e7b1675dSTing-Kang Chang	mLast := make([]byte, bs)
88*e7b1675dSTing-Kang Chang	mLastStart := (n - 1) * bs
89*e7b1675dSTing-Kang Chang	for i := 0; i < bs; i++ {
90*e7b1675dSTing-Kang Chang		// if depends on mLastStart and len(data), which depend on len(data)
91*e7b1675dSTing-Kang Chang		if i+mLastStart < len(data) {
92*e7b1675dSTing-Kang Chang			mLast[i] = data[i+mLastStart]
93*e7b1675dSTing-Kang Chang		} else if i+mLastStart == len(data) {
94*e7b1675dSTing-Kang Chang			mLast[i] = pad
95*e7b1675dSTing-Kang Chang		}
96*e7b1675dSTing-Kang Chang		// if only depends on flag, which depends on len(data)
97*e7b1675dSTing-Kang Chang		if flag {
98*e7b1675dSTing-Kang Chang			mLast[i] ^= a.subkey1[i]
99*e7b1675dSTing-Kang Chang		} else {
100*e7b1675dSTing-Kang Chang			mLast[i] ^= a.subkey2[i]
101*e7b1675dSTing-Kang Chang		}
102*e7b1675dSTing-Kang Chang	}
103*e7b1675dSTing-Kang Chang	input := make([]byte, bs)
104*e7b1675dSTing-Kang Chang	output := make([]byte, bs)
105*e7b1675dSTing-Kang Chang	for i := 0; i < n; i++ {
106*e7b1675dSTing-Kang Chang		// if depends on n, which depends on len(data)
107*e7b1675dSTing-Kang Chang		if i+1 == n {
108*e7b1675dSTing-Kang Chang			copy(input, mLast)
109*e7b1675dSTing-Kang Chang		} else {
110*e7b1675dSTing-Kang Chang			copy(input, data[i*bs:(i+1)*bs])
111*e7b1675dSTing-Kang Chang		}
112*e7b1675dSTing-Kang Chang		for j := 0; j < bs; j++ {
113*e7b1675dSTing-Kang Chang			input[j] ^= output[j]
114*e7b1675dSTing-Kang Chang		}
115*e7b1675dSTing-Kang Chang		a.bc.Encrypt(output, input)
116*e7b1675dSTing-Kang Chang	}
117*e7b1675dSTing-Kang Chang	return output[:outputLength], nil
118*e7b1675dSTing-Kang Chang}
119*e7b1675dSTing-Kang Chang
120*e7b1675dSTing-Kang Changfunc mulByX(block []byte) {
121*e7b1675dSTing-Kang Chang	bs := len(block)
122*e7b1675dSTing-Kang Chang	v := int(block[0] >> 7)
123*e7b1675dSTing-Kang Chang	for i := 0; i < bs-1; i++ {
124*e7b1675dSTing-Kang Chang		block[i] = block[i]<<1 | block[i+1]>>7
125*e7b1675dSTing-Kang Chang	}
126*e7b1675dSTing-Kang Chang	block[bs-1] = (block[bs-1] << 1) ^ byte(subtle.ConstantTimeSelect(v, mul, 0x00))
127*e7b1675dSTing-Kang Chang}
128