OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / crypto / openpgp / packet / symmetric_key_encrypted.go
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         "crypto/cipher"
10         "io"
11         "strconv"
12
13         "golang.org/x/crypto/openpgp/errors"
14         "golang.org/x/crypto/openpgp/s2k"
15 )
16
17 // This is the largest session key that we'll support. Since no 512-bit cipher
18 // has even been seriously used, this is comfortably large.
19 const maxSessionKeySizeInBytes = 64
20
21 // SymmetricKeyEncrypted represents a passphrase protected session key. See RFC
22 // 4880, section 5.3.
23 type SymmetricKeyEncrypted struct {
24         CipherFunc   CipherFunction
25         s2k          func(out, in []byte)
26         encryptedKey []byte
27 }
28
29 const symmetricKeyEncryptedVersion = 4
30
31 func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error {
32         // RFC 4880, section 5.3.
33         var buf [2]byte
34         if _, err := readFull(r, buf[:]); err != nil {
35                 return err
36         }
37         if buf[0] != symmetricKeyEncryptedVersion {
38                 return errors.UnsupportedError("SymmetricKeyEncrypted version")
39         }
40         ske.CipherFunc = CipherFunction(buf[1])
41
42         if ske.CipherFunc.KeySize() == 0 {
43                 return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1])))
44         }
45
46         var err error
47         ske.s2k, err = s2k.Parse(r)
48         if err != nil {
49                 return err
50         }
51
52         encryptedKey := make([]byte, maxSessionKeySizeInBytes)
53         // The session key may follow. We just have to try and read to find
54         // out. If it exists then we limit it to maxSessionKeySizeInBytes.
55         n, err := readFull(r, encryptedKey)
56         if err != nil && err != io.ErrUnexpectedEOF {
57                 return err
58         }
59
60         if n != 0 {
61                 if n == maxSessionKeySizeInBytes {
62                         return errors.UnsupportedError("oversized encrypted session key")
63                 }
64                 ske.encryptedKey = encryptedKey[:n]
65         }
66
67         return nil
68 }
69
70 // Decrypt attempts to decrypt an encrypted session key and returns the key and
71 // the cipher to use when decrypting a subsequent Symmetrically Encrypted Data
72 // packet.
73 func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunction, error) {
74         key := make([]byte, ske.CipherFunc.KeySize())
75         ske.s2k(key, passphrase)
76
77         if len(ske.encryptedKey) == 0 {
78                 return key, ske.CipherFunc, nil
79         }
80
81         // the IV is all zeros
82         iv := make([]byte, ske.CipherFunc.blockSize())
83         c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv)
84         plaintextKey := make([]byte, len(ske.encryptedKey))
85         c.XORKeyStream(plaintextKey, ske.encryptedKey)
86         cipherFunc := CipherFunction(plaintextKey[0])
87         if cipherFunc.blockSize() == 0 {
88                 return nil, ske.CipherFunc, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
89         }
90         plaintextKey = plaintextKey[1:]
91         if l := len(plaintextKey); l == 0 || l%cipherFunc.blockSize() != 0 {
92                 return nil, cipherFunc, errors.StructuralError("length of decrypted key not a multiple of block size")
93         }
94
95         return plaintextKey, cipherFunc, nil
96 }
97
98 // SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w. The
99 // packet contains a random session key, encrypted by a key derived from the
100 // given passphrase. The session key is returned and must be passed to
101 // SerializeSymmetricallyEncrypted.
102 // If config is nil, sensible defaults will be used.
103 func SerializeSymmetricKeyEncrypted(w io.Writer, passphrase []byte, config *Config) (key []byte, err error) {
104         cipherFunc := config.Cipher()
105         keySize := cipherFunc.KeySize()
106         if keySize == 0 {
107                 return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
108         }
109
110         s2kBuf := new(bytes.Buffer)
111         keyEncryptingKey := make([]byte, keySize)
112         // s2k.Serialize salts and stretches the passphrase, and writes the
113         // resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf.
114         err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase, &s2k.Config{Hash: config.Hash(), S2KCount: config.PasswordHashIterations()})
115         if err != nil {
116                 return
117         }
118         s2kBytes := s2kBuf.Bytes()
119
120         packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize
121         err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength)
122         if err != nil {
123                 return
124         }
125
126         var buf [2]byte
127         buf[0] = symmetricKeyEncryptedVersion
128         buf[1] = byte(cipherFunc)
129         _, err = w.Write(buf[:])
130         if err != nil {
131                 return
132         }
133         _, err = w.Write(s2kBytes)
134         if err != nil {
135                 return
136         }
137
138         sessionKey := make([]byte, keySize)
139         _, err = io.ReadFull(config.Random(), sessionKey)
140         if err != nil {
141                 return
142         }
143         iv := make([]byte, cipherFunc.blockSize())
144         c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv)
145         encryptedCipherAndKey := make([]byte, keySize+1)
146         c.XORKeyStream(encryptedCipherAndKey, buf[1:])
147         c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey)
148         _, err = w.Write(encryptedCipherAndKey)
149         if err != nil {
150                 return
151         }
152
153         key = sessionKey
154         return
155 }