forked from hardcoresushi/DroidFS
99 lines
2.5 KiB
Go
99 lines
2.5 KiB
Go
// Copyright 2012 Aaron Jacobs. All Rights Reserved.
|
|
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
|
|
//
|
|
// 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 siv
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/aes"
|
|
"fmt"
|
|
|
|
"../cmac"
|
|
"../common"
|
|
)
|
|
|
|
var s2vZero []byte
|
|
|
|
func init() {
|
|
s2vZero = bytes.Repeat([]byte{0x00}, aes.BlockSize)
|
|
}
|
|
|
|
// The output size of the s2v function.
|
|
const s2vSize = cmac.Size
|
|
|
|
// 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{})
|
|
}
|