]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blobdiff - vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted.go
vendor: github.com/hashicorp/terraform/...@v0.10.0
[github/fretlink/terraform-provider-statuscake.git] / vendor / golang.org / x / crypto / openpgp / packet / symmetric_key_encrypted.go
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted.go b/vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted.go
new file mode 100644 (file)
index 0000000..744c2d2
--- /dev/null
@@ -0,0 +1,155 @@
+// Copyright 2011 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.
+
+package packet
+
+import (
+       "bytes"
+       "crypto/cipher"
+       "io"
+       "strconv"
+
+       "golang.org/x/crypto/openpgp/errors"
+       "golang.org/x/crypto/openpgp/s2k"
+)
+
+// This is the largest session key that we'll support. Since no 512-bit cipher
+// has even been seriously used, this is comfortably large.
+const maxSessionKeySizeInBytes = 64
+
+// SymmetricKeyEncrypted represents a passphrase protected session key. See RFC
+// 4880, section 5.3.
+type SymmetricKeyEncrypted struct {
+       CipherFunc   CipherFunction
+       s2k          func(out, in []byte)
+       encryptedKey []byte
+}
+
+const symmetricKeyEncryptedVersion = 4
+
+func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error {
+       // RFC 4880, section 5.3.
+       var buf [2]byte
+       if _, err := readFull(r, buf[:]); err != nil {
+               return err
+       }
+       if buf[0] != symmetricKeyEncryptedVersion {
+               return errors.UnsupportedError("SymmetricKeyEncrypted version")
+       }
+       ske.CipherFunc = CipherFunction(buf[1])
+
+       if ske.CipherFunc.KeySize() == 0 {
+               return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1])))
+       }
+
+       var err error
+       ske.s2k, err = s2k.Parse(r)
+       if err != nil {
+               return err
+       }
+
+       encryptedKey := make([]byte, maxSessionKeySizeInBytes)
+       // The session key may follow. We just have to try and read to find
+       // out. If it exists then we limit it to maxSessionKeySizeInBytes.
+       n, err := readFull(r, encryptedKey)
+       if err != nil && err != io.ErrUnexpectedEOF {
+               return err
+       }
+
+       if n != 0 {
+               if n == maxSessionKeySizeInBytes {
+                       return errors.UnsupportedError("oversized encrypted session key")
+               }
+               ske.encryptedKey = encryptedKey[:n]
+       }
+
+       return nil
+}
+
+// Decrypt attempts to decrypt an encrypted session key and returns the key and
+// the cipher to use when decrypting a subsequent Symmetrically Encrypted Data
+// packet.
+func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunction, error) {
+       key := make([]byte, ske.CipherFunc.KeySize())
+       ske.s2k(key, passphrase)
+
+       if len(ske.encryptedKey) == 0 {
+               return key, ske.CipherFunc, nil
+       }
+
+       // the IV is all zeros
+       iv := make([]byte, ske.CipherFunc.blockSize())
+       c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv)
+       plaintextKey := make([]byte, len(ske.encryptedKey))
+       c.XORKeyStream(plaintextKey, ske.encryptedKey)
+       cipherFunc := CipherFunction(plaintextKey[0])
+       if cipherFunc.blockSize() == 0 {
+               return nil, ske.CipherFunc, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
+       }
+       plaintextKey = plaintextKey[1:]
+       if l, cipherKeySize := len(plaintextKey), cipherFunc.KeySize(); l != cipherFunc.KeySize() {
+               return nil, cipherFunc, errors.StructuralError("length of decrypted key (" + strconv.Itoa(l) + ") " +
+                       "not equal to cipher keysize (" + strconv.Itoa(cipherKeySize) + ")")
+       }
+       return plaintextKey, cipherFunc, nil
+}
+
+// SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w. The
+// packet contains a random session key, encrypted by a key derived from the
+// given passphrase. The session key is returned and must be passed to
+// SerializeSymmetricallyEncrypted.
+// If config is nil, sensible defaults will be used.
+func SerializeSymmetricKeyEncrypted(w io.Writer, passphrase []byte, config *Config) (key []byte, err error) {
+       cipherFunc := config.Cipher()
+       keySize := cipherFunc.KeySize()
+       if keySize == 0 {
+               return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
+       }
+
+       s2kBuf := new(bytes.Buffer)
+       keyEncryptingKey := make([]byte, keySize)
+       // s2k.Serialize salts and stretches the passphrase, and writes the
+       // resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf.
+       err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase, &s2k.Config{Hash: config.Hash(), S2KCount: config.PasswordHashIterations()})
+       if err != nil {
+               return
+       }
+       s2kBytes := s2kBuf.Bytes()
+
+       packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize
+       err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength)
+       if err != nil {
+               return
+       }
+
+       var buf [2]byte
+       buf[0] = symmetricKeyEncryptedVersion
+       buf[1] = byte(cipherFunc)
+       _, err = w.Write(buf[:])
+       if err != nil {
+               return
+       }
+       _, err = w.Write(s2kBytes)
+       if err != nil {
+               return
+       }
+
+       sessionKey := make([]byte, keySize)
+       _, err = io.ReadFull(config.Random(), sessionKey)
+       if err != nil {
+               return
+       }
+       iv := make([]byte, cipherFunc.blockSize())
+       c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv)
+       encryptedCipherAndKey := make([]byte, keySize+1)
+       c.XORKeyStream(encryptedCipherAndKey, buf[1:])
+       c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey)
+       _, err = w.Write(encryptedCipherAndKey)
+       if err != nil {
+               return
+       }
+
+       key = sessionKey
+       return
+}