// Given the supplied cipher, whose block size must be 16 bytes, return two // subkeys that can be used in MAC generation. See section 5.3 of NIST SP // 800-38B. Note that the other NIST-approved block size of 8 bytes is not // supported by this function. func generateSubkeys(ciph cipher.Block) (k1 []byte, k2 []byte) { if ciph.BlockSize() != blockSize { panic("generateSubkeys requires a cipher with a block size of 16 bytes.") } // Step 1 l := make([]byte, blockSize) ciph.Encrypt(l, subkeyZero) // Step 2: Derive the first subkey. if common.Msb(l) == 0 { // TODO(jacobsa): Accept a destination buffer in ShiftLeft and then hoist // the allocation in the else branch below. k1 = common.ShiftLeft(l) } else { k1 = make([]byte, blockSize) common.Xor(k1, common.ShiftLeft(l), subkeyRb) } // Step 3: Derive the second subkey. if common.Msb(k1) == 0 { k2 = common.ShiftLeft(k1) } else { k2 = make([]byte, blockSize) common.Xor(k2, common.ShiftLeft(k1), subkeyRb) } return }
func (h *cmacHash) Sum(b []byte) []byte { dataLen := len(h.data) // We should have at most one block left. if dataLen > blockSize { panic(fmt.Sprintf("Unexpected data: %x", h.data)) } // Calculate M_last. mLast := make([]byte, blockSize) if dataLen == blockSize { common.Xor(mLast, h.data, h.k1) } else { // TODO(jacobsa): Accept a destination buffer in common.PadBlock and // simplify this code. common.Xor(mLast, common.PadBlock(h.data), h.k2) } y := make([]byte, blockSize) common.Xor(y, mLast, h.x) result := make([]byte, blockSize) h.ciph.Encrypt(result, y) b = append(b, result...) return b }
// Run the S2V "string to vector" function of RFC 5297 using the input key and // string vector, which must be non-empty. (RFC 5297 defines S2V to handle the // empty vector case, but it is never used that way by higher-level functions.) // // If provided, the supplied scatch space will be used to avoid an allocation. // It should be (but is not required to be) as large as the last element of // strings. // // The result is guaranteed to be of length s2vSize. func s2v(key []byte, strings [][]byte, scratch []byte) []byte { numStrings := len(strings) if numStrings == 0 { panic("strings vector must be non-empty.") } // Create a CMAC hash. h, err := cmac.New(key) if err != nil { panic(fmt.Sprintf("cmac.New: %v", err)) } // Initialize. if _, err := h.Write(s2vZero); err != nil { panic(fmt.Sprintf("h.Write: %v", err)) } d := h.Sum([]byte{}) h.Reset() // Handle all strings but the last. for i := 0; i < numStrings-1; i++ { if _, err := h.Write(strings[i]); err != nil { panic(fmt.Sprintf("h.Write: %v", err)) } common.Xor(d, dbl(d), h.Sum([]byte{})) h.Reset() } // Handle the last string. lastString := strings[numStrings-1] var t []byte if len(lastString) >= aes.BlockSize { // Make an output buffer the length of lastString. if cap(scratch) >= len(lastString) { t = scratch[:len(lastString)] } else { t = make([]byte, len(lastString)) } // XOR d on the end of lastString. xorend(t, lastString, d) } else { t = make([]byte, aes.BlockSize) common.Xor(t, dbl(d), common.PadBlock(lastString)) } if _, err := h.Write(t); err != nil { panic(fmt.Sprintf("h.Write: %v", err)) } return h.Sum([]byte{}) }
// Given a 128-bit binary string, shift the string left by one bit and XOR the // result with 0x00...87 if the bit shifted off was one. This is the dbl // function of RFC 5297. func dbl(b []byte) []byte { if len(b) != aes.BlockSize { panic("dbl requires a 16-byte buffer.") } shiftedOne := common.Msb(b) == 1 b = common.ShiftLeft(b) if shiftedOne { tmp := make([]byte, aes.BlockSize) common.Xor(tmp, b, dblRb) b = tmp } return b }
// The xorend operator of RFC 5297. // // Given strings A and B with len(A) >= len(B), let D be len(A) - len(B). Write // A[:D] followed by xor(A[D:], B) into dst. In other words, xor B over the // rightmost end of A and write the result into dst. func xorend(dst, a, b []byte) { aLen := len(a) bLen := len(b) dstLen := len(dst) if dstLen < aLen || aLen < bLen { log.Panicf("Bad buffer lengths: %d, %d, %d", dstLen, aLen, bLen) } // Copy the left part. difference := aLen - bLen copy(dst, a[:difference]) // XOR in the right part. common.Xor(dst[difference:difference+bLen], a[difference:], b) }
func xorWithResult(a []byte, b []byte) (result []byte) { result = make([]byte, len(a)) common.Xor(result, a, b) return }