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