// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// package subtle import ( "crypto/aes" "crypto/cipher" "crypto/subtle" "fmt" // Placeholder for internal crypto/cipher allowlist, please ignore. // Placeholder for internal crypto/subtle allowlist, please ignore. ) const ( mul = 0x87 pad = byte(0x80) recommendedKeySize = uint32(32) ) // AESCMACPRF is a type that can be used to compute several CMACs with the same key material. type AESCMACPRF struct { bc cipher.Block subkey1, subkey2 []byte } // NewAESCMACPRF creates a new AESCMACPRF object and initializes it with the correct key material. func NewAESCMACPRF(key []byte) (*AESCMACPRF, error) { aesCmac := &AESCMACPRF{} var err error aesCmac.bc, err = aes.NewCipher(key) if err != nil { return nil, fmt.Errorf("Could not obtain cipher: %v", err) } bs := aesCmac.bc.BlockSize() zeroBlock := make([]byte, bs) // Generate Subkeys aesCmac.subkey1 = make([]byte, bs) aesCmac.subkey2 = make([]byte, bs) aesCmac.bc.Encrypt(aesCmac.subkey1, zeroBlock) mulByX(aesCmac.subkey1) copy(aesCmac.subkey2, aesCmac.subkey1) mulByX(aesCmac.subkey2) return aesCmac, nil } // ValidateAESCMACPRFParams checks that the key is the recommended size for AES-CMAC. func ValidateAESCMACPRFParams(keySize uint32) error { if keySize != recommendedKeySize { return fmt.Errorf("Recommended key size for AES-CMAC is %d, but %d given", recommendedKeySize, keySize) } return nil } // ComputePRF computes the AES-CMAC for the given key and data, returning outputLength bytes. // The timing of this function will only depend on len(data), and not leak any additional information about the key or the data. func (a AESCMACPRF) ComputePRF(data []byte, outputLength uint32) ([]byte, error) { // Setup bs := a.bc.BlockSize() if outputLength > uint32(bs) { return nil, fmt.Errorf("outputLength must be between 0 and %d", bs) } // Pad flag := false n := len(data)/bs + 1 // if only depends on len(data). if len(data) > 0 && len(data)%bs == 0 { n-- flag = true } mLast := make([]byte, bs) mLastStart := (n - 1) * bs for i := 0; i < bs; i++ { // if depends on mLastStart and len(data), which depend on len(data) if i+mLastStart < len(data) { mLast[i] = data[i+mLastStart] } else if i+mLastStart == len(data) { mLast[i] = pad } // if only depends on flag, which depends on len(data) if flag { mLast[i] ^= a.subkey1[i] } else { mLast[i] ^= a.subkey2[i] } } input := make([]byte, bs) output := make([]byte, bs) for i := 0; i < n; i++ { // if depends on n, which depends on len(data) if i+1 == n { copy(input, mLast) } else { copy(input, data[i*bs:(i+1)*bs]) } for j := 0; j < bs; j++ { input[j] ^= output[j] } a.bc.Encrypt(output, input) } return output[:outputLength], nil } func mulByX(block []byte) { bs := len(block) v := int(block[0] >> 7) for i := 0; i < bs-1; i++ { block[i] = block[i]<<1 | block[i+1]>>7 } block[bs-1] = (block[bs-1] << 1) ^ byte(subtle.ConstantTimeSelect(v, mul, 0x00)) }