1// Copyright 2020 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14// 15//////////////////////////////////////////////////////////////////////////////// 16 17package subtle 18 19import ( 20 "crypto/aes" 21 "crypto/cipher" 22 "crypto/subtle" 23 "fmt" 24 25 // Placeholder for internal crypto/cipher allowlist, please ignore. 26 // Placeholder for internal crypto/subtle allowlist, please ignore. 27) 28 29const ( 30 mul = 0x87 31 pad = byte(0x80) 32 recommendedKeySize = uint32(32) 33) 34 35// AESCMACPRF is a type that can be used to compute several CMACs with the same key material. 36type AESCMACPRF struct { 37 bc cipher.Block 38 subkey1, subkey2 []byte 39} 40 41// NewAESCMACPRF creates a new AESCMACPRF object and initializes it with the correct key material. 42func NewAESCMACPRF(key []byte) (*AESCMACPRF, error) { 43 aesCmac := &AESCMACPRF{} 44 var err error 45 aesCmac.bc, err = aes.NewCipher(key) 46 if err != nil { 47 return nil, fmt.Errorf("Could not obtain cipher: %v", err) 48 } 49 bs := aesCmac.bc.BlockSize() 50 zeroBlock := make([]byte, bs) 51 52 // Generate Subkeys 53 aesCmac.subkey1 = make([]byte, bs) 54 aesCmac.subkey2 = make([]byte, bs) 55 aesCmac.bc.Encrypt(aesCmac.subkey1, zeroBlock) 56 mulByX(aesCmac.subkey1) 57 copy(aesCmac.subkey2, aesCmac.subkey1) 58 mulByX(aesCmac.subkey2) 59 return aesCmac, nil 60} 61 62// ValidateAESCMACPRFParams checks that the key is the recommended size for AES-CMAC. 63func ValidateAESCMACPRFParams(keySize uint32) error { 64 if keySize != recommendedKeySize { 65 return fmt.Errorf("Recommended key size for AES-CMAC is %d, but %d given", recommendedKeySize, keySize) 66 } 67 return nil 68} 69 70// ComputePRF computes the AES-CMAC for the given key and data, returning outputLength bytes. 71// The timing of this function will only depend on len(data), and not leak any additional information about the key or the data. 72func (a AESCMACPRF) ComputePRF(data []byte, outputLength uint32) ([]byte, error) { 73 // Setup 74 bs := a.bc.BlockSize() 75 if outputLength > uint32(bs) { 76 return nil, fmt.Errorf("outputLength must be between 0 and %d", bs) 77 } 78 79 // Pad 80 flag := false 81 n := len(data)/bs + 1 82 // if only depends on len(data). 83 if len(data) > 0 && len(data)%bs == 0 { 84 n-- 85 flag = true 86 } 87 mLast := make([]byte, bs) 88 mLastStart := (n - 1) * bs 89 for i := 0; i < bs; i++ { 90 // if depends on mLastStart and len(data), which depend on len(data) 91 if i+mLastStart < len(data) { 92 mLast[i] = data[i+mLastStart] 93 } else if i+mLastStart == len(data) { 94 mLast[i] = pad 95 } 96 // if only depends on flag, which depends on len(data) 97 if flag { 98 mLast[i] ^= a.subkey1[i] 99 } else { 100 mLast[i] ^= a.subkey2[i] 101 } 102 } 103 input := make([]byte, bs) 104 output := make([]byte, bs) 105 for i := 0; i < n; i++ { 106 // if depends on n, which depends on len(data) 107 if i+1 == n { 108 copy(input, mLast) 109 } else { 110 copy(input, data[i*bs:(i+1)*bs]) 111 } 112 for j := 0; j < bs; j++ { 113 input[j] ^= output[j] 114 } 115 a.bc.Encrypt(output, input) 116 } 117 return output[:outputLength], nil 118} 119 120func mulByX(block []byte) { 121 bs := len(block) 122 v := int(block[0] >> 7) 123 for i := 0; i < bs-1; i++ { 124 block[i] = block[i]<<1 | block[i+1]>>7 125 } 126 block[bs-1] = (block[bs-1] << 1) ^ byte(subtle.ConstantTimeSelect(v, mul, 0x00)) 127} 128