1
// Copyright 2011 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
9
"code.google.com/p/go.crypto/openpgp/errors"
10
"code.google.com/p/go.crypto/openpgp/s2k"
16
// This is the largest session key that we'll support. Since no 512-bit cipher
17
// has even been seriously used, this is comfortably large.
18
const maxSessionKeySizeInBytes = 64
20
// SymmetricKeyEncrypted represents a passphrase protected session key. See RFC
22
type SymmetricKeyEncrypted struct {
23
CipherFunc CipherFunction
25
Key []byte // Empty unless Encrypted is false.
26
s2k func(out, in []byte)
30
const symmetricKeyEncryptedVersion = 4
32
func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err error) {
33
// RFC 4880, section 5.3.
35
_, err = readFull(r, buf[:])
39
if buf[0] != symmetricKeyEncryptedVersion {
40
return errors.UnsupportedError("SymmetricKeyEncrypted version")
42
ske.CipherFunc = CipherFunction(buf[1])
44
if ske.CipherFunc.KeySize() == 0 {
45
return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1])))
48
ske.s2k, err = s2k.Parse(r)
53
encryptedKey := make([]byte, maxSessionKeySizeInBytes)
54
// The session key may follow. We just have to try and read to find
55
// out. If it exists then we limit it to maxSessionKeySizeInBytes.
56
n, err := readFull(r, encryptedKey)
57
if err != nil && err != io.ErrUnexpectedEOF {
62
if n == maxSessionKeySizeInBytes {
63
return errors.UnsupportedError("oversized encrypted session key")
65
ske.encryptedKey = encryptedKey[:n]
73
// Decrypt attempts to decrypt an encrypted session key. If it returns nil,
74
// ske.Key will contain the session key.
75
func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) error {
80
key := make([]byte, ske.CipherFunc.KeySize())
81
ske.s2k(key, passphrase)
83
if len(ske.encryptedKey) == 0 {
86
// the IV is all zeros
87
iv := make([]byte, ske.CipherFunc.blockSize())
88
c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv)
89
c.XORKeyStream(ske.encryptedKey, ske.encryptedKey)
90
ske.CipherFunc = CipherFunction(ske.encryptedKey[0])
91
if ske.CipherFunc.blockSize() == 0 {
92
return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(ske.CipherFunc)))
94
ske.CipherFunc = CipherFunction(ske.encryptedKey[0])
95
ske.Key = ske.encryptedKey[1:]
96
if len(ske.Key)%ske.CipherFunc.blockSize() != 0 {
98
return errors.StructuralError("length of decrypted key not a multiple of block size")
102
ske.Encrypted = false
106
// SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w. The
107
// packet contains a random session key, encrypted by a key derived from the
108
// given passphrase. The session key is returned and must be passed to
109
// SerializeSymmetricallyEncrypted.
110
// If config is nil, sensible defaults will be used.
111
func SerializeSymmetricKeyEncrypted(w io.Writer, passphrase []byte, config *Config) (key []byte, err error) {
112
cipherFunc := config.Cipher()
113
keySize := cipherFunc.KeySize()
115
return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
118
s2kBuf := new(bytes.Buffer)
119
keyEncryptingKey := make([]byte, keySize)
120
// s2k.Serialize salts and stretches the passphrase, and writes the
121
// resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf.
122
err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase)
126
s2kBytes := s2kBuf.Bytes()
128
packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize
129
err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength)
135
buf[0] = symmetricKeyEncryptedVersion
136
buf[1] = byte(cipherFunc)
137
_, err = w.Write(buf[:])
141
_, err = w.Write(s2kBytes)
146
sessionKey := make([]byte, keySize)
147
_, err = io.ReadFull(config.Random(), sessionKey)
151
iv := make([]byte, cipherFunc.blockSize())
152
c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv)
153
encryptedCipherAndKey := make([]byte, keySize+1)
154
c.XORKeyStream(encryptedCipherAndKey, buf[1:])
155
c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey)
156
_, err = w.Write(encryptedCipherAndKey)