73 changed files with 26 additions and 6035 deletions
@ -0,0 +1,3 @@
|
||||
[submodule "app/libgocryptfs"] |
||||
path = app/libgocryptfs |
||||
url = https://forge.chapril.org/hardcoresushi/libgocryptfs.git |
@ -1,75 +0,0 @@
|
||||
#!/bin/bash |
||||
|
||||
if [ -z ${ANDROID_NDK_HOME+x} ]; then |
||||
echo "Error: \$ANDROID_NDK_HOME is not defined." |
||||
elif [ -z ${OPENSSL_PATH+x} ]; then |
||||
echo "Error: \$OPENSSL_PATH is not defined." |
||||
else |
||||
NDK_BIN_PATH="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin" |
||||
declare -a ABIs=("x86_64" "arm64-v8a" "armeabi-v7a") |
||||
|
||||
compile_openssl(){ |
||||
if [ ! -d "./lib/$1" ]; then |
||||
if [ "$1" = "x86_64" ]; then |
||||
OPENSSL_ARCH="android-x86_64" |
||||
elif [ "$1" = "arm64-v8a" ]; then |
||||
OPENSSL_ARCH="android-arm64" |
||||
elif [ "$1" = "armeabi-v7a" ]; then |
||||
OPENSSL_ARCH="android-arm" |
||||
else |
||||
echo "Invalid ABI: $1" |
||||
exit |
||||
fi |
||||
|
||||
export CFLAGS=-D__ANDROID_API__=21 |
||||
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin:$PATH |
||||
(cd "$OPENSSL_PATH" && if [ -f "Makefile" ]; then make clean; fi && ./Configure $OPENSSL_ARCH -D__ANDROID_API__=21 no-stdio && make build_libs) |
||||
mkdir -p "./lib/$1" && cp "$OPENSSL_PATH/libcrypto.a" "$OPENSSL_PATH/libssl.a" "./lib/$1" |
||||
mkdir -p "./include/$1" && cp -r "$OPENSSL_PATH"/include/* "./include/$1/" |
||||
fi |
||||
} |
||||
|
||||
compile_for_arch(){ |
||||
compile_openssl $1 |
||||
MAIN_PACKAGE="main.go" |
||||
if [ "$1" = "x86_64" ]; then |
||||
CFN="x86_64-linux-android21-clang" |
||||
elif [ "$1" = "arm64-v8a" ]; then |
||||
CFN="aarch64-linux-android21-clang" |
||||
export GOARCH=arm64 |
||||
export GOARM=7 |
||||
elif [ "$1" = "armeabi-v7a" ]; then |
||||
CFN="armv7a-linux-androideabi21-clang" |
||||
export GOARCH=arm |
||||
export GOARM=7 |
||||
MAIN_PACKAGE="main32.go" |
||||
#patch arch specific code |
||||
sed "s/C.malloc(C.ulong/C.malloc(C.uint/g" main.go > $MAIN_PACKAGE |
||||
sed -i "s/st.Mtim.Sec/int64(st.Mtim.Sec)/g" $MAIN_PACKAGE |
||||
else |
||||
echo "Invalid ABI: $1" |
||||
exit |
||||
fi |
||||
|
||||
export CC="$NDK_BIN_PATH/$CFN" |
||||
export CXX="$NDK_BIN_PATH/$CFN++" |
||||
export CGO_ENABLED=1 |
||||
export GOOS=android |
||||
export CGO_CFLAGS="-I ${PWD}/include/$1" |
||||
export CGO_LDFLAGS="-Wl,-soname=libgocryptfs.so -L${PWD}/lib/$1" |
||||
go build -o build/$1/libgocryptfs.so -buildmode=c-shared $MAIN_PACKAGE |
||||
if [ $MAIN_PACKAGE = "main32.go" ]; then |
||||
rm $MAIN_PACKAGE |
||||
fi |
||||
} |
||||
|
||||
if [ "$#" -eq 1 ]; then |
||||
compile_for_arch $1 |
||||
else |
||||
for abi in ${ABIs[@]}; do |
||||
echo "Compiling for $abi..." |
||||
compile_for_arch $abi |
||||
done |
||||
fi |
||||
echo "Done." |
||||
fi |
@ -1,168 +0,0 @@
|
||||
// Package cryptocore wraps OpenSSL and Go GCM crypto and provides
|
||||
// a nonce generator.
|
||||
package cryptocore |
||||
|
||||
import ( |
||||
"crypto/aes" |
||||
"crypto/cipher" |
||||
"crypto/sha512" |
||||
"fmt" |
||||
"log" |
||||
"runtime" |
||||
|
||||
"../eme" |
||||
|
||||
"../siv_aead" |
||||
"../stupidgcm" |
||||
) |
||||
|
||||
const ( |
||||
// KeyLen is the cipher key length in bytes. 32 for AES-256.
|
||||
KeyLen = 32 |
||||
// AuthTagLen is the length of a GCM auth tag in bytes.
|
||||
AuthTagLen = 16 |
||||
) |
||||
|
||||
// AEADTypeEnum indicates the type of AEAD backend in use.
|
||||
type AEADTypeEnum int |
||||
|
||||
const ( |
||||
// BackendOpenSSL specifies the OpenSSL backend.
|
||||
BackendOpenSSL AEADTypeEnum = 3 |
||||
// BackendGoGCM specifies the Go based GCM backend.
|
||||
BackendGoGCM AEADTypeEnum = 4 |
||||
// BackendAESSIV specifies an AESSIV backend.
|
||||
BackendAESSIV AEADTypeEnum = 5 |
||||
) |
||||
|
||||
// CryptoCore is the low level crypto implementation.
|
||||
type CryptoCore struct { |
||||
// EME is used for filename encryption.
|
||||
EMECipher *eme.EMECipher |
||||
// GCM or AES-SIV. This is used for content encryption.
|
||||
AEADCipher cipher.AEAD |
||||
// Which backend is behind AEADCipher?
|
||||
AEADBackend AEADTypeEnum |
||||
// GCM needs unique IVs (nonces)
|
||||
IVGenerator *nonceGenerator |
||||
IVLen int |
||||
} |
||||
|
||||
// New returns a new CryptoCore object or panics.
|
||||
//
|
||||
// Even though the "GCMIV128" feature flag is now mandatory, we must still
|
||||
// support 96-bit IVs here because they were used for encrypting the master
|
||||
// key in gocryptfs.conf up to gocryptfs v1.2. v1.3 switched to 128 bits.
|
||||
//
|
||||
// Note: "key" is either the scrypt hash of the password (when decrypting
|
||||
// a config file) or the masterkey (when finally mounting the filesystem).
|
||||
func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool, forceDecode bool) *CryptoCore { |
||||
if len(key) != KeyLen { |
||||
log.Panic(fmt.Sprintf("Unsupported key length %d", len(key))) |
||||
} |
||||
// We want the IV size in bytes
|
||||
IVLen := IVBitLen / 8 |
||||
|
||||
// Initialize EME for filename encryption.
|
||||
var emeCipher *eme.EMECipher |
||||
var err error |
||||
{ |
||||
var emeBlockCipher cipher.Block |
||||
if useHKDF { |
||||
emeKey := HkdfDerive(key, HkdfInfoEMENames, KeyLen) |
||||
emeBlockCipher, err = aes.NewCipher(emeKey) |
||||
for i := range emeKey { |
||||
emeKey[i] = 0 |
||||
} |
||||
} else { |
||||
emeBlockCipher, err = aes.NewCipher(key) |
||||
} |
||||
if err != nil { |
||||
log.Panic(err) |
||||
} |
||||
emeCipher = eme.New(emeBlockCipher) |
||||
} |
||||
|
||||
// Initialize an AEAD cipher for file content encryption.
|
||||
var aeadCipher cipher.AEAD |
||||
if aeadType == BackendOpenSSL || aeadType == BackendGoGCM { |
||||
var gcmKey []byte |
||||
if useHKDF { |
||||
gcmKey = HkdfDerive(key, hkdfInfoGCMContent, KeyLen) |
||||
} else { |
||||
gcmKey = append([]byte{}, key...) |
||||
} |
||||
switch aeadType { |
||||
case BackendOpenSSL: |
||||
if IVLen != 16 { |
||||
log.Panic("stupidgcm only supports 128-bit IVs") |
||||
} |
||||
aeadCipher = stupidgcm.New(gcmKey, forceDecode) |
||||
case BackendGoGCM: |
||||
goGcmBlockCipher, err := aes.NewCipher(gcmKey) |
||||
if err != nil { |
||||
log.Panic(err) |
||||
} |
||||
aeadCipher, err = cipher.NewGCMWithNonceSize(goGcmBlockCipher, IVLen) |
||||
if err != nil { |
||||
log.Panic(err) |
||||
} |
||||
} |
||||
for i := range gcmKey { |
||||
gcmKey[i] = 0 |
||||
} |
||||
} else if aeadType == BackendAESSIV { |
||||
if IVLen != 16 { |
||||
// SIV supports any nonce size, but we only use 16.
|
||||
log.Panic("AES-SIV must use 16-byte nonces") |
||||
} |
||||
// AES-SIV uses 1/2 of the key for authentication, 1/2 for
|
||||
// encryption, so we need a 64-bytes key for AES-256. Derive it from
|
||||
// the 32-byte master key using HKDF, or, for older filesystems, with
|
||||
// SHA256.
|
||||
var key64 []byte |
||||
if useHKDF { |
||||
key64 = HkdfDerive(key, hkdfInfoSIVContent, siv_aead.KeyLen) |
||||
} else { |
||||
s := sha512.Sum512(key) |
||||
key64 = s[:] |
||||
} |
||||
aeadCipher = siv_aead.New(key64) |
||||
for i := range key64 { |
||||
key64[i] = 0 |
||||
} |
||||
} else { |
||||
log.Panic("unknown backend cipher") |
||||
} |
||||
return &CryptoCore{ |
||||
EMECipher: emeCipher, |
||||
AEADCipher: aeadCipher, |
||||
AEADBackend: aeadType, |
||||
IVGenerator: &nonceGenerator{nonceLen: IVLen}, |
||||
IVLen: IVLen, |
||||
} |
||||
} |
||||
|
||||
type wiper interface { |
||||
Wipe() |
||||
} |
||||
|
||||
// Wipe tries to wipe secret keys from memory by overwriting them with zeros
|
||||
// and/or setting references to nil.
|
||||
//
|
||||
// This is not bulletproof due to possible GC copies, but
|
||||
// still raises to bar for extracting the key.
|
||||
func (c *CryptoCore) Wipe() { |
||||
be := c.AEADBackend |
||||
if be == BackendOpenSSL || be == BackendAESSIV { |
||||
// We don't use "x, ok :=" because we *want* to crash loudly if the
|
||||
// type assertion fails.
|
||||
w := c.AEADCipher.(wiper) |
||||
w.Wipe() |
||||
} |
||||
// We have no access to the keys (or key-equivalents) stored inside the
|
||||
// Go stdlib. Best we can is to nil the references and force a GC.
|
||||
c.AEADCipher = nil |
||||
c.EMECipher = nil |
||||
runtime.GC() |
||||
} |
@ -1,29 +0,0 @@
|
||||
package cryptocore |
||||
|
||||
import ( |
||||
"crypto/sha256" |
||||
"log" |
||||
|
||||
"golang.org/x/crypto/hkdf" |
||||
) |
||||
|
||||
const ( |
||||
// "info" data that HKDF mixes into the generated key to make it unique.
|
||||
// For convenience, we use a readable string.
|
||||
HkdfInfoEMENames = "EME filename encryption" |
||||
hkdfInfoGCMContent = "AES-GCM file content encryption" |
||||
hkdfInfoSIVContent = "AES-SIV file content encryption" |
||||
) |
||||
|
||||
// hkdfDerive derives "outLen" bytes from "masterkey" and "info" using
|
||||
// HKDF-SHA256 (RFC 5869).
|
||||
// It returns the derived bytes or panics.
|
||||
func HkdfDerive(masterkey []byte, info string, outLen int) (out []byte) { |
||||
h := hkdf.New(sha256.New, masterkey, nil, []byte(info)) |
||||
out = make([]byte, outLen) |
||||
n, err := h.Read(out) |
||||
if n != outLen || err != nil { |
||||
log.Panicf("hkdfDerive: hkdf read failed, got %d bytes, error: %v", n, err) |
||||
} |
||||
return out |
||||
} |
@ -1,32 +0,0 @@
|
||||
package cryptocore |
||||
|
||||
import ( |
||||
"crypto/rand" |
||||
"encoding/binary" |
||||
"log" |
||||
) |
||||
|
||||
// RandBytes gets "n" random bytes from /dev/urandom or panics
|
||||
func RandBytes(n int) []byte { |
||||
b := make([]byte, n) |
||||
_, err := rand.Read(b) |
||||
if err != nil { |
||||
log.Panic("Failed to read random bytes: " + err.Error()) |
||||
} |
||||
return b |
||||
} |
||||
|
||||
// RandUint64 returns a secure random uint64
|
||||
func RandUint64() uint64 { |
||||
b := RandBytes(8) |
||||
return binary.BigEndian.Uint64(b) |
||||
} |
||||
|
||||
type nonceGenerator struct { |
||||
nonceLen int // bytes
|
||||
} |
||||
|
||||
// Get a random "nonceLen"-byte nonce
|
||||
func (n *nonceGenerator) Get() []byte { |
||||
return randPrefetcher.read(n.nonceLen) |
||||
} |
@ -1,55 +0,0 @@
|
||||
package cryptocore |
||||
|
||||
import ( |
||||
"bytes" |
||||
"log" |
||||
"sync" |
||||
) |
||||
|
||||
// Number of bytes to prefetch.
|
||||
// 512 looks like a good compromise between throughput and latency - see
|
||||
// randsize_test.go for numbers.
|
||||
const prefetchN = 512 |
||||
|
||||
func init() { |
||||
randPrefetcher.refill = make(chan []byte) |
||||
go randPrefetcher.refillWorker() |
||||
} |
||||
|
||||
type randPrefetcherT struct { |
||||
sync.Mutex |
||||
buf bytes.Buffer |
||||
refill chan []byte |
||||
} |
||||
|
||||
func (r *randPrefetcherT) read(want int) (out []byte) { |
||||
out = make([]byte, want) |
||||
r.Lock() |
||||
// Note: don't use defer, it slows us down!
|
||||
have, err := r.buf.Read(out) |
||||
if have == want && err == nil { |
||||
r.Unlock() |
||||
return out |
||||
} |
||||
// Buffer was empty -> re-fill
|
||||
fresh := <-r.refill |
||||
if len(fresh) != prefetchN { |
||||
log.Panicf("randPrefetcher: refill: got %d bytes instead of %d", len(fresh), prefetchN) |
||||
} |
||||
r.buf.Reset() |
||||
r.buf.Write(fresh) |
||||
have, err = r.buf.Read(out) |
||||
if have != want || err != nil { |
||||
log.Panicf("randPrefetcher could not satisfy read: have=%d want=%d err=%v", have, want, err) |
||||
} |
||||
r.Unlock() |
||||
return out |
||||
} |
||||
|
||||
func (r *randPrefetcherT) refillWorker() { |
||||
for { |
||||
r.refill <- RandBytes(prefetchN) |
||||
} |
||||
} |
||||
|
||||
var randPrefetcher randPrefetcherT |
@ -1,11 +0,0 @@
|
||||
language: go |
||||
|
||||
go: |
||||
- 1.11.x # Debian 10 "Buster" |
||||
- 1.12.x # Ubuntu 19.10 |
||||
- 1.13.x # Debian 11 "Bullseye" |
||||
- stable |
||||
|
||||
script: |
||||
- go build |
||||
- ./test.bash |
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT) |
||||
|
||||
Copyright (c) 2015 Jakob Unterwurzacher |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
@ -1,111 +0,0 @@
|
||||
EME for Go [](https://travis-ci.org/rfjakob/eme) [](https://godoc.org/github.com/rfjakob/eme)  |
||||
========== |
||||
|
||||
**EME** (ECB-Mix-ECB or, clearer, **Encrypt-Mix-Encrypt**) is a wide-block |
||||
encryption mode developed by Halevi |
||||
and Rogaway in 2003 [[eme]](#eme). |
||||
|
||||
EME uses multiple invocations of a block cipher to construct a new |
||||
cipher of bigger block size (in multiples of 16 bytes, up to 2048 bytes). |
||||
|
||||
Quoting from the original [[eme]](#eme) paper: |
||||
|
||||
> We describe a block-cipher mode of operation, EME, that turns an n-bit block cipher into |
||||
> a tweakable enciphering scheme that acts on strings of mn bits, where m โ [1..n]. The mode is |
||||
> parallelizable, but as serial-efficient as the non-parallelizable mode CMC [6]. EME can be used |
||||
> to solve the disk-sector encryption problem. The algorithm entails two layers of ECB encryption |
||||
> and a โlightweight mixingโ in between. We prove EME secure, in the reduction-based sense of |
||||
> modern cryptography. |
||||
|
||||
Figure 2 from the [[eme]](#eme) paper shows an overview of the transformation: |
||||
|
||||
[![Figure 2 from [eme]](paper-eme-fig2.png)](#) |
||||
|
||||
This is an implementation of EME in Go, complete with test vectors from IEEE [[p1619-2]](#p1619-2) |
||||
and Halevi [[eme-32-testvec]](#eme-32-testvec). |
||||
|
||||
It has no dependencies outside the standard library. |
||||
|
||||
Is it patentend? |
||||
---------------- |
||||
|
||||
In 2007, the UC Davis has decided to abandon [[patabandon]](#patabandon) |
||||
the patent application [[patappl]](#patappl) for EME. |
||||
|
||||
Related algorithms |
||||
------------------ |
||||
|
||||
**EME-32** is EME with the cipher set to AES and the length set to 512. |
||||
That is, EME-32 [[eme-32-pdf]](#eme-32-pdf) is a subset of EME. |
||||
|
||||
**EME2**, also known as EME\* [[emestar]](#emestar), is an extended version of EME |
||||
that has built-in handling for data that is not a multiple of 16 bytes |
||||
long. |
||||
EME2 has been selected for standardization in IEEE P1619.2 [[p1619.2]](#p1619.2). |
||||
|
||||
References |
||||
---------- |
||||
|
||||
#### [eme] |
||||
*A Parallelizable Enciphering Mode* |
||||
Shai Halevi, Phillip Rogaway, 28 Jul 2003 |
||||
https://eprint.iacr.org/2003/147.pdf |
||||
|
||||
Note: This is the original EME paper. EME is specified for an arbitrary |
||||
number of block-cipher blocks. EME-32 is a concrete implementation of |
||||
EME with a fixed length of 32 AES blocks. |
||||
|
||||
#### [eme-32-email] |
||||
*Re: EME-32-AES with editorial comments* |
||||
Shai Halevi, 07 Jun 2005 |
||||
http://grouper.ieee.org/groups/1619/email/msg00310.html |
||||
|
||||
#### [eme-32-pdf] |
||||
*Draft Standard for Tweakable Wide-block Encryption* |
||||
Shai Halevi, 02 June 2005 |
||||
http://grouper.ieee.org/groups/1619/email/pdf00020.pdf |
||||
|
||||
Note: This is the latest version of the EME-32 draft that I could find. It |
||||
includes test vectors and C source code. |
||||
|
||||
#### [eme-32-testvec] |
||||
*Re: Test vectors for LRW and EME* |
||||
Shai Halevi, 16 Nov 2004 |
||||
http://grouper.ieee.org/groups/1619/email/msg00218.html |
||||
|
||||
#### [emestar] |
||||
*EME\*: extending EME to handle arbitrary-length messages with associated data* |
||||
Shai Halevi, 27 May 2004 |
||||
https://eprint.iacr.org/2004/125.pdf |
||||
|
||||
#### [patabandon] |
||||
*Re: [P1619-2] Non-awareness patent statement made by UC Davis* |
||||
Mat Ball, 26 Nov 2007 |
||||
http://grouper.ieee.org/groups/1619/email-2/msg00005.html |
||||
|
||||
#### [patappl] |
||||
*Block cipher mode of operation for constructing a wide-blocksize block cipher from a conventional block cipher* |
||||
US patent application US20040131182 |
||||
http://www.google.com/patents/US20040131182 |
||||
|
||||
#### [p1619-2] |
||||
*IEEE P1619.2โข/D9 Draft Standard for Wide-Block Encryption for Shared Storage Media* |
||||
IEEE, Dec 2008 |
||||
http://siswg.net/index2.php?option=com_docman&task=doc_view&gid=156&Itemid=41 |
||||
|
||||
Note: This is a draft version. The final version is not freely available |
||||
and must be bought from IEEE. |
||||
|
||||
Package Changelog |
||||
----------------- |
||||
|
||||
v1.1.1, 2020-04-13 |
||||
* Update `go vet` call in `test.bash` to work on recent Go versions |
||||
* No code changes |
||||
|
||||
v1.1, 2017-03-05 |
||||
* Add eme.New() / \*EMECipher convenience wrapper |
||||
* Improve panic message and parameter wording |
||||
|
||||
v1.0, 2015-12-08 |
||||
* Stable release |
@ -1,3 +0,0 @@
|
||||
#!/bin/bash -eu |
||||
|
||||
go test -bench=. |
@ -1,206 +0,0 @@
|
||||
// EME (ECB-Mix-ECB or, clearer, Encrypt-Mix-Encrypt) is a wide-block
|
||||
// encryption mode developed by Halevi and Rogaway.
|
||||
//
|
||||
// It was presented in the 2003 paper "A Parallelizable Enciphering Mode" by
|
||||
// Halevi and Rogaway.
|
||||
//
|
||||
// EME uses multiple invocations of a block cipher to construct a new cipher
|
||||
// of bigger block size (in multiples of 16 bytes, up to 2048 bytes).
|
||||
package eme |
||||
|
||||
import ( |
||||
"crypto/cipher" |
||||
"log" |
||||
) |
||||
|
||||
type directionConst bool |
||||
|
||||
const ( |
||||
// Encrypt "inputData"
|
||||
DirectionEncrypt = directionConst(true) |
||||
// Decrypt "inputData"
|
||||
DirectionDecrypt = directionConst(false) |
||||
) |
||||
|
||||
// multByTwo - GF multiplication as specified in the EME-32 draft
|
||||
func multByTwo(out []byte, in []byte) { |
||||
if len(in) != 16 { |
||||
panic("len must be 16") |
||||
} |
||||
tmp := make([]byte, 16) |
||||
|
||||
tmp[0] = 2 * in[0] |
||||
if in[15] >= 128 { |
||||
tmp[0] = tmp[0] ^ 135 |
||||
} |
||||
for j := 1; j < 16; j++ { |
||||
tmp[j] = 2 * in[j] |
||||
if in[j-1] >= 128 { |
||||
tmp[j] += 1 |
||||
} |
||||
} |
||||
copy(out, tmp) |
||||
} |
||||
|
||||
func xorBlocks(out []byte, in1 []byte, in2 []byte) { |
||||
if len(in1) != len(in2) { |
||||
log.Panicf("len(in1)=%d is not equal to len(in2)=%d", len(in1), len(in2)) |
||||
} |
||||
|
||||
for i := range in1 { |
||||
out[i] = in1[i] ^ in2[i] |
||||
} |
||||
} |
||||
|
||||
// aesTransform - encrypt or decrypt (according to "direction") using block
|
||||
// cipher "bc" (typically AES)
|
||||
func aesTransform(dst []byte, src []byte, direction directionConst, bc cipher.Block) { |
||||
if direction == DirectionEncrypt { |
||||
bc.Encrypt(dst, src) |
||||
return |
||||
} else if direction == DirectionDecrypt { |
||||
bc.Decrypt(dst, src) |
||||
return |
||||
} |
||||
} |
||||
|
||||
// tabulateL - calculate L_i for messages up to a length of m cipher blocks
|
||||
func tabulateL(bc cipher.Block, m int) [][]byte { |
||||
/* set L0 = 2*AESenc(K; 0) */ |
||||
eZero := make([]byte, 16) |
||||
Li := make([]byte, 16) |
||||
bc.Encrypt(Li, eZero) |
||||
|
||||
LTable := make([][]byte, m) |
||||
// Allocate pool once and slice into m pieces in the loop
|
||||
pool := make([]byte, m*16) |
||||
for i := 0; i < m; i++ { |
||||
multByTwo(Li, Li) |
||||
LTable[i] = pool[i*16 : (i+1)*16] |
||||
copy(LTable[i], Li) |
||||
} |
||||
return LTable |
||||
} |
||||
|
||||
// Transform - EME-encrypt or EME-decrypt, according to "direction"
|
||||
// (defined in the constants DirectionEncrypt and DirectionDecrypt).
|
||||
// The data in "inputData" is en- or decrypted with the block ciper "bc" under
|
||||
// "tweak" (also known as IV).
|
||||
//
|
||||
// The tweak is used to randomize the encryption in the same way as an
|
||||
// IV. A use of this encryption mode envisioned by the authors of the
|
||||
// algorithm was to encrypt each sector of a disk, with the tweak
|
||||
// being the sector number. If you encipher the same data with the
|
||||
// same tweak you will get the same ciphertext.
|
||||
//
|
||||
// The result is returned in a freshly allocated slice of the same
|
||||
// size as inputData.
|
||||
//
|
||||
// Limitations:
|
||||
// * The block cipher must have block size 16 (usually AES).
|
||||
// * The size of "tweak" must be 16
|
||||
// * "inputData" must be a multiple of 16 bytes long
|
||||
// If any of these pre-conditions are not met, the function will panic.
|
||||
//
|
||||
// Note that you probably don't want to call this function directly and instead
|
||||
// use eme.New(), which provides conventient wrappers.
|
||||
func Transform(bc cipher.Block, tweak []byte, inputData []byte, direction directionConst) []byte { |
||||
// In the paper, the tweak is just called "T". Call it the same here to
|
||||
// make following the paper easy.
|
||||
T := tweak |
||||
// In the paper, the plaintext data is called "P" and the ciphertext is
|
||||
// called "C". Because encryption and decryption are virtually identical,
|
||||
// we share the code and always call the input data "P" and the output data
|
||||
// "C", regardless of the direction.
|
||||
P := inputData |
||||
|
||||
if bc.BlockSize() != 16 { |
||||
log.Panicf("Using a block size other than 16 is not implemented") |
||||
} |
||||
if len(T) != 16 { |
||||
log.Panicf("Tweak must be 16 bytes long, is %d", len(T)) |
||||
} |
||||
if len(P)%16 != 0 { |
||||
log.Panicf("Data P must be a multiple of 16 long, is %d", len(P)) |
||||
} |
||||
m := len(P) / 16 |
||||
if m == 0 || m > 16*8 { |
||||
log.Panicf("EME operates on 1 to %d block-cipher blocks, you passed %d", 16*8, m) |
||||
} |
||||
|
||||
C := make([]byte, len(P)) |
||||
|
||||
LTable := tabulateL(bc, m) |
||||
|
||||
PPj := make([]byte, 16) |
||||
for j := 0; j < m; j++ { |
||||
Pj := P[j*16 : (j+1)*16] |
||||
/* PPj = 2**(j-1)*L xor Pj */ |
||||
xorBlocks(PPj, Pj, LTable[j]) |
||||
/* PPPj = AESenc(K; PPj) */ |
||||
aesTransform(C[j*16:(j+1)*16], PPj, direction, bc) |
||||
} |
||||
|
||||
/* MP =(xorSum PPPj) xor T */ |
||||
MP := make([]byte, 16) |
||||
xorBlocks(MP, C[0:16], T) |
||||
for j := 1; j < m; j++ { |
||||
xorBlocks(MP, MP, C[j*16:(j+1)*16]) |
||||
} |
||||
|
||||
/* MC = AESenc(K; MP) */ |
||||
MC := make([]byte, 16) |
||||
aesTransform(MC, MP, direction, bc) |
||||
|
||||
/* M = MP xor MC */ |
||||
M := make([]byte, 16) |
||||
xorBlocks(M, MP, MC) |
||||
CCCj := make([]byte, 16) |
||||
for j := 1; j < m; j++ { |
||||
multByTwo(M, M) |
||||
/* CCCj = 2**(j-1)*M xor PPPj */ |
||||
xorBlocks(CCCj, C[j*16:(j+1)*16], M) |
||||
copy(C[j*16:(j+1)*16], CCCj) |
||||
} |
||||
|
||||
/* CCC1 = (xorSum CCCj) xor T xor MC */ |
||||
CCC1 := make([]byte, 16) |
||||
xorBlocks(CCC1, MC, T) |
||||
for j := 1; j < m; j++ { |
||||
xorBlocks(CCC1, CCC1, C[j*16:(j+1)*16]) |
||||
} |
||||
copy(C[0:16], CCC1) |
||||
|
||||
for j := 0; j < m; j++ { |
||||
/* CCj = AES-enc(K; CCCj) */ |
||||
aesTransform(C[j*16:(j+1)*16], C[j*16:(j+1)*16], direction, bc) |
||||
/* Cj = 2**(j-1)*L xor CCj */ |
||||
xorBlocks(C[j*16:(j+1)*16], C[j*16:(j+1)*16], LTable[j]) |
||||
} |
||||
|
||||
return C |
||||
} |
||||
|
||||
// EMECipher provides EME-Encryption and -Decryption functions that are more
|
||||
// convenient than calling Transform directly.
|
||||
type EMECipher struct { |
||||
bc cipher.Block |
||||
} |
||||
|
||||
// New returns a new EMECipher object. "bc" must have a block size of 16,
|
||||
// or subsequent calls to Encrypt and Decrypt will panic.
|
||||
func New(bc cipher.Block) *EMECipher { |
||||
return &EMECipher{ |
||||
bc: bc, |
||||
} |
||||
} |
||||
|
||||
// Encrypt is equivalent to calling Transform with direction=DirectionEncrypt.
|
||||
func (e *EMECipher) Encrypt(tweak []byte, inputData []byte) []byte { |
||||
return Transform(e.bc, tweak, inputData, DirectionEncrypt) |
||||
} |
||||
|
||||
// Decrypt is equivalent to calling Transform with direction=DirectionDecrypt.
|
||||
func (e *EMECipher) Decrypt(tweak []byte, inputData []byte) []byte { |
||||
return Transform(e.bc, tweak, inputData, DirectionDecrypt) |
||||
} |
Before Width: | Height: | Size: 9.4 KiB |
@ -1,97 +0,0 @@
|
||||
// Package exitcodes contains all well-defined exit codes that gocryptfs
|
||||
// can return.
|
||||
package exitcodes |
||||
|
||||
import ( |
||||
"fmt" |
||||
"os" |
||||
) |
||||
|
||||
const ( |
||||
// Usage - usage error like wrong cli syntax, wrong number of parameters.
|
||||
Usage = 1 |
||||
// 2 is reserved because it is used by Go panic
|
||||
// 3 is reserved because it was used by earlier gocryptfs version as a generic
|
||||
// "mount" error.
|
||||
|
||||
// CipherDir means that the CIPHERDIR does not exist, is not empty, or is not
|
||||
// a directory.
|
||||
CipherDir = 6 |
||||
// Init is an error on filesystem init
|
||||
Init = 7 |
||||
// LoadConf is an error while loading gocryptfs.conf
|
||||
LoadConf = 8 |
||||
// ReadPassword means something went wrong reading the password
|
||||
ReadPassword = 9 |
||||
// MountPoint error means that the mountpoint is invalid (not empty etc).
|
||||
MountPoint = 10 |
||||
// Other error - please inspect the message
|
||||
Other = 11 |
||||
// PasswordIncorrect - the password was incorrect when mounting or when
|
||||
// changing the password.
|
||||
PasswordIncorrect = 12 |
||||
// ScryptParams means that scrypt was called with invalid parameters
|
||||
ScryptParams = 13 |
||||
// MasterKey means that something went wrong when parsing the "-masterkey"
|
||||
// command line option
|
||||
MasterKey = 14 |
||||
// SigInt means we got SIGINT
|
||||
SigInt = 15 |
||||
// PanicLogNotEmpty means the panic log was not empty when we were unmounted
|
||||
PanicLogNotEmpty = 16 |
||||
// ForkChild means forking the worker child failed
|
||||
ForkChild = 17 |
||||
// OpenSSL means you tried to enable OpenSSL, but we were compiled without it.
|
||||
OpenSSL = 18 |
||||
// FuseNewServer - this exit code means that the call to fuse.NewServer failed.
|
||||
// This usually means that there was a problem executing fusermount, or
|
||||
// fusermount could not attach the mountpoint to the kernel.
|
||||
FuseNewServer = 19 |
||||
// CtlSock - the control socket file could not be created.
|
||||
CtlSock = 20 |
||||
// Downgraded to a warning in gocryptfs v1.4
|
||||
//PanicLogCreate = 21
|
||||
|
||||
// PasswordEmpty - we received an empty password
|
||||
PasswordEmpty = 22 |
||||
// OpenConf - the was an error opening the gocryptfs.conf file for reading
|
||||
OpenConf = 23 |
||||
// WriteConf - could not write the gocryptfs.conf
|
||||
WriteConf = 24 |
||||
// Profiler - error occurred when trying to write cpu or memory profile or
|
||||
// execution trace
|
||||
Profiler = 25 |
||||
// FsckErrors - the filesystem check found errors
|
||||
FsckErrors = 26 |
||||
// DeprecatedFS - this filesystem is deprecated
|
||||
DeprecatedFS = 27 |
||||
// skip 28
|
||||
// ExcludeError - an error occurred while processing "-exclude"
|
||||
ExcludeError = 29 |
||||
// DevNull means that /dev/null could not be opened
|
||||
DevNull = 30 |
||||
) |
||||
|
||||
// Err wraps an error with an associated numeric exit code
|
||||
type Err struct { |
||||
error |
||||
code int |
||||
} |
||||
|
||||
// NewErr returns an error containing "msg" and the exit code "code".
|
||||
func NewErr(msg string, code int) Err { |
||||
return Err{ |
||||
error: fmt.Errorf(msg), |
||||
code: code, |
||||
} |
||||
} |
||||
|
||||
// Exit extracts the numeric exit code from "err" (if available) and exits the
|
||||
// application.
|
||||
func Exit(err error) { |
||||
err2, ok := err.(Err) |
||||
if !ok { |
||||
os.Exit(Other) |
||||
} |
||||
os.Exit(err2.code) |
||||
} |
@ -1,22 +0,0 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects) |
||||
*.o |
||||
*.a |
||||
*.so |
||||
|
||||
# Folders |
||||
_obj |
||||
_test |
||||
|
||||
# Architecture specific extensions/prefixes |
||||
*.[568vq] |
||||
[568vq].out |
||||
|
||||
*.cgo1.go |
||||
*.cgo2.c |
||||
_cgo_defun.c |
||||
_cgo_gotypes.go |
||||
_cgo_export.* |
||||
|
||||
_testmain.go |
||||
|
||||
*.exe |
@ -1,4 +0,0 @@
|
||||
# Cf. http://docs.travis-ci.com/user/getting-started/ |
||||
# Cf. http://docs.travis-ci.com/user/languages/go/ |
||||
|
||||
language: go |
@ -1,202 +0,0 @@
|
||||
|
||||
Apache License |
||||
Version 2.0, January 2004 |
||||
http://www.apache.org/licenses/ |
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
||||
|
||||
1. Definitions. |
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, |
||||
and distribution as defined by Sections 1 through 9 of this document. |
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by |
||||
the copyright owner that is granting the License. |
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all |
||||
other entities that control, are controlled by, or are under common |
||||
control with that entity. For the purposes of this definition, |
||||
"control" means (i) the power, direct or indirect, to cause the |
||||
direction or management of such entity, whether by contract or |
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
||||
outstanding shares, or (iii) beneficial ownership of such entity. |
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity |
||||
exercising permissions granted by this License. |
||||
|
||||
"Source" form shall mean the preferred form for making modifications, |
||||
including but not limited to software source code, documentation |
||||
source, and configuration files. |
||||
|
||||
"Object" form shall mean any form resulting from mechanical |
||||
transformation or translation of a Source form, including but |
||||
not limited to compiled object code, generated documentation, |
||||
and conversions to other media types. |
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or |
||||
Object form, made available under the License, as indicated by a |
||||
copyright notice that is included in or attached to the work |
||||
(an example is provided in the Appendix below). |
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object |
||||
form, that is based on (or derived from) the Work and for which the |
||||
editorial revisions, annotations, elaborations, or other modifications |
||||
represent, as a whole, an original work of authorship. For the purposes |
||||
of this License, Derivative Works shall not include works that remain |
||||
separable from, or merely link (or bind by name) to the interfaces of, |
||||
the Work and Derivative Works thereof. |
||||
|
||||
"Contribution" shall mean any work of authorship, including |
||||
the original version of the Work and any modifications or additions |
||||
to that Work or Derivative Works thereof, that is intentionally |
||||
submitted to Licensor for inclusion in the Work by the copyright owner |
||||
or by an individual or Legal Entity authorized to submit on behalf of |
||||
the copyright owner. For the purposes of this definition, "submitted" |
||||
means any form of electronic, verbal, or written communication sent |
||||
to the Licensor or its representatives, including but not limited to |
||||
communication on electronic mailing lists, source code control systems, |
||||
and issue tracking systems that are managed by, or on behalf of, the |
||||
Licensor for the purpose of discussing and improving the Work, but |
||||
excluding communication that is conspicuously marked or otherwise |
||||
designated in writing by the copyright owner as "Not a Contribution." |
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity |
||||
on behalf of whom a Contribution has been received by Licensor and |
||||
subsequently incorporated within the Work. |
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of |
||||
this License, each Contributor hereby grants to You a perpetual, |
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||
copyright license to reproduce, prepare Derivative Works of, |
||||
publicly display, publicly perform, sublicense, and distribute the |
||||
Work and such Derivative Works in Source or Object form. |
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of |
||||
this License, each Contributor hereby grants to You a perpetual, |
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||
(except as stated in this section) patent license to make, have made, |
||||
use, offer to sell, sell, import, and otherwise transfer the Work, |
||||
where such license applies only to those patent claims licensable |
||||
by such Contributor that are necessarily infringed by their |
||||
Contribution(s) alone or by combination of their Contribution(s) |
||||
with the Work to which such Contribution(s) was submitted. If You |
||||
institute patent litigation against any entity (including a |
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work |
||||
or a Contribution incorporated within the Work constitutes direct |
||||
or contributory patent infringement, then any patent licenses |
||||
granted to You under this License for that Work shall terminate |
||||
as of the date such litigation is filed. |
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the |
||||
Work or Derivative Works thereof in any medium, with or without |
||||
modifications, and in Source or Object form, provided that You |
||||
meet the following conditions: |
||||
|
||||
(a) You must give any other recipients of the Work or |
||||
Derivative Works a copy of this License; and |
||||
|
||||
(b) You must cause any modified files to carry prominent notices |
||||
stating that You changed the files; and |
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works |
||||
that You distribute, all copyright, patent, trademark, and |
||||
attribution notices from the Source form of the Work, |
||||
excluding those notices that do not pertain to any part of |
||||
the Derivative Works; and |
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its |
||||
distribution, then any Derivative Works that You distribute must |
||||
include a readable copy of the attribution notices contained |
||||
within such NOTICE file, excluding those notices that do not |
||||
pertain to any part of the Derivative Works, in at least one |
||||
of the following places: within a NOTICE text file distributed |
||||
as part of the Derivative Works; within the Source form or |
||||
documentation, if provided along with the Derivative Works; or, |
||||
within a display generated by the Derivative Works, if and |
||||
wherever such third-party notices normally appear. The contents |
||||
of the NOTICE file are for informational purposes only and |
||||
do not modify the License. You may add Your own attribution |
||||
notices within Derivative Works that You distribute, alongside |
||||
or as an addendum to the NOTICE text from the Work, provided |
||||
that such additional attribution notices cannot be construed |
||||
as modifying the License. |
||||
|
||||
You may add Your own copyright statement to Your modifications and |
||||
may provide additional or different license terms and conditions |
||||
for use, reproduction, or distribution of Your modifications, or |
||||
for any such Derivative Works as a whole, provided Your use, |
||||
reproduction, and distribution of the Work otherwise complies with |
||||
the conditions stated in this License. |
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, |
||||
any Contribution intentionally submitted for inclusion in the Work |
||||
by You to the Licensor shall be under the terms and conditions of |
||||
this License, without any additional terms or conditions. |
||||
Notwithstanding the above, nothing herein shall supersede or modify |
||||
the terms of any separate license agreement you may have executed |
||||
with Licensor regarding such Contributions. |
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade |
||||
names, trademarks, service marks, or product names of the Licensor, |
||||
except as required for reasonable and customary use in describing the |
||||
origin of the Work and reproducing the content of the NOTICE file. |
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or |
||||
agreed to in writing, Licensor provides the Work (and each |
||||
Contributor provides its Contributions) on an "AS IS" BASIS, |
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
||||
implied, including, without limitation, any warranties or conditions |
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
||||
PARTICULAR PURPOSE. You are solely responsible for determining the |
||||
appropriateness of using or redistributing the Work and assume any |
||||
risks associated with Your exercise of permissions under this License. |
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, |
||||
whether in tort (including negligence), contract, or otherwise, |
||||
unless required by applicable law (such as deliberate and grossly |
||||
negligent acts) or agreed to in writing, shall any Contributor be |
||||
liable to You for damages, including any direct, indirect, special, |
||||
incidental, or consequential damages of any character arising as a |
||||
result of this License or out of the use or inability to use the |
||||
Work (including but not limited to damages for loss of goodwill, |
||||
work stoppage, computer failure or malfunction, or any and all |
||||
other commercial damages or losses), even if such Contributor |
||||
has been advised of the possibility of such damages. |
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing |
||||
the Work or Derivative Works thereof, You may choose to offer, |
||||
and charge a fee for, acceptance of support, warranty, indemnity, |
||||
or other liability obligations and/or rights consistent with this |
||||
License. However, in accepting such obligations, You may act only |
||||
on Your own behalf and on Your sole responsibility, not on behalf |
||||
of any other Contributor, and only if You agree to indemnify, |
||||
defend, and hold each Contributor harmless for any liability |
||||
incurred by, or claims asserted against, such Contributor by reason |
||||
of your accepting any such warranty or additional liability. |
||||
|
||||
END OF TERMS AND CONDITIONS |
||||
|
||||
APPENDIX: How to apply the Apache License to your work. |
||||
|
||||
To apply the Apache License to your work, attach the following |
||||
boilerplate notice, with the fields enclosed by brackets "[]" |
||||
replaced with your own identifying information. (Don't include |
||||
the brackets!) The text should be enclosed in the appropriate |
||||
comment syntax for the file format. We also recommend that a |
||||
file or class name and description of purpose be included on the |
||||
same "printed page" as the copyright notice for easier |
||||
identification within third-party archives. |
||||
|
||||
Copyright [yyyy] [name of copyright owner] |
||||
|
||||
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. |
@ -1,10 +0,0 @@
|
||||
This repository contains Go packages related to cryptographic standards that are |
||||
not included in the Go standard library. These include: |
||||
|
||||
* [SIV mode][siv], which provides deterministic encryption with |
||||
authentication. |
||||
|
||||
* [CMAC][cmac], a message authentication system used by SIV mode. |
||||
|
||||
[siv]: https://godoc.org/github.com/jacobsa/crypto/siv |
||||
[cmac]: https://godoc.org/github.com/jacobsa/crypto/cmac |
@ -1,23 +0,0 @@
|
||||
// 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 cmac |
||||
|
||||
import "crypto/aes" |
||||
|
||||
// The size of an AES-CMAC checksum, in bytes.
|
||||
const Size = aes.BlockSize |
||||
|
||||
const blockSize = Size |
@ -1,19 +0,0 @@
|
||||
// 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 cmac implements the CMAC mode for message authentication, as defined
|
||||
// by NIST Special Publication 800-38B. When a 16-byte key is used, this
|
||||
// matches the AES-CMAC algorithm defined by RFC 4493.
|
||||
package cmac |
@ -1,170 +0,0 @@
|
||||
// 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 cmac |
||||
|
||||
import ( |
||||
"crypto/aes" |
||||
"crypto/cipher" |
||||
"fmt" |
||||
"hash" |
||||
"unsafe" |
||||
|
||||
"../common" |
||||
) |
||||
|
||||
type cmacHash struct { |
||||
// An AES cipher configured with the original key.
|
||||
ciph cipher.Block |
||||
|
||||
// Generated sub-keys.
|
||||
k1 []byte |
||||
k2 []byte |
||||
|
||||
// Data that has been seen by Write but not yet incorporated into x, due to
|
||||
// us not being sure if it is the final block or not.
|
||||
//
|
||||
// INVARIANT: len(data) <= blockSize
|
||||
data []byte |
||||
|
||||
// The current value of X, as defined in the AES-CMAC algorithm in RFC 4493.
|
||||
// Initially this is a 128-bit zero, and it is updated with the current block
|
||||
// when we're sure it's not the last one.
|
||||
x []byte |
||||
} |
||||
|
||||
func (h *cmacHash) Write(p []byte) (n int, err error) { |
||||
n = len(p) |
||||
|
||||
// First step: consume enough data to expand h.data to a full block, if
|
||||
// possible.
|
||||
{ |
||||
toConsume := blockSize - len(h.data) |
||||
if toConsume > len(p) { |
||||
toConsume = len(p) |
||||
} |
||||
|
||||
h.data = append(h.data, p[:toConsume]...) |
||||
p = p[toConsume:] |
||||
} |
||||
|
||||
// If there's no data left in p, it means h.data might not be a full block.
|
||||
// Even if it is, we're not sure it's the final block, which we must treat
|
||||
// specially. So we must stop here.
|
||||
if len(p) == 0 { |
||||
return |
||||
} |
||||
|
||||
// h.data is a full block and is not the last; process it.
|
||||
h.writeBlocks(h.data) |
||||
h.data = h.data[:0] |
||||
|
||||
// Consume any further full blocks in p that we're sure aren't the last. Note
|
||||
// that we're sure that len(p) is greater than zero here.
|
||||
blocksToProcess := (len(p) - 1) / blockSize |
||||
bytesToProcess := blocksToProcess * blockSize |
||||
|
||||
h.writeBlocks(p[:bytesToProcess]) |
||||
p = p[bytesToProcess:] |
||||
|
||||
// Store the rest for later.
|
||||
h.data = append(h.data, p...) |
||||
|
||||
return |
||||
} |
||||
|
||||
// Process block-aligned data that we're sure does not contain the final block.
|
||||
//
|
||||
// REQUIRES: len(p) % blockSize == 0
|
||||
func (h *cmacHash) writeBlocks(p []byte) { |
||||
y := make([]byte, blockSize) |
||||
|
||||
for off := 0; off < len(p); off += blockSize { |
||||
block := p[off : off+blockSize] |
||||
|
||||
xorBlock( |
||||
unsafe.Pointer(&y[0]), |
||||
unsafe.Pointer(&h.x[0]), |
||||
unsafe.Pointer(&block[0])) |
||||
|
||||
h.ciph.Encrypt(h.x, y) |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
func (h *cmacHash) Reset() { |
||||
h.data = h.data[:0] |
||||
h.x = make([]byte, blockSize) |
||||
} |
||||
|
||||
func (h *cmacHash) Size() int { |
||||
return h.ciph.BlockSize() |
||||
} |
||||
|
||||
func (h *cmacHash) BlockSize() int { |
||||
return h.ciph.BlockSize() |
||||
} |
||||
|
||||
// New returns an AES-CMAC hash using the supplied key. The key must be 16, 24,
|
||||
// or 32 bytes long.
|
||||
func New(key []byte) (hash.Hash, error) { |
||||
switch len(key) { |
||||
case 16, 24, 32: |
||||
default: |
||||
return nil, fmt.Errorf("AES-CMAC requires a 16-, 24-, or 32-byte key.") |
||||
} |
||||
|
||||
// Create a cipher.
|
||||
ciph, err := aes.NewCipher(key) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("aes.NewCipher: %v", err) |
||||
} |
||||
|
||||
// Set up the hash object.
|
||||
h := &cmacHash{ciph: ciph} |
||||
h.k1, h.k2 = generateSubkeys(ciph) |
||||
h.Reset() |
||||
|
||||
return h, nil |
||||
} |
@ -1,47 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// +build 386 arm,!arm64 mips mipsle
|
||||
|
||||
package cmac |
||||
|
||||
import ( |
||||
"log" |
||||
"unsafe" |
||||
) |
||||
|
||||
// XOR the blockSize bytes starting at a and b, writing the result over dst.
|
||||
func xorBlock( |
||||
dstPtr unsafe.Pointer, |
||||
aPtr unsafe.Pointer, |
||||
bPtr unsafe.Pointer) { |
||||
// Check assumptions. (These are compile-time constants, so this should
|
||||
// compile out.)
|
||||
const wordSize = unsafe.Sizeof(uintptr(0)) |
||||
if blockSize != 4*wordSize { |
||||
log.Panicf("%d %d", blockSize, wordSize) |
||||
} |
||||
|
||||
// Convert.
|
||||
a := (*[4]uintptr)(aPtr) |
||||
b := (*[4]uintptr)(bPtr) |
||||
dst := (*[4]uintptr)(dstPtr) |
||||
|
||||
// Compute.
|
||||
dst[0] = a[0] ^ b[0] |
||||
dst[1] = a[1] ^ b[1] |
||||
dst[2] = a[2] ^ b[2] |
||||
dst[3] = a[3] ^ b[3] |
||||
} |
@ -1,55 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// +build amd64 arm64 ppc64 ppc64le s390x mips64 mips64le
|
||||
|
||||
// This code assumes that it's safe to perform unaligned word-sized loads. This is safe on:
|
||||
// - arm64 per http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/ch05s01s02.html
|
||||
// - Section "5.5.8 Alignment Interrupt" of PowerPC Operating Environment Architecture Book III Version 2.02
|
||||
// (the first PowerPC ISA version to include 64-bit), available from
|
||||
// http://www.ibm.com/developerworks/systems/library/es-archguide-v2.html does not permit fixed-point loads
|
||||
// or stores to generate exceptions on unaligned access
|
||||
// - IBM mainframe's have allowed unaligned accesses since the System/370 arrived in 1970
|
||||
// - On mips unaligned accesses are fixed up by the kernel per https://www.linux-mips.org/wiki/Alignment
|
||||
// so performance might be quite bad but it will work.
|
||||
|
||||
package cmac |
||||
|
||||
import ( |
||||
"log" |
||||
"unsafe" |
||||
) |
||||
|
||||
// XOR the blockSize bytes starting at a and b, writing the result over dst.
|
||||
func xorBlock( |
||||
dstPtr unsafe.Pointer, |
||||
aPtr unsafe.Pointer, |
||||
bPtr unsafe.Pointer) { |
||||
// Check assumptions. (These are compile-time constants, so this should
|
||||
// compile out.)
|
||||
const wordSize = unsafe.Sizeof(uintptr(0)) |
||||
if blockSize != 2*wordSize { |
||||
log.Panicf("%d %d", blockSize, wordSize) |
||||
} |
||||
|
||||
// Convert.
|
||||
a := (*[2]uintptr)(aPtr) |
||||
b := (*[2]uintptr)(bPtr) |
||||
dst := (*[2]uintptr)(dstPtr) |
||||
|
||||
// Compute.
|
||||
dst[0] = a[0] ^ b[0] |
||||
dst[1] = a[1] ^ b[1] |
||||
} |
@ -1,65 +0,0 @@
|
||||
// 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 cmac |
||||
|
||||
import ( |
||||
"bytes" |
||||
"crypto/cipher" |
||||
|
||||
"../common" |
||||
) |
||||
|
||||
var subkeyZero []byte |
||||
var su |