Add crypto dependencies/vendoring

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
This commit is contained in:
Stefan Berger
2018-10-03 09:02:59 -04:00
committed by Brandon Lum
parent b5d0c78225
commit 30c3443947
71 changed files with 21809 additions and 0 deletions

22
vendor/github.com/fullsailor/pkcs7/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Andrew Smith
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.

8
vendor/github.com/fullsailor/pkcs7/README.md generated vendored Normal file
View File

@@ -0,0 +1,8 @@
# pkcs7
[![GoDoc](https://godoc.org/github.com/fullsailor/pkcs7?status.svg)](https://godoc.org/github.com/fullsailor/pkcs7)
[![Build Status](https://travis-ci.org/fullsailor/pkcs7.svg?branch=master)](https://travis-ci.org/fullsailor/pkcs7)
pkcs7 implements parsing and creating signed and enveloped messages.
- Documentation on [GoDoc](http://godoc.org/github.com/fullsailor/pkcs7)

248
vendor/github.com/fullsailor/pkcs7/ber.go generated vendored Normal file
View File

@@ -0,0 +1,248 @@
package pkcs7
import (
"bytes"
"errors"
)
var encodeIndent = 0
type asn1Object interface {
EncodeTo(writer *bytes.Buffer) error
}
type asn1Structured struct {
tagBytes []byte
content []asn1Object
}
func (s asn1Structured) EncodeTo(out *bytes.Buffer) error {
//fmt.Printf("%s--> tag: % X\n", strings.Repeat("| ", encodeIndent), s.tagBytes)
encodeIndent++
inner := new(bytes.Buffer)
for _, obj := range s.content {
err := obj.EncodeTo(inner)
if err != nil {
return err
}
}
encodeIndent--
out.Write(s.tagBytes)
encodeLength(out, inner.Len())
out.Write(inner.Bytes())
return nil
}
type asn1Primitive struct {
tagBytes []byte
length int
content []byte
}
func (p asn1Primitive) EncodeTo(out *bytes.Buffer) error {
_, err := out.Write(p.tagBytes)
if err != nil {
return err
}
if err = encodeLength(out, p.length); err != nil {
return err
}
//fmt.Printf("%s--> tag: % X length: %d\n", strings.Repeat("| ", encodeIndent), p.tagBytes, p.length)
//fmt.Printf("%s--> content length: %d\n", strings.Repeat("| ", encodeIndent), len(p.content))
out.Write(p.content)
return nil
}
func ber2der(ber []byte) ([]byte, error) {
if len(ber) == 0 {
return nil, errors.New("ber2der: input ber is empty")
}
//fmt.Printf("--> ber2der: Transcoding %d bytes\n", len(ber))
out := new(bytes.Buffer)
obj, _, err := readObject(ber, 0)
if err != nil {
return nil, err
}
obj.EncodeTo(out)
// if offset < len(ber) {
// return nil, fmt.Errorf("ber2der: Content longer than expected. Got %d, expected %d", offset, len(ber))
//}
return out.Bytes(), nil
}
// encodes lengths that are longer than 127 into string of bytes
func marshalLongLength(out *bytes.Buffer, i int) (err error) {
n := lengthLength(i)
for ; n > 0; n-- {
err = out.WriteByte(byte(i >> uint((n-1)*8)))
if err != nil {
return
}
}
return nil
}
// computes the byte length of an encoded length value
func lengthLength(i int) (numBytes int) {
numBytes = 1
for i > 255 {
numBytes++
i >>= 8
}
return
}
// encodes the length in DER format
// If the length fits in 7 bits, the value is encoded directly.
//
// Otherwise, the number of bytes to encode the length is first determined.
// This number is likely to be 4 or less for a 32bit length. This number is
// added to 0x80. The length is encoded in big endian encoding follow after
//
// Examples:
// length | byte 1 | bytes n
// 0 | 0x00 | -
// 120 | 0x78 | -
// 200 | 0x81 | 0xC8
// 500 | 0x82 | 0x01 0xF4
//
func encodeLength(out *bytes.Buffer, length int) (err error) {
if length >= 128 {
l := lengthLength(length)
err = out.WriteByte(0x80 | byte(l))
if err != nil {
return
}
err = marshalLongLength(out, length)
if err != nil {
return
}
} else {
err = out.WriteByte(byte(length))
if err != nil {
return
}
}
return
}
func readObject(ber []byte, offset int) (asn1Object, int, error) {
//fmt.Printf("\n====> Starting readObject at offset: %d\n\n", offset)
tagStart := offset
b := ber[offset]
offset++
tag := b & 0x1F // last 5 bits
if tag == 0x1F {
tag = 0
for ber[offset] >= 0x80 {
tag = tag*128 + ber[offset] - 0x80
offset++
}
tag = tag*128 + ber[offset] - 0x80
offset++
}
tagEnd := offset
kind := b & 0x20
/*
if kind == 0 {
fmt.Print("--> Primitive\n")
} else {
fmt.Print("--> Constructed\n")
}
*/
// read length
var length int
l := ber[offset]
offset++
indefinite := false
if l > 0x80 {
numberOfBytes := (int)(l & 0x7F)
if numberOfBytes > 4 { // int is only guaranteed to be 32bit
return nil, 0, errors.New("ber2der: BER tag length too long")
}
if numberOfBytes == 4 && (int)(ber[offset]) > 0x7F {
return nil, 0, errors.New("ber2der: BER tag length is negative")
}
if 0x0 == (int)(ber[offset]) {
return nil, 0, errors.New("ber2der: BER tag length has leading zero")
}
//fmt.Printf("--> (compute length) indicator byte: %x\n", l)
//fmt.Printf("--> (compute length) length bytes: % X\n", ber[offset:offset+numberOfBytes])
for i := 0; i < numberOfBytes; i++ {
length = length*256 + (int)(ber[offset])
offset++
}
} else if l == 0x80 {
indefinite = true
} else {
length = (int)(l)
}
//fmt.Printf("--> length : %d\n", length)
contentEnd := offset + length
if contentEnd > len(ber) {
return nil, 0, errors.New("ber2der: BER tag length is more than available data")
}
//fmt.Printf("--> content start : %d\n", offset)
//fmt.Printf("--> content end : %d\n", contentEnd)
//fmt.Printf("--> content : % X\n", ber[offset:contentEnd])
var obj asn1Object
if indefinite && kind == 0 {
return nil, 0, errors.New("ber2der: Indefinite form tag must have constructed encoding")
}
if kind == 0 {
obj = asn1Primitive{
tagBytes: ber[tagStart:tagEnd],
length: length,
content: ber[offset:contentEnd],
}
} else {
var subObjects []asn1Object
for (offset < contentEnd) || indefinite {
var subObj asn1Object
var err error
subObj, offset, err = readObject(ber, offset)
if err != nil {
return nil, 0, err
}
subObjects = append(subObjects, subObj)
if indefinite {
terminated, err := isIndefiniteTermination(ber, offset)
if err != nil {
return nil, 0, err
}
if terminated {
break
}
}
}
obj = asn1Structured{
tagBytes: ber[tagStart:tagEnd],
content: subObjects,
}
}
// Apply indefinite form length with 0x0000 terminator.
if indefinite {
contentEnd = offset + 2
}
return obj, contentEnd, nil
}
func isIndefiniteTermination(ber []byte, offset int) (bool, error) {
if len(ber) - offset < 2 {
return false, errors.New("ber2der: Invalid BER format")
}
return bytes.Index(ber[offset:], []byte{0x0, 0x0}) == 0, nil
}

962
vendor/github.com/fullsailor/pkcs7/pkcs7.go generated vendored Normal file
View File

@@ -0,0 +1,962 @@
// Package pkcs7 implements parsing and generation of some PKCS#7 structures.
package pkcs7
import (
"bytes"
"crypto"
"crypto/aes"
"crypto/cipher"
"crypto/des"
"crypto/hmac"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"errors"
"fmt"
"math/big"
"sort"
"time"
_ "crypto/sha1" // for crypto.SHA1
)
// PKCS7 Represents a PKCS7 structure
type PKCS7 struct {
Content []byte
Certificates []*x509.Certificate
CRLs []pkix.CertificateList
Signers []signerInfo
raw interface{}
}
type contentInfo struct {
ContentType asn1.ObjectIdentifier
Content asn1.RawValue `asn1:"explicit,optional,tag:0"`
}
// ErrUnsupportedContentType is returned when a PKCS7 content is not supported.
// Currently only Data (1.2.840.113549.1.7.1), Signed Data (1.2.840.113549.1.7.2),
// and Enveloped Data are supported (1.2.840.113549.1.7.3)
var ErrUnsupportedContentType = errors.New("pkcs7: cannot parse data: unimplemented content type")
type unsignedData []byte
var (
oidData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1}
oidSignedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 2}
oidEnvelopedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 3}
oidSignedAndEnvelopedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 4}
oidDigestedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 5}
oidEncryptedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 6}
oidAttributeContentType = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 3}
oidAttributeMessageDigest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 4}
oidAttributeSigningTime = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 5}
)
type signedData struct {
Version int `asn1:"default:1"`
DigestAlgorithmIdentifiers []pkix.AlgorithmIdentifier `asn1:"set"`
ContentInfo contentInfo
Certificates rawCertificates `asn1:"optional,tag:0"`
CRLs []pkix.CertificateList `asn1:"optional,tag:1"`
SignerInfos []signerInfo `asn1:"set"`
}
type rawCertificates struct {
Raw asn1.RawContent
}
type envelopedData struct {
Version int
RecipientInfos []recipientInfo `asn1:"set"`
EncryptedContentInfo encryptedContentInfo
}
type recipientInfo struct {
Version int
IssuerAndSerialNumber issuerAndSerial
KeyEncryptionAlgorithm pkix.AlgorithmIdentifier
EncryptedKey []byte
}
type encryptedContentInfo struct {
ContentType asn1.ObjectIdentifier
ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
EncryptedContent asn1.RawValue `asn1:"tag:0,optional"`
}
type attribute struct {
Type asn1.ObjectIdentifier
Value asn1.RawValue `asn1:"set"`
}
type issuerAndSerial struct {
IssuerName asn1.RawValue
SerialNumber *big.Int
}
// MessageDigestMismatchError is returned when the signer data digest does not
// match the computed digest for the contained content
type MessageDigestMismatchError struct {
ExpectedDigest []byte
ActualDigest []byte
}
func (err *MessageDigestMismatchError) Error() string {
return fmt.Sprintf("pkcs7: Message digest mismatch\n\tExpected: %X\n\tActual : %X", err.ExpectedDigest, err.ActualDigest)
}
type signerInfo struct {
Version int `asn1:"default:1"`
IssuerAndSerialNumber issuerAndSerial
DigestAlgorithm pkix.AlgorithmIdentifier
AuthenticatedAttributes []attribute `asn1:"optional,tag:0"`
DigestEncryptionAlgorithm pkix.AlgorithmIdentifier
EncryptedDigest []byte
UnauthenticatedAttributes []attribute `asn1:"optional,tag:1"`
}
// Parse decodes a DER encoded PKCS7 package
func Parse(data []byte) (p7 *PKCS7, err error) {
if len(data) == 0 {
return nil, errors.New("pkcs7: input data is empty")
}
var info contentInfo
der, err := ber2der(data)
if err != nil {
return nil, err
}
rest, err := asn1.Unmarshal(der, &info)
if len(rest) > 0 {
err = asn1.SyntaxError{Msg: "trailing data"}
return
}
if err != nil {
return
}
// fmt.Printf("--> Content Type: %s", info.ContentType)
switch {
case info.ContentType.Equal(oidSignedData):
return parseSignedData(info.Content.Bytes)
case info.ContentType.Equal(oidEnvelopedData):
return parseEnvelopedData(info.Content.Bytes)
}
return nil, ErrUnsupportedContentType
}
func parseSignedData(data []byte) (*PKCS7, error) {
var sd signedData
asn1.Unmarshal(data, &sd)
certs, err := sd.Certificates.Parse()
if err != nil {
return nil, err
}
// fmt.Printf("--> Signed Data Version %d\n", sd.Version)
var compound asn1.RawValue
var content unsignedData
// The Content.Bytes maybe empty on PKI responses.
if len(sd.ContentInfo.Content.Bytes) > 0 {
if _, err := asn1.Unmarshal(sd.ContentInfo.Content.Bytes, &compound); err != nil {
return nil, err
}
}
// Compound octet string
if compound.IsCompound {
if _, err = asn1.Unmarshal(compound.Bytes, &content); err != nil {
return nil, err
}
} else {
// assuming this is tag 04
content = compound.Bytes
}
return &PKCS7{
Content: content,
Certificates: certs,
CRLs: sd.CRLs,
Signers: sd.SignerInfos,
raw: sd}, nil
}
func (raw rawCertificates) Parse() ([]*x509.Certificate, error) {
if len(raw.Raw) == 0 {
return nil, nil
}
var val asn1.RawValue
if _, err := asn1.Unmarshal(raw.Raw, &val); err != nil {
return nil, err
}
return x509.ParseCertificates(val.Bytes)
}
func parseEnvelopedData(data []byte) (*PKCS7, error) {
var ed envelopedData
if _, err := asn1.Unmarshal(data, &ed); err != nil {
return nil, err
}
return &PKCS7{
raw: ed,
}, nil
}
// Verify checks the signatures of a PKCS7 object
// WARNING: Verify does not check signing time or verify certificate chains at
// this time.
func (p7 *PKCS7) Verify() (err error) {
if len(p7.Signers) == 0 {
return errors.New("pkcs7: Message has no signers")
}
for _, signer := range p7.Signers {
if err := verifySignature(p7, signer); err != nil {
return err
}
}
return nil
}
func verifySignature(p7 *PKCS7, signer signerInfo) error {
signedData := p7.Content
hash, err := getHashForOID(signer.DigestAlgorithm.Algorithm)
if err != nil {
return err
}
if len(signer.AuthenticatedAttributes) > 0 {
// TODO(fullsailor): First check the content type match
var digest []byte
err := unmarshalAttribute(signer.AuthenticatedAttributes, oidAttributeMessageDigest, &digest)
if err != nil {
return err
}
h := hash.New()
h.Write(p7.Content)
computed := h.Sum(nil)
if !hmac.Equal(digest, computed) {
return &MessageDigestMismatchError{
ExpectedDigest: digest,
ActualDigest: computed,
}
}
// TODO(fullsailor): Optionally verify certificate chain
// TODO(fullsailor): Optionally verify signingTime against certificate NotAfter/NotBefore
signedData, err = marshalAttributes(signer.AuthenticatedAttributes)
if err != nil {
return err
}
}
cert := getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber)
if cert == nil {
return errors.New("pkcs7: No certificate for signer")
}
algo := getSignatureAlgorithmFromAI(signer.DigestEncryptionAlgorithm)
if algo == x509.UnknownSignatureAlgorithm {
// I'm not sure what the spec here is, and the openssl sources were not
// helpful. But, this is what App Store receipts appear to do.
// The DigestEncryptionAlgorithm is just "rsaEncryption (PKCS #1)"
// But we're expecting a digest + encryption algorithm. So... we're going
// to determine an algorithm based on the DigestAlgorithm and this
// encryption algorithm.
if signer.DigestEncryptionAlgorithm.Algorithm.Equal(oidEncryptionAlgorithmRSA) {
algo = getRSASignatureAlgorithmForDigestAlgorithm(hash)
}
}
return cert.CheckSignature(algo, signedData, signer.EncryptedDigest)
}
func marshalAttributes(attrs []attribute) ([]byte, error) {
encodedAttributes, err := asn1.Marshal(struct {
A []attribute `asn1:"set"`
}{A: attrs})
if err != nil {
return nil, err
}
// Remove the leading sequence octets
var raw asn1.RawValue
asn1.Unmarshal(encodedAttributes, &raw)
return raw.Bytes, nil
}
var (
oidDigestAlgorithmSHA1 = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 26}
oidEncryptionAlgorithmRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
)
func getCertFromCertsByIssuerAndSerial(certs []*x509.Certificate, ias issuerAndSerial) *x509.Certificate {
for _, cert := range certs {
if isCertMatchForIssuerAndSerial(cert, ias) {
return cert
}
}
return nil
}
func getHashForOID(oid asn1.ObjectIdentifier) (crypto.Hash, error) {
switch {
case oid.Equal(oidDigestAlgorithmSHA1):
return crypto.SHA1, nil
case oid.Equal(oidSHA256):
return crypto.SHA256, nil
}
return crypto.Hash(0), ErrUnsupportedAlgorithm
}
func getRSASignatureAlgorithmForDigestAlgorithm(hash crypto.Hash) x509.SignatureAlgorithm {
for _, details := range signatureAlgorithmDetails {
if details.pubKeyAlgo == x509.RSA && details.hash == hash {
return details.algo
}
}
return x509.UnknownSignatureAlgorithm
}
// GetOnlySigner returns an x509.Certificate for the first signer of the signed
// data payload. If there are more or less than one signer, nil is returned
func (p7 *PKCS7) GetOnlySigner() *x509.Certificate {
if len(p7.Signers) != 1 {
return nil
}
signer := p7.Signers[0]
return getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber)
}
// ErrUnsupportedAlgorithm tells you when our quick dev assumptions have failed
var ErrUnsupportedAlgorithm = errors.New("pkcs7: cannot decrypt data: only RSA, DES, DES-EDE3, AES-256-CBC and AES-128-GCM supported")
// ErrNotEncryptedContent is returned when attempting to Decrypt data that is not encrypted data
var ErrNotEncryptedContent = errors.New("pkcs7: content data is a decryptable data type")
// Decrypt decrypts encrypted content info for recipient cert and private key
func (p7 *PKCS7) Decrypt(cert *x509.Certificate, pk crypto.PrivateKey) ([]byte, error) {
data, ok := p7.raw.(envelopedData)
if !ok {
return nil, ErrNotEncryptedContent
}
recipient := selectRecipientForCertificate(data.RecipientInfos, cert)
if recipient.EncryptedKey == nil {
return nil, errors.New("pkcs7: no enveloped recipient for provided certificate")
}
if priv := pk.(*rsa.PrivateKey); priv != nil {
var contentKey []byte
contentKey, err := rsa.DecryptPKCS1v15(rand.Reader, priv, recipient.EncryptedKey)
if err != nil {
return nil, err
}
return data.EncryptedContentInfo.decrypt(contentKey)
}
fmt.Printf("Unsupported Private Key: %v\n", pk)
return nil, ErrUnsupportedAlgorithm
}
var oidEncryptionAlgorithmDESCBC = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 7}
var oidEncryptionAlgorithmDESEDE3CBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 3, 7}
var oidEncryptionAlgorithmAES256CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 42}
var oidEncryptionAlgorithmAES128GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 6}
var oidEncryptionAlgorithmAES128CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 2}
func (eci encryptedContentInfo) decrypt(key []byte) ([]byte, error) {
alg := eci.ContentEncryptionAlgorithm.Algorithm
if !alg.Equal(oidEncryptionAlgorithmDESCBC) &&
!alg.Equal(oidEncryptionAlgorithmDESEDE3CBC) &&
!alg.Equal(oidEncryptionAlgorithmAES256CBC) &&
!alg.Equal(oidEncryptionAlgorithmAES128CBC) &&
!alg.Equal(oidEncryptionAlgorithmAES128GCM) {
fmt.Printf("Unsupported Content Encryption Algorithm: %s\n", alg)
return nil, ErrUnsupportedAlgorithm
}
// EncryptedContent can either be constructed of multple OCTET STRINGs
// or _be_ a tagged OCTET STRING
var cyphertext []byte
if eci.EncryptedContent.IsCompound {
// Complex case to concat all of the children OCTET STRINGs
var buf bytes.Buffer
cypherbytes := eci.EncryptedContent.Bytes
for {
var part []byte
cypherbytes, _ = asn1.Unmarshal(cypherbytes, &part)
buf.Write(part)
if cypherbytes == nil {
break
}
}
cyphertext = buf.Bytes()
} else {
// Simple case, the bytes _are_ the cyphertext
cyphertext = eci.EncryptedContent.Bytes
}
var block cipher.Block
var err error
switch {
case alg.Equal(oidEncryptionAlgorithmDESCBC):
block, err = des.NewCipher(key)
case alg.Equal(oidEncryptionAlgorithmDESEDE3CBC):
block, err = des.NewTripleDESCipher(key)
case alg.Equal(oidEncryptionAlgorithmAES256CBC):
fallthrough
case alg.Equal(oidEncryptionAlgorithmAES128GCM), alg.Equal(oidEncryptionAlgorithmAES128CBC):
block, err = aes.NewCipher(key)
}
if err != nil {
return nil, err
}
if alg.Equal(oidEncryptionAlgorithmAES128GCM) {
params := aesGCMParameters{}
paramBytes := eci.ContentEncryptionAlgorithm.Parameters.Bytes
_, err := asn1.Unmarshal(paramBytes, &params)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
if len(params.Nonce) != gcm.NonceSize() {
return nil, errors.New("pkcs7: encryption algorithm parameters are incorrect")
}
if params.ICVLen != gcm.Overhead() {
return nil, errors.New("pkcs7: encryption algorithm parameters are incorrect")
}
plaintext, err := gcm.Open(nil, params.Nonce, cyphertext, nil)
if err != nil {
return nil, err
}
return plaintext, nil
}
iv := eci.ContentEncryptionAlgorithm.Parameters.Bytes
if len(iv) != block.BlockSize() {
return nil, errors.New("pkcs7: encryption algorithm parameters are malformed")
}
mode := cipher.NewCBCDecrypter(block, iv)
plaintext := make([]byte, len(cyphertext))
mode.CryptBlocks(plaintext, cyphertext)
if plaintext, err = unpad(plaintext, mode.BlockSize()); err != nil {
return nil, err
}
return plaintext, nil
}
func selectRecipientForCertificate(recipients []recipientInfo, cert *x509.Certificate) recipientInfo {
for _, recp := range recipients {
if isCertMatchForIssuerAndSerial(cert, recp.IssuerAndSerialNumber) {
return recp
}
}
return recipientInfo{}
}
func isCertMatchForIssuerAndSerial(cert *x509.Certificate, ias issuerAndSerial) bool {
return cert.SerialNumber.Cmp(ias.SerialNumber) == 0 && bytes.Compare(cert.RawIssuer, ias.IssuerName.FullBytes) == 0
}
func pad(data []byte, blocklen int) ([]byte, error) {
if blocklen < 1 {
return nil, fmt.Errorf("invalid blocklen %d", blocklen)
}
padlen := blocklen - (len(data) % blocklen)
if padlen == 0 {
padlen = blocklen
}
pad := bytes.Repeat([]byte{byte(padlen)}, padlen)
return append(data, pad...), nil
}
func unpad(data []byte, blocklen int) ([]byte, error) {
if blocklen < 1 {
return nil, fmt.Errorf("invalid blocklen %d", blocklen)
}
if len(data)%blocklen != 0 || len(data) == 0 {
return nil, fmt.Errorf("invalid data len %d", len(data))
}
// the last byte is the length of padding
padlen := int(data[len(data)-1])
// check padding integrity, all bytes should be the same
pad := data[len(data)-padlen:]
for _, padbyte := range pad {
if padbyte != byte(padlen) {
return nil, errors.New("invalid padding")
}
}
return data[:len(data)-padlen], nil
}
func unmarshalAttribute(attrs []attribute, attributeType asn1.ObjectIdentifier, out interface{}) error {
for _, attr := range attrs {
if attr.Type.Equal(attributeType) {
_, err := asn1.Unmarshal(attr.Value.Bytes, out)
return err
}
}
return errors.New("pkcs7: attribute type not in attributes")
}
// UnmarshalSignedAttribute decodes a single attribute from the signer info
func (p7 *PKCS7) UnmarshalSignedAttribute(attributeType asn1.ObjectIdentifier, out interface{}) error {
sd, ok := p7.raw.(signedData)
if !ok {
return errors.New("pkcs7: payload is not signedData content")
}
if len(sd.SignerInfos) < 1 {
return errors.New("pkcs7: payload has no signers")
}
attributes := sd.SignerInfos[0].AuthenticatedAttributes
return unmarshalAttribute(attributes, attributeType, out)
}
// SignedData is an opaque data structure for creating signed data payloads
type SignedData struct {
sd signedData
certs []*x509.Certificate
messageDigest []byte
}
// Attribute represents a key value pair attribute. Value must be marshalable byte
// `encoding/asn1`
type Attribute struct {
Type asn1.ObjectIdentifier
Value interface{}
}
// SignerInfoConfig are optional values to include when adding a signer
type SignerInfoConfig struct {
ExtraSignedAttributes []Attribute
}
// NewSignedData initializes a SignedData with content
func NewSignedData(data []byte) (*SignedData, error) {
content, err := asn1.Marshal(data)
if err != nil {
return nil, err
}
ci := contentInfo{
ContentType: oidData,
Content: asn1.RawValue{Class: 2, Tag: 0, Bytes: content, IsCompound: true},
}
digAlg := pkix.AlgorithmIdentifier{
Algorithm: oidDigestAlgorithmSHA1,
}
h := crypto.SHA1.New()
h.Write(data)
md := h.Sum(nil)
sd := signedData{
ContentInfo: ci,
Version: 1,
DigestAlgorithmIdentifiers: []pkix.AlgorithmIdentifier{digAlg},
}
return &SignedData{sd: sd, messageDigest: md}, nil
}
type attributes struct {
types []asn1.ObjectIdentifier
values []interface{}
}
// Add adds the attribute, maintaining insertion order
func (attrs *attributes) Add(attrType asn1.ObjectIdentifier, value interface{}) {
attrs.types = append(attrs.types, attrType)
attrs.values = append(attrs.values, value)
}
type sortableAttribute struct {
SortKey []byte
Attribute attribute
}
type attributeSet []sortableAttribute
func (sa attributeSet) Len() int {
return len(sa)
}
func (sa attributeSet) Less(i, j int) bool {
return bytes.Compare(sa[i].SortKey, sa[j].SortKey) < 0
}
func (sa attributeSet) Swap(i, j int) {
sa[i], sa[j] = sa[j], sa[i]
}
func (sa attributeSet) Attributes() []attribute {
attrs := make([]attribute, len(sa))
for i, attr := range sa {
attrs[i] = attr.Attribute
}
return attrs
}
func (attrs *attributes) ForMarshaling() ([]attribute, error) {
sortables := make(attributeSet, len(attrs.types))
for i := range sortables {
attrType := attrs.types[i]
attrValue := attrs.values[i]
asn1Value, err := asn1.Marshal(attrValue)
if err != nil {
return nil, err
}
attr := attribute{
Type: attrType,
Value: asn1.RawValue{Tag: 17, IsCompound: true, Bytes: asn1Value}, // 17 == SET tag
}
encoded, err := asn1.Marshal(attr)
if err != nil {
return nil, err
}
sortables[i] = sortableAttribute{
SortKey: encoded,
Attribute: attr,
}
}
sort.Sort(sortables)
return sortables.Attributes(), nil
}
// AddSigner signs attributes about the content and adds certificate to payload
func (sd *SignedData) AddSigner(cert *x509.Certificate, pkey crypto.PrivateKey, config SignerInfoConfig) error {
attrs := &attributes{}
attrs.Add(oidAttributeContentType, sd.sd.ContentInfo.ContentType)
attrs.Add(oidAttributeMessageDigest, sd.messageDigest)
attrs.Add(oidAttributeSigningTime, time.Now())
for _, attr := range config.ExtraSignedAttributes {
attrs.Add(attr.Type, attr.Value)
}
finalAttrs, err := attrs.ForMarshaling()
if err != nil {
return err
}
signature, err := signAttributes(finalAttrs, pkey, crypto.SHA1)
if err != nil {
return err
}
ias, err := cert2issuerAndSerial(cert)
if err != nil {
return err
}
signer := signerInfo{
AuthenticatedAttributes: finalAttrs,
DigestAlgorithm: pkix.AlgorithmIdentifier{Algorithm: oidDigestAlgorithmSHA1},
DigestEncryptionAlgorithm: pkix.AlgorithmIdentifier{Algorithm: oidSignatureSHA1WithRSA},
IssuerAndSerialNumber: ias,
EncryptedDigest: signature,
Version: 1,
}
// create signature of signed attributes
sd.certs = append(sd.certs, cert)
sd.sd.SignerInfos = append(sd.sd.SignerInfos, signer)
return nil
}
// AddCertificate adds the certificate to the payload. Useful for parent certificates
func (sd *SignedData) AddCertificate(cert *x509.Certificate) {
sd.certs = append(sd.certs, cert)
}
// Detach removes content from the signed data struct to make it a detached signature.
// This must be called right before Finish()
func (sd *SignedData) Detach() {
sd.sd.ContentInfo = contentInfo{ContentType: oidData}
}
// Finish marshals the content and its signers
func (sd *SignedData) Finish() ([]byte, error) {
sd.sd.Certificates = marshalCertificates(sd.certs)
inner, err := asn1.Marshal(sd.sd)
if err != nil {
return nil, err
}
outer := contentInfo{
ContentType: oidSignedData,
Content: asn1.RawValue{Class: 2, Tag: 0, Bytes: inner, IsCompound: true},
}
return asn1.Marshal(outer)
}
func cert2issuerAndSerial(cert *x509.Certificate) (issuerAndSerial, error) {
var ias issuerAndSerial
// The issuer RDNSequence has to match exactly the sequence in the certificate
// We cannot use cert.Issuer.ToRDNSequence() here since it mangles the sequence
ias.IssuerName = asn1.RawValue{FullBytes: cert.RawIssuer}
ias.SerialNumber = cert.SerialNumber
return ias, nil
}
// signs the DER encoded form of the attributes with the private key
func signAttributes(attrs []attribute, pkey crypto.PrivateKey, hash crypto.Hash) ([]byte, error) {
attrBytes, err := marshalAttributes(attrs)
if err != nil {
return nil, err
}
h := hash.New()
h.Write(attrBytes)
hashed := h.Sum(nil)
switch priv := pkey.(type) {
case *rsa.PrivateKey:
return rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA1, hashed)
}
return nil, ErrUnsupportedAlgorithm
}
// concats and wraps the certificates in the RawValue structure
func marshalCertificates(certs []*x509.Certificate) rawCertificates {
var buf bytes.Buffer
for _, cert := range certs {
buf.Write(cert.Raw)
}
rawCerts, _ := marshalCertificateBytes(buf.Bytes())
return rawCerts
}
// Even though, the tag & length are stripped out during marshalling the
// RawContent, we have to encode it into the RawContent. If its missing,
// then `asn1.Marshal()` will strip out the certificate wrapper instead.
func marshalCertificateBytes(certs []byte) (rawCertificates, error) {
var val = asn1.RawValue{Bytes: certs, Class: 2, Tag: 0, IsCompound: true}
b, err := asn1.Marshal(val)
if err != nil {
return rawCertificates{}, err
}
return rawCertificates{Raw: b}, nil
}
// DegenerateCertificate creates a signed data structure containing only the
// provided certificate or certificate chain.
func DegenerateCertificate(cert []byte) ([]byte, error) {
rawCert, err := marshalCertificateBytes(cert)
if err != nil {
return nil, err
}
emptyContent := contentInfo{ContentType: oidData}
sd := signedData{
Version: 1,
ContentInfo: emptyContent,
Certificates: rawCert,
CRLs: []pkix.CertificateList{},
}
content, err := asn1.Marshal(sd)
if err != nil {
return nil, err
}
signedContent := contentInfo{
ContentType: oidSignedData,
Content: asn1.RawValue{Class: 2, Tag: 0, Bytes: content, IsCompound: true},
}
return asn1.Marshal(signedContent)
}
const (
EncryptionAlgorithmDESCBC = iota
EncryptionAlgorithmAES128GCM
)
// ContentEncryptionAlgorithm determines the algorithm used to encrypt the
// plaintext message. Change the value of this variable to change which
// algorithm is used in the Encrypt() function.
var ContentEncryptionAlgorithm = EncryptionAlgorithmDESCBC
// ErrUnsupportedEncryptionAlgorithm is returned when attempting to encrypt
// content with an unsupported algorithm.
var ErrUnsupportedEncryptionAlgorithm = errors.New("pkcs7: cannot encrypt content: only DES-CBC and AES-128-GCM supported")
const nonceSize = 12
type aesGCMParameters struct {
Nonce []byte `asn1:"tag:4"`
ICVLen int
}
func encryptAES128GCM(content []byte) ([]byte, *encryptedContentInfo, error) {
// Create AES key and nonce
key := make([]byte, 16)
nonce := make([]byte, nonceSize)
_, err := rand.Read(key)
if err != nil {
return nil, nil, err
}
_, err = rand.Read(nonce)
if err != nil {
return nil, nil, err
}
// Encrypt content
block, err := aes.NewCipher(key)
if err != nil {
return nil, nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, nil, err
}
ciphertext := gcm.Seal(nil, nonce, content, nil)
// Prepare ASN.1 Encrypted Content Info
paramSeq := aesGCMParameters{
Nonce: nonce,
ICVLen: gcm.Overhead(),
}
paramBytes, err := asn1.Marshal(paramSeq)
if err != nil {
return nil, nil, err
}
eci := encryptedContentInfo{
ContentType: oidData,
ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{
Algorithm: oidEncryptionAlgorithmAES128GCM,
Parameters: asn1.RawValue{
Tag: asn1.TagSequence,
Bytes: paramBytes,
},
},
EncryptedContent: marshalEncryptedContent(ciphertext),
}
return key, &eci, nil
}
func encryptDESCBC(content []byte) ([]byte, *encryptedContentInfo, error) {
// Create DES key & CBC IV
key := make([]byte, 8)
iv := make([]byte, des.BlockSize)
_, err := rand.Read(key)
if err != nil {
return nil, nil, err
}
_, err = rand.Read(iv)
if err != nil {
return nil, nil, err
}
// Encrypt padded content
block, err := des.NewCipher(key)
if err != nil {
return nil, nil, err
}
mode := cipher.NewCBCEncrypter(block, iv)
plaintext, err := pad(content, mode.BlockSize())
cyphertext := make([]byte, len(plaintext))
mode.CryptBlocks(cyphertext, plaintext)
// Prepare ASN.1 Encrypted Content Info
eci := encryptedContentInfo{
ContentType: oidData,
ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{
Algorithm: oidEncryptionAlgorithmDESCBC,
Parameters: asn1.RawValue{Tag: 4, Bytes: iv},
},
EncryptedContent: marshalEncryptedContent(cyphertext),
}
return key, &eci, nil
}
// Encrypt creates and returns an envelope data PKCS7 structure with encrypted
// recipient keys for each recipient public key.
//
// The algorithm used to perform encryption is determined by the current value
// of the global ContentEncryptionAlgorithm package variable. By default, the
// value is EncryptionAlgorithmDESCBC. To use a different algorithm, change the
// value before calling Encrypt(). For example:
//
// ContentEncryptionAlgorithm = EncryptionAlgorithmAES128GCM
//
// TODO(fullsailor): Add support for encrypting content with other algorithms
func Encrypt(content []byte, recipients []*x509.Certificate) ([]byte, error) {
var eci *encryptedContentInfo
var key []byte
var err error
// Apply chosen symmetric encryption method
switch ContentEncryptionAlgorithm {
case EncryptionAlgorithmDESCBC:
key, eci, err = encryptDESCBC(content)
case EncryptionAlgorithmAES128GCM:
key, eci, err = encryptAES128GCM(content)
default:
return nil, ErrUnsupportedEncryptionAlgorithm
}
if err != nil {
return nil, err
}
// Prepare each recipient's encrypted cipher key
recipientInfos := make([]recipientInfo, len(recipients))
for i, recipient := range recipients {
encrypted, err := encryptKey(key, recipient)
if err != nil {
return nil, err
}
ias, err := cert2issuerAndSerial(recipient)
if err != nil {
return nil, err
}
info := recipientInfo{
Version: 0,
IssuerAndSerialNumber: ias,
KeyEncryptionAlgorithm: pkix.AlgorithmIdentifier{
Algorithm: oidEncryptionAlgorithmRSA,
},
EncryptedKey: encrypted,
}
recipientInfos[i] = info
}
// Prepare envelope content
envelope := envelopedData{
EncryptedContentInfo: *eci,
Version: 0,
RecipientInfos: recipientInfos,
}
innerContent, err := asn1.Marshal(envelope)
if err != nil {
return nil, err
}
// Prepare outer payload structure
wrapper := contentInfo{
ContentType: oidEnvelopedData,
Content: asn1.RawValue{Class: 2, Tag: 0, IsCompound: true, Bytes: innerContent},
}
return asn1.Marshal(wrapper)
}
func marshalEncryptedContent(content []byte) asn1.RawValue {
asn1Content, _ := asn1.Marshal(content)
return asn1.RawValue{Tag: 0, Class: 2, Bytes: asn1Content, IsCompound: true}
}
func encryptKey(key []byte, recipient *x509.Certificate) ([]byte, error) {
if pub := recipient.PublicKey.(*rsa.PublicKey); pub != nil {
return rsa.EncryptPKCS1v15(rand.Reader, pub, key)
}
return nil, ErrUnsupportedAlgorithm
}

133
vendor/github.com/fullsailor/pkcs7/x509.go generated vendored Normal file
View File

@@ -0,0 +1,133 @@
// 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 go/golang LICENSE file.
package pkcs7
// These are private constants and functions from the crypto/x509 package that
// are useful when dealing with signatures verified by x509 certificates
import (
"bytes"
"crypto"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
)
var (
oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2}
oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8}
// oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA
// but it's specified by ISO. Microsoft's makecert.exe has been known
// to produce certificates with this OID.
oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29}
)
var signatureAlgorithmDetails = []struct {
algo x509.SignatureAlgorithm
name string
oid asn1.ObjectIdentifier
pubKeyAlgo x509.PublicKeyAlgorithm
hash crypto.Hash
}{
{x509.MD2WithRSA, "MD2-RSA", oidSignatureMD2WithRSA, x509.RSA, crypto.Hash(0) /* no value for MD2 */},
{x509.MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, x509.RSA, crypto.MD5},
{x509.SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, x509.RSA, crypto.SHA1},
{x509.SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, x509.RSA, crypto.SHA1},
{x509.SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, x509.RSA, crypto.SHA256},
{x509.SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, x509.RSA, crypto.SHA384},
{x509.SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, x509.RSA, crypto.SHA512},
{x509.SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA256},
{x509.SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA384},
{x509.SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA512},
{x509.DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, x509.DSA, crypto.SHA1},
{x509.DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, x509.DSA, crypto.SHA256},
{x509.ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, x509.ECDSA, crypto.SHA1},
{x509.ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, x509.ECDSA, crypto.SHA256},
{x509.ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, x509.ECDSA, crypto.SHA384},
{x509.ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, x509.ECDSA, crypto.SHA512},
}
// pssParameters reflects the parameters in an AlgorithmIdentifier that
// specifies RSA PSS. See https://tools.ietf.org/html/rfc3447#appendix-A.2.3
type pssParameters struct {
// The following three fields are not marked as
// optional because the default values specify SHA-1,
// which is no longer suitable for use in signatures.
Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"`
MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"`
SaltLength int `asn1:"explicit,tag:2"`
TrailerField int `asn1:"optional,explicit,tag:3,default:1"`
}
// asn1.NullBytes is not available prior to Go 1.9
var nullBytes = []byte{5, 0}
func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) x509.SignatureAlgorithm {
if !ai.Algorithm.Equal(oidSignatureRSAPSS) {
for _, details := range signatureAlgorithmDetails {
if ai.Algorithm.Equal(details.oid) {
return details.algo
}
}
return x509.UnknownSignatureAlgorithm
}
// RSA PSS is special because it encodes important parameters
// in the Parameters.
var params pssParameters
if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, &params); err != nil {
return x509.UnknownSignatureAlgorithm
}
var mgf1HashFunc pkix.AlgorithmIdentifier
if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil {
return x509.UnknownSignatureAlgorithm
}
// PSS is greatly overburdened with options. This code forces
// them into three buckets by requiring that the MGF1 hash
// function always match the message hash function (as
// recommended in
// https://tools.ietf.org/html/rfc3447#section-8.1), that the
// salt length matches the hash length, and that the trailer
// field has the default value.
if !bytes.Equal(params.Hash.Parameters.FullBytes, nullBytes) ||
!params.MGF.Algorithm.Equal(oidMGF1) ||
!mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) ||
!bytes.Equal(mgf1HashFunc.Parameters.FullBytes, nullBytes) ||
params.TrailerField != 1 {
return x509.UnknownSignatureAlgorithm
}
switch {
case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32:
return x509.SHA256WithRSAPSS
case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48:
return x509.SHA384WithRSAPSS
case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64:
return x509.SHA512WithRSAPSS
}
return x509.UnknownSignatureAlgorithm
}

25
vendor/github.com/miscreant/miscreant-go/LICENSE.txt generated vendored Normal file
View 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
View 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
View 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)
}

View 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
View 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
View 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
View 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
View 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[:]
}