Add crypto dependencies/vendoring
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
This commit is contained in:
committed by
Brandon Lum
parent
b5d0c78225
commit
30c3443947
25
vendor/github.com/miscreant/miscreant-go/LICENSE.txt
generated
vendored
Normal file
25
vendor/github.com/miscreant/miscreant-go/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
Copyright (c) 2017-2018 The Miscreant Developers. The canonical list of project
|
||||
contributors who hold copyright over the project can be found at:
|
||||
|
||||
https://github.com/miscreant/miscreant/blob/master/AUTHORS.md
|
||||
|
||||
MIT License
|
||||
|
||||
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.
|
||||
95
vendor/github.com/miscreant/miscreant-go/README.md
generated
vendored
Normal file
95
vendor/github.com/miscreant/miscreant-go/README.md
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
# miscreant.go [![Build Status][build-shield]][build-link] [![GoDoc][godoc-shield]][godoc-link] [![Go Report Card][goreport-shield]][goreport-link] [![MIT licensed][license-shield]][license-link] [![Gitter Chat][gitter-image]][gitter-link]
|
||||
|
||||
> The best crypto you've never heard of, brought to you by [Phil Rogaway]
|
||||
|
||||
Go implementation of **Miscreant**: Advanced symmetric encryption library
|
||||
which provides the [AES-SIV] ([RFC 5297]), [AES-PMAC-SIV], and [STREAM]
|
||||
constructions. These algorithms are easy-to-use (or rather, hard-to-misuse)
|
||||
and support encryption of individual messages or message streams.
|
||||
|
||||
```go
|
||||
import "github.com/miscreant/miscreant-go"
|
||||
```
|
||||
|
||||
All types are designed to be **thread-compatible**: Methods of an instance shared between
|
||||
multiple threads (or goroutines) must not be accessed concurrently. Callers are responsible for
|
||||
implementing their own mutual exclusion.
|
||||
|
||||
|
||||
- [Documentation] (Wiki)
|
||||
- [godoc][godoc-link]
|
||||
|
||||
## About AES-SIV and AES-PMAC-SIV
|
||||
|
||||
**AES-SIV** and **AES-PMAC-SIV** provide [nonce-reuse misuse-resistance] (NRMR):
|
||||
accidentally reusing a nonce with this construction is not a security
|
||||
catastrophe, unlike more popular AES encryption modes like [AES-GCM] where
|
||||
nonce reuse leaks both the authentication key and the XOR of both plaintexts,
|
||||
both of which can potentially be leveraged for *full plaintext recovery attacks*.
|
||||
|
||||
With **AES-SIV**, the worst outcome of reusing a nonce is an attacker
|
||||
can see you've sent the same plaintext twice, as opposed to almost all other
|
||||
AES modes where it can facilitate [chosen ciphertext attacks] and/or
|
||||
full plaintext recovery.
|
||||
|
||||
## Help and Discussion
|
||||
|
||||
Have questions? Want to suggest a feature or change?
|
||||
|
||||
* [Gitter]: web-based chat about miscreant projects including **miscreant.go**
|
||||
* [Google Group]: join via web or email ([miscreant-crypto+subscribe@googlegroups.com])
|
||||
|
||||
## Security Notice
|
||||
|
||||
Though this library is written by cryptographic professionals, it has not
|
||||
undergone a thorough security audit, and cryptographic professionals are still
|
||||
humans that make mistakes.
|
||||
|
||||
This library makes an effort to use constant time operations throughout its
|
||||
implementation, however actual constant time behavior has not been verified.
|
||||
|
||||
Use this library at your own risk.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
We abide by the [Contributor Covenant][cc] and ask that you do as well.
|
||||
|
||||
For more information, please see [CODE_OF_CONDUCT.md].
|
||||
|
||||
## Contributing
|
||||
|
||||
Bug reports and pull requests are welcome on GitHub at:
|
||||
|
||||
<https://github.com/miscreant/miscreant-go>
|
||||
|
||||
## Copyright
|
||||
|
||||
Copyright (c) 2017-2018 [The Miscreant Developers][AUTHORS].
|
||||
See [LICENSE.txt] for further details.
|
||||
|
||||
[build-shield]: https://secure.travis-ci.org/miscreant/miscreant-go.svg?branch=master
|
||||
[build-link]: https://travis-ci.org/miscreant/miscreant-go
|
||||
[godoc-shield]: https://godoc.org/github.com/miscreant/miscreant-go?status.svg
|
||||
[godoc-link]: https://godoc.org/github.com/miscreant/miscreant-go
|
||||
[goreport-shield]: https://goreportcard.com/badge/github.com/miscreant/miscreant-go
|
||||
[goreport-link]: https://goreportcard.com/report/github.com/miscreant/miscreant-go
|
||||
[license-shield]: https://img.shields.io/badge/license-MIT-blue.svg
|
||||
[license-link]: https://github.com/miscreant/miscreant-go/blob/master/LICENSE.txt
|
||||
[gitter-image]: https://badges.gitter.im/badge.svg
|
||||
[gitter-link]: https://gitter.im/miscreant/Lobby
|
||||
[Phil Rogaway]: https://en.wikipedia.org/wiki/Phillip_Rogaway
|
||||
[AES-SIV]: https://github.com/miscreant/miscreant/wiki/AES-SIV
|
||||
[RFC 5297]: https://tools.ietf.org/html/rfc5297
|
||||
[AES-PMAC-SIV]: https://github.com/miscreant/miscreant/wiki/AES-PMAC-SIV
|
||||
[STREAM]: https://github.com/miscreant/miscreant/wiki/STREAM
|
||||
[nonce-reuse misuse-resistance]: https://github.com/miscreant/miscreant/wiki/Nonce-Reuse-Misuse-Resistance
|
||||
[AES-GCM]: https://en.wikipedia.org/wiki/Galois/Counter_Mode
|
||||
[chosen ciphertext attacks]: https://en.wikipedia.org/wiki/Chosen-ciphertext_attack
|
||||
[Documentation]: https://github.com/miscreant/miscreant/wiki/Go-Documentation
|
||||
[Gitter]: https://gitter.im/miscreant/Lobby
|
||||
[Google Group]: https://groups.google.com/forum/#!forum/miscreant-crypto
|
||||
[miscreant-crypto+subscribe@googlegroups.com]: mailto:miscreant-crypto+subscribe@googlegroups.com?subject=subscribe
|
||||
[cc]: https://contributor-covenant.org
|
||||
[CODE_OF_CONDUCT.md]: https://github.com/miscreant/miscreant-go/blob/master/CODE_OF_CONDUCT.md
|
||||
[AUTHORS]: https://github.com/miscreant/miscreant-go/blob/master/AUTHORS.md
|
||||
[LICENSE.txt]: https://github.com/miscreant/miscreant-go/blob/master/LICENSE.txt
|
||||
108
vendor/github.com/miscreant/miscreant-go/aead.go
generated
vendored
Normal file
108
vendor/github.com/miscreant/miscreant-go/aead.go
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
// Written in 2015 by Dmitry Chestnykh.
|
||||
|
||||
package miscreant
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Minimum nonce size for which we'll allow the generation of random nonces
|
||||
const minimumRandomNonceSize = 16
|
||||
|
||||
// aead is a wrapper for Cipher implementing cipher.AEAD interface.
|
||||
type aead struct {
|
||||
// miscreant.Cipher instance underlying this AEAD
|
||||
c *Cipher
|
||||
|
||||
// Size of the nonce required
|
||||
nonceSize int
|
||||
}
|
||||
|
||||
// GenerateKey generates a random 32-byte or 64-byte encryption key.
|
||||
// Panics if the key size is unsupported or source of randomness fails.
|
||||
func GenerateKey(length int) []byte {
|
||||
if length != 32 && length != 64 {
|
||||
panic("miscreant.GenerateKey: invalid key size: " + string(length))
|
||||
}
|
||||
|
||||
key := make([]byte, length)
|
||||
_, err := io.ReadFull(rand.Reader, key[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return key
|
||||
}
|
||||
|
||||
// GenerateNonce generates a random nonce for the given `cipher.AEAD`.
|
||||
// Panics if the configured nonce size is less than 16-bytes (128-bits)
|
||||
func GenerateNonce(c cipher.AEAD) []byte {
|
||||
if c.NonceSize() < minimumRandomNonceSize {
|
||||
panic("miscreant.GenerateNonce: nonce size is too small: " + string(c.NonceSize()))
|
||||
}
|
||||
|
||||
nonce := make([]byte, c.NonceSize())
|
||||
_, err := io.ReadFull(rand.Reader, nonce[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return nonce
|
||||
}
|
||||
|
||||
// NewAEAD returns an AES-SIV instance implementing cipher.AEAD interface,
|
||||
// with the given cipher, nonce size, and a key which must be twice as long
|
||||
// as an AES key, either 32 or 64 bytes to select AES-128 (AES-SIV-256)
|
||||
// or AES-256 (AES-SIV-512).
|
||||
//
|
||||
// Unless the given nonce size is less than zero, Seal and Open will panic when
|
||||
// passed nonce of a different size.
|
||||
func NewAEAD(alg string, key []byte, nonceSize int) (cipher.AEAD, error) {
|
||||
switch alg {
|
||||
case "AES-SIV", "AES-CMAC-SIV":
|
||||
c, err := NewAESCMACSIV(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &aead{c: c, nonceSize: nonceSize}, nil
|
||||
case "AES-PMAC-SIV":
|
||||
c, err := NewAESPMACSIV(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &aead{c: c, nonceSize: nonceSize}, nil
|
||||
default:
|
||||
panic("NewAEAD: unknown cipher: " + alg)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *aead) NonceSize() int { return a.nonceSize }
|
||||
func (a *aead) Overhead() int { return a.c.Overhead() }
|
||||
|
||||
func (a *aead) Seal(dst, nonce, plaintext, data []byte) (out []byte) {
|
||||
if len(nonce) != a.nonceSize && a.nonceSize >= 0 {
|
||||
panic("miscreant.AEAD: incorrect nonce length")
|
||||
}
|
||||
var err error
|
||||
if data == nil {
|
||||
out, err = a.c.Seal(dst, plaintext, nonce)
|
||||
} else {
|
||||
out, err = a.c.Seal(dst, plaintext, data, nonce)
|
||||
}
|
||||
if err != nil {
|
||||
panic("miscreant.AEAD: " + err.Error())
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (a *aead) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
|
||||
if len(nonce) != a.nonceSize && a.nonceSize >= 0 {
|
||||
panic("miscreant.AEAD: incorrect nonce length")
|
||||
}
|
||||
if data == nil {
|
||||
return a.c.Open(dst, ciphertext, nonce)
|
||||
}
|
||||
return a.c.Open(dst, ciphertext, data, nonce)
|
||||
}
|
||||
49
vendor/github.com/miscreant/miscreant-go/block/block.go
generated
vendored
Normal file
49
vendor/github.com/miscreant/miscreant-go/block/block.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
// Common block cipher functionality shared across this library
|
||||
|
||||
package block
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"crypto/subtle"
|
||||
)
|
||||
|
||||
const (
|
||||
// Size of an AES block in bytes
|
||||
Size = 16
|
||||
|
||||
// R is the minimal irreducible polynomial for a 128-bit block size
|
||||
R = 0x87
|
||||
)
|
||||
|
||||
// Block is a 128-bit array used by certain block ciphers (i.e. AES)
|
||||
type Block [Size]byte
|
||||
|
||||
// Clear zeroes out the contents of the block
|
||||
func (b *Block) Clear() {
|
||||
// TODO: use a more secure zeroing method that won't be optimized away
|
||||
for i := range b {
|
||||
b[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Dbl performs a doubling of a block over GF(2^128):
|
||||
//
|
||||
// a<<1 if firstbit(a)=0
|
||||
// (a<<1) ⊕ 0¹²⁰10000111 if firstbit(a)=1
|
||||
//
|
||||
func (b *Block) Dbl() {
|
||||
var z byte
|
||||
|
||||
for i := Size - 1; i >= 0; i-- {
|
||||
zz := b[i] >> 7
|
||||
b[i] = b[i]<<1 | z
|
||||
z = zz
|
||||
}
|
||||
|
||||
b[Size-1] ^= byte(subtle.ConstantTimeSelect(int(z), R, 0))
|
||||
}
|
||||
|
||||
// Encrypt a block with the given block cipher
|
||||
func (b *Block) Encrypt(c cipher.Block) {
|
||||
c.Encrypt(b[:], b[:])
|
||||
}
|
||||
114
vendor/github.com/miscreant/miscreant-go/cmac/cmac.go
generated
vendored
Normal file
114
vendor/github.com/miscreant/miscreant-go/cmac/cmac.go
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// CMAC message authentication code, defined in
|
||||
// NIST Special Publication SP 800-38B.
|
||||
|
||||
package cmac
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"hash"
|
||||
|
||||
"github.com/miscreant/miscreant-go/block"
|
||||
)
|
||||
|
||||
type cmac struct {
|
||||
// c is the block cipher we're using (i.e. AES-128 or AES-256)
|
||||
c cipher.Block
|
||||
|
||||
// k1 and k2 are CMAC subkeys (for finishing the tag)
|
||||
k1, k2 block.Block
|
||||
|
||||
// digest contains the PMAC tag-in-progress
|
||||
digest block.Block
|
||||
|
||||
// buffer contains a part of the input message, processed a block-at-a-time
|
||||
buf block.Block
|
||||
|
||||
// pos marks the end of plaintext in the buffer
|
||||
pos uint
|
||||
}
|
||||
|
||||
// New returns a new instance of a CMAC message authentication code
|
||||
// digest using the given cipher.Block.
|
||||
func New(c cipher.Block) hash.Hash {
|
||||
if c.BlockSize() != block.Size {
|
||||
panic("pmac: invalid cipher block size")
|
||||
}
|
||||
|
||||
d := new(cmac)
|
||||
d.c = c
|
||||
|
||||
// Subkey generation, p. 7
|
||||
d.k1.Encrypt(c)
|
||||
d.k1.Dbl()
|
||||
|
||||
copy(d.k2[:], d.k1[:])
|
||||
d.k2.Dbl()
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
// Reset clears the digest state, starting a new digest.
|
||||
func (d *cmac) Reset() {
|
||||
d.digest.Clear()
|
||||
d.buf.Clear()
|
||||
d.pos = 0
|
||||
}
|
||||
|
||||
// Write adds the given data to the digest state.
|
||||
func (d *cmac) Write(p []byte) (nn int, err error) {
|
||||
nn = len(p)
|
||||
left := block.Size - d.pos
|
||||
|
||||
if uint(len(p)) > left {
|
||||
xor(d.buf[d.pos:], p[:left])
|
||||
p = p[left:]
|
||||
d.buf.Encrypt(d.c)
|
||||
d.pos = 0
|
||||
}
|
||||
|
||||
for uint(len(p)) > block.Size {
|
||||
xor(d.buf[:], p[:block.Size])
|
||||
p = p[block.Size:]
|
||||
d.buf.Encrypt(d.c)
|
||||
}
|
||||
|
||||
if len(p) > 0 {
|
||||
xor(d.buf[d.pos:], p)
|
||||
d.pos += uint(len(p))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Sum returns the CMAC digest, one cipher block in length,
|
||||
// of the data written with Write.
|
||||
func (d *cmac) Sum(in []byte) []byte {
|
||||
// Finish last block, mix in key, encrypt.
|
||||
// Don't edit ci, in case caller wants
|
||||
// to keep digesting after call to Sum.
|
||||
k := d.k1
|
||||
if d.pos < uint(len(d.digest)) {
|
||||
k = d.k2
|
||||
}
|
||||
for i := 0; i < len(d.buf); i++ {
|
||||
d.digest[i] = d.buf[i] ^ k[i]
|
||||
}
|
||||
if d.pos < uint(len(d.digest)) {
|
||||
d.digest[d.pos] ^= 0x80
|
||||
}
|
||||
d.digest.Encrypt(d.c)
|
||||
return append(in, d.digest[:]...)
|
||||
}
|
||||
|
||||
func (d *cmac) Size() int { return len(d.digest) }
|
||||
|
||||
func (d *cmac) BlockSize() int { return d.c.BlockSize() }
|
||||
|
||||
func xor(a, b []byte) {
|
||||
for i, v := range b {
|
||||
a[i] ^= v
|
||||
}
|
||||
}
|
||||
201
vendor/github.com/miscreant/miscreant-go/pmac/pmac.go
generated
vendored
Normal file
201
vendor/github.com/miscreant/miscreant-go/pmac/pmac.go
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
// PMAC message authentication code, defined in
|
||||
// http://web.cs.ucdavis.edu/~rogaway/ocb/pmac.pdf
|
||||
|
||||
package pmac
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"crypto/subtle"
|
||||
"hash"
|
||||
"math/bits"
|
||||
|
||||
"github.com/miscreant/miscreant-go/block"
|
||||
)
|
||||
|
||||
// Number of L blocks to precompute (i.e. µ in the PMAC paper)
|
||||
// TODO: dynamically compute these as needed
|
||||
const precomputedBlocks = 31
|
||||
|
||||
type pmac struct {
|
||||
// c is the block cipher we're using (i.e. AES-128 or AES-256)
|
||||
c cipher.Block
|
||||
|
||||
// l is defined as follows (quoted from the PMAC paper):
|
||||
//
|
||||
// Equation 1:
|
||||
//
|
||||
// a · x =
|
||||
// a<<1 if firstbit(a)=0
|
||||
// (a<<1) ⊕ 0¹²⁰10000111 if firstbit(a)=1
|
||||
//
|
||||
// Equation 2:
|
||||
//
|
||||
// a · x⁻¹ =
|
||||
// a>>1 if lastbit(a)=0
|
||||
// (a>>1) ⊕ 10¹²⁰1000011 if lastbit(a)=1
|
||||
//
|
||||
// Let L(0) ← L. For i ∈ [1..µ], compute L(i) ← L(i − 1) · x by
|
||||
// Equation (1) using a shift and a conditional xor.
|
||||
//
|
||||
// Compute L(−1) ← L · x⁻¹ by Equation (2), using a shift and a
|
||||
// conditional xor.
|
||||
//
|
||||
// Save the values L(−1), L(0), L(1), L(2), ..., L(µ) in a table.
|
||||
// (Alternatively, [ed: as we have done in this codebase] defer computing
|
||||
// some or all of these L(i) values until the value is actually needed.)
|
||||
l [precomputedBlocks]block.Block
|
||||
|
||||
// lInv contains the multiplicative inverse (i.e. right shift) of the first
|
||||
// l-value, computed as described above, and is XORed into the tag in the
|
||||
// event the message length is a multiple of the block size
|
||||
lInv block.Block
|
||||
|
||||
// digest contains the PMAC tag-in-progress
|
||||
digest block.Block
|
||||
|
||||
// offset is a block specific tweak to the input message
|
||||
offset block.Block
|
||||
|
||||
// buf contains a part of the input message, processed a block-at-a-time
|
||||
buf block.Block
|
||||
|
||||
// pos marks the end of plaintext in the buf
|
||||
pos uint
|
||||
|
||||
// ctr is the number of blocks we have MAC'd so far
|
||||
ctr uint
|
||||
|
||||
// finished is set true when we are done processing a message, and forbids
|
||||
// any subsequent writes until we reset the internal state
|
||||
finished bool
|
||||
}
|
||||
|
||||
// New creates a new PMAC instance using the given cipher
|
||||
func New(c cipher.Block) hash.Hash {
|
||||
if c.BlockSize() != block.Size {
|
||||
panic("pmac: invalid cipher block size")
|
||||
}
|
||||
|
||||
d := new(pmac)
|
||||
d.c = c
|
||||
|
||||
var tmp block.Block
|
||||
tmp.Encrypt(c)
|
||||
|
||||
for i := range d.l {
|
||||
copy(d.l[i][:], tmp[:])
|
||||
tmp.Dbl()
|
||||
}
|
||||
|
||||
// Compute L(−1) ← L · x⁻¹:
|
||||
//
|
||||
// a>>1 if lastbit(a)=0
|
||||
// (a>>1) ⊕ 10¹²⁰1000011 if lastbit(a)=1
|
||||
//
|
||||
copy(tmp[:], d.l[0][:])
|
||||
lastBit := int(tmp[block.Size-1] & 0x01)
|
||||
|
||||
for i := block.Size - 1; i > 0; i-- {
|
||||
carry := byte(subtle.ConstantTimeSelect(int(tmp[i-1]&1), 0x80, 0))
|
||||
tmp[i] = (tmp[i] >> 1) | carry
|
||||
}
|
||||
|
||||
tmp[0] >>= 1
|
||||
tmp[0] ^= byte(subtle.ConstantTimeSelect(lastBit, 0x80, 0))
|
||||
tmp[block.Size-1] ^= byte(subtle.ConstantTimeSelect(lastBit, block.R>>1, 0))
|
||||
copy(d.lInv[:], tmp[:])
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
// Reset clears the digest state, starting a new digest.
|
||||
func (d *pmac) Reset() {
|
||||
d.digest.Clear()
|
||||
d.offset.Clear()
|
||||
d.buf.Clear()
|
||||
d.pos = 0
|
||||
d.ctr = 0
|
||||
d.finished = false
|
||||
}
|
||||
|
||||
// Write adds the given data to the digest state.
|
||||
func (d *pmac) Write(msg []byte) (int, error) {
|
||||
if d.finished {
|
||||
panic("pmac: already finished")
|
||||
}
|
||||
|
||||
var msgPos, msgLen, remaining uint
|
||||
msgLen = uint(len(msg))
|
||||
remaining = block.Size - d.pos
|
||||
|
||||
// Finish filling the internal buf with the message
|
||||
if msgLen > remaining {
|
||||
copy(d.buf[d.pos:], msg[:remaining])
|
||||
|
||||
msgPos += remaining
|
||||
msgLen -= remaining
|
||||
|
||||
d.processBuffer()
|
||||
}
|
||||
|
||||
// So long as we have more than a blocks worth of data, compute
|
||||
// whole-sized blocks at a time.
|
||||
for msgLen > block.Size {
|
||||
copy(d.buf[:], msg[msgPos:msgPos+block.Size])
|
||||
|
||||
msgPos += block.Size
|
||||
msgLen -= block.Size
|
||||
|
||||
d.processBuffer()
|
||||
}
|
||||
|
||||
if msgLen > 0 {
|
||||
copy(d.buf[d.pos:d.pos+msgLen], msg[msgPos:])
|
||||
d.pos += msgLen
|
||||
}
|
||||
|
||||
return len(msg), nil
|
||||
}
|
||||
|
||||
// Sum returns the PMAC digest, one cipher block in length,
|
||||
// of the data written with Write.
|
||||
func (d *pmac) Sum(in []byte) []byte {
|
||||
if d.finished {
|
||||
panic("pmac: already finished")
|
||||
}
|
||||
|
||||
if d.pos == block.Size {
|
||||
xor(d.digest[:], d.buf[:])
|
||||
xor(d.digest[:], d.lInv[:])
|
||||
} else {
|
||||
xor(d.digest[:], d.buf[:d.pos])
|
||||
d.digest[d.pos] ^= 0x80
|
||||
}
|
||||
|
||||
d.digest.Encrypt(d.c)
|
||||
d.finished = true
|
||||
|
||||
return append(in, d.digest[:]...)
|
||||
}
|
||||
|
||||
func (d *pmac) Size() int { return block.Size }
|
||||
|
||||
func (d *pmac) BlockSize() int { return block.Size }
|
||||
|
||||
// Update the internal tag state based on the buf contents
|
||||
func (d *pmac) processBuffer() {
|
||||
xor(d.offset[:], d.l[bits.TrailingZeros(d.ctr+1)][:])
|
||||
xor(d.buf[:], d.offset[:])
|
||||
d.ctr++
|
||||
|
||||
d.buf.Encrypt(d.c)
|
||||
xor(d.digest[:], d.buf[:])
|
||||
d.pos = 0
|
||||
}
|
||||
|
||||
// XOR the contents of b into a in-place
|
||||
func xor(a, b []byte) {
|
||||
for i, v := range b {
|
||||
a[i] ^= v
|
||||
}
|
||||
}
|
||||
243
vendor/github.com/miscreant/miscreant-go/siv.go
generated
vendored
Normal file
243
vendor/github.com/miscreant/miscreant-go/siv.go
generated
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
// Originally written in 2015 by Dmitry Chestnykh.
|
||||
// Modified in 2017 by Tony Arcieri.
|
||||
//
|
||||
// Miscreant implements Synthetic Initialization Vector (SIV)-based
|
||||
// authenticated encryption using the AES block cipher (RFC 5297).
|
||||
|
||||
package miscreant
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"github.com/miscreant/miscreant-go/block"
|
||||
"github.com/miscreant/miscreant-go/cmac"
|
||||
"github.com/miscreant/miscreant-go/pmac"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// MaxAssociatedDataItems is the maximum number of associated data items
|
||||
const MaxAssociatedDataItems = 126
|
||||
|
||||
var (
|
||||
// ErrKeySize indicates the given key size is not supported
|
||||
ErrKeySize = errors.New("siv: bad key size")
|
||||
|
||||
// ErrNotAuthentic indicates a ciphertext is malformed or corrupt
|
||||
ErrNotAuthentic = errors.New("siv: authentication failed")
|
||||
|
||||
// ErrTooManyAssociatedDataItems indicates more than MaxAssociatedDataItems were given
|
||||
ErrTooManyAssociatedDataItems = errors.New("siv: too many associated data items")
|
||||
)
|
||||
|
||||
// Cipher is an instance of AES-SIV, configured with either AES-CMAC or
|
||||
// AES-PMAC as a message authentication code.
|
||||
type Cipher struct {
|
||||
// MAC function used to derive a synthetic IV and authenticate the message
|
||||
h hash.Hash
|
||||
|
||||
// Block cipher function used to encrypt the message
|
||||
b cipher.Block
|
||||
|
||||
// Internal buffers
|
||||
tmp1, tmp2 block.Block
|
||||
}
|
||||
|
||||
// NewAESCMACSIV returns a new AES-SIV cipher with the given key, which must be
|
||||
// twice as long as an AES key, either 32 or 64 bytes to select AES-128
|
||||
// (AES-CMAC-SIV-256), or AES-256 (AES-CMAC-SIV-512).
|
||||
func NewAESCMACSIV(key []byte) (c *Cipher, err error) {
|
||||
n := len(key)
|
||||
if n != 32 && n != 64 {
|
||||
return nil, ErrKeySize
|
||||
}
|
||||
|
||||
macBlock, err := aes.NewCipher(key[:n/2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctrBlock, err := aes.NewCipher(key[n/2:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c = new(Cipher)
|
||||
c.h = cmac.New(macBlock)
|
||||
c.b = ctrBlock
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// NewAESPMACSIV returns a new AES-SIV cipher with the given key, which must be
|
||||
// twice as long as an AES key, either 32 or 64 bytes to select AES-128
|
||||
// (AES-PMAC-SIV-256), or AES-256 (AES-PMAC-SIV-512).
|
||||
func NewAESPMACSIV(key []byte) (c *Cipher, err error) {
|
||||
n := len(key)
|
||||
if n != 32 && n != 64 {
|
||||
return nil, ErrKeySize
|
||||
}
|
||||
|
||||
macBlock, err := aes.NewCipher(key[:n/2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctrBlock, err := aes.NewCipher(key[n/2:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c = new(Cipher)
|
||||
c.h = pmac.New(macBlock)
|
||||
c.b = ctrBlock
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Overhead returns the difference between plaintext and ciphertext lengths.
|
||||
func (c *Cipher) Overhead() int {
|
||||
return c.h.Size()
|
||||
}
|
||||
|
||||
// Seal encrypts and authenticates plaintext, authenticates the given
|
||||
// associated data items, and appends the result to dst, returning the updated
|
||||
// slice.
|
||||
//
|
||||
// The plaintext and dst may alias exactly or not at all.
|
||||
//
|
||||
// For nonce-based encryption, the nonce should be the last associated data item.
|
||||
func (c *Cipher) Seal(dst []byte, plaintext []byte, data ...[]byte) ([]byte, error) {
|
||||
if len(data) > MaxAssociatedDataItems {
|
||||
return nil, ErrTooManyAssociatedDataItems
|
||||
}
|
||||
|
||||
// Authenticate
|
||||
iv := c.s2v(data, plaintext)
|
||||
ret, out := sliceForAppend(dst, len(iv)+len(plaintext))
|
||||
copy(out, iv)
|
||||
|
||||
// Encrypt
|
||||
zeroIVBits(iv)
|
||||
ctr := cipher.NewCTR(c.b, iv)
|
||||
ctr.XORKeyStream(out[len(iv):], plaintext)
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Open decrypts ciphertext, authenticates the decrypted plaintext and the given
|
||||
// associated data items and, if successful, appends the resulting plaintext
|
||||
// to dst, returning the updated slice. The additional data items must match the
|
||||
// items passed to Seal.
|
||||
//
|
||||
// The ciphertext and dst may alias exactly or not at all.
|
||||
//
|
||||
// For nonce-based encryption, the nonce should be the last associated data item.
|
||||
func (c *Cipher) Open(dst []byte, ciphertext []byte, data ...[]byte) ([]byte, error) {
|
||||
if len(data) > MaxAssociatedDataItems {
|
||||
return nil, ErrTooManyAssociatedDataItems
|
||||
}
|
||||
if len(ciphertext) < c.Overhead() {
|
||||
return nil, ErrNotAuthentic
|
||||
}
|
||||
|
||||
// Decrypt
|
||||
iv := c.tmp1[:c.Overhead()]
|
||||
copy(iv, ciphertext)
|
||||
zeroIVBits(iv)
|
||||
ctr := cipher.NewCTR(c.b, iv)
|
||||
ret, out := sliceForAppend(dst, len(ciphertext)-len(iv))
|
||||
ctr.XORKeyStream(out, ciphertext[len(iv):])
|
||||
|
||||
// Authenticate
|
||||
expected := c.s2v(data, out)
|
||||
if subtle.ConstantTimeCompare(ciphertext[:len(iv)], expected) != 1 {
|
||||
return nil, ErrNotAuthentic
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (c *Cipher) s2v(s [][]byte, sn []byte) []byte {
|
||||
h := c.h
|
||||
h.Reset()
|
||||
|
||||
tmp, d := c.tmp1, c.tmp2
|
||||
tmp.Clear()
|
||||
|
||||
// NOTE(dchest): The standalone S2V returns CMAC(1) if the number of
|
||||
// passed vectors is zero, however in SIV construction this case is
|
||||
// never triggered, since we always pass plaintext as the last vector
|
||||
// (even if it's zero-length), so we omit this case.
|
||||
|
||||
_, err := h.Write(tmp[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
copy(d[:], h.Sum(d[:0]))
|
||||
h.Reset()
|
||||
|
||||
for _, v := range s {
|
||||
_, err := h.Write(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
copy(tmp[:], h.Sum(tmp[:0]))
|
||||
h.Reset()
|
||||
d.Dbl()
|
||||
xor(d[:], tmp[:])
|
||||
}
|
||||
|
||||
tmp.Clear()
|
||||
|
||||
if len(sn) >= h.BlockSize() {
|
||||
n := len(sn) - len(d)
|
||||
copy(tmp[:], sn[n:])
|
||||
_, err = h.Write(sn[:n])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
copy(tmp[:], sn)
|
||||
tmp[len(sn)] = 0x80
|
||||
d.Dbl()
|
||||
}
|
||||
xor(tmp[:], d[:])
|
||||
_, err = h.Write(tmp[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return h.Sum(tmp[:0])
|
||||
}
|
||||
|
||||
func xor(a, b []byte) {
|
||||
for i, v := range b {
|
||||
a[i] ^= v
|
||||
}
|
||||
}
|
||||
|
||||
func zeroIVBits(iv []byte) {
|
||||
// "We zero-out the top bit in each of the last two 32-bit words
|
||||
// of the IV before assigning it to Ctr"
|
||||
// — http://web.cs.ucdavis.edu/~rogaway/papers/siv.pdf
|
||||
iv[len(iv)-8] &= 0x7f
|
||||
iv[len(iv)-4] &= 0x7f
|
||||
}
|
||||
|
||||
// sliceForAppend takes a slice and a requested number of bytes. It returns a
|
||||
// slice with the contents of the given slice followed by that many bytes and a
|
||||
// second slice that aliases into it and contains only the extra bytes. If the
|
||||
// original slice has sufficient capacity then no allocation is performed.
|
||||
func sliceForAppend(in []byte, n int) (head, tail []byte) {
|
||||
if total := len(in) + n; cap(in) >= total {
|
||||
head = in[:total]
|
||||
} else {
|
||||
head = make([]byte, total)
|
||||
copy(head, in)
|
||||
}
|
||||
tail = head[len(in):]
|
||||
return
|
||||
}
|
||||
173
vendor/github.com/miscreant/miscreant-go/stream.go
generated
vendored
Normal file
173
vendor/github.com/miscreant/miscreant-go/stream.go
generated
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
package miscreant
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// streamNoncePrefixSize is the user-supplied nonce size
|
||||
const streamNoncePrefixSize = 8
|
||||
|
||||
// streamExtendedNonceSize is the nonce prefix + 32-bit counter + 1-byte last block flag
|
||||
const streamExtendedNonceSize = streamNoncePrefixSize + 4 + 1
|
||||
|
||||
// lastBlockFlag indicates that a block is the last in the STREAM
|
||||
const lastBlockFlag byte = 1
|
||||
|
||||
// counterMax is the maximum allowable value for the stream counter
|
||||
const counterMax uint64 = 0xFFFFFFFF
|
||||
|
||||
// StreamEncryptor encrypts message streams, selecting the nonces using a
|
||||
// 32-bit counter, generalized for any cipher.AEAD algorithm
|
||||
//
|
||||
// This construction corresponds to the ℰ stream encryptor object as defined in
|
||||
// the paper Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance
|
||||
type StreamEncryptor struct {
|
||||
// cipher.AEAD instance underlying this STREAM
|
||||
a cipher.AEAD
|
||||
|
||||
// Nonce encoder instance which computes per-message nonces
|
||||
n *nonceEncoder32
|
||||
}
|
||||
|
||||
// NewStreamEncryptor returns a STREAM encryptor instance with the given
|
||||
// cipher, nonce, and a key which must be twice as long as an AES key, either
|
||||
// 32 or 64 bytes to select AES-128 (AES-SIV-256) or AES-256 (AES-SIV-512).
|
||||
func NewStreamEncryptor(alg string, key, nonce []byte) (*StreamEncryptor, error) {
|
||||
aead, err := NewAEAD(alg, key, streamExtendedNonceSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nonceEncoder, err := newNonceEncoder32(nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &StreamEncryptor{a: aead, n: nonceEncoder}, nil
|
||||
}
|
||||
|
||||
// NonceSize returns the size of the nonce that must be passed to
|
||||
// NewStreamEncryptor
|
||||
func (e *StreamEncryptor) NonceSize() int { return streamNoncePrefixSize }
|
||||
|
||||
// Overhead returns the maximum difference between the lengths of a
|
||||
// plaintext and its ciphertext, which in the case of AES-SIV modes
|
||||
// is the size of the initialization vector
|
||||
func (e *StreamEncryptor) Overhead() int { return e.a.Overhead() }
|
||||
|
||||
// Seal the next message in the STREAM, which encrypts and authenticates
|
||||
// plaintext, authenticates the additional data and appends the result to dst,
|
||||
// returning the updated slice.
|
||||
//
|
||||
// The plaintext and dst may alias exactly or not at all. To reuse
|
||||
// plaintext's storage for the encrypted output, use plaintext[:0] as dst.
|
||||
//
|
||||
// The lastBlock argument should be set to true if this is the last message
|
||||
// in the STREAM. No further messages can be encrypted after the last one
|
||||
func (e *StreamEncryptor) Seal(dst, plaintext, aData []byte, lastBlock bool) []byte {
|
||||
return e.a.Seal(dst, e.n.Next(lastBlock), plaintext, aData)
|
||||
}
|
||||
|
||||
// StreamDecryptor decrypts message streams, selecting the nonces using a
|
||||
// 32-bit counter, generalized for any cipher.AEAD algorithm
|
||||
//
|
||||
// This construction corresponds to the ℰ stream encryptor object as defined in
|
||||
// the paper Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance
|
||||
type StreamDecryptor struct {
|
||||
// cipher.AEAD instance underlying this STREAM
|
||||
a cipher.AEAD
|
||||
|
||||
// Nonce encoder instance which computes per-message nonces
|
||||
n *nonceEncoder32
|
||||
}
|
||||
|
||||
// NewStreamDecryptor returns a STREAM encryptor instance with the given
|
||||
// cipher, nonce, and a key which must be twice as long as an AES key, either
|
||||
// 32 or 64 bytes to select AES-128 (AES-SIV-256) or AES-256 (AES-SIV-512).
|
||||
func NewStreamDecryptor(alg string, key, nonce []byte) (*StreamDecryptor, error) {
|
||||
aead, err := NewAEAD(alg, key, streamExtendedNonceSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
}
|
||||
|
||||
nonceEncoder, err := newNonceEncoder32(nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &StreamDecryptor{a: aead, n: nonceEncoder}, nil
|
||||
}
|
||||
|
||||
// NonceSize returns the size of the nonce that must be passed to
|
||||
// NewStreamDecryptor
|
||||
func (d *StreamDecryptor) NonceSize() int { return streamNoncePrefixSize }
|
||||
|
||||
// Overhead returns the maximum difference between the lengths of a
|
||||
// plaintext and its ciphertext, which in the case of AES-SIV modes
|
||||
// is the size of the initialization vector
|
||||
func (d *StreamDecryptor) Overhead() int { return d.a.Overhead() }
|
||||
|
||||
// Open decrypts and authenticates the next ciphertext in the STREAM,
|
||||
// and also authenticates the additional data, ensuring it matches
|
||||
// the value passed to Seal.
|
||||
//
|
||||
// If successful, it appends the resulting plaintext to dst and returns
|
||||
// the updated slice.
|
||||
//
|
||||
// The ciphertext and dst may alias exactly or not at all. To reuse
|
||||
// ciphertext's storage for the decrypted output, use ciphertext[:0] as dst.
|
||||
//
|
||||
// Even if the function fails, the contents of dst, up to its capacity,
|
||||
// may be overwritten.
|
||||
func (d *StreamDecryptor) Open(dst, ciphertext, aData []byte, lastBlock bool) ([]byte, error) {
|
||||
return d.a.Open(dst, d.n.Next(lastBlock), ciphertext, aData)
|
||||
}
|
||||
|
||||
// Computes STREAM nonces based on the current position in the STREAM.
|
||||
//
|
||||
// Accepts a 64-bit nonce and uses a 32-bit counter internally.
|
||||
//
|
||||
// Panics if the nonce size is incorrect, or the 32-bit counter overflows
|
||||
type nonceEncoder32 struct {
|
||||
value [streamExtendedNonceSize]byte
|
||||
counter uint64
|
||||
finished bool
|
||||
}
|
||||
|
||||
func newNonceEncoder32(noncePrefix []byte) (*nonceEncoder32, error) {
|
||||
if len(noncePrefix) != streamNoncePrefixSize {
|
||||
panic("miscreant.STREAM: incorrect nonce length")
|
||||
}
|
||||
|
||||
value := [streamExtendedNonceSize]byte{0}
|
||||
copy(value[:streamNoncePrefixSize], noncePrefix)
|
||||
|
||||
return &nonceEncoder32{
|
||||
value: value,
|
||||
counter: 0,
|
||||
finished: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (n *nonceEncoder32) Next(lastBlock bool) []byte {
|
||||
if n.finished {
|
||||
panic("miscreant.STREAM: already finished")
|
||||
}
|
||||
|
||||
counterSlice := n.value[streamNoncePrefixSize : streamNoncePrefixSize+4]
|
||||
binary.BigEndian.PutUint32(counterSlice, uint32(n.counter))
|
||||
|
||||
if lastBlock {
|
||||
n.value[len(n.value)-1] = lastBlockFlag
|
||||
n.finished = true
|
||||
} else {
|
||||
n.counter++
|
||||
if n.counter > counterMax {
|
||||
panic("miscreant.STREAM: nonce counter overflowed")
|
||||
}
|
||||
}
|
||||
|
||||
return n.value[:]
|
||||
}
|
||||
Reference in New Issue
Block a user