Switch to external libgocryptfs
This commit is contained in:
parent
5da1c05c7b
commit
ae93d78615
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "app/libgocryptfs"]
|
||||
path = app/libgocryptfs
|
||||
url = https://forge.chapril.org/hardcoresushi/libgocryptfs.git
|
1
app/libgocryptfs
Submodule
1
app/libgocryptfs
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 847d4fa7817c84fe1b78726f031172ea508dab19
|
4
app/libgocryptfs/.gitignore
vendored
4
app/libgocryptfs/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
openssl*
|
||||
lib
|
||||
include
|
||||
build
|
@ -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)
|
||||
}
|
Binary file not shown.
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 subkeyRb []byte
|
||||
|
||||
func init() {
|
||||
subkeyZero = bytes.Repeat([]byte{0x00}, blockSize)
|
||||
subkeyRb = append(bytes.Repeat([]byte{0x00}, blockSize-1), 0x87)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
@ -1,18 +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 common contains common implementation details of other packages, and
|
||||
// should not be used directly.
|
||||
package common
|