This patch allows the user to choose the strength of the passphrase mangling during the process in which the key is produced from the passphrase. It only affects symmetric encryption. Unmodified code that calls openpgp.SymmetricallyEncrypt() will continue to get the now-default count of 65536. Otherwise, a count in the range [1024, 65011712] may be configured. Illegal values in and outside this range will silently be rounded up to legal values within the said range. The test to s2k.Serialize() has been modified to test a variety of non-default counts with all the valid hashes and ensure that the decoding component of s2k can parse and decrypt the result. Additional testing has been done with GPG to ensure that the latter can parse and decrypt files encrypted/encoded with various counts. LGTM=agl R=golang-codereviews, agl CC=golang-codereviews https://golang.org/cl/176080043
138 lines
3.2 KiB
Go
138 lines
3.2 KiB
Go
// Copyright 2011 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package s2k
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto"
|
|
_ "crypto/md5"
|
|
"crypto/rand"
|
|
"crypto/sha1"
|
|
_ "crypto/sha256"
|
|
_ "crypto/sha512"
|
|
"encoding/hex"
|
|
"testing"
|
|
|
|
_ "golang.org/x/crypto/ripemd160"
|
|
)
|
|
|
|
var saltedTests = []struct {
|
|
in, out string
|
|
}{
|
|
{"hello", "10295ac1"},
|
|
{"world", "ac587a5e"},
|
|
{"foo", "4dda8077"},
|
|
{"bar", "bd8aac6b9ea9cae04eae6a91c6133b58b5d9a61c14f355516ed9370456"},
|
|
{"x", "f1d3f289"},
|
|
{"xxxxxxxxxxxxxxxxxxxxxxx", "e00d7b45"},
|
|
}
|
|
|
|
func TestSalted(t *testing.T) {
|
|
h := sha1.New()
|
|
salt := [4]byte{1, 2, 3, 4}
|
|
|
|
for i, test := range saltedTests {
|
|
expected, _ := hex.DecodeString(test.out)
|
|
out := make([]byte, len(expected))
|
|
Salted(out, h, []byte(test.in), salt[:])
|
|
if !bytes.Equal(expected, out) {
|
|
t.Errorf("#%d, got: %x want: %x", i, out, expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
var iteratedTests = []struct {
|
|
in, out string
|
|
}{
|
|
{"hello", "83126105"},
|
|
{"world", "6fa317f9"},
|
|
{"foo", "8fbc35b9"},
|
|
{"bar", "2af5a99b54f093789fd657f19bd245af7604d0f6ae06f66602a46a08ae"},
|
|
{"x", "5a684dfe"},
|
|
{"xxxxxxxxxxxxxxxxxxxxxxx", "18955174"},
|
|
}
|
|
|
|
func TestIterated(t *testing.T) {
|
|
h := sha1.New()
|
|
salt := [4]byte{4, 3, 2, 1}
|
|
|
|
for i, test := range iteratedTests {
|
|
expected, _ := hex.DecodeString(test.out)
|
|
out := make([]byte, len(expected))
|
|
Iterated(out, h, []byte(test.in), salt[:], 31)
|
|
if !bytes.Equal(expected, out) {
|
|
t.Errorf("#%d, got: %x want: %x", i, out, expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
var parseTests = []struct {
|
|
spec, in, out string
|
|
}{
|
|
/* Simple with SHA1 */
|
|
{"0002", "hello", "aaf4c61d"},
|
|
/* Salted with SHA1 */
|
|
{"01020102030405060708", "hello", "f4f7d67e"},
|
|
/* Iterated with SHA1 */
|
|
{"03020102030405060708f1", "hello", "f2a57b7c"},
|
|
}
|
|
|
|
func TestParse(t *testing.T) {
|
|
for i, test := range parseTests {
|
|
spec, _ := hex.DecodeString(test.spec)
|
|
buf := bytes.NewBuffer(spec)
|
|
f, err := Parse(buf)
|
|
if err != nil {
|
|
t.Errorf("%d: Parse returned error: %s", i, err)
|
|
continue
|
|
}
|
|
|
|
expected, _ := hex.DecodeString(test.out)
|
|
out := make([]byte, len(expected))
|
|
f(out, []byte(test.in))
|
|
if !bytes.Equal(out, expected) {
|
|
t.Errorf("%d: output got: %x want: %x", i, out, expected)
|
|
}
|
|
if testing.Short() {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSerialize(t *testing.T) {
|
|
hashes := []crypto.Hash{crypto.MD5, crypto.SHA1, crypto.RIPEMD160,
|
|
crypto.SHA256, crypto.SHA384, crypto.SHA512, crypto.SHA224}
|
|
testCounts := []int{-1, 0, 1024, 65536, 4063232, 65011712}
|
|
for _, h := range hashes {
|
|
for _, c := range testCounts {
|
|
testSerializeConfig(t, &Config{Hash: h, S2KCount: c})
|
|
}
|
|
}
|
|
}
|
|
|
|
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, c)
|
|
if err != nil {
|
|
t.Errorf("failed to serialize: %s", err)
|
|
return
|
|
}
|
|
|
|
f, err := Parse(buf)
|
|
if err != nil {
|
|
t.Errorf("failed to reparse: %s", err)
|
|
return
|
|
}
|
|
key2 := make([]byte, len(key))
|
|
f(key2, passphrase)
|
|
if !bytes.Equal(key2, key) {
|
|
t.Errorf("keys don't match: %x (serialied) vs %x (parsed)", key, key2)
|
|
}
|
|
}
|