Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1461)

Delta Between Two Patch Sets: openpgp/packet/symmetric_key_encrypted.go

Issue 5564059: code review 5564059: go.crypto: initial code (Closed)
Left Patch Set: Created 12 years, 2 months ago
Right Patch Set: diff -r b50a7fb49394 https://code.google.com/p/go.crypto Created 12 years, 2 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « openpgp/packet/signature_test.go ('k') | openpgp/packet/symmetric_key_encrypted_test.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
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 sess ion 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: " + strc onv.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 n ot 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 func SerializeSymmetricKeyEncrypted(w io.Writer, rand io.Reader, passphrase []by te, cipherFunc CipherFunction) (key []byte, err error) {
111 keySize := cipherFunc.KeySize()
112 if keySize == 0 {
113 return nil, errors.UnsupportedError("unknown cipher: " + strconv .Itoa(int(cipherFunc)))
114 }
115
116 s2kBuf := new(bytes.Buffer)
117 keyEncryptingKey := make([]byte, keySize)
118 // s2k.Serialize salts and stretches the passphrase, and writes the
119 // resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf.
120 err = s2k.Serialize(s2kBuf, keyEncryptingKey, rand, passphrase)
121 if err != nil {
122 return
123 }
124 s2kBytes := s2kBuf.Bytes()
125
126 packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + k eySize
127 err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength)
128 if err != nil {
129 return
130 }
131
132 var buf [2]byte
133 buf[0] = symmetricKeyEncryptedVersion
134 buf[1] = byte(cipherFunc)
135 _, err = w.Write(buf[:])
136 if err != nil {
137 return
138 }
139 _, err = w.Write(s2kBytes)
140 if err != nil {
141 return
142 }
143
144 sessionKey := make([]byte, keySize)
145 _, err = io.ReadFull(rand, sessionKey)
146 if err != nil {
147 return
148 }
149 iv := make([]byte, cipherFunc.blockSize())
150 c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv)
151 encryptedCipherAndKey := make([]byte, keySize+1)
152 c.XORKeyStream(encryptedCipherAndKey, buf[1:])
153 c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey)
154 _, err = w.Write(encryptedCipherAndKey)
155 if err != nil {
156 return
157 }
158
159 key = sessionKey
160 return
161 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b