~ubuntu-branches/ubuntu/vivid/juju-core/vivid-proposed

« back to all changes in this revision

Viewing changes to src/code.google.com/p/go.crypto/openpgp/packet/symmetric_key_encrypted.go

  • Committer: Package Import Robot
  • Author(s): Curtis C. Hovey
  • Date: 2015-09-29 19:43:29 UTC
  • mfrom: (47.1.4 wily-proposed)
  • Revision ID: package-import@ubuntu.com-20150929194329-9y496tbic30hc7vp
Tags: 1.24.6-0ubuntu1~15.04.1
Backport of 1.24.6 from wily. (LP: #1500916, #1497087)

Show diffs side-by-side

added added

removed removed

Lines of Context:
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.
4
 
 
5
 
package packet
6
 
 
7
 
import (
8
 
        "bytes"
9
 
        "code.google.com/p/go.crypto/openpgp/errors"
10
 
        "code.google.com/p/go.crypto/openpgp/s2k"
11
 
        "crypto/cipher"
12
 
        "io"
13
 
        "strconv"
14
 
)
15
 
 
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
19
 
 
20
 
// SymmetricKeyEncrypted represents a passphrase protected session key. See RFC
21
 
// 4880, section 5.3.
22
 
type SymmetricKeyEncrypted struct {
23
 
        CipherFunc   CipherFunction
24
 
        Encrypted    bool
25
 
        Key          []byte // Empty unless Encrypted is false.
26
 
        s2k          func(out, in []byte)
27
 
        encryptedKey []byte
28
 
}
29
 
 
30
 
const symmetricKeyEncryptedVersion = 4
31
 
 
32
 
func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err error) {
33
 
        // RFC 4880, section 5.3.
34
 
        var buf [2]byte
35
 
        _, err = readFull(r, buf[:])
36
 
        if err != nil {
37
 
                return
38
 
        }
39
 
        if buf[0] != symmetricKeyEncryptedVersion {
40
 
                return errors.UnsupportedError("SymmetricKeyEncrypted version")
41
 
        }
42
 
        ske.CipherFunc = CipherFunction(buf[1])
43
 
 
44
 
        if ske.CipherFunc.KeySize() == 0 {
45
 
                return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1])))
46
 
        }
47
 
 
48
 
        ske.s2k, err = s2k.Parse(r)
49
 
        if err != nil {
50
 
                return
51
 
        }
52
 
 
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 {
58
 
                return
59
 
        }
60
 
        err = nil
61
 
        if n != 0 {
62
 
                if n == maxSessionKeySizeInBytes {
63
 
                        return errors.UnsupportedError("oversized encrypted session key")
64
 
                }
65
 
                ske.encryptedKey = encryptedKey[:n]
66
 
        }
67
 
 
68
 
        ske.Encrypted = true
69
 
 
70
 
        return
71
 
}
72
 
 
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 {
76
 
        if !ske.Encrypted {
77
 
                return nil
78
 
        }
79
 
 
80
 
        key := make([]byte, ske.CipherFunc.KeySize())
81
 
        ske.s2k(key, passphrase)
82
 
 
83
 
        if len(ske.encryptedKey) == 0 {
84
 
                ske.Key = key
85
 
        } else {
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)))
93
 
                }
94
 
                ske.CipherFunc = CipherFunction(ske.encryptedKey[0])
95
 
                ske.Key = ske.encryptedKey[1:]
96
 
                if len(ske.Key)%ske.CipherFunc.blockSize() != 0 {
97
 
                        ske.Key = nil
98
 
                        return errors.StructuralError("length of decrypted key not a multiple of block size")
99
 
                }
100
 
        }
101
 
 
102
 
        ske.Encrypted = false
103
 
        return nil
104
 
}
105
 
 
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()
114
 
        if keySize == 0 {
115
 
                return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
116
 
        }
117
 
 
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)
123
 
        if err != nil {
124
 
                return
125
 
        }
126
 
        s2kBytes := s2kBuf.Bytes()
127
 
 
128
 
        packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize
129
 
        err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength)
130
 
        if err != nil {
131
 
                return
132
 
        }
133
 
 
134
 
        var buf [2]byte
135
 
        buf[0] = symmetricKeyEncryptedVersion
136
 
        buf[1] = byte(cipherFunc)
137
 
        _, err = w.Write(buf[:])
138
 
        if err != nil {
139
 
                return
140
 
        }
141
 
        _, err = w.Write(s2kBytes)
142
 
        if err != nil {
143
 
                return
144
 
        }
145
 
 
146
 
        sessionKey := make([]byte, keySize)
147
 
        _, err = io.ReadFull(config.Random(), sessionKey)
148
 
        if err != nil {
149
 
                return
150
 
        }
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)
157
 
        if err != nil {
158
 
                return
159
 
        }
160
 
 
161
 
        key = sessionKey
162
 
        return
163
 
}