Skip to content

Commit 0c93e1f

Browse files
committedSep 30, 2015
golang.org/x/crypto/openssh: don't loop forever after a bad password.
SymmetricKeyEncrypted cached the results of decryption so, if a bad password was given, ReadMessage would prompt forever because a later, correct password wouldn't override the cached decryption. The SymmetricKeyEncrypted object can't know whether a given passphrase is correct so it should never have been a mutable object in the first place. This change makes it so that it doesn't cache anything. Fixes #9315 Change-Id: Ic2b75f7f60a575e2182ac7e5c5d4198597c5d0a2 Reviewed-on: https://go-review.googlesource.com/14038 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Adam Langley <agl@golang.org>
1 parent 59a4410 commit 0c93e1f

File tree

4 files changed

+48
-50
lines changed

4 files changed

+48
-50
lines changed
 

‎openpgp/packet/symmetric_key_encrypted.go

+28-37
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,17 @@ const maxSessionKeySizeInBytes = 64
2222
// 4880, section 5.3.
2323
type SymmetricKeyEncrypted struct {
2424
CipherFunc CipherFunction
25-
Encrypted bool
26-
Key []byte // Empty unless Encrypted is false.
2725
s2k func(out, in []byte)
2826
encryptedKey []byte
2927
}
3028

3129
const symmetricKeyEncryptedVersion = 4
3230

33-
func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err error) {
31+
func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error {
3432
// RFC 4880, section 5.3.
3533
var buf [2]byte
36-
_, err = readFull(r, buf[:])
37-
if err != nil {
38-
return
34+
if _, err := readFull(r, buf[:]); err != nil {
35+
return err
3936
}
4037
if buf[0] != symmetricKeyEncryptedVersion {
4138
return errors.UnsupportedError("SymmetricKeyEncrypted version")
@@ -46,62 +43,56 @@ func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err error) {
4643
return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1])))
4744
}
4845

46+
var err error
4947
ske.s2k, err = s2k.Parse(r)
5048
if err != nil {
51-
return
49+
return err
5250
}
5351

5452
encryptedKey := make([]byte, maxSessionKeySizeInBytes)
5553
// The session key may follow. We just have to try and read to find
5654
// out. If it exists then we limit it to maxSessionKeySizeInBytes.
5755
n, err := readFull(r, encryptedKey)
5856
if err != nil && err != io.ErrUnexpectedEOF {
59-
return
57+
return err
6058
}
61-
err = nil
59+
6260
if n != 0 {
6361
if n == maxSessionKeySizeInBytes {
6462
return errors.UnsupportedError("oversized encrypted session key")
6563
}
6664
ske.encryptedKey = encryptedKey[:n]
6765
}
6866

69-
ske.Encrypted = true
70-
71-
return
67+
return nil
7268
}
7369

74-
// Decrypt attempts to decrypt an encrypted session key. If it returns nil,
75-
// ske.Key will contain the session key.
76-
func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) error {
77-
if !ske.Encrypted {
78-
return nil
79-
}
80-
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) {
8174
key := make([]byte, ske.CipherFunc.KeySize())
8275
ske.s2k(key, passphrase)
8376

8477
if len(ske.encryptedKey) == 0 {
85-
ske.Key = key
86-
} else {
87-
// the IV is all zeros
88-
iv := make([]byte, ske.CipherFunc.blockSize())
89-
c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv)
90-
c.XORKeyStream(ske.encryptedKey, ske.encryptedKey)
91-
ske.CipherFunc = CipherFunction(ske.encryptedKey[0])
92-
if ske.CipherFunc.blockSize() == 0 {
93-
return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(ske.CipherFunc)))
94-
}
95-
ske.CipherFunc = CipherFunction(ske.encryptedKey[0])
96-
ske.Key = ske.encryptedKey[1:]
97-
if len(ske.Key)%ske.CipherFunc.blockSize() != 0 {
98-
ske.Key = nil
99-
return errors.StructuralError("length of decrypted key not a multiple of block size")
100-
}
78+
return key, ske.CipherFunc, nil
10179
}
10280

103-
ske.Encrypted = false
104-
return nil
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(ske.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
10596
}
10697

10798
// SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w. The

‎openpgp/packet/symmetric_key_encrypted_test.go

+10-9
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ func TestSymmetricKeyEncrypted(t *testing.T) {
2424
t.Error("didn't find SymmetricKeyEncrypted packet")
2525
return
2626
}
27-
err = ske.Decrypt([]byte("password"))
27+
key, cipherFunc, err := ske.Decrypt([]byte("password"))
2828
if err != nil {
2929
t.Error(err)
3030
return
@@ -40,7 +40,7 @@ func TestSymmetricKeyEncrypted(t *testing.T) {
4040
t.Error("didn't find SymmetricallyEncrypted packet")
4141
return
4242
}
43-
r, err := se.Decrypt(ske.CipherFunc, ske.Key)
43+
r, err := se.Decrypt(cipherFunc, key)
4444
if err != nil {
4545
t.Error(err)
4646
return
@@ -64,8 +64,9 @@ const symmetricallyEncryptedContentsHex = "cb1062004d14c4df636f6e74656e74732e0a"
6464
func TestSerializeSymmetricKeyEncrypted(t *testing.T) {
6565
buf := bytes.NewBuffer(nil)
6666
passphrase := []byte("testing")
67+
const cipherFunc = CipherAES128
6768
config := &Config{
68-
DefaultCipher: CipherAES128,
69+
DefaultCipher: cipherFunc,
6970
}
7071

7172
key, err := SerializeSymmetricKeyEncrypted(buf, passphrase, config)
@@ -85,18 +86,18 @@ func TestSerializeSymmetricKeyEncrypted(t *testing.T) {
8586
return
8687
}
8788

88-
if !ske.Encrypted {
89-
t.Errorf("SKE not encrypted but should be")
90-
}
9189
if ske.CipherFunc != config.DefaultCipher {
9290
t.Errorf("SKE cipher function is %d (expected %d)", ske.CipherFunc, config.DefaultCipher)
9391
}
94-
err = ske.Decrypt(passphrase)
92+
parsedKey, parsedCipherFunc, err := ske.Decrypt(passphrase)
9593
if err != nil {
9694
t.Errorf("failed to decrypt reparsed SKE: %s", err)
9795
return
9896
}
99-
if !bytes.Equal(key, ske.Key) {
100-
t.Errorf("keys don't match after Decrpyt: %x (original) vs %x (parsed)", key, ske.Key)
97+
if !bytes.Equal(key, parsedKey) {
98+
t.Errorf("keys don't match after Decrypt: %x (original) vs %x (parsed)", key, parsedKey)
99+
}
100+
if parsedCipherFunc != cipherFunc {
101+
t.Errorf("cipher function doesn't match after Decrypt: %d (original) vs %d (parsed)", cipherFunc, parsedCipherFunc)
101102
}
102103
}

‎openpgp/read.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,9 @@ FindKey:
196196
// Try the symmetric passphrase first
197197
if len(symKeys) != 0 && passphrase != nil {
198198
for _, s := range symKeys {
199-
err = s.Decrypt(passphrase)
200-
if err == nil && !s.Encrypted {
201-
decrypted, err = se.Decrypt(s.CipherFunc, s.Key)
199+
key, cipherFunc, err := s.Decrypt(passphrase)
200+
if err == nil {
201+
decrypted, err = se.Decrypt(cipherFunc, key)
202202
if err != nil && err != errors.ErrKeyIncorrect {
203203
return nil, err
204204
}

‎openpgp/read_test.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ func TestUnspecifiedRecipient(t *testing.T) {
243243
}
244244

245245
func TestSymmetricallyEncrypted(t *testing.T) {
246-
expected := "Symmetrically encrypted.\n"
246+
firstTimeCalled := true
247247

248248
prompt := func(keys []Key, symmetric bool) ([]byte, error) {
249249
if len(keys) != 0 {
@@ -254,6 +254,11 @@ func TestSymmetricallyEncrypted(t *testing.T) {
254254
t.Errorf("symmetric is not set")
255255
}
256256

257+
if firstTimeCalled {
258+
firstTimeCalled = false
259+
return []byte("wrongpassword"), nil
260+
}
261+
257262
return []byte("password"), nil
258263
}
259264

@@ -273,6 +278,7 @@ func TestSymmetricallyEncrypted(t *testing.T) {
273278
t.Errorf("LiteralData.Time is %d, want %d", md.LiteralData.Time, expectedCreationTime)
274279
}
275280

281+
const expected = "Symmetrically encrypted.\n"
276282
if string(contents) != expected {
277283
t.Errorf("contents got: %s want: %s", string(contents), expected)
278284
}

0 commit comments

Comments
 (0)