Skip to content

Commit c24604d

Browse files
mareteagl
authored andcommitted
go.crypto/openpgp: Allow configuration of s2k hash during encryption.
This patch/CL allows the user to configure the hash function used in the s2k key-stretching transformation during encryption. It fixes the current limitation in which SHA1 is hard-coded for that task. With this change, packet.Config.DefaultHash is used by default for the mode 3 s2k key-stretching that is currently used for encryption, but the user may choose any other valid openpgp hash by passing a new (possibly nil) pointer argument to s2k.Serialize(). Note that this change introduces an API change to s2k.Serialize() in the form of an additional argument. However, the s2k package is a low-level facility that (as far as I could tell) is used directly by go.crypto/openpgp only. The CL comes with an modified test to check the use and decoding of all the valid hash functions with regard to s2k.Serialize(). This patch should be followed by one that allows the user to configure the iteration count in mode 3 s2k, and it is a prerequisite for that forthcoming change. R=golang-codereviews, agl CC=agl, golang-codereviews https://golang.org/cl/160110045
1 parent 3e22713 commit c24604d

File tree

3 files changed

+49
-10
lines changed

3 files changed

+49
-10
lines changed

openpgp/packet/symmetric_key_encrypted.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ package packet
66

77
import (
88
"bytes"
9-
"code.google.com/p/go.crypto/openpgp/errors"
10-
"code.google.com/p/go.crypto/openpgp/s2k"
119
"crypto/cipher"
1210
"io"
1311
"strconv"
12+
13+
"code.google.com/p/go.crypto/openpgp/errors"
14+
"code.google.com/p/go.crypto/openpgp/s2k"
1415
)
1516

1617
// This is the largest session key that we'll support. Since no 512-bit cipher
@@ -119,7 +120,7 @@ func SerializeSymmetricKeyEncrypted(w io.Writer, passphrase []byte, config *Conf
119120
keyEncryptingKey := make([]byte, keySize)
120121
// s2k.Serialize salts and stretches the passphrase, and writes the
121122
// resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf.
122-
err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase)
123+
err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase, &s2k.Config{Hash: config.Hash()})
123124
if err != nil {
124125
return
125126
}

openpgp/s2k/s2k.go

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,33 @@
77
package s2k
88

99
import (
10-
"code.google.com/p/go.crypto/openpgp/errors"
1110
"crypto"
1211
"hash"
1312
"io"
1413
"strconv"
14+
15+
"code.google.com/p/go.crypto/openpgp/errors"
1516
)
1617

18+
// Config collects configuration parameters for s2k key-stretching
19+
// transformatioms. A nil *Config is valid and results in all default
20+
// values. Currently, Config is used only by the Serialize function in
21+
// this package.
22+
type Config struct {
23+
// Hash is the default hash function to be used. If
24+
// nil, SHA1 is used.
25+
Hash crypto.Hash
26+
}
27+
28+
func (c *Config) hash() crypto.Hash {
29+
if c == nil || uint(c.Hash) == 0 {
30+
// SHA1 is the historical default in this package.
31+
return crypto.SHA1
32+
}
33+
34+
return c.Hash
35+
}
36+
1737
// Simple writes to out the result of computing the Simple S2K function (RFC
1838
// 4880, section 3.7.1.1) using the given hash and input passphrase.
1939
func Simple(out []byte, h hash.Hash, in []byte) {
@@ -126,12 +146,14 @@ func Parse(r io.Reader) (f func(out, in []byte), err error) {
126146
return nil, errors.UnsupportedError("S2K function")
127147
}
128148

129-
// Serialize salts and stretches the given passphrase and writes the resulting
130-
// key into key. It also serializes an S2K descriptor to w.
131-
func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte) error {
149+
// Serialize salts and stretches the given passphrase and writes the
150+
// resulting key into key. It also serializes an S2K descriptor to
151+
// w. The key stretching can be configured with c, which may be
152+
// nil. In that case, sensible defaults will be used.
153+
func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Config) error {
132154
var buf [11]byte
133155
buf[0] = 3 /* iterated and salted */
134-
buf[1], _ = HashToHashId(crypto.SHA1)
156+
buf[1], _ = HashToHashId(c.hash())
135157
salt := buf[2:10]
136158
if _, err := io.ReadFull(rand, salt); err != nil {
137159
return err
@@ -142,7 +164,7 @@ func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte) error
142164
return err
143165
}
144166

145-
Iterated(key, crypto.SHA1.New(), passphrase, salt, count)
167+
Iterated(key, c.hash().New(), passphrase, salt, count)
146168
return nil
147169
}
148170

openpgp/s2k/s2k_test.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,16 @@ package s2k
66

77
import (
88
"bytes"
9+
"crypto"
10+
_ "crypto/md5"
911
"crypto/rand"
1012
"crypto/sha1"
13+
_ "crypto/sha256"
14+
_ "crypto/sha512"
1115
"encoding/hex"
1216
"testing"
17+
18+
_ "code.google.com/p/go.crypto/ripemd160"
1319
)
1420

1521
var saltedTests = []struct {
@@ -96,10 +102,20 @@ func TestParse(t *testing.T) {
96102
}
97103

98104
func TestSerialize(t *testing.T) {
105+
hashes := []crypto.Hash{crypto.MD5, crypto.SHA1, crypto.RIPEMD160,
106+
crypto.SHA256, crypto.SHA384, crypto.SHA512, crypto.SHA224}
107+
for _, h := range hashes {
108+
testSerializeConfig(t, &Config{Hash: h})
109+
}
110+
}
111+
112+
func testSerializeConfig(t *testing.T, c *Config) {
113+
t.Logf("Running testSerializeConfig() with config: %+v", c)
114+
99115
buf := bytes.NewBuffer(nil)
100116
key := make([]byte, 16)
101117
passphrase := []byte("testing")
102-
err := Serialize(buf, key, rand.Reader, passphrase)
118+
err := Serialize(buf, key, rand.Reader, passphrase, c)
103119
if err != nil {
104120
t.Errorf("failed to serialize: %s", err)
105121
return

0 commit comments

Comments
 (0)