diff --git a/openpgp/packet/symmetric_key_encrypted.go b/openpgp/packet/symmetric_key_encrypted.go index a78344f..30d02b2 100644 --- a/openpgp/packet/symmetric_key_encrypted.go +++ b/openpgp/packet/symmetric_key_encrypted.go @@ -6,11 +6,12 @@ package packet import ( "bytes" - "code.google.com/p/go.crypto/openpgp/errors" - "code.google.com/p/go.crypto/openpgp/s2k" "crypto/cipher" "io" "strconv" + + "code.google.com/p/go.crypto/openpgp/errors" + "code.google.com/p/go.crypto/openpgp/s2k" ) // 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 keyEncryptingKey := make([]byte, keySize) // s2k.Serialize salts and stretches the passphrase, and writes the // resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf. - err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase) + err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase, &s2k.Config{Hash: config.Hash()}) if err != nil { return } diff --git a/openpgp/s2k/s2k.go b/openpgp/s2k/s2k.go index aab3041..cf06a25 100644 --- a/openpgp/s2k/s2k.go +++ b/openpgp/s2k/s2k.go @@ -7,13 +7,33 @@ package s2k import ( - "code.google.com/p/go.crypto/openpgp/errors" "crypto" "hash" "io" "strconv" + + "code.google.com/p/go.crypto/openpgp/errors" ) +// Config collects configuration parameters for s2k key-stretching +// transformatioms. A nil *Config is valid and results in all default +// values. Currently, Config is used only by the Serialize function in +// this package. +type Config struct { + // Hash is the default hash function to be used. If + // nil, SHA1 is used. + Hash crypto.Hash +} + +func (c *Config) hash() crypto.Hash { + if c == nil || uint(c.Hash) == 0 { + // SHA1 is the historical default in this package. + return crypto.SHA1 + } + + return c.Hash +} + // Simple writes to out the result of computing the Simple S2K function (RFC // 4880, section 3.7.1.1) using the given hash and input passphrase. 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) { return nil, errors.UnsupportedError("S2K function") } -// Serialize salts and stretches the given passphrase and writes the resulting -// key into key. It also serializes an S2K descriptor to w. -func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte) error { +// Serialize salts and stretches the given passphrase and writes the +// resulting key into key. It also serializes an S2K descriptor to +// w. The key stretching can be configured with c, which may be +// nil. In that case, sensible defaults will be used. +func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Config) error { var buf [11]byte buf[0] = 3 /* iterated and salted */ - buf[1], _ = HashToHashId(crypto.SHA1) + buf[1], _ = HashToHashId(c.hash()) salt := buf[2:10] if _, err := io.ReadFull(rand, salt); err != nil { return err @@ -142,7 +164,7 @@ func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte) error return err } - Iterated(key, crypto.SHA1.New(), passphrase, salt, count) + Iterated(key, c.hash().New(), passphrase, salt, count) return nil } diff --git a/openpgp/s2k/s2k_test.go b/openpgp/s2k/s2k_test.go index 4898828..ed2255d 100644 --- a/openpgp/s2k/s2k_test.go +++ b/openpgp/s2k/s2k_test.go @@ -6,10 +6,16 @@ package s2k import ( "bytes" + "crypto" + _ "crypto/md5" "crypto/rand" "crypto/sha1" + _ "crypto/sha256" + _ "crypto/sha512" "encoding/hex" "testing" + + _ "code.google.com/p/go.crypto/ripemd160" ) var saltedTests = []struct { @@ -96,10 +102,20 @@ func TestParse(t *testing.T) { } func TestSerialize(t *testing.T) { + hashes := []crypto.Hash{crypto.MD5, crypto.SHA1, crypto.RIPEMD160, + crypto.SHA256, crypto.SHA384, crypto.SHA512, crypto.SHA224} + for _, h := range hashes { + testSerializeConfig(t, &Config{Hash: h}) + } +} + +func testSerializeConfig(t *testing.T, c *Config) { + t.Logf("Running testSerializeConfig() with config: %+v", c) + buf := bytes.NewBuffer(nil) key := make([]byte, 16) passphrase := []byte("testing") - err := Serialize(buf, key, rand.Reader, passphrase) + err := Serialize(buf, key, rand.Reader, passphrase, c) if err != nil { t.Errorf("failed to serialize: %s", err) return