DroidFS/app/libgocryptfs/gocryptfs_internal/jacobsa_crypto/siv/encrypt.go
2020-07-17 22:12:20 +02:00

125 lines
3.8 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 (
"crypto/aes"
"crypto/cipher"
"fmt"
)
func dup(d []byte) []byte {
result := make([]byte, len(d))
copy(result, d)
return result
}
// Given a key and plaintext, encrypt the plaintext using the SIV mode of AES,
// as defined by RFC 5297, append the result (including both the synthetic
// initialization vector and the ciphertext) to dst, and return the updated
// slice. The output can later be fed to Decrypt to recover the plaintext.
//
// In addition to confidentiality, this function also offers authenticity. That
// is, without the secret key an attacker is unable to construct a byte string
// that Decrypt will accept.
//
// The supplied key must be 32, 48, or 64 bytes long.
//
// The supplied associated data, up to 126 strings, is also authenticated,
// though it is not included in the ciphertext. The user must supply the same
// associated data to Decrypt in order for the Decrypt call to succeed. If no
// associated data is desired, pass an empty slice.
//
// If the same key, plaintext, and associated data are supplied to this
// function multiple times, the output is guaranteed to be identical. As per
// RFC 5297 section 3, you may use this function for nonce-based authenticated
// encryption by passing a nonce as the last associated data element.
func Encrypt(dst, key, plaintext []byte, associated [][]byte) ([]byte, error) {
keyLen := len(key)
associatedLen := len(associated)
// The output will consist of the current contents of dst, followed by the IV
// generated by s2v, followed by the ciphertext (which is the same size as
// the plaintext).
//
// Make sure dst is long enough, then carve it up.
var iv []byte
var ciphertext []byte
{
dstSize := len(dst)
dstAndIVSize := dstSize + s2vSize
outputSize := dstAndIVSize + len(plaintext)
if cap(dst) < outputSize {
tmp := make([]byte, dstSize, outputSize+outputSize/4)
copy(tmp, dst)
dst = tmp
}
dst = dst[:outputSize]
iv = dst[dstSize:dstAndIVSize]
ciphertext = dst[dstAndIVSize:outputSize]
}
// Make sure the key length is legal.
switch keyLen {
case 32, 48, 64:
default:
return nil, fmt.Errorf("SIV requires a 32-, 48-, or 64-byte key.")
}
// Make sure the number of associated data is legal, per RFC 5297 section 7.
if associatedLen > 126 {
return nil, fmt.Errorf("len(associated) may be no more than 126.")
}
// Derive subkeys.
k1 := key[:keyLen/2]
k2 := key[keyLen/2:]
// Call S2V to derive the synthetic initialization vector. Use the ciphertext
// output buffer as scratch space, since it's the same length as the final
// string.
s2vStrings := make([][]byte, associatedLen+1)
copy(s2vStrings, associated)
s2vStrings[associatedLen] = plaintext
v := s2v(k1, s2vStrings, ciphertext)
if len(v) != len(iv) {
panic(fmt.Sprintf("Unexpected vector: %v", v))
}
copy(iv, v)
// Create a CTR cipher using a version of v with the 31st and 63rd bits
// zeroed out.
q := dup(v)
q[aes.BlockSize-4] &= 0x7f
q[aes.BlockSize-8] &= 0x7f
ciph, err := aes.NewCipher(k2)
if err != nil {
return nil, fmt.Errorf("aes.NewCipher: %v", err)
}
ctrCiph := cipher.NewCTR(ciph, q)
// Fill in the ciphertext.
ctrCiph.XORKeyStream(ciphertext, plaintext)
return dst, nil
}